diff --git a/.stats.yml b/.stats.yml index 47c2bce1cc..2814bb7778 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 55 +configured_endpoints: 62 diff --git a/README.md b/README.md index 3bdd6c4a43..84d9017e45 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ so that your API Key is not stored in source control. ### Polling Helpers -When interacting with the API some actions such as starting a Run may take time to complete. The SDK includes +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 which could benefit from polling there will be a corresponding version of the method ending in '\_and_poll'. @@ -69,6 +69,20 @@ run = client.beta.threads.runs.create_and_poll( 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 an interacting with vector stores, you can use the 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 the incoming events. diff --git a/api.md b/api.md index c772fb7c7b..962ed7b7c5 100644 --- a/api.md +++ b/api.md @@ -196,6 +196,59 @@ Methods: # Beta +## VectorStores + +Types: + +```python +from openai.types.beta import 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: @@ -207,9 +260,9 @@ from openai.types.beta import ( AssistantStreamEvent, AssistantTool, CodeInterpreterTool, + FileSearchTool, FunctionTool, MessageStreamEvent, - RetrievalTool, RunStepStreamEvent, RunStreamEvent, ThreadStreamEvent, @@ -218,26 +271,11 @@ from openai.types.beta import ( Methods: -- client.beta.assistants.create(\*\*params) -> Assistant -- client.beta.assistants.retrieve(assistant_id) -> Assistant -- client.beta.assistants.update(assistant_id, \*\*params) -> Assistant -- client.beta.assistants.list(\*\*params) -> SyncCursorPage[Assistant] -- client.beta.assistants.delete(assistant_id) -> AssistantDeleted - -### Files - -Types: - -```python -from openai.types.beta.assistants import AssistantFile, FileDeleteResponse -``` - -Methods: - -- client.beta.assistants.files.create(assistant_id, \*\*params) -> AssistantFile -- client.beta.assistants.files.retrieve(file_id, \*, assistant_id) -> AssistantFile -- client.beta.assistants.files.list(assistant_id, \*\*params) -> SyncCursorPage[AssistantFile] -- client.beta.assistants.files.delete(file_id, \*, assistant_id) -> FileDeleteResponse +- client.beta.assistants.create(\*\*params) -> Assistant +- client.beta.assistants.retrieve(assistant_id) -> Assistant +- client.beta.assistants.update(assistant_id, \*\*params) -> Assistant +- client.beta.assistants.list(\*\*params) -> SyncCursorPage[Assistant] +- client.beta.assistants.delete(assistant_id) -> AssistantDeleted ## Threads @@ -298,11 +336,11 @@ from openai.types.beta.threads.runs import ( CodeInterpreterOutputImage, CodeInterpreterToolCall, CodeInterpreterToolCallDelta, + FileSearchToolCall, + FileSearchToolCallDelta, FunctionToolCall, FunctionToolCallDelta, MessageCreationStepDetails, - RetrievalToolCall, - RetrievalToolCallDelta, RunStep, RunStepDelta, RunStepDeltaEvent, @@ -350,23 +388,10 @@ from openai.types.beta.threads import ( Methods: -- client.beta.threads.messages.create(thread_id, \*\*params) -> Message -- client.beta.threads.messages.retrieve(message_id, \*, thread_id) -> Message -- client.beta.threads.messages.update(message_id, \*, thread_id, \*\*params) -> Message -- client.beta.threads.messages.list(thread_id, \*\*params) -> SyncCursorPage[Message] - -#### Files - -Types: - -```python -from openai.types.beta.threads.messages import MessageFile -``` - -Methods: - -- client.beta.threads.messages.files.retrieve(file_id, \*, thread_id, message_id) -> MessageFile -- client.beta.threads.messages.files.list(message_id, \*, thread_id, \*\*params) -> SyncCursorPage[MessageFile] +- client.beta.threads.messages.create(thread_id, \*\*params) -> Message +- client.beta.threads.messages.retrieve(message_id, \*, thread_id) -> Message +- client.beta.threads.messages.update(message_id, \*, thread_id, \*\*params) -> Message +- client.beta.threads.messages.list(thread_id, \*\*params) -> SyncCursorPage[Message] # Batches diff --git a/helpers.md b/helpers.md index 4271cd9ede..cf738f3f16 100644 --- a/helpers.md +++ b/helpers.md @@ -213,3 +213,24 @@ def get_final_messages(self) -> List[Message] These methods are provided for convenience to collect information at the end of a stream. Calling these events will trigger consumption of the stream until completion and then return the relevant accumulated objects. + +# 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 which could benefit from polling there will be a corresponding version of the +method ending in `_and_poll`. + +All methods also allow you to set the polling frequency, how often the API is checked for an update, via a function argument (`poll_interval_ms`). + +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.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(...) +``` diff --git a/pyproject.toml b/pyproject.toml index 11ab55cbe9..6c3ae2b592 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,8 @@ dev-dependencies = [ "inline-snapshot >=0.7.0", "azure-identity >=1.14.1", "types-tqdm > 4", - "types-pyaudio > 0" + "types-pyaudio > 0", + "trio >=0.22.2" ] [tool.rye.scripts] diff --git a/requirements-dev.lock b/requirements-dev.lock index 4461f65738..657e6cb810 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -18,7 +18,9 @@ argcomplete==3.1.2 asttokens==2.4.1 # via inline-snapshot attrs==23.1.0 + # via outcome # via pytest + # via trio azure-core==1.30.1 # via azure-identity azure-identity==1.15.0 @@ -48,6 +50,7 @@ distro==1.8.0 # via openai exceptiongroup==1.1.3 # via anyio + # via trio executing==2.0.1 # via inline-snapshot filelock==3.12.4 @@ -63,6 +66,7 @@ idna==3.4 # via anyio # via httpx # via requests + # via trio importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -83,6 +87,8 @@ numpy==1.26.3 # via openai # via pandas # via pandas-stubs +outcome==1.3.0.post0 + # via trio packaging==23.2 # via black # via msal-extensions @@ -136,6 +142,9 @@ sniffio==1.3.0 # via anyio # via httpx # via openai + # via trio +sortedcontainers==2.4.0 + # via trio time-machine==2.9.0 toml==0.10.2 # via inline-snapshot @@ -145,6 +154,7 @@ tomli==2.0.1 # via pytest tqdm==4.66.1 # via openai +trio==0.22.2 types-pyaudio==0.2.16.20240106 types-pytz==2024.1.0.20240203 # via pandas-stubs diff --git a/src/openai/resources/beta/__init__.py b/src/openai/resources/beta/__init__.py index 87fea25267..01f5338757 100644 --- a/src/openai/resources/beta/__init__.py +++ b/src/openai/resources/beta/__init__.py @@ -24,8 +24,22 @@ 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/assistants.py b/src/openai/resources/beta/assistants.py similarity index 71% rename from src/openai/resources/beta/assistants/assistants.py rename to src/openai/resources/beta/assistants.py index 9e88794ebc..8695a949ca 100644 --- a/src/openai/resources/beta/assistants/assistants.py +++ b/src/openai/resources/beta/assistants.py @@ -2,38 +2,31 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal import httpx -from .... import _legacy_response -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import ( +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 SyncCursorPage, AsyncCursorPage -from ....types.beta import ( +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 ( Assistant, AssistantDeleted, AssistantToolParam, + AssistantResponseFormatOptionParam, assistant_list_params, assistant_create_params, assistant_update_params, ) -from ...._base_client import ( +from ..._base_client import ( AsyncPaginator, make_request_options, ) @@ -42,10 +35,6 @@ class Assistants(SyncAPIResource): - @cached_property - def files(self) -> Files: - return Files(self._client) - @cached_property def with_raw_response(self) -> AssistantsWithRawResponse: return AssistantsWithRawResponse(self) @@ -81,11 +70,14 @@ def create( ], ], description: Optional[str] | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[object] | NotGiven = NOT_GIVEN, name: Optional[str] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -105,10 +97,6 @@ def create( description: The description of the assistant. The maximum length is 512 characters. - file_ids: A list of [file](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. - instructions: The system instructions that the assistant uses. The maximum length is 256,000 characters. @@ -119,8 +107,39 @@ 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-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + + 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. + + tool_resources: 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. + tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `retrieval`, or `function`. + assistant. Tools can be of types `code_interpreter`, `file_search`, or + `function`. + + 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. extra_headers: Send extra headers @@ -130,18 +149,21 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( "/assistants", body=maybe_transform( { "model": model, "description": description, - "file_ids": file_ids, "instructions": instructions, "metadata": metadata, "name": name, + "response_format": response_format, + "temperature": temperature, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, }, assistant_create_params.AssistantCreateParams, ), @@ -176,7 +198,7 @@ def retrieve( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( f"/assistants/{assistant_id}", options=make_request_options( @@ -190,12 +212,15 @@ def update( assistant_id: str, *, description: Optional[str] | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[object] | NotGiven = NOT_GIVEN, model: str | NotGiven = NOT_GIVEN, name: Optional[str] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -210,12 +235,6 @@ def update( The maximum length is 512 characters. - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. If a - file was previously attached to the list but does not show up in the list, it - will be deleted from the assistant. - instructions: The system instructions that the assistant uses. The maximum length is 256,000 characters. @@ -232,8 +251,39 @@ def update( 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-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + + 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. + + tool_resources: 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. + tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `retrieval`, or `function`. + assistant. Tools can be of types `code_interpreter`, `file_search`, or + `function`. + + 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. extra_headers: Send extra headers @@ -245,18 +295,21 @@ def update( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/assistants/{assistant_id}", body=maybe_transform( { "description": description, - "file_ids": file_ids, "instructions": instructions, "metadata": metadata, "model": model, "name": name, + "response_format": response_format, + "temperature": temperature, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, }, assistant_update_params.AssistantUpdateParams, ), @@ -309,7 +362,7 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( "/assistants", page=SyncCursorPage[Assistant], @@ -356,7 +409,7 @@ def delete( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( f"/assistants/{assistant_id}", options=make_request_options( @@ -367,10 +420,6 @@ def delete( class AsyncAssistants(AsyncAPIResource): - @cached_property - def files(self) -> AsyncFiles: - return AsyncFiles(self._client) - @cached_property def with_raw_response(self) -> AsyncAssistantsWithRawResponse: return AsyncAssistantsWithRawResponse(self) @@ -406,11 +455,14 @@ async def create( ], ], description: Optional[str] | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[object] | NotGiven = NOT_GIVEN, name: Optional[str] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -430,10 +482,6 @@ async def create( description: The description of the assistant. The maximum length is 512 characters. - file_ids: A list of [file](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. - instructions: The system instructions that the assistant uses. The maximum length is 256,000 characters. @@ -444,8 +492,39 @@ 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-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + + 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. + + tool_resources: 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. + tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `retrieval`, or `function`. + assistant. Tools can be of types `code_interpreter`, `file_search`, or + `function`. + + 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. extra_headers: Send extra headers @@ -455,18 +534,21 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( "/assistants", body=await async_maybe_transform( { "model": model, "description": description, - "file_ids": file_ids, "instructions": instructions, "metadata": metadata, "name": name, + "response_format": response_format, + "temperature": temperature, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, }, assistant_create_params.AssistantCreateParams, ), @@ -501,7 +583,7 @@ async def retrieve( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( f"/assistants/{assistant_id}", options=make_request_options( @@ -515,12 +597,15 @@ async def update( assistant_id: str, *, description: Optional[str] | NotGiven = NOT_GIVEN, - file_ids: List[str] | NotGiven = NOT_GIVEN, instructions: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[object] | NotGiven = NOT_GIVEN, model: str | NotGiven = NOT_GIVEN, name: Optional[str] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -535,12 +620,6 @@ async def update( The maximum length is 512 characters. - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. If a - file was previously attached to the list but does not show up in the list, it - will be deleted from the assistant. - instructions: The system instructions that the assistant uses. The maximum length is 256,000 characters. @@ -557,8 +636,39 @@ async def update( 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-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + + 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. + + tool_resources: 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. + tools: A list of tool enabled on the assistant. There can be a maximum of 128 tools per - assistant. Tools can be of types `code_interpreter`, `retrieval`, or `function`. + assistant. Tools can be of types `code_interpreter`, `file_search`, or + `function`. + + 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. extra_headers: Send extra headers @@ -570,18 +680,21 @@ async def update( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/assistants/{assistant_id}", body=await async_maybe_transform( { "description": description, - "file_ids": file_ids, "instructions": instructions, "metadata": metadata, "model": model, "name": name, + "response_format": response_format, + "temperature": temperature, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, }, assistant_update_params.AssistantUpdateParams, ), @@ -634,7 +747,7 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( "/assistants", page=AsyncCursorPage[Assistant], @@ -681,7 +794,7 @@ async def delete( """ if not assistant_id: raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( f"/assistants/{assistant_id}", options=make_request_options( @@ -711,10 +824,6 @@ def __init__(self, assistants: Assistants) -> None: assistants.delete, ) - @cached_property - def files(self) -> FilesWithRawResponse: - return FilesWithRawResponse(self._assistants.files) - class AsyncAssistantsWithRawResponse: def __init__(self, assistants: AsyncAssistants) -> None: @@ -736,10 +845,6 @@ def __init__(self, assistants: AsyncAssistants) -> None: assistants.delete, ) - @cached_property - def files(self) -> AsyncFilesWithRawResponse: - return AsyncFilesWithRawResponse(self._assistants.files) - class AssistantsWithStreamingResponse: def __init__(self, assistants: Assistants) -> None: @@ -761,10 +866,6 @@ def __init__(self, assistants: Assistants) -> None: assistants.delete, ) - @cached_property - def files(self) -> FilesWithStreamingResponse: - return FilesWithStreamingResponse(self._assistants.files) - class AsyncAssistantsWithStreamingResponse: def __init__(self, assistants: AsyncAssistants) -> None: @@ -785,7 +886,3 @@ def __init__(self, assistants: AsyncAssistants) -> None: self.delete = async_to_streamed_response_wrapper( assistants.delete, ) - - @cached_property - def files(self) -> AsyncFilesWithStreamingResponse: - return AsyncFilesWithStreamingResponse(self._assistants.files) diff --git a/src/openai/resources/beta/assistants/__init__.py b/src/openai/resources/beta/assistants/__init__.py deleted file mode 100644 index 736def9388..0000000000 --- a/src/openai/resources/beta/assistants/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .assistants import ( - Assistants, - AsyncAssistants, - AssistantsWithRawResponse, - AsyncAssistantsWithRawResponse, - AssistantsWithStreamingResponse, - AsyncAssistantsWithStreamingResponse, -) - -__all__ = [ - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", - "Assistants", - "AsyncAssistants", - "AssistantsWithRawResponse", - "AsyncAssistantsWithRawResponse", - "AssistantsWithStreamingResponse", - "AsyncAssistantsWithStreamingResponse", -] diff --git a/src/openai/resources/beta/beta.py b/src/openai/resources/beta/beta.py index 67baad2716..0d9806678f 100644 --- a/src/openai/resources/beta/beta.py +++ b/src/openai/resources/beta/beta.py @@ -20,13 +20,25 @@ AsyncAssistantsWithStreamingResponse, ) from ..._resource import SyncAPIResource, AsyncAPIResource +from .vector_stores import ( + VectorStores, + AsyncVectorStores, + VectorStoresWithRawResponse, + AsyncVectorStoresWithRawResponse, + VectorStoresWithStreamingResponse, + AsyncVectorStoresWithStreamingResponse, +) from .threads.threads import Threads, AsyncThreads -from .assistants.assistants import Assistants, AsyncAssistants +from .vector_stores.vector_stores import VectorStores, AsyncVectorStores __all__ = ["Beta", "AsyncBeta"] class Beta(SyncAPIResource): + @cached_property + def vector_stores(self) -> VectorStores: + return VectorStores(self._client) + @cached_property def assistants(self) -> Assistants: return Assistants(self._client) @@ -45,6 +57,10 @@ def with_streaming_response(self) -> BetaWithStreamingResponse: class AsyncBeta(AsyncAPIResource): + @cached_property + def vector_stores(self) -> AsyncVectorStores: + return AsyncVectorStores(self._client) + @cached_property def assistants(self) -> AsyncAssistants: return AsyncAssistants(self._client) @@ -66,6 +82,10 @@ class BetaWithRawResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def vector_stores(self) -> VectorStoresWithRawResponse: + return VectorStoresWithRawResponse(self._beta.vector_stores) + @cached_property def assistants(self) -> AssistantsWithRawResponse: return AssistantsWithRawResponse(self._beta.assistants) @@ -79,6 +99,10 @@ class AsyncBetaWithRawResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @cached_property + def vector_stores(self) -> AsyncVectorStoresWithRawResponse: + return AsyncVectorStoresWithRawResponse(self._beta.vector_stores) + @cached_property def assistants(self) -> AsyncAssistantsWithRawResponse: return AsyncAssistantsWithRawResponse(self._beta.assistants) @@ -92,6 +116,10 @@ class BetaWithStreamingResponse: def __init__(self, beta: Beta) -> None: self._beta = beta + @cached_property + def vector_stores(self) -> VectorStoresWithStreamingResponse: + return VectorStoresWithStreamingResponse(self._beta.vector_stores) + @cached_property def assistants(self) -> AssistantsWithStreamingResponse: return AssistantsWithStreamingResponse(self._beta.assistants) @@ -105,6 +133,10 @@ class AsyncBetaWithStreamingResponse: def __init__(self, beta: AsyncBeta) -> None: self._beta = beta + @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/threads/messages/messages.py b/src/openai/resources/beta/threads/messages.py similarity index 88% rename from src/openai/resources/beta/threads/messages/messages.py rename to src/openai/resources/beta/threads/messages.py index bbce3e99e4..7a24b80dea 100644 --- a/src/openai/resources/beta/threads/messages/messages.py +++ b/src/openai/resources/beta/threads/messages.py @@ -2,43 +2,31 @@ from __future__ import annotations -from typing import List, Optional +from typing import Iterable, Optional from typing_extensions import Literal import httpx -from ..... import _legacy_response -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ....._utils import ( +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 SyncCursorPage, AsyncCursorPage -from ....._base_client import ( +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.beta.threads import Message, message_list_params, message_create_params, message_update_params +from ....types.beta.threads import Message, message_list_params, message_create_params, message_update_params __all__ = ["Messages", "AsyncMessages"] class Messages(SyncAPIResource): - @cached_property - def files(self) -> Files: - return Files(self._client) - @cached_property def with_raw_response(self) -> MessagesWithRawResponse: return MessagesWithRawResponse(self) @@ -53,7 +41,7 @@ def create( *, content: str, role: Literal["user", "assistant"], - file_ids: List[str] | NotGiven = NOT_GIVEN, + attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, metadata: Optional[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. @@ -76,10 +64,7 @@ def create( - `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation. - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. + 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 @@ -96,14 +81,14 @@ def create( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/messages", body=maybe_transform( { "content": content, "role": role, - "file_ids": file_ids, + "attachments": attachments, "metadata": metadata, }, message_create_params.MessageCreateParams, @@ -142,7 +127,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not message_id: raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( f"/threads/{thread_id}/messages/{message_id}", options=make_request_options( @@ -185,7 +170,7 @@ def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not message_id: raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/messages/{message_id}", body=maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), @@ -243,7 +228,7 @@ def list( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/messages", page=SyncCursorPage[Message], @@ -268,10 +253,6 @@ def list( class AsyncMessages(AsyncAPIResource): - @cached_property - def files(self) -> AsyncFiles: - return AsyncFiles(self._client) - @cached_property def with_raw_response(self) -> AsyncMessagesWithRawResponse: return AsyncMessagesWithRawResponse(self) @@ -286,7 +267,7 @@ async def create( *, content: str, role: Literal["user", "assistant"], - file_ids: List[str] | NotGiven = NOT_GIVEN, + attachments: Optional[Iterable[message_create_params.Attachment]] | NotGiven = NOT_GIVEN, metadata: Optional[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. @@ -309,10 +290,7 @@ async def create( - `assistant`: Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation. - file_ids: A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. + 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 @@ -329,14 +307,14 @@ async def create( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/messages", body=await async_maybe_transform( { "content": content, "role": role, - "file_ids": file_ids, + "attachments": attachments, "metadata": metadata, }, message_create_params.MessageCreateParams, @@ -375,7 +353,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not message_id: raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( f"/threads/{thread_id}/messages/{message_id}", options=make_request_options( @@ -418,7 +396,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not message_id: raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/messages/{message_id}", body=await async_maybe_transform({"metadata": metadata}, message_update_params.MessageUpdateParams), @@ -476,7 +454,7 @@ def list( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/messages", page=AsyncCursorPage[Message], @@ -517,10 +495,6 @@ def __init__(self, messages: Messages) -> None: messages.list, ) - @cached_property - def files(self) -> FilesWithRawResponse: - return FilesWithRawResponse(self._messages.files) - class AsyncMessagesWithRawResponse: def __init__(self, messages: AsyncMessages) -> None: @@ -539,10 +513,6 @@ def __init__(self, messages: AsyncMessages) -> None: messages.list, ) - @cached_property - def files(self) -> AsyncFilesWithRawResponse: - return AsyncFilesWithRawResponse(self._messages.files) - class MessagesWithStreamingResponse: def __init__(self, messages: Messages) -> None: @@ -561,10 +531,6 @@ def __init__(self, messages: Messages) -> None: messages.list, ) - @cached_property - def files(self) -> FilesWithStreamingResponse: - return FilesWithStreamingResponse(self._messages.files) - class AsyncMessagesWithStreamingResponse: def __init__(self, messages: AsyncMessages) -> None: @@ -582,7 +548,3 @@ def __init__(self, messages: AsyncMessages) -> None: self.list = async_to_streamed_response_wrapper( messages.list, ) - - @cached_property - def files(self) -> AsyncFilesWithStreamingResponse: - return AsyncFilesWithStreamingResponse(self._messages.files) diff --git a/src/openai/resources/beta/threads/messages/__init__.py b/src/openai/resources/beta/threads/messages/__init__.py deleted file mode 100644 index a3286e6ace..0000000000 --- a/src/openai/resources/beta/threads/messages/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .files import ( - Files, - AsyncFiles, - FilesWithRawResponse, - AsyncFilesWithRawResponse, - FilesWithStreamingResponse, - AsyncFilesWithStreamingResponse, -) -from .messages import ( - Messages, - AsyncMessages, - MessagesWithRawResponse, - AsyncMessagesWithRawResponse, - MessagesWithStreamingResponse, - AsyncMessagesWithStreamingResponse, -) - -__all__ = [ - "Files", - "AsyncFiles", - "FilesWithRawResponse", - "AsyncFilesWithRawResponse", - "FilesWithStreamingResponse", - "AsyncFilesWithStreamingResponse", - "Messages", - "AsyncMessages", - "MessagesWithRawResponse", - "AsyncMessagesWithRawResponse", - "MessagesWithStreamingResponse", - "AsyncMessagesWithStreamingResponse", -] diff --git a/src/openai/resources/beta/threads/messages/files.py b/src/openai/resources/beta/threads/messages/files.py deleted file mode 100644 index 349f99725e..0000000000 --- a/src/openai/resources/beta/threads/messages/files.py +++ /dev/null @@ -1,312 +0,0 @@ -# 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.beta.threads.messages import MessageFile, file_list_params - -__all__ = ["Files", "AsyncFiles"] - - -class Files(SyncAPIResource): - @cached_property - def with_raw_response(self) -> FilesWithRawResponse: - return FilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> FilesWithStreamingResponse: - return FilesWithStreamingResponse(self) - - def retrieve( - self, - file_id: str, - *, - thread_id: str, - message_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, - ) -> MessageFile: - """ - Retrieves a message 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 thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_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=v1", **(extra_headers or {})} - return self._get( - f"/threads/{thread_id}/messages/{message_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageFile, - ) - - def list( - self, - message_id: str, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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[MessageFile]: - """Returns a list of message 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. - - 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. - - 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 thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/messages/{message_id}/files", - page=SyncCursorPage[MessageFile], - 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, - }, - file_list_params.FileListParams, - ), - ), - model=MessageFile, - ) - - -class AsyncFiles(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncFilesWithRawResponse: - return AsyncFilesWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: - return AsyncFilesWithStreamingResponse(self) - - async def retrieve( - self, - file_id: str, - *, - thread_id: str, - message_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, - ) -> MessageFile: - """ - Retrieves a message 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 thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_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=v1", **(extra_headers or {})} - return await self._get( - f"/threads/{thread_id}/messages/{message_id}/files/{file_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageFile, - ) - - def list( - self, - message_id: str, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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[MessageFile, AsyncCursorPage[MessageFile]]: - """Returns a list of message 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. - - 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. - - 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 thread_id: - raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - if not message_id: - raise ValueError(f"Expected a non-empty value for `message_id` but received {message_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} - return self._get_api_list( - f"/threads/{thread_id}/messages/{message_id}/files", - page=AsyncCursorPage[MessageFile], - 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, - }, - file_list_params.FileListParams, - ), - ), - model=MessageFile, - ) - - -class FilesWithRawResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.retrieve = _legacy_response.to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.to_raw_response_wrapper( - files.list, - ) - - -class AsyncFilesWithRawResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.retrieve = _legacy_response.async_to_raw_response_wrapper( - files.retrieve, - ) - self.list = _legacy_response.async_to_raw_response_wrapper( - files.list, - ) - - -class FilesWithStreamingResponse: - def __init__(self, files: Files) -> None: - self._files = files - - self.retrieve = to_streamed_response_wrapper( - files.retrieve, - ) - self.list = to_streamed_response_wrapper( - files.list, - ) - - -class AsyncFilesWithStreamingResponse: - def __init__(self, files: AsyncFiles) -> None: - self._files = files - - self.retrieve = async_to_streamed_response_wrapper( - files.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - files.list, - ) diff --git a/src/openai/resources/beta/threads/runs/runs.py b/src/openai/resources/beta/threads/runs/runs.py index 9fa7239c0b..7aab17a30d 100644 --- a/src/openai/resources/beta/threads/runs/runs.py +++ b/src/openai/resources/beta/threads/runs/runs.py @@ -115,6 +115,7 @@ def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -196,6 +197,10 @@ def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -248,6 +253,7 @@ def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -329,6 +335,10 @@ def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -381,6 +391,7 @@ def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -462,6 +473,10 @@ def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -514,6 +529,7 @@ def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -524,7 +540,7 @@ def create( ) -> Run | Stream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/runs", body=maybe_transform( @@ -542,6 +558,7 @@ def create( "temperature": temperature, "tool_choice": tool_choice, "tools": tools, + "top_p": top_p, "truncation_strategy": truncation_strategy, }, run_create_params.RunCreateParams, @@ -582,7 +599,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( f"/threads/{thread_id}/runs/{run_id}", options=make_request_options( @@ -625,7 +642,7 @@ def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/runs/{run_id}", body=maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), @@ -680,7 +697,7 @@ def list( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/runs", page=SyncCursorPage[Run], @@ -730,7 +747,7 @@ def cancel( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/runs/{run_id}/cancel", options=make_request_options( @@ -778,6 +795,7 @@ def create_and_poll( 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, thread_id: str, @@ -810,6 +828,7 @@ def create_and_poll( stream=False, tools=tools, truncation_strategy=truncation_strategy, + top_p=top_p, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -866,6 +885,7 @@ def create_and_stream( 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, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -919,6 +939,7 @@ def create_and_stream( 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, thread_id: str, event_handler: AssistantEventHandlerT, @@ -972,6 +993,7 @@ def create_and_stream( 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, thread_id: str, event_handler: AssistantEventHandlerT | None = None, @@ -987,7 +1009,7 @@ def create_and_stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -1011,6 +1033,7 @@ def create_and_stream( "stream": True, "tools": tools, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, run_create_params.RunCreateParams, ), @@ -1108,6 +1131,7 @@ def stream( 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, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1160,6 +1184,7 @@ def stream( 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, thread_id: str, event_handler: AssistantEventHandlerT, @@ -1212,6 +1237,7 @@ def stream( 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, thread_id: str, event_handler: AssistantEventHandlerT | None = None, @@ -1227,7 +1253,7 @@ def stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -1251,6 +1277,7 @@ def stream( "stream": True, "tools": tools, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, run_create_params.RunCreateParams, ), @@ -1396,7 +1423,7 @@ def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", body=maybe_transform( @@ -1522,7 +1549,7 @@ def submit_tool_outputs_stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.submit_tool_outputs_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -1602,6 +1629,7 @@ async def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1683,6 +1711,10 @@ async def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1735,6 +1767,7 @@ async def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1816,6 +1849,10 @@ async def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1868,6 +1905,7 @@ async def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1949,6 +1987,10 @@ async def create( tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2001,6 +2043,7 @@ async def create( 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -2011,7 +2054,7 @@ async def create( ) -> Run | AsyncStream[AssistantStreamEvent]: if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/runs", body=await async_maybe_transform( @@ -2029,6 +2072,7 @@ async def create( "temperature": temperature, "tool_choice": tool_choice, "tools": tools, + "top_p": top_p, "truncation_strategy": truncation_strategy, }, run_create_params.RunCreateParams, @@ -2069,7 +2113,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( f"/threads/{thread_id}/runs/{run_id}", options=make_request_options( @@ -2112,7 +2156,7 @@ async def update( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/runs/{run_id}", body=await async_maybe_transform({"metadata": metadata}, run_update_params.RunUpdateParams), @@ -2167,7 +2211,7 @@ def list( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/runs", page=AsyncCursorPage[Run], @@ -2217,7 +2261,7 @@ async def cancel( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/runs/{run_id}/cancel", options=make_request_options( @@ -2265,6 +2309,7 @@ async def create_and_poll( 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, thread_id: str, @@ -2297,6 +2342,7 @@ async def create_and_poll( stream=False, tools=tools, truncation_strategy=truncation_strategy, + top_p=top_p, extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, @@ -2353,6 +2399,7 @@ def create_and_stream( 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, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2406,6 +2453,7 @@ def create_and_stream( 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, thread_id: str, event_handler: AsyncAssistantEventHandlerT, @@ -2459,6 +2507,7 @@ def create_and_stream( 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, thread_id: str, event_handler: AsyncAssistantEventHandlerT | None = None, @@ -2477,7 +2526,7 @@ def create_and_stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -2500,6 +2549,7 @@ def create_and_stream( "stream": True, "tools": tools, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, run_create_params.RunCreateParams, ), @@ -2597,6 +2647,7 @@ def stream( 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, thread_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2649,6 +2700,7 @@ def stream( 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, thread_id: str, event_handler: AsyncAssistantEventHandlerT, @@ -2701,6 +2753,7 @@ def stream( 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, thread_id: str, event_handler: AsyncAssistantEventHandlerT | None = None, @@ -2719,7 +2772,7 @@ def stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.create_and_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -2742,6 +2795,7 @@ def stream( "stream": True, "tools": tools, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, run_create_params.RunCreateParams, ), @@ -2887,7 +2941,7 @@ async def submit_tool_outputs( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}/runs/{run_id}/submit_tool_outputs", body=await async_maybe_transform( @@ -3016,7 +3070,7 @@ def submit_tool_outputs_stream( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.runs.submit_tool_outputs_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), diff --git a/src/openai/resources/beta/threads/runs/steps.py b/src/openai/resources/beta/threads/runs/steps.py index 118bd8822a..986ef2997a 100644 --- a/src/openai/resources/beta/threads/runs/steps.py +++ b/src/openai/resources/beta/threads/runs/steps.py @@ -62,7 +62,7 @@ def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") if not step_id: raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", options=make_request_options( @@ -119,7 +119,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/runs/{run_id}/steps", page=SyncCursorPage[RunStep], @@ -182,7 +182,7 @@ async def retrieve( raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") if not step_id: raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( f"/threads/{thread_id}/runs/{run_id}/steps/{step_id}", options=make_request_options( @@ -239,7 +239,7 @@ def list( raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") if not run_id: raise ValueError(f"Expected a non-empty value for `run_id` but received {run_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get_api_list( f"/threads/{thread_id}/runs/{run_id}/steps", page=AsyncCursorPage[RunStep], diff --git a/src/openai/resources/beta/threads/threads.py b/src/openai/resources/beta/threads/threads.py index 9c2e2f0043..678c621a10 100644 --- a/src/openai/resources/beta/threads/threads.py +++ b/src/openai/resources/beta/threads/threads.py @@ -57,7 +57,6 @@ AsyncAssistantEventHandlerT, AsyncAssistantStreamManager, ) -from .messages.messages import Messages, AsyncMessages from ....types.beta.threads import Run __all__ = ["Threads", "AsyncThreads"] @@ -85,6 +84,7 @@ def create( *, messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, metadata: Optional[object] | 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. extra_headers: Headers | None = None, @@ -104,6 +104,11 @@ def create( can be a maximum of 64 characters long and values can be a maxium of 512 characters long. + 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 + `code_interpreter` tool requires a list of file IDs, while the `file_search` + tool requires a list of vector store IDs. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -112,13 +117,14 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( "/threads", body=maybe_transform( { "messages": messages, "metadata": metadata, + "tool_resources": tool_resources, }, thread_create_params.ThreadCreateParams, ), @@ -153,7 +159,7 @@ def retrieve( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( f"/threads/{thread_id}", options=make_request_options( @@ -167,6 +173,7 @@ def update( thread_id: str, *, metadata: Optional[object] | 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. extra_headers: Headers | None = None, @@ -183,6 +190,11 @@ def update( can be a maximum of 64 characters long and values can be a maxium of 512 characters long. + 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 + `code_interpreter` tool requires a list of file IDs, while the `file_search` + tool requires a list of vector store IDs. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -193,10 +205,16 @@ def update( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( f"/threads/{thread_id}", - body=maybe_transform({"metadata": metadata}, thread_update_params.ThreadUpdateParams), + body=maybe_transform( + { + "metadata": metadata, + "tool_resources": tool_resources, + }, + thread_update_params.ThreadUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -228,7 +246,7 @@ def delete( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( f"/threads/{thread_id}", options=make_request_options( @@ -276,7 +294,9 @@ def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -299,13 +319,13 @@ def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -350,9 +370,18 @@ def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -402,7 +431,9 @@ def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -429,13 +460,13 @@ def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -476,9 +507,18 @@ def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -528,7 +568,9 @@ def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -555,13 +597,13 @@ def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -602,9 +644,18 @@ def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -654,7 +705,9 @@ def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -663,7 +716,7 @@ def create_and_run( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Run | Stream[AssistantStreamEvent]: - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._post( "/threads/runs", body=maybe_transform( @@ -679,7 +732,9 @@ def create_and_run( "temperature": temperature, "thread": thread, "tool_choice": tool_choice, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, "truncation_strategy": truncation_strategy, }, thread_create_and_run_params.ThreadCreateAndRunParams, @@ -729,7 +784,9 @@ def create_and_run_poll( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -755,8 +812,10 @@ def create_and_run_poll( temperature=temperature, stream=False, thread=thread, + tool_resources=tool_resources, tool_choice=tool_choice, truncation_strategy=truncation_strategy, + top_p=top_p, tools=tools, extra_headers=extra_headers, extra_query=extra_query, @@ -803,7 +862,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -853,7 +914,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -903,7 +966,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -915,7 +980,7 @@ def create_and_run_stream( ) -> AssistantStreamManager[AssistantEventHandler] | AssistantStreamManager[AssistantEventHandlerT]: """Create a thread and stream the run back""" extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.create_and_run_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -937,7 +1002,9 @@ def create_and_run_stream( "stream": True, "thread": thread, "tools": tools, + "tool": tool_resources, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, thread_create_and_run_params.ThreadCreateAndRunParams, ), @@ -973,6 +1040,7 @@ async def create( *, messages: Iterable[thread_create_params.Message] | NotGiven = NOT_GIVEN, metadata: Optional[object] | 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. extra_headers: Headers | None = None, @@ -992,6 +1060,11 @@ async def create( can be a maximum of 64 characters long and values can be a maxium of 512 characters long. + 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 + `code_interpreter` tool requires a list of file IDs, while the `file_search` + tool requires a list of vector store IDs. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1000,13 +1073,14 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( "/threads", body=await async_maybe_transform( { "messages": messages, "metadata": metadata, + "tool_resources": tool_resources, }, thread_create_params.ThreadCreateParams, ), @@ -1041,7 +1115,7 @@ async def retrieve( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( f"/threads/{thread_id}", options=make_request_options( @@ -1055,6 +1129,7 @@ async def update( thread_id: str, *, metadata: Optional[object] | 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. extra_headers: Headers | None = None, @@ -1071,6 +1146,11 @@ async def update( can be a maximum of 64 characters long and values can be a maxium of 512 characters long. + 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 + `code_interpreter` tool requires a list of file IDs, while the `file_search` + tool requires a list of vector store IDs. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1081,10 +1161,16 @@ async def update( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( f"/threads/{thread_id}", - body=await async_maybe_transform({"metadata": metadata}, thread_update_params.ThreadUpdateParams), + body=await async_maybe_transform( + { + "metadata": metadata, + "tool_resources": tool_resources, + }, + thread_update_params.ThreadUpdateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -1116,7 +1202,7 @@ async def delete( """ if not thread_id: raise ValueError(f"Expected a non-empty value for `thread_id` but received {thread_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( f"/threads/{thread_id}", options=make_request_options( @@ -1164,7 +1250,9 @@ async def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1187,13 +1275,13 @@ async def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -1238,9 +1326,18 @@ async def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1290,7 +1387,9 @@ async def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1317,13 +1416,13 @@ async def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -1364,9 +1463,18 @@ async def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1416,7 +1524,9 @@ async def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1443,13 +1553,13 @@ async def create_and_run( max_completion_tokens: The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. max_prompt_tokens: The maximum number of prompt tokens that may be used over the course of the run. The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -1490,9 +1600,18 @@ async def create_and_run( `{"type": "function", "function": {"name": "my_function"}}` forces the model to call that tool. + tool_resources: 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. + tools: Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. + 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. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1542,7 +1661,9 @@ async def create_and_run( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1551,7 +1672,7 @@ async def create_and_run( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Run | AsyncStream[AssistantStreamEvent]: - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._post( "/threads/runs", body=await async_maybe_transform( @@ -1567,7 +1688,9 @@ async def create_and_run( "temperature": temperature, "thread": thread, "tool_choice": tool_choice, + "tool_resources": tool_resources, "tools": tools, + "top_p": top_p, "truncation_strategy": truncation_strategy, }, thread_create_and_run_params.ThreadCreateAndRunParams, @@ -1617,7 +1740,9 @@ async def create_and_run_poll( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1643,8 +1768,10 @@ async def create_and_run_poll( temperature=temperature, stream=False, thread=thread, + tool_resources=tool_resources, tool_choice=tool_choice, truncation_strategy=truncation_strategy, + top_p=top_p, tools=tools, extra_headers=extra_headers, extra_query=extra_query, @@ -1693,7 +1820,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1743,7 +1872,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1793,7 +1924,9 @@ def create_and_run_stream( 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[thread_create_and_run_params.Tool]] | 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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1808,7 +1941,7 @@ def create_and_run_stream( ): """Create a thread and stream the run back""" extra_headers = { - "OpenAI-Beta": "assistants=v1", + "OpenAI-Beta": "assistants=v2", "X-Stainless-Stream-Helper": "threads.create_and_run_stream", "X-Stainless-Custom-Event-Handler": "true" if event_handler else "false", **(extra_headers or {}), @@ -1829,7 +1962,9 @@ def create_and_run_stream( "stream": True, "thread": thread, "tools": tools, + "tool": tool_resources, "truncation_strategy": truncation_strategy, + "top_p": top_p, }, thread_create_and_run_params.ThreadCreateAndRunParams, ), diff --git a/src/openai/resources/beta/vector_stores/__init__.py b/src/openai/resources/beta/vector_stores/__init__.py new file mode 100644 index 0000000000..96ae16c302 --- /dev/null +++ b/src/openai/resources/beta/vector_stores/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .files import ( + Files, + AsyncFiles, + FilesWithRawResponse, + AsyncFilesWithRawResponse, + FilesWithStreamingResponse, + AsyncFilesWithStreamingResponse, +) +from .file_batches import ( + FileBatches, + AsyncFileBatches, + FileBatchesWithRawResponse, + AsyncFileBatchesWithRawResponse, + FileBatchesWithStreamingResponse, + AsyncFileBatchesWithStreamingResponse, +) +from .vector_stores import ( + VectorStores, + AsyncVectorStores, + VectorStoresWithRawResponse, + AsyncVectorStoresWithRawResponse, + VectorStoresWithStreamingResponse, + AsyncVectorStoresWithStreamingResponse, +) + +__all__ = [ + "Files", + "AsyncFiles", + "FilesWithRawResponse", + "AsyncFilesWithRawResponse", + "FilesWithStreamingResponse", + "AsyncFilesWithStreamingResponse", + "FileBatches", + "AsyncFileBatches", + "FileBatchesWithRawResponse", + "AsyncFileBatchesWithRawResponse", + "FileBatchesWithStreamingResponse", + "AsyncFileBatchesWithStreamingResponse", + "VectorStores", + "AsyncVectorStores", + "VectorStoresWithRawResponse", + "AsyncVectorStoresWithRawResponse", + "VectorStoresWithStreamingResponse", + "AsyncVectorStoresWithStreamingResponse", +] diff --git a/src/openai/resources/beta/vector_stores/file_batches.py b/src/openai/resources/beta/vector_stores/file_batches.py new file mode 100644 index 0000000000..55b30b08e3 --- /dev/null +++ b/src/openai/resources/beta/vector_stores/file_batches.py @@ -0,0 +1,739 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import asyncio +from typing import List, Iterable +from typing_extensions import 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 ( + 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 ...._base_client import ( + AsyncPaginator, + make_request_options, +) +from ....types.beta.vector_stores import ( + VectorStoreFile, + VectorStoreFileBatch, + file_batch_create_params, + file_batch_list_files_params, +) + +__all__ = ["FileBatches", "AsyncFileBatches"] + + +class FileBatches(SyncAPIResource): + @cached_property + def with_raw_response(self) -> FileBatchesWithRawResponse: + return FileBatchesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> FileBatchesWithStreamingResponse: + return FileBatchesWithStreamingResponse(self) + + def create( + self, + vector_store_id: str, + *, + file_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, + ) -> VectorStoreFileBatch: + """ + 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. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the 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._post( + f"/vector_stores/{vector_store_id}/file_batches", + body=maybe_transform({"file_ids": file_ids}, file_batch_create_params.FileBatchCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + def retrieve( + self, + batch_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, + ) -> VectorStoreFileBatch: + """ + Retrieves a vector store file batch. + + 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 batch_id: + 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}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + def cancel( + self, + batch_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, + ) -> VectorStoreFileBatch: + """Cancel a vector store file batch. + + This attempts to cancel the processing of + files in this batch as soon as possible. + + 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 batch_id: + 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", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + def create_and_poll( + self, + vector_store_id: str, + *, + file_ids: List[str], + poll_interval_ms: int | 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, + ) + # TODO: don't poll unless necessary?? + return self.poll( + batch.id, + vector_store_id=vector_store_id, + poll_interval_ms=poll_interval_ms, + ) + + def list_files( + self, + 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, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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[VectorStoreFile]: + """ + Returns a list of vector store files in a batch. + + 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, + ending 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`. + + 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 vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not batch_id: + 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", + page=SyncCursorPage[VectorStoreFile], + 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, + "filter": filter, + "limit": limit, + "order": order, + }, + file_batch_list_files_params.FileBatchListFilesParams, + ), + ), + model=VectorStoreFile, + ) + + def poll( + self, + batch_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFileBatch: + """Wait for the given file batch to be processed. + + Note: this will return even if one of the files failed to process, you need to + check batch.file_counts.failed_count to handle this case. + """ + 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( + batch_id, + vector_store_id=vector_store_id, + extra_headers=headers, + ) + + batch = response.parse() + if batch.file_counts.in_progress > 0: + 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) + continue + + return batch + + def upload_and_poll( + self, + vector_store_id: str, + *, + files: Iterable[FileTypes], + max_concurrency: int = 5, + file_ids: List[str] = [], + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFileBatch: + """Uploads the given files concurrently and then creates a vector store file batch. + + If you've already uploaded certain files that you want to include in this batch + then you can pass their IDs through the `file_ids` argument. + + By default, if any file upload fails then an exception will be eagerly raised. + + The number of concurrency uploads is configurable using the `max_concurrency` + parameter. + + Note: this method only supports `asyncio` or `trio` as the backing async + runtime. + """ + results: list[FileObject] = [] + + with ThreadPoolExecutor(max_workers=max_concurrency) as executor: + futures: list[Future[FileObject]] = [ + executor.submit( + self._client.files.create, + file=file, + purpose="assistants", + ) + for file in files + ] + + for future in as_completed(futures): + exc = future.exception() + if exc: + raise exc + + results.append(future.result()) + + batch = self.create_and_poll( + vector_store_id=vector_store_id, + file_ids=[*file_ids, *(f.id for f in results)], + poll_interval_ms=poll_interval_ms, + ) + return batch + + +class AsyncFileBatches(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncFileBatchesWithRawResponse: + return AsyncFileBatchesWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncFileBatchesWithStreamingResponse: + return AsyncFileBatchesWithStreamingResponse(self) + + async def create( + self, + vector_store_id: str, + *, + file_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, + ) -> VectorStoreFileBatch: + """ + 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. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the 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 await self._post( + f"/vector_stores/{vector_store_id}/file_batches", + body=await async_maybe_transform({"file_ids": file_ids}, file_batch_create_params.FileBatchCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + async def retrieve( + self, + batch_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, + ) -> VectorStoreFileBatch: + """ + Retrieves a vector store file batch. + + 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 batch_id: + 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}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + async def cancel( + self, + batch_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, + ) -> VectorStoreFileBatch: + """Cancel a vector store file batch. + + This attempts to cancel the processing of + files in this batch as soon as possible. + + 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 batch_id: + 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", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreFileBatch, + ) + + async def create_and_poll( + self, + vector_store_id: str, + *, + file_ids: List[str], + poll_interval_ms: int | 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, + ) + # TODO: don't poll unless necessary?? + return await self.poll( + batch.id, + vector_store_id=vector_store_id, + poll_interval_ms=poll_interval_ms, + ) + + def list_files( + self, + 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, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: + """ + Returns a list of vector store files in a batch. + + 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, + ending 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`. + + 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 vector_store_id: + raise ValueError(f"Expected a non-empty value for `vector_store_id` but received {vector_store_id!r}") + if not batch_id: + 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", + page=AsyncCursorPage[VectorStoreFile], + 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, + "filter": filter, + "limit": limit, + "order": order, + }, + file_batch_list_files_params.FileBatchListFilesParams, + ), + ), + model=VectorStoreFile, + ) + + async def poll( + self, + batch_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFileBatch: + """Wait for the given file batch to be processed. + + Note: this will return even if one of the files failed to process, you need to + check batch.file_counts.failed_count to handle this case. + """ + 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( + batch_id, + vector_store_id=vector_store_id, + extra_headers=headers, + ) + + batch = response.parse() + if batch.file_counts.in_progress > 0: + 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) + continue + + return batch + + async def upload_and_poll( + self, + vector_store_id: str, + *, + files: Iterable[FileTypes], + max_concurrency: int = 5, + file_ids: List[str] = [], + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFileBatch: + """Uploads the given files concurrently and then creates a vector store file batch. + + If you've already uploaded certain files that you want to include in this batch + then you can pass their IDs through the `file_ids` argument. + + By default, if any file upload fails then an exception will be eagerly raised. + + The number of concurrency uploads is configurable using the `max_concurrency` + parameter. + + Note: this method only supports `asyncio` or `trio` as the backing async + runtime. + """ + uploaded_files: list[FileObject] = [] + + async_library = sniffio.current_async_library() + + if async_library == "asyncio": + + async def asyncio_upload_file(semaphore: asyncio.Semaphore, file: FileTypes) -> None: + async with semaphore: + file_obj = await self._client.files.create( + file=file, + purpose="assistants", + ) + uploaded_files.append(file_obj) + + semaphore = asyncio.Semaphore(max_concurrency) + + tasks = [asyncio_upload_file(semaphore, file) for file in files] + + await asyncio.gather(*tasks) + elif async_library == "trio": + # We only import if the library is being used. + # We support Python 3.7 so are using an older version of trio that does not have type information + import trio # type: ignore # pyright: ignore[reportMissingTypeStubs] + + async def trio_upload_file(limiter: trio.CapacityLimiter, file: FileTypes) -> None: + async with limiter: + file_obj = await self._client.files.create( + file=file, + purpose="assistants", + ) + uploaded_files.append(file_obj) + + limiter = trio.CapacityLimiter(max_concurrency) + + async with trio.open_nursery() as nursery: + for file in files: + nursery.start_soon(trio_upload_file, limiter, file) # pyright: ignore [reportUnknownMemberType] + else: + raise RuntimeError( + f"Async runtime {async_library} is not supported yet. Only asyncio or trio is supported", + ) + + batch = await self.create_and_poll( + vector_store_id=vector_store_id, + file_ids=[*file_ids, *(f.id for f in uploaded_files)], + poll_interval_ms=poll_interval_ms, + ) + return batch + + +class FileBatchesWithRawResponse: + def __init__(self, file_batches: FileBatches) -> None: + self._file_batches = file_batches + + self.create = _legacy_response.to_raw_response_wrapper( + file_batches.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + file_batches.retrieve, + ) + self.cancel = _legacy_response.to_raw_response_wrapper( + file_batches.cancel, + ) + self.list_files = _legacy_response.to_raw_response_wrapper( + file_batches.list_files, + ) + + +class AsyncFileBatchesWithRawResponse: + def __init__(self, file_batches: AsyncFileBatches) -> None: + self._file_batches = file_batches + + self.create = _legacy_response.async_to_raw_response_wrapper( + file_batches.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + file_batches.retrieve, + ) + self.cancel = _legacy_response.async_to_raw_response_wrapper( + file_batches.cancel, + ) + self.list_files = _legacy_response.async_to_raw_response_wrapper( + file_batches.list_files, + ) + + +class FileBatchesWithStreamingResponse: + def __init__(self, file_batches: FileBatches) -> None: + self._file_batches = file_batches + + self.create = to_streamed_response_wrapper( + file_batches.create, + ) + self.retrieve = to_streamed_response_wrapper( + file_batches.retrieve, + ) + self.cancel = to_streamed_response_wrapper( + file_batches.cancel, + ) + self.list_files = to_streamed_response_wrapper( + file_batches.list_files, + ) + + +class AsyncFileBatchesWithStreamingResponse: + def __init__(self, file_batches: AsyncFileBatches) -> None: + self._file_batches = file_batches + + self.create = async_to_streamed_response_wrapper( + file_batches.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + file_batches.retrieve, + ) + self.cancel = async_to_streamed_response_wrapper( + file_batches.cancel, + ) + self.list_files = async_to_streamed_response_wrapper( + file_batches.list_files, + ) diff --git a/src/openai/resources/beta/assistants/files.py b/src/openai/resources/beta/vector_stores/files.py similarity index 57% rename from src/openai/resources/beta/assistants/files.py rename to src/openai/resources/beta/vector_stores/files.py index dc57dfb96c..6404b9d54c 100644 --- a/src/openai/resources/beta/assistants/files.py +++ b/src/openai/resources/beta/vector_stores/files.py @@ -2,13 +2,15 @@ from __future__ import annotations -from typing_extensions import Literal +from typing import TYPE_CHECKING +from typing_extensions import Literal, assert_never import httpx from .... import _legacy_response -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes from ...._utils import ( + is_given, maybe_transform, async_maybe_transform, ) @@ -20,7 +22,7 @@ AsyncPaginator, make_request_options, ) -from ....types.beta.assistants import AssistantFile, FileDeleteResponse, file_list_params, file_create_params +from ....types.beta.vector_stores import VectorStoreFile, VectorStoreFileDeleted, file_list_params, file_create_params __all__ = ["Files", "AsyncFiles"] @@ -36,7 +38,7 @@ def with_streaming_response(self) -> FilesWithStreamingResponse: def create( self, - assistant_id: str, + vector_store_id: str, *, file_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -45,16 +47,16 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantFile: + ) -> VectorStoreFile: """ - Create an assistant file by attaching a - [File](https://platform.openai.com/docs/api-reference/files) to an - [assistant](https://platform.openai.com/docs/api-reference/assistants). + Create a vector store file by attaching a + [File](https://platform.openai.com/docs/api-reference/files) to a + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). Args: - file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID (with - `purpose="assistants"`) that the assistant should use. Useful for tools like - `retrieval` and `code_interpreter` that can access files. + 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. extra_headers: Send extra headers @@ -64,32 +66,32 @@ def create( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + 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._post( - f"/assistants/{assistant_id}/files", + f"/vector_stores/{vector_store_id}/files", body=maybe_transform({"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=AssistantFile, + cast_to=VectorStoreFile, ) def retrieve( self, file_id: str, *, - assistant_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, - ) -> AssistantFile: + ) -> VectorStoreFile: """ - Retrieves an AssistantFile. + Retrieves a vector store file. Args: extra_headers: Send extra headers @@ -100,25 +102,26 @@ def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") + 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=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._get( - f"/assistants/{assistant_id}/files/{file_id}", + f"/vector_stores/{vector_store_id}/files/{file_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AssistantFile, + cast_to=VectorStoreFile, ) def list( self, - assistant_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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -127,9 +130,9 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> SyncCursorPage[AssistantFile]: + ) -> SyncCursorPage[VectorStoreFile]: """ - Returns a list of assistant files. + Returns a list of vector store files. Args: after: A cursor for use in pagination. `after` is an object ID that defines your place @@ -142,6 +145,8 @@ def list( ending 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`. + limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -156,12 +161,12 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + 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"/assistants/{assistant_id}/files", - page=SyncCursorPage[AssistantFile], + f"/vector_stores/{vector_store_id}/files", + page=SyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -171,29 +176,34 @@ def list( { "after": after, "before": before, + "filter": filter, "limit": limit, "order": order, }, file_list_params.FileListParams, ), ), - model=AssistantFile, + model=VectorStoreFile, ) def delete( self, file_id: str, *, - assistant_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, - ) -> FileDeleteResponse: - """ - Delete an assistant file. + ) -> VectorStoreFileDeleted: + """Delete a vector store file. + + This will remove the file from the vector store but + the file itself will not be deleted. To delete the file, use the + [delete file](https://platform.openai.com/docs/api-reference/files/delete) + endpoint. Args: extra_headers: Send extra headers @@ -204,17 +214,103 @@ def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") + 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=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return self._delete( - f"/assistants/{assistant_id}/files/{file_id}", + f"/vector_stores/{vector_store_id}/files/{file_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=FileDeleteResponse, + cast_to=VectorStoreFileDeleted, + ) + + def create_and_poll( + self, + file_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | 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) + + return self.poll( + file_id, + vector_store_id=vector_store_id, + poll_interval_ms=poll_interval_ms, + ) + + def poll( + self, + file_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFile: + """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( + file_id, + vector_store_id=vector_store_id, + extra_headers=headers, + ) + + file = response.parse() + if file.status == "in_progress": + 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 file.status == "cancelled" or file.status == "completed" or file.status == "failed": + return file + else: + if TYPE_CHECKING: # type: ignore[unreachable] + assert_never(file.status) + else: + return file + + def upload( + self, + *, + vector_store_id: str, + file: FileTypes, + ) -> VectorStoreFile: + """Upload a file to the `files` API and then attach it to the given vector store. + + Note the file will be asynchronously processed (you can use the alternative + polling helper method to wait for processing to complete). + """ + file_obj = self._client.files.create(file=file, purpose="assistants") + return self.create(vector_store_id=vector_store_id, file_id=file_obj.id) + + def upload_and_poll( + self, + *, + vector_store_id: str, + file: FileTypes, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFile: + """Add a file to a vector store and poll until processing is complete.""" + file_obj = self._client.files.create(file=file, purpose="assistants") + return self.create_and_poll( + vector_store_id=vector_store_id, + file_id=file_obj.id, + poll_interval_ms=poll_interval_ms, ) @@ -229,7 +325,7 @@ def with_streaming_response(self) -> AsyncFilesWithStreamingResponse: async def create( self, - assistant_id: str, + vector_store_id: str, *, file_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -238,16 +334,16 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AssistantFile: + ) -> VectorStoreFile: """ - Create an assistant file by attaching a - [File](https://platform.openai.com/docs/api-reference/files) to an - [assistant](https://platform.openai.com/docs/api-reference/assistants). + Create a vector store file by attaching a + [File](https://platform.openai.com/docs/api-reference/files) to a + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). Args: - file_id: A [File](https://platform.openai.com/docs/api-reference/files) ID (with - `purpose="assistants"`) that the assistant should use. Useful for tools like - `retrieval` and `code_interpreter` that can access files. + 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. extra_headers: Send extra headers @@ -257,32 +353,32 @@ async def create( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + 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 await self._post( - f"/assistants/{assistant_id}/files", + f"/vector_stores/{vector_store_id}/files", body=await async_maybe_transform({"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=AssistantFile, + cast_to=VectorStoreFile, ) async def retrieve( self, file_id: str, *, - assistant_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, - ) -> AssistantFile: + ) -> VectorStoreFile: """ - Retrieves an AssistantFile. + Retrieves a vector store file. Args: extra_headers: Send extra headers @@ -293,25 +389,26 @@ async def retrieve( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") + 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=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._get( - f"/assistants/{assistant_id}/files/{file_id}", + f"/vector_stores/{vector_store_id}/files/{file_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=AssistantFile, + cast_to=VectorStoreFile, ) def list( self, - assistant_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, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -320,9 +417,9 @@ def list( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> AsyncPaginator[AssistantFile, AsyncCursorPage[AssistantFile]]: + ) -> AsyncPaginator[VectorStoreFile, AsyncCursorPage[VectorStoreFile]]: """ - Returns a list of assistant files. + Returns a list of vector store files. Args: after: A cursor for use in pagination. `after` is an object ID that defines your place @@ -335,6 +432,8 @@ def list( ending 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`. + limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. @@ -349,12 +448,12 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") - extra_headers = {"OpenAI-Beta": "assistants=v1", **(extra_headers or {})} + 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"/assistants/{assistant_id}/files", - page=AsyncCursorPage[AssistantFile], + f"/vector_stores/{vector_store_id}/files", + page=AsyncCursorPage[VectorStoreFile], options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -364,29 +463,34 @@ def list( { "after": after, "before": before, + "filter": filter, "limit": limit, "order": order, }, file_list_params.FileListParams, ), ), - model=AssistantFile, + model=VectorStoreFile, ) async def delete( self, file_id: str, *, - assistant_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, - ) -> FileDeleteResponse: - """ - Delete an assistant file. + ) -> VectorStoreFileDeleted: + """Delete a vector store file. + + This will remove the file from the vector store but + the file itself will not be deleted. To delete the file, use the + [delete file](https://platform.openai.com/docs/api-reference/files/delete) + endpoint. Args: extra_headers: Send extra headers @@ -397,17 +501,103 @@ async def delete( timeout: Override the client-level default timeout for this request, in seconds """ - if not assistant_id: - raise ValueError(f"Expected a non-empty value for `assistant_id` but received {assistant_id!r}") + 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=v1", **(extra_headers or {})} + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} return await self._delete( - f"/assistants/{assistant_id}/files/{file_id}", + f"/vector_stores/{vector_store_id}/files/{file_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=FileDeleteResponse, + cast_to=VectorStoreFileDeleted, + ) + + async def create_and_poll( + self, + file_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | 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) + + return await self.poll( + file_id, + vector_store_id=vector_store_id, + poll_interval_ms=poll_interval_ms, + ) + + async def poll( + self, + file_id: str, + *, + vector_store_id: str, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> VectorStoreFile: + """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( + file_id, + vector_store_id=vector_store_id, + extra_headers=headers, + ) + + file = response.parse() + if file.status == "in_progress": + 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 file.status == "cancelled" or file.status == "completed" or file.status == "failed": + return file + else: + if TYPE_CHECKING: # type: ignore[unreachable] + assert_never(file.status) + else: + return file + + async def upload( + self, + *, + vector_store_id: str, + file: FileTypes, + ) -> VectorStoreFile: + """Upload a file to the `files` API and then attach it to the given vector store. + + Note the file will be asynchronously processed (you can use the alternative + polling helper method to wait for processing to complete). + """ + file_obj = await self._client.files.create(file=file, purpose="assistants") + return await self.create(vector_store_id=vector_store_id, file_id=file_obj.id) + + async def upload_and_poll( + self, + *, + vector_store_id: str, + file: FileTypes, + poll_interval_ms: int | NotGiven = NOT_GIVEN, + ) -> 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") + return await self.create_and_poll( + vector_store_id=vector_store_id, + file_id=file_obj.id, + poll_interval_ms=poll_interval_ms, ) diff --git a/src/openai/resources/beta/vector_stores/vector_stores.py b/src/openai/resources/beta/vector_stores/vector_stores.py new file mode 100644 index 0000000000..6e2c9ab70c --- /dev/null +++ b/src/openai/resources/beta/vector_stores/vector_stores.py @@ -0,0 +1,688 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from .... import _legacy_response +from .files import ( + Files, + AsyncFiles, + FilesWithRawResponse, + AsyncFilesWithRawResponse, + FilesWithStreamingResponse, + AsyncFilesWithStreamingResponse, +) +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 .file_batches import ( + FileBatches, + AsyncFileBatches, + FileBatchesWithRawResponse, + AsyncFileBatchesWithRawResponse, + FileBatchesWithStreamingResponse, + AsyncFileBatchesWithStreamingResponse, +) +from ....pagination import SyncCursorPage, AsyncCursorPage +from ....types.beta import ( + VectorStore, + VectorStoreDeleted, + vector_store_list_params, + vector_store_create_params, + vector_store_update_params, +) +from ...._base_client import ( + AsyncPaginator, + make_request_options, +) + +__all__ = ["VectorStores", "AsyncVectorStores"] + + +class VectorStores(SyncAPIResource): + @cached_property + def files(self) -> Files: + return Files(self._client) + + @cached_property + def file_batches(self) -> FileBatches: + return FileBatches(self._client) + + @cached_property + def with_raw_response(self) -> VectorStoresWithRawResponse: + return VectorStoresWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VectorStoresWithStreamingResponse: + return VectorStoresWithStreamingResponse(self) + + def create( + self, + *, + expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + file_ids: List[str] | NotGiven = NOT_GIVEN, + metadata: Optional[object] | 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, + ) -> VectorStore: + """ + Create a vector store. + + Args: + 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 + the vector store should use. Useful for tools like `file_search` that can access + 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 maxium of 512 + characters long. + + name: The name of the vector store. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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( + "/vector_stores", + body=maybe_transform( + { + "expires_after": expires_after, + "file_ids": file_ids, + "metadata": metadata, + "name": name, + }, + vector_store_create_params.VectorStoreCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + def retrieve( + self, + 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, + ) -> VectorStore: + """ + Retrieves a vector store. + + 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}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get( + f"/vector_stores/{vector_store_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + def update( + self, + vector_store_id: str, + *, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, + metadata: Optional[object] | 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> VectorStore: + """ + Modifies a vector store. + + Args: + 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 maxium of 512 + characters long. + + name: The name of the vector store. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the 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._post( + f"/vector_stores/{vector_store_id}", + body=maybe_transform( + { + "expires_after": expires_after, + "metadata": metadata, + "name": name, + }, + vector_store_update_params.VectorStoreUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + 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, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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[VectorStore]: + """Returns a list of vector stores. + + 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, + ending 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. + + 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 + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + "/vector_stores", + page=SyncCursorPage[VectorStore], + 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, + }, + vector_store_list_params.VectorStoreListParams, + ), + ), + model=VectorStore, + ) + + def delete( + self, + 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, + ) -> VectorStoreDeleted: + """ + Delete a vector store. + + 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}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._delete( + f"/vector_stores/{vector_store_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreDeleted, + ) + + +class AsyncVectorStores(AsyncAPIResource): + @cached_property + def files(self) -> AsyncFiles: + return AsyncFiles(self._client) + + @cached_property + def file_batches(self) -> AsyncFileBatches: + return AsyncFileBatches(self._client) + + @cached_property + def with_raw_response(self) -> AsyncVectorStoresWithRawResponse: + return AsyncVectorStoresWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVectorStoresWithStreamingResponse: + return AsyncVectorStoresWithStreamingResponse(self) + + async def create( + self, + *, + expires_after: vector_store_create_params.ExpiresAfter | NotGiven = NOT_GIVEN, + file_ids: List[str] | NotGiven = NOT_GIVEN, + metadata: Optional[object] | 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, + ) -> VectorStore: + """ + Create a vector store. + + Args: + 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 + the vector store should use. Useful for tools like `file_search` that can access + 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 maxium of 512 + characters long. + + name: The name of the vector store. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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( + "/vector_stores", + body=await async_maybe_transform( + { + "expires_after": expires_after, + "file_ids": file_ids, + "metadata": metadata, + "name": name, + }, + vector_store_create_params.VectorStoreCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + async def retrieve( + self, + 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, + ) -> VectorStore: + """ + Retrieves a vector store. + + 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}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return await self._get( + f"/vector_stores/{vector_store_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + async def update( + self, + vector_store_id: str, + *, + expires_after: Optional[vector_store_update_params.ExpiresAfter] | NotGiven = NOT_GIVEN, + metadata: Optional[object] | 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. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> VectorStore: + """ + Modifies a vector store. + + Args: + 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 maxium of 512 + characters long. + + name: The name of the vector store. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the 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 await self._post( + f"/vector_stores/{vector_store_id}", + body=await async_maybe_transform( + { + "expires_after": expires_after, + "metadata": metadata, + "name": name, + }, + vector_store_update_params.VectorStoreUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStore, + ) + + 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, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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[VectorStore, AsyncCursorPage[VectorStore]]: + """Returns a list of vector stores. + + 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, + ending 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. + + 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 + """ + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return self._get_api_list( + "/vector_stores", + page=AsyncCursorPage[VectorStore], + 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, + }, + vector_store_list_params.VectorStoreListParams, + ), + ), + model=VectorStore, + ) + + async def delete( + self, + 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, + ) -> VectorStoreDeleted: + """ + Delete a vector store. + + 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}") + extra_headers = {"OpenAI-Beta": "assistants=v2", **(extra_headers or {})} + return await self._delete( + f"/vector_stores/{vector_store_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=VectorStoreDeleted, + ) + + +class VectorStoresWithRawResponse: + def __init__(self, vector_stores: VectorStores) -> None: + self._vector_stores = vector_stores + + self.create = _legacy_response.to_raw_response_wrapper( + vector_stores.create, + ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + vector_stores.retrieve, + ) + self.update = _legacy_response.to_raw_response_wrapper( + vector_stores.update, + ) + self.list = _legacy_response.to_raw_response_wrapper( + vector_stores.list, + ) + self.delete = _legacy_response.to_raw_response_wrapper( + vector_stores.delete, + ) + + @cached_property + def files(self) -> FilesWithRawResponse: + return FilesWithRawResponse(self._vector_stores.files) + + @cached_property + def file_batches(self) -> FileBatchesWithRawResponse: + return FileBatchesWithRawResponse(self._vector_stores.file_batches) + + +class AsyncVectorStoresWithRawResponse: + def __init__(self, vector_stores: AsyncVectorStores) -> None: + self._vector_stores = vector_stores + + self.create = _legacy_response.async_to_raw_response_wrapper( + vector_stores.create, + ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + vector_stores.retrieve, + ) + self.update = _legacy_response.async_to_raw_response_wrapper( + vector_stores.update, + ) + self.list = _legacy_response.async_to_raw_response_wrapper( + vector_stores.list, + ) + self.delete = _legacy_response.async_to_raw_response_wrapper( + vector_stores.delete, + ) + + @cached_property + def files(self) -> AsyncFilesWithRawResponse: + return AsyncFilesWithRawResponse(self._vector_stores.files) + + @cached_property + def file_batches(self) -> AsyncFileBatchesWithRawResponse: + return AsyncFileBatchesWithRawResponse(self._vector_stores.file_batches) + + +class VectorStoresWithStreamingResponse: + def __init__(self, vector_stores: VectorStores) -> None: + self._vector_stores = vector_stores + + self.create = to_streamed_response_wrapper( + vector_stores.create, + ) + self.retrieve = to_streamed_response_wrapper( + vector_stores.retrieve, + ) + self.update = to_streamed_response_wrapper( + vector_stores.update, + ) + self.list = to_streamed_response_wrapper( + vector_stores.list, + ) + self.delete = to_streamed_response_wrapper( + vector_stores.delete, + ) + + @cached_property + def files(self) -> FilesWithStreamingResponse: + return FilesWithStreamingResponse(self._vector_stores.files) + + @cached_property + def file_batches(self) -> FileBatchesWithStreamingResponse: + return FileBatchesWithStreamingResponse(self._vector_stores.file_batches) + + +class AsyncVectorStoresWithStreamingResponse: + def __init__(self, vector_stores: AsyncVectorStores) -> None: + self._vector_stores = vector_stores + + self.create = async_to_streamed_response_wrapper( + vector_stores.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + vector_stores.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + vector_stores.update, + ) + self.list = async_to_streamed_response_wrapper( + vector_stores.list, + ) + self.delete = async_to_streamed_response_wrapper( + vector_stores.delete, + ) + + @cached_property + def files(self) -> AsyncFilesWithStreamingResponse: + return AsyncFilesWithStreamingResponse(self._vector_stores.files) + + @cached_property + def file_batches(self) -> AsyncFileBatchesWithStreamingResponse: + return AsyncFileBatchesWithStreamingResponse(self._vector_stores.file_batches) diff --git a/src/openai/resources/fine_tuning/jobs/jobs.py b/src/openai/resources/fine_tuning/jobs/jobs.py index 229f716c48..8e49571b14 100644 --- a/src/openai/resources/fine_tuning/jobs/jobs.py +++ b/src/openai/resources/fine_tuning/jobs/jobs.py @@ -85,7 +85,7 @@ def create( training_file: The ID of an uploaded file that contains training data. - See [upload file](https://platform.openai.com/docs/api-reference/files/upload) + See [upload file](https://platform.openai.com/docs/api-reference/files/create) for how to upload a file. Your dataset must be formatted as a JSONL file. Additionally, you must upload @@ -360,7 +360,7 @@ async def create( training_file: The ID of an uploaded file that contains training data. - See [upload file](https://platform.openai.com/docs/api-reference/files/upload) + See [upload file](https://platform.openai.com/docs/api-reference/files/create) for how to upload a file. Your dataset must be formatted as a JSONL file. Additionally, you must upload diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index 0171694587..d851a3619c 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -4,23 +4,28 @@ 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 .retrieval_tool import RetrievalTool as RetrievalTool from .thread_deleted import ThreadDeleted as ThreadDeleted +from .file_search_tool import FileSearchTool as FileSearchTool from .assistant_deleted import AssistantDeleted as AssistantDeleted from .function_tool_param import FunctionToolParam as FunctionToolParam from .assistant_tool_param import AssistantToolParam as AssistantToolParam -from .retrieval_tool_param import RetrievalToolParam as RetrievalToolParam 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_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 .assistant_response_format import AssistantResponseFormat as AssistantResponseFormat +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 diff --git a/src/openai/types/beta/assistant.py b/src/openai/types/beta/assistant.py index 0a0d28ed01..fa09efb0cc 100644 --- a/src/openai/types/beta/assistant.py +++ b/src/openai/types/beta/assistant.py @@ -6,7 +6,32 @@ from ..._models import BaseModel from .assistant_tool import AssistantTool -__all__ = ["Assistant"] +__all__ = ["Assistant", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] + + +class ToolResourcesCodeInterpreter(BaseModel): + file_ids: Optional[List[str]] = None + """ + 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 + associated with the tool. + """ + + +class ToolResourcesFileSearch(BaseModel): + vector_store_ids: Optional[List[str]] = None + """ + The ID of the + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this assistant. There can be a maximum of 1 vector store attached to + the assistant. + """ + + +class ToolResources(BaseModel): + code_interpreter: Optional[ToolResourcesCodeInterpreter] = None + + file_search: Optional[ToolResourcesFileSearch] = None class Assistant(BaseModel): @@ -19,13 +44,6 @@ class Assistant(BaseModel): description: Optional[str] = None """The description of the assistant. The maximum length is 512 characters.""" - file_ids: List[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. - """ - instructions: Optional[str] = None """The system instructions that the assistant uses. @@ -60,5 +78,13 @@ class Assistant(BaseModel): """A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `retrieval`, or `function`. + `code_interpreter`, `file_search`, or `function`. + """ + + tool_resources: Optional[ToolResources] = None + """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. """ diff --git a/src/openai/types/beta/assistant_create_params.py b/src/openai/types/beta/assistant_create_params.py index 011121485f..925b85050f 100644 --- a/src/openai/types/beta/assistant_create_params.py +++ b/src/openai/types/beta/assistant_create_params.py @@ -6,8 +6,15 @@ from typing_extensions import Literal, Required, TypedDict from .assistant_tool_param import AssistantToolParam +from .assistant_response_format_option_param import AssistantResponseFormatOptionParam -__all__ = ["AssistantCreateParams"] +__all__ = [ + "AssistantCreateParams", + "ToolResources", + "ToolResourcesCodeInterpreter", + "ToolResourcesFileSearch", + "ToolResourcesFileSearchVectorStore", +] class AssistantCreateParams(TypedDict, total=False): @@ -48,13 +55,6 @@ class AssistantCreateParams(TypedDict, total=False): description: Optional[str] """The description of the assistant. The maximum length is 512 characters.""" - file_ids: List[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. - """ - instructions: Optional[str] """The system instructions that the assistant uses. @@ -72,9 +72,102 @@ class AssistantCreateParams(TypedDict, total=False): name: Optional[str] """The name of the assistant. The maximum length is 256 characters.""" + response_format: Optional[AssistantResponseFormatOptionParam] + """Specifies the format that the model must output. + + Compatible with + [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + """ + + 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. + """ + + tool_resources: Optional[ToolResources] + """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. + """ + tools: Iterable[AssistantToolParam] """A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `retrieval`, or `function`. + `code_interpreter`, `file_search`, or `function`. + """ + + 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. + """ + + +class ToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[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 + associated with the tool. + """ + + +class ToolResourcesFileSearchVectorStore(TypedDict, total=False): + file_ids: List[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. + """ + + metadata: object + """Set of 16 key-value pairs that can be attached to a vector store. + + 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. """ + + +class ToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + The + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this assistant. There can be a maximum of 1 vector store attached to + the assistant. + """ + + vector_stores: Iterable[ToolResourcesFileSearchVectorStore] + """ + A helper to create a + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + with file_ids and attach it to this assistant. There can be a maximum of 1 + vector store attached to the assistant. + """ + + +class ToolResources(TypedDict, total=False): + code_interpreter: ToolResourcesCodeInterpreter + + file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/assistant_tool.py b/src/openai/types/beta/assistant_tool.py index a4420385e8..7832da48cc 100644 --- a/src/openai/types/beta/assistant_tool.py +++ b/src/openai/types/beta/assistant_tool.py @@ -5,9 +5,9 @@ from ..._utils import PropertyInfo from .function_tool import FunctionTool -from .retrieval_tool import RetrievalTool +from .file_search_tool import FileSearchTool from .code_interpreter_tool import CodeInterpreterTool __all__ = ["AssistantTool"] -AssistantTool = Annotated[Union[CodeInterpreterTool, RetrievalTool, FunctionTool], PropertyInfo(discriminator="type")] +AssistantTool = Annotated[Union[CodeInterpreterTool, FileSearchTool, FunctionTool], PropertyInfo(discriminator="type")] diff --git a/src/openai/types/beta/assistant_tool_choice.py b/src/openai/types/beta/assistant_tool_choice.py index 4314d4b41e..d73439f006 100644 --- a/src/openai/types/beta/assistant_tool_choice.py +++ b/src/openai/types/beta/assistant_tool_choice.py @@ -10,7 +10,7 @@ class AssistantToolChoice(BaseModel): - type: Literal["function", "code_interpreter", "retrieval"] + type: Literal["function", "code_interpreter", "file_search"] """The type of the tool. If type is `function`, the function name must be set""" function: Optional[AssistantToolChoiceFunction] = None diff --git a/src/openai/types/beta/assistant_tool_choice_param.py b/src/openai/types/beta/assistant_tool_choice_param.py index 5cf6ea27be..904f489e26 100644 --- a/src/openai/types/beta/assistant_tool_choice_param.py +++ b/src/openai/types/beta/assistant_tool_choice_param.py @@ -10,7 +10,7 @@ class AssistantToolChoiceParam(TypedDict, total=False): - type: Required[Literal["function", "code_interpreter", "retrieval"]] + type: Required[Literal["function", "code_interpreter", "file_search"]] """The type of the tool. If type is `function`, the function name must be set""" function: AssistantToolChoiceFunctionParam diff --git a/src/openai/types/beta/assistant_tool_param.py b/src/openai/types/beta/assistant_tool_param.py index d5758f169e..5b1d30ba2f 100644 --- a/src/openai/types/beta/assistant_tool_param.py +++ b/src/openai/types/beta/assistant_tool_param.py @@ -5,9 +5,9 @@ from typing import Union from .function_tool_param import FunctionToolParam -from .retrieval_tool_param import RetrievalToolParam +from .file_search_tool_param import FileSearchToolParam from .code_interpreter_tool_param import CodeInterpreterToolParam __all__ = ["AssistantToolParam"] -AssistantToolParam = Union[CodeInterpreterToolParam, RetrievalToolParam, FunctionToolParam] +AssistantToolParam = Union[CodeInterpreterToolParam, FileSearchToolParam, FunctionToolParam] diff --git a/src/openai/types/beta/assistant_update_params.py b/src/openai/types/beta/assistant_update_params.py index 6e9d9ed5db..1354b078a8 100644 --- a/src/openai/types/beta/assistant_update_params.py +++ b/src/openai/types/beta/assistant_update_params.py @@ -6,23 +6,15 @@ from typing_extensions import TypedDict from .assistant_tool_param import AssistantToolParam +from .assistant_response_format_option_param import AssistantResponseFormatOptionParam -__all__ = ["AssistantUpdateParams"] +__all__ = ["AssistantUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] class AssistantUpdateParams(TypedDict, total=False): description: Optional[str] """The description of the assistant. The maximum length is 512 characters.""" - file_ids: List[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs - attached to this assistant. There can be a maximum of 20 files attached to the - assistant. Files are ordered by their creation date in ascending order. If a - file was previously attached to the list but does not show up in the list, it - will be deleted from the assistant. - """ - instructions: Optional[str] """The system instructions that the assistant uses. @@ -50,9 +42,78 @@ class AssistantUpdateParams(TypedDict, total=False): name: Optional[str] """The name of the assistant. The maximum length is 256 characters.""" + response_format: Optional[AssistantResponseFormatOptionParam] + """Specifies the format that the model must output. + + Compatible with + [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo) and + all GPT-3.5 Turbo models newer than `gpt-3.5-turbo-1106`. + + Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees 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. + """ + + 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. + """ + + tool_resources: Optional[ToolResources] + """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. + """ + tools: Iterable[AssistantToolParam] """A list of tool enabled on the assistant. There can be a maximum of 128 tools per assistant. Tools can be of types - `code_interpreter`, `retrieval`, or `function`. + `code_interpreter`, `file_search`, or `function`. """ + + 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. + """ + + +class ToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[str] + """ + Overrides the 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 associated + with the tool. + """ + + +class ToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + Overrides the + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this assistant. There can be a maximum of 1 vector store attached to + the assistant. + """ + + +class ToolResources(TypedDict, total=False): + code_interpreter: ToolResourcesCodeInterpreter + + file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/assistants/__init__.py b/src/openai/types/beta/assistants/__init__.py deleted file mode 100644 index d4dd2de018..0000000000 --- a/src/openai/types/beta/assistants/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .assistant_file import AssistantFile as AssistantFile -from .file_list_params import FileListParams as FileListParams -from .file_create_params import FileCreateParams as FileCreateParams -from .file_delete_response import FileDeleteResponse as FileDeleteResponse diff --git a/src/openai/types/beta/assistants/assistant_file.py b/src/openai/types/beta/assistants/assistant_file.py deleted file mode 100644 index 25aec07b49..0000000000 --- a/src/openai/types/beta/assistants/assistant_file.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__ = ["AssistantFile"] - - -class AssistantFile(BaseModel): - id: str - """The identifier, which can be referenced in API endpoints.""" - - assistant_id: str - """The assistant ID that the file is attached to.""" - - created_at: int - """The Unix timestamp (in seconds) for when the assistant file was created.""" - - object: Literal["assistant.file"] - """The object type, which is always `assistant.file`.""" diff --git a/src/openai/types/beta/file_search_tool.py b/src/openai/types/beta/file_search_tool.py new file mode 100644 index 0000000000..eea55ea6ac --- /dev/null +++ b/src/openai/types/beta/file_search_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__ = ["FileSearchTool"] + + +class FileSearchTool(BaseModel): + type: Literal["file_search"] + """The type of tool being defined: `file_search`""" diff --git a/src/openai/types/beta/retrieval_tool_param.py b/src/openai/types/beta/file_search_tool_param.py similarity index 50% rename from src/openai/types/beta/retrieval_tool_param.py rename to src/openai/types/beta/file_search_tool_param.py index d76c0beefc..d33fd06da4 100644 --- a/src/openai/types/beta/retrieval_tool_param.py +++ b/src/openai/types/beta/file_search_tool_param.py @@ -4,9 +4,9 @@ from typing_extensions import Literal, Required, TypedDict -__all__ = ["RetrievalToolParam"] +__all__ = ["FileSearchToolParam"] -class RetrievalToolParam(TypedDict, total=False): - type: Required[Literal["retrieval"]] - """The type of tool being defined: `retrieval`""" +class FileSearchToolParam(TypedDict, total=False): + type: Required[Literal["file_search"]] + """The type of tool being defined: `file_search`""" diff --git a/src/openai/types/beta/thread.py b/src/openai/types/beta/thread.py index 8fd1423068..6f7a6c7d0c 100644 --- a/src/openai/types/beta/thread.py +++ b/src/openai/types/beta/thread.py @@ -1,11 +1,36 @@ # 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__ = ["Thread"] +__all__ = ["Thread", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] + + +class ToolResourcesCodeInterpreter(BaseModel): + file_ids: Optional[List[str]] = None + """ + 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 + associated with the tool. + """ + + +class ToolResourcesFileSearch(BaseModel): + vector_store_ids: Optional[List[str]] = None + """ + The + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this thread. There can be a maximum of 1 vector store attached to + the thread. + """ + + +class ToolResources(BaseModel): + code_interpreter: Optional[ToolResourcesCodeInterpreter] = None + + file_search: Optional[ToolResourcesFileSearch] = None class Thread(BaseModel): @@ -25,3 +50,11 @@ class Thread(BaseModel): object: Literal["thread"] """The object type, which is always `thread`.""" + + tool_resources: Optional[ToolResources] = None + """ + 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. + """ 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 50f947a40a..d7d5a758e8 100644 --- a/src/openai/types/beta/thread_create_and_run_params.py +++ b/src/openai/types/beta/thread_create_and_run_params.py @@ -6,7 +6,7 @@ from typing_extensions import Literal, Required, TypedDict from .function_tool_param import FunctionToolParam -from .retrieval_tool_param import RetrievalToolParam +from .file_search_tool_param import FileSearchToolParam from .code_interpreter_tool_param import CodeInterpreterToolParam from .assistant_tool_choice_option_param import AssistantToolChoiceOptionParam from .assistant_response_format_option_param import AssistantResponseFormatOptionParam @@ -15,6 +15,14 @@ "ThreadCreateAndRunParamsBase", "Thread", "ThreadMessage", + "ThreadMessageAttachment", + "ThreadToolResources", + "ThreadToolResourcesCodeInterpreter", + "ThreadToolResourcesFileSearch", + "ThreadToolResourcesFileSearchVectorStore", + "ToolResources", + "ToolResourcesCodeInterpreter", + "ToolResourcesFileSearch", "Tool", "TruncationStrategy", "ThreadCreateAndRunParamsNonStreaming", @@ -41,7 +49,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): The maximum number of completion tokens that may be used over the course of the run. The run will make a best effort to use only the number of completion tokens specified, across multiple turns of the run. If the run exceeds the number of - completion tokens specified, the run will end with status `complete`. See + completion tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. """ @@ -50,7 +58,7 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): The run will make a best effort to use only the number of prompt tokens specified, across multiple turns of the run. If the run exceeds the number of - prompt tokens specified, the run will end with status `complete`. See + prompt tokens specified, the run will end with status `incomplete`. See `incomplete_details` for more info. """ @@ -132,15 +140,37 @@ class ThreadCreateAndRunParamsBase(TypedDict, total=False): call that tool. """ + tool_resources: Optional[ToolResources] + """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. + """ + tools: Optional[Iterable[Tool]] """Override the tools the assistant can use for this run. This is useful for modifying the behavior on a per-run basis. """ + 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. + """ + truncation_strategy: Optional[TruncationStrategy] +class ThreadMessageAttachment(TypedDict, total=False): + add_to: List[Literal["file_search", "code_interpreter"]] + + file_id: str + """The ID of the file to attach to the message.""" + + class ThreadMessage(TypedDict, total=False): content: Required[str] """The content of the message.""" @@ -154,13 +184,8 @@ class ThreadMessage(TypedDict, total=False): value to insert messages from the assistant into the conversation. """ - file_ids: List[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. - """ + attachments: Optional[Iterable[ThreadMessageAttachment]] + """A list of files attached to the message, and the tools they should be added to.""" metadata: Optional[object] """Set of 16 key-value pairs that can be attached to an object. @@ -171,6 +196,56 @@ class ThreadMessage(TypedDict, total=False): """ +class ThreadToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[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 + associated with the tool. + """ + + +class ThreadToolResourcesFileSearchVectorStore(TypedDict, total=False): + file_ids: List[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. + """ + + metadata: object + """Set of 16 key-value pairs that can be attached to a vector store. + + 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. + """ + + +class ThreadToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + The + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this thread. There can be a maximum of 1 vector store attached to + the thread. + """ + + vector_stores: Iterable[ThreadToolResourcesFileSearchVectorStore] + """ + A helper to create a + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + with file_ids and attach it to this thread. There can be a maximum of 1 vector + store attached to the thread. + """ + + +class ThreadToolResources(TypedDict, total=False): + code_interpreter: ThreadToolResourcesCodeInterpreter + + file_search: ThreadToolResourcesFileSearch + + class Thread(TypedDict, total=False): messages: Iterable[ThreadMessage] """ @@ -186,8 +261,41 @@ class Thread(TypedDict, total=False): a maxium of 512 characters long. """ + tool_resources: Optional[ThreadToolResources] + """ + 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. + """ + + +class ToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[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 + associated with the tool. + """ + + +class ToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + The ID of the + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this assistant. There can be a maximum of 1 vector store attached to + the assistant. + """ + + +class ToolResources(TypedDict, total=False): + code_interpreter: ToolResourcesCodeInterpreter + + file_search: ToolResourcesFileSearch + -Tool = Union[CodeInterpreterToolParam, RetrievalToolParam, FunctionToolParam] +Tool = Union[CodeInterpreterToolParam, FileSearchToolParam, FunctionToolParam] class TruncationStrategy(TypedDict, total=False): diff --git a/src/openai/types/beta/thread_create_params.py b/src/openai/types/beta/thread_create_params.py index 1b382186aa..84a98a74d7 100644 --- a/src/openai/types/beta/thread_create_params.py +++ b/src/openai/types/beta/thread_create_params.py @@ -5,7 +5,15 @@ from typing import List, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["ThreadCreateParams", "Message"] +__all__ = [ + "ThreadCreateParams", + "Message", + "MessageAttachment", + "ToolResources", + "ToolResourcesCodeInterpreter", + "ToolResourcesFileSearch", + "ToolResourcesFileSearchVectorStore", +] class ThreadCreateParams(TypedDict, total=False): @@ -23,6 +31,21 @@ class ThreadCreateParams(TypedDict, total=False): a maxium of 512 characters long. """ + tool_resources: Optional[ToolResources] + """ + 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. + """ + + +class MessageAttachment(TypedDict, total=False): + add_to: List[Literal["file_search", "code_interpreter"]] + + file_id: str + """The ID of the file to attach to the message.""" + class Message(TypedDict, total=False): content: Required[str] @@ -37,13 +60,8 @@ class Message(TypedDict, total=False): value to insert messages from the assistant into the conversation. """ - file_ids: List[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. - """ + attachments: Optional[Iterable[MessageAttachment]] + """A list of files attached to the message, and the tools they should be added to.""" metadata: Optional[object] """Set of 16 key-value pairs that can be attached to an object. @@ -52,3 +70,53 @@ class Message(TypedDict, total=False): structured format. Keys can be a maximum of 64 characters long and values can be a maxium of 512 characters long. """ + + +class ToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[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 + associated with the tool. + """ + + +class ToolResourcesFileSearchVectorStore(TypedDict, total=False): + file_ids: List[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. + """ + + metadata: object + """Set of 16 key-value pairs that can be attached to a vector store. + + 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. + """ + + +class ToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + The + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this thread. There can be a maximum of 1 vector store attached to + the thread. + """ + + vector_stores: Iterable[ToolResourcesFileSearchVectorStore] + """ + A helper to create a + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + with file_ids and attach it to this thread. There can be a maximum of 1 vector + store attached to the thread. + """ + + +class ToolResources(TypedDict, total=False): + 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 94f1b1e22e..7210ab77c9 100644 --- a/src/openai/types/beta/thread_update_params.py +++ b/src/openai/types/beta/thread_update_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import Optional +from typing import List, Optional from typing_extensions import TypedDict -__all__ = ["ThreadUpdateParams"] +__all__ = ["ThreadUpdateParams", "ToolResources", "ToolResourcesCodeInterpreter", "ToolResourcesFileSearch"] class ThreadUpdateParams(TypedDict, total=False): @@ -16,3 +16,36 @@ class ThreadUpdateParams(TypedDict, total=False): structured format. Keys can be a maximum of 64 characters long and values can be a maxium of 512 characters long. """ + + tool_resources: Optional[ToolResources] + """ + 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. + """ + + +class ToolResourcesCodeInterpreter(TypedDict, total=False): + file_ids: List[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 + associated with the tool. + """ + + +class ToolResourcesFileSearch(TypedDict, total=False): + vector_store_ids: List[str] + """ + The + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + attached to this thread. There can be a maximum of 1 vector store attached to + the thread. + """ + + +class ToolResources(TypedDict, total=False): + code_interpreter: ToolResourcesCodeInterpreter + + file_search: ToolResourcesFileSearch diff --git a/src/openai/types/beta/threads/message.py b/src/openai/types/beta/threads/message.py index bde0263975..42f0162734 100644 --- a/src/openai/types/beta/threads/message.py +++ b/src/openai/types/beta/threads/message.py @@ -6,7 +6,14 @@ from ...._models import BaseModel from .message_content import MessageContent -__all__ = ["Message", "IncompleteDetails"] +__all__ = ["Message", "Attachment", "IncompleteDetails"] + + +class Attachment(BaseModel): + add_to: Optional[List[Literal["file_search", "code_interpreter"]]] = None + + file_id: Optional[str] = None + """The ID of the file to attach to the message.""" class IncompleteDetails(BaseModel): @@ -25,6 +32,9 @@ class Message(BaseModel): authored this message. """ + attachments: Optional[List[Attachment]] = None + """A list of files attached to the message, and the tools they were added to.""" + completed_at: Optional[int] = None """The Unix timestamp (in seconds) for when the message was completed.""" @@ -34,13 +44,6 @@ class Message(BaseModel): created_at: int """The Unix timestamp (in seconds) for when the message was created.""" - file_ids: List[str] - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs that - the assistant should use. Useful for tools like retrieval and code_interpreter - that can access files. A maximum of 10 files can be attached to a message. - """ - incomplete_at: Optional[int] = None """The Unix timestamp (in seconds) for when the message was marked as incomplete.""" diff --git a/src/openai/types/beta/threads/message_create_params.py b/src/openai/types/beta/threads/message_create_params.py index 9b9467ef4d..1ef1d9ae10 100644 --- a/src/openai/types/beta/threads/message_create_params.py +++ b/src/openai/types/beta/threads/message_create_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import List, Optional +from typing import List, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["MessageCreateParams"] +__all__ = ["MessageCreateParams", "Attachment"] class MessageCreateParams(TypedDict, total=False): @@ -21,13 +21,8 @@ class MessageCreateParams(TypedDict, total=False): value to insert messages from the assistant into the conversation. """ - file_ids: List[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. - """ + attachments: Optional[Iterable[Attachment]] + """A list of files attached to the message, and the tools they should be added to.""" metadata: Optional[object] """Set of 16 key-value pairs that can be attached to an object. @@ -36,3 +31,10 @@ class MessageCreateParams(TypedDict, total=False): structured format. Keys can be a maximum of 64 characters long and values can be a maxium of 512 characters long. """ + + +class Attachment(TypedDict, total=False): + add_to: List[Literal["file_search", "code_interpreter"]] + + file_id: str + """The ID of the file to attach to the message.""" diff --git a/src/openai/types/beta/threads/message_delta.py b/src/openai/types/beta/threads/message_delta.py index 3a55e1442a..ecd0dfe319 100644 --- a/src/openai/types/beta/threads/message_delta.py +++ b/src/openai/types/beta/threads/message_delta.py @@ -13,12 +13,5 @@ class MessageDelta(BaseModel): content: Optional[List[MessageContentDelta]] = None """The content of the message in array of text and/or images.""" - file_ids: Optional[List[str]] = None - """ - A list of [file](https://platform.openai.com/docs/api-reference/files) IDs that - the assistant should use. Useful for tools like retrieval and code_interpreter - that can access files. A maximum of 10 files can be attached to a message. - """ - role: Optional[Literal["user", "assistant"]] = None """The entity that produced the message. One of `user` or `assistant`.""" diff --git a/src/openai/types/beta/threads/messages/__init__.py b/src/openai/types/beta/threads/messages/__init__.py deleted file mode 100644 index d129297620..0000000000 --- a/src/openai/types/beta/threads/messages/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .message_file import MessageFile as MessageFile -from .file_list_params import FileListParams as FileListParams diff --git a/src/openai/types/beta/threads/messages/message_file.py b/src/openai/types/beta/threads/messages/message_file.py deleted file mode 100644 index 342479ab7b..0000000000 --- a/src/openai/types/beta/threads/messages/message_file.py +++ /dev/null @@ -1,25 +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__ = ["MessageFile"] - - -class MessageFile(BaseModel): - id: str - """The identifier, which can be referenced in API endpoints.""" - - created_at: int - """The Unix timestamp (in seconds) for when the message file was created.""" - - message_id: str - """ - The ID of the [message](https://platform.openai.com/docs/api-reference/messages) - that the [File](https://platform.openai.com/docs/api-reference/files) is - attached to. - """ - - object: Literal["thread.message.file"] - """The object type, which is always `thread.message.file`.""" diff --git a/src/openai/types/beta/threads/run.py b/src/openai/types/beta/threads/run.py index 2efc3c77fa..8f427ce6e8 100644 --- a/src/openai/types/beta/threads/run.py +++ b/src/openai/types/beta/threads/run.py @@ -105,13 +105,6 @@ class Run(BaseModel): failed_at: Optional[int] = None """The Unix timestamp (in seconds) for when the run failed.""" - file_ids: List[str] - """ - The list of [File](https://platform.openai.com/docs/api-reference/files) IDs the - [assistant](https://platform.openai.com/docs/api-reference/assistants) used for - this run. - """ - incomplete_details: Optional[IncompleteDetails] = None """Details on why the run is incomplete. @@ -227,3 +220,6 @@ class Run(BaseModel): temperature: Optional[float] = None """The sampling temperature used for this run. If not set, defaults to 1.""" + + top_p: Optional[float] = None + """The nucleus sampling value used for this run. If not set, defaults to 1.""" diff --git a/src/openai/types/beta/threads/run_create_params.py b/src/openai/types/beta/threads/run_create_params.py index 9f2d4ba18b..fd0b4e7920 100644 --- a/src/openai/types/beta/threads/run_create_params.py +++ b/src/openai/types/beta/threads/run_create_params.py @@ -12,6 +12,7 @@ __all__ = [ "RunCreateParamsBase", "AdditionalMessage", + "AdditionalMessageAttachment", "TruncationStrategy", "RunCreateParamsNonStreaming", "RunCreateParamsStreaming", @@ -142,9 +143,23 @@ class RunCreateParamsBase(TypedDict, total=False): This is useful for modifying the behavior on a per-run basis. """ + 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. + """ + truncation_strategy: Optional[TruncationStrategy] +class AdditionalMessageAttachment(TypedDict, total=False): + add_to: List[Literal["file_search", "code_interpreter"]] + + file_id: str + """The ID of the file to attach to the message.""" + + class AdditionalMessage(TypedDict, total=False): content: Required[str] """The content of the message.""" @@ -158,13 +173,8 @@ class AdditionalMessage(TypedDict, total=False): value to insert messages from the assistant into the conversation. """ - file_ids: List[str] - """ - A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that - the message should use. There can be a maximum of 10 files attached to a - message. Useful for tools like `retrieval` and `code_interpreter` that can - access and use files. - """ + attachments: Optional[Iterable[AdditionalMessageAttachment]] + """A list of files attached to the message, and the tools they should be added to.""" metadata: Optional[object] """Set of 16 key-value pairs that can be attached to an object. diff --git a/src/openai/types/beta/threads/runs/__init__.py b/src/openai/types/beta/threads/runs/__init__.py index 256510dcc7..a312ce3df2 100644 --- a/src/openai/types/beta/threads/runs/__init__.py +++ b/src/openai/types/beta/threads/runs/__init__.py @@ -8,14 +8,14 @@ from .tool_call_delta import ToolCallDelta as ToolCallDelta from .step_list_params import StepListParams as StepListParams from .function_tool_call import FunctionToolCall as FunctionToolCall -from .retrieval_tool_call import RetrievalToolCall as RetrievalToolCall from .run_step_delta_event import RunStepDeltaEvent as RunStepDeltaEvent from .code_interpreter_logs import CodeInterpreterLogs as CodeInterpreterLogs +from .file_search_tool_call import FileSearchToolCall as FileSearchToolCall from .tool_call_delta_object import ToolCallDeltaObject as ToolCallDeltaObject from .tool_calls_step_details import ToolCallsStepDetails as ToolCallsStepDetails from .function_tool_call_delta import FunctionToolCallDelta as FunctionToolCallDelta -from .retrieval_tool_call_delta import RetrievalToolCallDelta as RetrievalToolCallDelta from .code_interpreter_tool_call import CodeInterpreterToolCall as CodeInterpreterToolCall +from .file_search_tool_call_delta import FileSearchToolCallDelta as FileSearchToolCallDelta from .run_step_delta_message_delta import RunStepDeltaMessageDelta as RunStepDeltaMessageDelta from .code_interpreter_output_image import CodeInterpreterOutputImage as CodeInterpreterOutputImage from .message_creation_step_details import MessageCreationStepDetails as MessageCreationStepDetails diff --git a/src/openai/types/beta/threads/runs/retrieval_tool_call.py b/src/openai/types/beta/threads/runs/file_search_tool_call.py similarity index 61% rename from src/openai/types/beta/threads/runs/retrieval_tool_call.py rename to src/openai/types/beta/threads/runs/file_search_tool_call.py index 48704ed331..57c0ca9a90 100644 --- a/src/openai/types/beta/threads/runs/retrieval_tool_call.py +++ b/src/openai/types/beta/threads/runs/file_search_tool_call.py @@ -4,18 +4,18 @@ from ....._models import BaseModel -__all__ = ["RetrievalToolCall"] +__all__ = ["FileSearchToolCall"] -class RetrievalToolCall(BaseModel): +class FileSearchToolCall(BaseModel): id: str """The ID of the tool call object.""" - retrieval: object + file_search: object """For now, this is always going to be an empty object.""" - type: Literal["retrieval"] + type: Literal["file_search"] """The type of tool call. - This is always going to be `retrieval` for this type of tool call. + This is always going to be `file_search` for this type of tool call. """ diff --git a/src/openai/types/beta/threads/runs/retrieval_tool_call_delta.py b/src/openai/types/beta/threads/runs/file_search_tool_call_delta.py similarity index 67% rename from src/openai/types/beta/threads/runs/retrieval_tool_call_delta.py rename to src/openai/types/beta/threads/runs/file_search_tool_call_delta.py index 3310079399..df5ac217dc 100644 --- a/src/openai/types/beta/threads/runs/retrieval_tool_call_delta.py +++ b/src/openai/types/beta/threads/runs/file_search_tool_call_delta.py @@ -5,21 +5,21 @@ from ....._models import BaseModel -__all__ = ["RetrievalToolCallDelta"] +__all__ = ["FileSearchToolCallDelta"] -class RetrievalToolCallDelta(BaseModel): +class FileSearchToolCallDelta(BaseModel): + file_search: object + """For now, this is always going to be an empty object.""" + index: int """The index of the tool call in the tool calls array.""" - type: Literal["retrieval"] + type: Literal["file_search"] """The type of tool call. - This is always going to be `retrieval` for this type of tool call. + This is always going to be `file_search` for this type of tool call. """ id: Optional[str] = None """The ID of the tool call object.""" - - retrieval: Optional[object] = None - """For now, this is always going to be an empty object.""" diff --git a/src/openai/types/beta/threads/runs/tool_call.py b/src/openai/types/beta/threads/runs/tool_call.py index dcca797bf0..77d86b46d9 100644 --- a/src/openai/types/beta/threads/runs/tool_call.py +++ b/src/openai/types/beta/threads/runs/tool_call.py @@ -5,11 +5,11 @@ from ....._utils import PropertyInfo from .function_tool_call import FunctionToolCall -from .retrieval_tool_call import RetrievalToolCall +from .file_search_tool_call import FileSearchToolCall from .code_interpreter_tool_call import CodeInterpreterToolCall __all__ = ["ToolCall"] ToolCall = Annotated[ - Union[CodeInterpreterToolCall, RetrievalToolCall, FunctionToolCall], PropertyInfo(discriminator="type") + Union[CodeInterpreterToolCall, FileSearchToolCall, FunctionToolCall], PropertyInfo(discriminator="type") ] diff --git a/src/openai/types/beta/threads/runs/tool_call_delta.py b/src/openai/types/beta/threads/runs/tool_call_delta.py index fc98981abf..90cfe0657e 100644 --- a/src/openai/types/beta/threads/runs/tool_call_delta.py +++ b/src/openai/types/beta/threads/runs/tool_call_delta.py @@ -5,12 +5,12 @@ from ....._utils import PropertyInfo from .function_tool_call_delta import FunctionToolCallDelta -from .retrieval_tool_call_delta import RetrievalToolCallDelta +from .file_search_tool_call_delta import FileSearchToolCallDelta from .code_interpreter_tool_call_delta import CodeInterpreterToolCallDelta __all__ = ["ToolCallDelta"] ToolCallDelta = Annotated[ - Union[CodeInterpreterToolCallDelta, RetrievalToolCallDelta, FunctionToolCallDelta], + Union[CodeInterpreterToolCallDelta, FileSearchToolCallDelta, FunctionToolCallDelta], PropertyInfo(discriminator="type"), ] 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 9cd59a6e24..189dce772c 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 @@ -17,5 +17,5 @@ class ToolCallDeltaObject(BaseModel): """An array of tool calls the run step was involved in. These can be associated with one of three types of tools: `code_interpreter`, - `retrieval`, or `function`. + `file_search`, or `function`. """ 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 ca08fabd0e..a084d387c7 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 @@ -14,7 +14,7 @@ class ToolCallsStepDetails(BaseModel): """An array of tool calls the run step was involved in. These can be associated with one of three types of tools: `code_interpreter`, - `retrieval`, or `function`. + `file_search`, or `function`. """ type: Literal["tool_calls"] diff --git a/src/openai/types/beta/vector_store.py b/src/openai/types/beta/vector_store.py new file mode 100644 index 0000000000..122705734d --- /dev/null +++ b/src/openai/types/beta/vector_store.py @@ -0,0 +1,79 @@ +# 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__ = ["VectorStore", "FileCounts", "ExpiresAfter"] + + +class FileCounts(BaseModel): + cancelled: int + """The number of files that were cancelled.""" + + completed: int + """The number of files that have been successfully processed.""" + + failed: int + """The number of files that have failed to process.""" + + in_progress: int + """The number of files that are currently being processed.""" + + total: int + """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.""" + + bytes: int + """The byte size of the vector store.""" + + created_at: int + """The Unix timestamp (in seconds) for when the vector store was created.""" + + file_counts: FileCounts + + last_active_at: Optional[int] = None + """The Unix timestamp (in seconds) for when the vector store was last active.""" + + 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 maxium of 512 characters long. + """ + + name: str + """The name of the vector store.""" + + object: Literal["vector_store"] + """The object type, which is always `vector_store`.""" + + status: Literal["expired", "in_progress", "completed"] + """ + The status of the vector store, which can be either `expired`, `in_progress`, or + `completed`. A status of `completed` indicates that the vector store is ready + for use. + """ + + expires_after: Optional[ExpiresAfter] = None + """The expiration policy for a vector store.""" + + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) for when the vector store will expire.""" diff --git a/src/openai/types/beta/vector_store_create_params.py b/src/openai/types/beta/vector_store_create_params.py new file mode 100644 index 0000000000..f1a3abcbdf --- /dev/null +++ b/src/openai/types/beta/vector_store_create_params.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 List, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VectorStoreCreateParams", "ExpiresAfter"] + + +class VectorStoreCreateParams(TypedDict, total=False): + expires_after: ExpiresAfter + """The expiration policy for a vector store.""" + + file_ids: List[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. + """ + + 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 maxium of 512 characters long. + """ + + 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/beta/retrieval_tool.py b/src/openai/types/beta/vector_store_deleted.py similarity index 52% rename from src/openai/types/beta/retrieval_tool.py rename to src/openai/types/beta/vector_store_deleted.py index b07b785c66..21ccda1db5 100644 --- a/src/openai/types/beta/retrieval_tool.py +++ b/src/openai/types/beta/vector_store_deleted.py @@ -4,9 +4,12 @@ from ..._models import BaseModel -__all__ = ["RetrievalTool"] +__all__ = ["VectorStoreDeleted"] -class RetrievalTool(BaseModel): - type: Literal["retrieval"] - """The type of tool being defined: `retrieval`""" +class VectorStoreDeleted(BaseModel): + id: str + + deleted: bool + + object: Literal["vector_store.deleted"] diff --git a/src/openai/types/beta/assistants/file_list_params.py b/src/openai/types/beta/vector_store_list_params.py similarity index 92% rename from src/openai/types/beta/assistants/file_list_params.py rename to src/openai/types/beta/vector_store_list_params.py index 53c493b36a..f39f67266d 100644 --- a/src/openai/types/beta/assistants/file_list_params.py +++ b/src/openai/types/beta/vector_store_list_params.py @@ -4,10 +4,10 @@ from typing_extensions import Literal, TypedDict -__all__ = ["FileListParams"] +__all__ = ["VectorStoreListParams"] -class FileListParams(TypedDict, total=False): +class VectorStoreListParams(TypedDict, total=False): after: str """A cursor for use in pagination. diff --git a/src/openai/types/beta/vector_store_update_params.py b/src/openai/types/beta/vector_store_update_params.py new file mode 100644 index 0000000000..0f9593e476 --- /dev/null +++ b/src/openai/types/beta/vector_store_update_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 Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["VectorStoreUpdateParams", "ExpiresAfter"] + + +class VectorStoreUpdateParams(TypedDict, total=False): + expires_after: Optional[ExpiresAfter] + """The expiration policy for a vector store.""" + + 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 maxium of 512 characters long. + """ + + 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.""" diff --git a/src/openai/types/beta/vector_stores/__init__.py b/src/openai/types/beta/vector_stores/__init__.py new file mode 100644 index 0000000000..ff05dd63d8 --- /dev/null +++ b/src/openai/types/beta/vector_stores/__init__.py @@ -0,0 +1,11 @@ +# 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 .vector_store_file import VectorStoreFile as VectorStoreFile +from .file_create_params import FileCreateParams as FileCreateParams +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 +from .file_batch_list_files_params import FileBatchListFilesParams as FileBatchListFilesParams diff --git a/src/openai/types/beta/vector_stores/file_batch_create_params.py b/src/openai/types/beta/vector_stores/file_batch_create_params.py new file mode 100644 index 0000000000..0882829732 --- /dev/null +++ b/src/openai/types/beta/vector_stores/file_batch_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 import List +from typing_extensions import Required, TypedDict + +__all__ = ["FileBatchCreateParams"] + + +class FileBatchCreateParams(TypedDict, total=False): + file_ids: Required[List[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. + """ 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 new file mode 100644 index 0000000000..24dee7d5a5 --- /dev/null +++ b/src/openai/types/beta/vector_stores/file_batch_list_files_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_extensions import Literal, Required, TypedDict + +__all__ = ["FileBatchListFilesParams"] + + +class FileBatchListFilesParams(TypedDict, total=False): + vector_store_id: Required[str] + + 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, ending with obj_foo, your + subsequent call can include before=obj_foo in order to fetch the previous page + of the list. + """ + + filter: Literal["in_progress", "completed", "failed", "cancelled"] + """Filter by file status. + + One of `in_progress`, `completed`, `failed`, `cancelled`. + """ + + 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/beta/assistants/file_create_params.py b/src/openai/types/beta/vector_stores/file_create_params.py similarity index 70% rename from src/openai/types/beta/assistants/file_create_params.py rename to src/openai/types/beta/vector_stores/file_create_params.py index 55f0e8cda1..2fee588abf 100644 --- a/src/openai/types/beta/assistants/file_create_params.py +++ b/src/openai/types/beta/vector_stores/file_create_params.py @@ -10,7 +10,7 @@ class FileCreateParams(TypedDict, total=False): file_id: Required[str] """ - A [File](https://platform.openai.com/docs/api-reference/files) ID (with - `purpose="assistants"`) that the assistant should use. Useful for tools like - `retrieval` and `code_interpreter` that can access files. + 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/beta/threads/messages/file_list_params.py b/src/openai/types/beta/vector_stores/file_list_params.py similarity index 84% rename from src/openai/types/beta/threads/messages/file_list_params.py rename to src/openai/types/beta/vector_stores/file_list_params.py index 7e2d6136ec..23dd7f0d94 100644 --- a/src/openai/types/beta/threads/messages/file_list_params.py +++ b/src/openai/types/beta/vector_stores/file_list_params.py @@ -2,14 +2,12 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, TypedDict __all__ = ["FileListParams"] class FileListParams(TypedDict, total=False): - thread_id: Required[str] - after: str """A cursor for use in pagination. @@ -28,6 +26,12 @@ class FileListParams(TypedDict, total=False): of the list. """ + filter: Literal["in_progress", "completed", "failed", "cancelled"] + """Filter by file status. + + One of `in_progress`, `completed`, `failed`, `cancelled`. + """ + limit: int """A limit on the number of objects to be returned. diff --git a/src/openai/types/beta/vector_stores/vector_store_file.py b/src/openai/types/beta/vector_stores/vector_store_file.py new file mode 100644 index 0000000000..a878b281d5 --- /dev/null +++ b/src/openai/types/beta/vector_stores/vector_store_file.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__ = ["VectorStoreFile", "LastError"] + + +class LastError(BaseModel): + code: Literal["internal_error", "file_not_found", "parsing_error", "unhandled_mime_type"] + """One of `server_error` or `rate_limit_exceeded`.""" + + message: str + """A human-readable description of the error.""" + + +class VectorStoreFile(BaseModel): + id: str + """The identifier, which can be referenced in API endpoints.""" + + created_at: int + """The Unix timestamp (in seconds) for when the vector store file was created.""" + + last_error: Optional[LastError] = None + """The last error associated with this vector store file. + + Will be `null` if there are no errors. + """ + + object: Literal["vector_store.file"] + """The object type, which is always `vector_store.file`.""" + + status: Literal["in_progress", "completed", "cancelled", "failed"] + """ + The status of the vector store file, which can be either `in_progress`, + `completed`, `cancelled`, or `failed`. The status `completed` indicates that the + vector store file is ready for use. + """ + + vector_store_id: str + """ + The ID of the + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + that the [File](https://platform.openai.com/docs/api-reference/files) is + attached to. + """ diff --git a/src/openai/types/beta/vector_stores/vector_store_file_batch.py b/src/openai/types/beta/vector_stores/vector_store_file_batch.py new file mode 100644 index 0000000000..df130a58de --- /dev/null +++ b/src/openai/types/beta/vector_stores/vector_store_file_batch.py @@ -0,0 +1,54 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["VectorStoreFileBatch", "FileCounts"] + + +class FileCounts(BaseModel): + cancelled: int + """The number of files that where cancelled.""" + + completed: int + """The number of files that have been processed.""" + + failed: int + """The number of files that have failed to process.""" + + in_progress: int + """The number of files that are currently being processed.""" + + total: int + """The total number of files.""" + + +class VectorStoreFileBatch(BaseModel): + id: str + """The identifier, which can be referenced in API endpoints.""" + + created_at: int + """ + The Unix timestamp (in seconds) for when the vector store files batch was + created. + """ + + file_counts: FileCounts + + object: Literal["vector_store.files_batch"] + """The object type, which is always `vector_store.file_batch`.""" + + status: Literal["in_progress", "completed", "cancelled", "failed"] + """ + The status of the vector store files batch, which can be either `in_progress`, + `completed`, `cancelled` or `failed`. + """ + + vector_store_id: str + """ + The ID of the + [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) + that the [File](https://platform.openai.com/docs/api-reference/files) is + attached to. + """ diff --git a/src/openai/types/beta/assistants/file_delete_response.py b/src/openai/types/beta/vector_stores/vector_store_file_deleted.py similarity index 60% rename from src/openai/types/beta/assistants/file_delete_response.py rename to src/openai/types/beta/vector_stores/vector_store_file_deleted.py index 685fb2a75c..ae37f84364 100644 --- a/src/openai/types/beta/assistants/file_delete_response.py +++ b/src/openai/types/beta/vector_stores/vector_store_file_deleted.py @@ -4,12 +4,12 @@ from ...._models import BaseModel -__all__ = ["FileDeleteResponse"] +__all__ = ["VectorStoreFileDeleted"] -class FileDeleteResponse(BaseModel): +class VectorStoreFileDeleted(BaseModel): id: str deleted: bool - object: Literal["assistant.file.deleted"] + object: Literal["vector_store.file.deleted"] diff --git a/src/openai/types/fine_tuning/job_create_params.py b/src/openai/types/fine_tuning/job_create_params.py index 892c737fa3..1925f90d12 100644 --- a/src/openai/types/fine_tuning/job_create_params.py +++ b/src/openai/types/fine_tuning/job_create_params.py @@ -19,7 +19,7 @@ class JobCreateParams(TypedDict, total=False): training_file: Required[str] """The ID of an uploaded file that contains training data. - See [upload file](https://platform.openai.com/docs/api-reference/files/upload) + See [upload file](https://platform.openai.com/docs/api-reference/files/create) for how to upload a file. Your dataset must be formatted as a JSONL file. Additionally, you must upload diff --git a/tests/api_resources/beta/test_assistants.py b/tests/api_resources/beta/test_assistants.py index a509627b8e..a92acb2ca5 100644 --- a/tests/api_resources/beta/test_assistants.py +++ b/tests/api_resources/beta/test_assistants.py @@ -33,11 +33,25 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: assistant = client.beta.assistants.create( model="gpt-4-turbo", description="string", - file_ids=["string", "string", "string"], instructions="string", metadata={}, name="string", + response_format="none", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -115,12 +129,18 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: assistant = client.beta.assistants.update( "string", description="string", - file_ids=["string", "string", "string"], instructions="string", metadata={}, model="string", name="string", + response_format="none", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -244,11 +264,25 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> assistant = await async_client.beta.assistants.create( model="gpt-4-turbo", description="string", - file_ids=["string", "string", "string"], instructions="string", metadata={}, name="string", + response_format="none", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, ) assert_matches_type(Assistant, assistant, path=["response"]) @@ -326,12 +360,18 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> assistant = await async_client.beta.assistants.update( "string", description="string", - file_ids=["string", "string", "string"], instructions="string", metadata={}, model="string", name="string", + response_format="none", + temperature=1, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"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 7c07251433..980fd9a75e 100644 --- a/tests/api_resources/beta/test_threads.py +++ b/tests/api_resources/beta/test_threads.py @@ -33,23 +33,74 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], metadata={}, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, ) assert_matches_type(Thread, thread, path=["response"]) @@ -123,6 +174,10 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: thread = client.beta.threads.update( "string", metadata={}, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, ) assert_matches_type(Thread, thread, path=["response"]) @@ -219,26 +274,82 @@ def test_method_create_and_run_with_all_params_overload_1(self, client: OpenAI) { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], + "tool_resources": { + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, "metadata": {}, }, tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -295,26 +406,82 @@ def test_method_create_and_run_with_all_params_overload_2(self, client: OpenAI) { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], + "tool_resources": { + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, "metadata": {}, }, tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -363,23 +530,74 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], metadata={}, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, ) assert_matches_type(Thread, thread, path=["response"]) @@ -453,6 +671,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> thread = await async_client.beta.threads.update( "string", metadata={}, + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, ) assert_matches_type(Thread, thread, path=["response"]) @@ -549,26 +771,82 @@ async def test_method_create_and_run_with_all_params_overload_1(self, async_clie { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], + "tool_resources": { + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, "metadata": {}, }, tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -625,26 +903,82 @@ async def test_method_create_and_run_with_all_params_overload_2(self, async_clie { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], + "tool_resources": { + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": { + "vector_store_ids": ["string"], + "vector_stores": [ + { + "file_ids": ["string", "string", "string"], + "metadata": {}, + } + ], + }, + }, "metadata": {}, }, tool_choice="none", + tool_resources={ + "code_interpreter": {"file_ids": ["string", "string", "string"]}, + "file_search": {"vector_store_ids": ["string"]}, + }, tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, diff --git a/tests/api_resources/beta/test_vector_stores.py b/tests/api_resources/beta/test_vector_stores.py new file mode 100644 index 0000000000..e671c96a45 --- /dev/null +++ b/tests/api_resources/beta/test_vector_stores.py @@ -0,0 +1,426 @@ +# 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 import ( + VectorStore, + VectorStoreDeleted, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVectorStores: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + vector_store = client.beta.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( + expires_after={ + "anchor": "last_active_at", + "days": 1, + }, + file_ids=["string", "string", "string"], + metadata={}, + name="string", + ) + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: OpenAI) -> None: + response = client.beta.vector_stores.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.beta.vector_stores.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + vector_store = client.beta.vector_stores.retrieve( + "string", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.beta.vector_stores.with_streaming_response.retrieve( + "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(VectorStore, vector_store, 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.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_update(self, client: OpenAI) -> None: + vector_store = client.beta.vector_stores.update( + "string", + ) + 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", + expires_after={ + "anchor": "last_active_at", + "days": 1, + }, + metadata={}, + name="string", + ) + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: OpenAI) -> None: + response = client.beta.vector_stores.with_raw_response.update( + "string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: OpenAI) -> None: + with client.beta.vector_stores.with_streaming_response.update( + "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(VectorStore, vector_store, 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.beta.vector_stores.with_raw_response.update( + "", + ) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + vector_store = client.beta.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", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[VectorStore], vector_store, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.beta.vector_stores.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(SyncCursorPage[VectorStore], vector_store, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.beta.vector_stores.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = response.parse() + assert_matches_type(SyncCursorPage[VectorStore], vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_delete(self, client: OpenAI) -> None: + vector_store = client.beta.vector_stores.delete( + "string", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStoreDeleted, vector_store, path=["response"]) + + @parametrize + def test_streaming_response_delete(self, client: OpenAI) -> None: + with client.beta.vector_stores.with_streaming_response.delete( + "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(VectorStoreDeleted, vector_store, 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.with_raw_response.delete( + "", + ) + + +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() + 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( + expires_after={ + "anchor": "last_active_at", + "days": 1, + }, + file_ids=["string", "string", "string"], + metadata={}, + name="string", + ) + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.vector_stores.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @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: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = await response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + vector_store = await async_client.beta.vector_stores.retrieve( + "string", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.vector_stores.with_streaming_response.retrieve( + "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(VectorStore, vector_store, 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.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", + ) + 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", + expires_after={ + "anchor": "last_active_at", + "days": 1, + }, + metadata={}, + name="string", + ) + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.vector_stores.with_raw_response.update( + "string", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStore, vector_store, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.vector_stores.with_streaming_response.update( + "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(VectorStore, vector_store, 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.beta.vector_stores.with_raw_response.update( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + vector_store = await async_client.beta.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", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[VectorStore], vector_store, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.beta.vector_stores.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(AsyncCursorPage[VectorStore], vector_store, path=["response"]) + + @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: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vector_store = await response.parse() + assert_matches_type(AsyncCursorPage[VectorStore], vector_store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_delete(self, async_client: AsyncOpenAI) -> None: + vector_store = await async_client.beta.vector_stores.delete( + "string", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vector_store = response.parse() + assert_matches_type(VectorStoreDeleted, vector_store, path=["response"]) + + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: + async with async_client.beta.vector_stores.with_streaming_response.delete( + "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(VectorStoreDeleted, vector_store, 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.with_raw_response.delete( + "", + ) diff --git a/tests/api_resources/beta/threads/messages/__init__.py b/tests/api_resources/beta/threads/messages/__init__.py deleted file mode 100644 index fd8019a9a1..0000000000 --- a/tests/api_resources/beta/threads/messages/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/beta/threads/messages/test_files.py b/tests/api_resources/beta/threads/messages/test_files.py deleted file mode 100644 index af4eea9377..0000000000 --- a/tests/api_resources/beta/threads/messages/test_files.py +++ /dev/null @@ -1,263 +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.threads.messages import MessageFile - -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_retrieve(self, client: OpenAI) -> None: - file = client.beta.threads.messages.files.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - assert_matches_type(MessageFile, file, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(MessageFile, file, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.threads.messages.files.with_streaming_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_abc123", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - file = response.parse() - assert_matches_type(MessageFile, 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 `thread_id` but received ''"): - client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="", - message_id="msg_abc123", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - client.beta.threads.messages.files.with_raw_response.retrieve( - "", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - - @parametrize - def test_method_list(self, client: OpenAI) -> None: - file = client.beta.threads.messages.files.list( - "string", - thread_id="string", - ) - assert_matches_type(SyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: OpenAI) -> None: - file = client.beta.threads.messages.files.list( - "string", - thread_id="string", - after="string", - before="string", - limit=0, - order="asc", - ) - assert_matches_type(SyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.threads.messages.files.with_raw_response.list( - "string", - thread_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(SyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.threads.messages.files.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" - - file = response.parse() - assert_matches_type(SyncCursorPage[MessageFile], 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 `thread_id` but received ''"): - client.beta.threads.messages.files.with_raw_response.list( - "string", - thread_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - client.beta.threads.messages.files.with_raw_response.list( - "", - thread_id="string", - ) - - -class TestAsyncFiles: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.threads.messages.files.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - assert_matches_type(MessageFile, file, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(MessageFile, file, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.files.with_streaming_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="msg_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(MessageFile, 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 `thread_id` but received ''"): - await async_client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="", - message_id="msg_abc123", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_id` but received ''"): - await async_client.beta.threads.messages.files.with_raw_response.retrieve( - "file-abc123", - thread_id="thread_abc123", - message_id="", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - await async_client.beta.threads.messages.files.with_raw_response.retrieve( - "", - thread_id="thread_abc123", - message_id="msg_abc123", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.threads.messages.files.list( - "string", - thread_id="string", - ) - assert_matches_type(AsyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.threads.messages.files.list( - "string", - thread_id="string", - after="string", - before="string", - limit=0, - order="asc", - ) - assert_matches_type(AsyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.threads.messages.files.with_raw_response.list( - "string", - thread_id="string", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - file = response.parse() - assert_matches_type(AsyncCursorPage[MessageFile], file, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.threads.messages.files.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" - - file = await response.parse() - assert_matches_type(AsyncCursorPage[MessageFile], 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 `thread_id` but received ''"): - await async_client.beta.threads.messages.files.with_raw_response.list( - "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.files.with_raw_response.list( - "", - thread_id="string", - ) diff --git a/tests/api_resources/beta/threads/test_messages.py b/tests/api_resources/beta/threads/test_messages.py index 22198ccbc5..5ea5ac3bd5 100644 --- a/tests/api_resources/beta/threads/test_messages.py +++ b/tests/api_resources/beta/threads/test_messages.py @@ -33,7 +33,20 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: "string", content="x", role="user", - file_ids=["string"], + attachments=[ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], metadata={}, ) assert_matches_type(Message, message, path=["response"]) @@ -249,7 +262,20 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> "string", content="x", role="user", - file_ids=["string"], + attachments=[ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], metadata={}, ) 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 cf5b2998b9..3d8a6ce058 100644 --- a/tests/api_resources/beta/threads/test_runs.py +++ b/tests/api_resources/beta/threads/test_runs.py @@ -40,19 +40,58 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], @@ -66,6 +105,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: temperature=1, tool_choice="none", tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -127,19 +167,58 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], @@ -152,6 +231,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: temperature=1, tool_choice="none", tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -552,19 +632,58 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], @@ -578,6 +697,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn temperature=1, tool_choice="none", tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, @@ -639,19 +759,58 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, { "role": "user", "content": "x", - "file_ids": ["string"], + "attachments": [ + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + { + "file_id": "string", + "add_to": ["file_search", "code_interpreter"], + }, + ], "metadata": {}, }, ], @@ -664,6 +823,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn temperature=1, tool_choice="none", tools=[{"type": "code_interpreter"}, {"type": "code_interpreter"}, {"type": "code_interpreter"}], + top_p=1, truncation_strategy={ "type": "auto", "last_messages": 1, diff --git a/tests/api_resources/beta/assistants/__init__.py b/tests/api_resources/beta/vector_stores/__init__.py similarity index 100% rename from tests/api_resources/beta/assistants/__init__.py rename to tests/api_resources/beta/vector_stores/__init__.py diff --git a/tests/api_resources/beta/vector_stores/test_file_batches.py b/tests/api_resources/beta/vector_stores/test_file_batches.py new file mode 100644 index 0000000000..9854d1a138 --- /dev/null +++ b/tests/api_resources/beta/vector_stores/test_file_batches.py @@ -0,0 +1,424 @@ +# 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, + VectorStoreFileBatch, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestFileBatches: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: OpenAI) -> None: + file_batch = client.beta.vector_stores.file_batches.create( + "vs_abc123", + file_ids=["string"], + ) + 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", + file_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: OpenAI) -> None: + with client.beta.vector_stores.file_batches.with_streaming_response.create( + "vs_abc123", + file_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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.file_batches.with_raw_response.create( + "", + file_ids=["string"], + ) + + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + file_batch = client.beta.vector_stores.file_batches.retrieve( + "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", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.beta.vector_stores.file_batches.with_streaming_response.retrieve( + "vsfb_abc123", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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.file_batches.with_raw_response.retrieve( + "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( + "", + 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", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @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", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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 `vector_store_id` but received ''"): + client.beta.vector_stores.file_batches.with_raw_response.cancel( + "string", + 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", + ) + + @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", + ) + 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", + filter="in_progress", + limit=0, + order="asc", + ) + assert_matches_type(SyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + @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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(SyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + @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", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = response.parse() + assert_matches_type(SyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @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", + 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", + ) + + +class TestAsyncFileBatches: + 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_batch = await async_client.beta.vector_stores.file_batches.create( + "vs_abc123", + file_ids=["string"], + ) + 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", + file_ids=["string"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @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", + file_ids=["string"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = await response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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.file_batches.with_raw_response.create( + "", + 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", + 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", + vector_store_id="vs_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @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", + vector_store_id="vs_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = await response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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.file_batches.with_raw_response.retrieve( + "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( + "", + 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", + ) + 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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, path=["response"]) + + @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", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = await response.parse() + assert_matches_type(VectorStoreFileBatch, file_batch, 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 `vector_store_id` but received ''"): + await async_client.beta.vector_stores.file_batches.with_raw_response.cancel( + "string", + 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", + ) + + @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", + ) + 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", + filter="in_progress", + limit=0, + order="asc", + ) + assert_matches_type(AsyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + @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", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + file_batch = response.parse() + assert_matches_type(AsyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + @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", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + file_batch = await response.parse() + assert_matches_type(AsyncCursorPage[VectorStoreFile], file_batch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @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", + 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", + ) diff --git a/tests/api_resources/beta/assistants/test_files.py b/tests/api_resources/beta/vector_stores/test_files.py similarity index 59% rename from tests/api_resources/beta/assistants/test_files.py rename to tests/api_resources/beta/vector_stores/test_files.py index 50106234aa..58301e2d37 100644 --- a/tests/api_resources/beta/assistants/test_files.py +++ b/tests/api_resources/beta/vector_stores/test_files.py @@ -10,7 +10,10 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type from openai.pagination import SyncCursorPage, AsyncCursorPage -from openai.types.beta.assistants import AssistantFile, FileDeleteResponse +from openai.types.beta.vector_stores import ( + VectorStoreFile, + VectorStoreFileDeleted, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -20,189 +23,190 @@ class TestFiles: @parametrize def test_method_create(self, client: OpenAI) -> None: - file = client.beta.assistants.files.create( - "file-abc123", + file = client.beta.vector_stores.files.create( + "vs_abc123", file_id="string", ) - assert_matches_type(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize def test_raw_response_create(self, client: OpenAI) -> None: - response = client.beta.assistants.files.with_raw_response.create( - "file-abc123", + 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(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize def test_streaming_response_create(self, client: OpenAI) -> None: - with client.beta.assistants.files.with_streaming_response.create( - "file-abc123", + 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(AssistantFile, file, path=["response"]) + 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 `assistant_id` but received ''"): - client.beta.assistants.files.with_raw_response.create( + 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.assistants.files.retrieve( - "string", - assistant_id="string", + file = client.beta.vector_stores.files.retrieve( + "file-abc123", + vector_store_id="vs_abc123", ) - assert_matches_type(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: OpenAI) -> None: - response = client.beta.assistants.files.with_raw_response.retrieve( - "string", - assistant_id="string", + 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(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize def test_streaming_response_retrieve(self, client: OpenAI) -> None: - with client.beta.assistants.files.with_streaming_response.retrieve( - "string", - assistant_id="string", + 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(AssistantFile, file, path=["response"]) + 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 `assistant_id` but received ''"): - client.beta.assistants.files.with_raw_response.retrieve( - "string", - assistant_id="", + 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.assistants.files.with_raw_response.retrieve( + client.beta.vector_stores.files.with_raw_response.retrieve( "", - assistant_id="string", + vector_store_id="vs_abc123", ) @parametrize def test_method_list(self, client: OpenAI) -> None: - file = client.beta.assistants.files.list( + file = client.beta.vector_stores.files.list( "string", ) - assert_matches_type(SyncCursorPage[AssistantFile], file, path=["response"]) + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: - file = client.beta.assistants.files.list( + file = client.beta.vector_stores.files.list( "string", after="string", before="string", + filter="in_progress", limit=0, order="asc", ) - assert_matches_type(SyncCursorPage[AssistantFile], file, path=["response"]) + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) @parametrize def test_raw_response_list(self, client: OpenAI) -> None: - response = client.beta.assistants.files.with_raw_response.list( + 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[AssistantFile], file, path=["response"]) + assert_matches_type(SyncCursorPage[VectorStoreFile], file, path=["response"]) @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: - with client.beta.assistants.files.with_streaming_response.list( + 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[AssistantFile], file, path=["response"]) + 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 `assistant_id` but received ''"): - client.beta.assistants.files.with_raw_response.list( + 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.assistants.files.delete( + file = client.beta.vector_stores.files.delete( "string", - assistant_id="string", + vector_store_id="string", ) - assert_matches_type(FileDeleteResponse, file, path=["response"]) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) @parametrize def test_raw_response_delete(self, client: OpenAI) -> None: - response = client.beta.assistants.files.with_raw_response.delete( + response = client.beta.vector_stores.files.with_raw_response.delete( "string", - assistant_id="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(FileDeleteResponse, file, path=["response"]) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) @parametrize def test_streaming_response_delete(self, client: OpenAI) -> None: - with client.beta.assistants.files.with_streaming_response.delete( + with client.beta.vector_stores.files.with_streaming_response.delete( "string", - assistant_id="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(FileDeleteResponse, file, path=["response"]) + 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 `assistant_id` but received ''"): - client.beta.assistants.files.with_raw_response.delete( + 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", - assistant_id="", + vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - client.beta.assistants.files.with_raw_response.delete( + client.beta.vector_stores.files.with_raw_response.delete( "", - assistant_id="string", + vector_store_id="string", ) @@ -211,187 +215,188 @@ class TestAsyncFiles: @parametrize async def test_method_create(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.assistants.files.create( - "file-abc123", + file = await async_client.beta.vector_stores.files.create( + "vs_abc123", file_id="string", ) - assert_matches_type(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.files.with_raw_response.create( - "file-abc123", + 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(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.files.with_streaming_response.create( - "file-abc123", + 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(AssistantFile, file, path=["response"]) + 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 `assistant_id` but received ''"): - await async_client.beta.assistants.files.with_raw_response.create( + 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.assistants.files.retrieve( - "string", - assistant_id="string", + file = await async_client.beta.vector_stores.files.retrieve( + "file-abc123", + vector_store_id="vs_abc123", ) - assert_matches_type(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.files.with_raw_response.retrieve( - "string", - assistant_id="string", + 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(AssistantFile, file, path=["response"]) + assert_matches_type(VectorStoreFile, file, path=["response"]) @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.files.with_streaming_response.retrieve( - "string", - assistant_id="string", + 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(AssistantFile, file, path=["response"]) + 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 `assistant_id` but received ''"): - await async_client.beta.assistants.files.with_raw_response.retrieve( - "string", - assistant_id="", + 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.assistants.files.with_raw_response.retrieve( + await async_client.beta.vector_stores.files.with_raw_response.retrieve( "", - assistant_id="string", + vector_store_id="vs_abc123", ) @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: - file = await async_client.beta.assistants.files.list( + file = await async_client.beta.vector_stores.files.list( "string", ) - assert_matches_type(AsyncCursorPage[AssistantFile], file, path=["response"]) + 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.assistants.files.list( + 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[AssistantFile], file, path=["response"]) + 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.assistants.files.with_raw_response.list( + 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[AssistantFile], file, path=["response"]) + 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.assistants.files.with_streaming_response.list( + 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[AssistantFile], file, path=["response"]) + 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 `assistant_id` but received ''"): - await async_client.beta.assistants.files.with_raw_response.list( + 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.assistants.files.delete( + file = await async_client.beta.vector_stores.files.delete( "string", - assistant_id="string", + vector_store_id="string", ) - assert_matches_type(FileDeleteResponse, file, path=["response"]) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None: - response = await async_client.beta.assistants.files.with_raw_response.delete( + response = await async_client.beta.vector_stores.files.with_raw_response.delete( "string", - assistant_id="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(FileDeleteResponse, file, path=["response"]) + assert_matches_type(VectorStoreFileDeleted, file, path=["response"]) @parametrize async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None: - async with async_client.beta.assistants.files.with_streaming_response.delete( + async with async_client.beta.vector_stores.files.with_streaming_response.delete( "string", - assistant_id="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(FileDeleteResponse, file, path=["response"]) + 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 `assistant_id` but received ''"): - await async_client.beta.assistants.files.with_raw_response.delete( + 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", - assistant_id="", + vector_store_id="", ) with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"): - await async_client.beta.assistants.files.with_raw_response.delete( + await async_client.beta.vector_stores.files.with_raw_response.delete( "", - assistant_id="string", + vector_store_id="string", )