diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 26b25a25e8..49df20d2b8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.20.0" + ".": "2.21.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 6c725eaa30..1d0140eb64 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 148 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-47ef7e0aaa2f2052404041650c9b4d7d8c9c51c45ef2cb081548f329c3f81a6a.yml -openapi_spec_hash: 0207b30cf74121a12c1647e25463cee9 -config_hash: 8dca0f2dc2706c07cf2f8d0ed4dc062e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0db5326a0fb6a30ffad9242c72872c3388ef927e8a4549ddd20aec3420541209.yml +openapi_spec_hash: 9523fe30739802e15c88f4e7aac44e7f +config_hash: 948733484caf41e71093c6582dbc319c diff --git a/CHANGELOG.md b/CHANGELOG.md index 39ed325e8e..6f558b3626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 2.21.0 (2026-02-13) + +Full Changelog: [v2.20.0...v2.21.0](https://github.com/openai/openai-python/compare/v2.20.0...v2.21.0) + +### Features + +* **api:** container network_policy and skills ([d19de2e](https://github.com/openai/openai-python/commit/d19de2ee5c74413f9dc52684b650df1898dee82b)) + + +### Bug Fixes + +* **structured outputs:** resolve memory leak in parse methods ([#2860](https://github.com/openai/openai-python/issues/2860)) ([6dcbe21](https://github.com/openai/openai-python/commit/6dcbe211f12f8470db542a5cb95724cb933786dd)) +* **webhooks:** preserve method visibility for compatibility checks ([44a8936](https://github.com/openai/openai-python/commit/44a8936d580b770f23fae79659101a27eadafad6)) + + +### Chores + +* **internal:** fix lint error on Python 3.14 ([534f215](https://github.com/openai/openai-python/commit/534f215941f504443d63509e872409a0b1236452)) + + +### Documentation + +* split `api.md` by standalone resources ([96e41b3](https://github.com/openai/openai-python/commit/96e41b398a110212ddec71436b2439343bea87d4)) +* update comment ([63def23](https://github.com/openai/openai-python/commit/63def23b7acd5c6dacf03337fe1bd08439d1dba8)) + ## 2.20.0 (2026-02-10) Full Changelog: [v2.19.0...v2.20.0](https://github.com/openai/openai-python/compare/v2.19.0...v2.20.0) diff --git a/api.md b/api.md index 54fa94da5f..da521d3418 100644 --- a/api.md +++ b/api.md @@ -419,30 +419,7 @@ Methods: - client.vector_stores.file_batches.poll(\*args) -> VectorStoreFileBatch - client.vector_stores.file_batches.upload_and_poll(\*args) -> VectorStoreFileBatch -# Webhooks - -Types: - -```python -from openai.types.webhooks import ( - BatchCancelledWebhookEvent, - BatchCompletedWebhookEvent, - BatchExpiredWebhookEvent, - BatchFailedWebhookEvent, - EvalRunCanceledWebhookEvent, - EvalRunFailedWebhookEvent, - EvalRunSucceededWebhookEvent, - FineTuningJobCancelledWebhookEvent, - FineTuningJobFailedWebhookEvent, - FineTuningJobSucceededWebhookEvent, - RealtimeCallIncomingWebhookEvent, - ResponseCancelledWebhookEvent, - ResponseCompletedWebhookEvent, - ResponseFailedWebhookEvent, - ResponseIncompleteWebhookEvent, - UnwrapWebhookEvent, -) -``` +# [Webhooks](src/openai/resources/webhooks/api.md) Methods: @@ -727,362 +704,11 @@ Methods: - client.uploads.parts.create(upload_id, \*\*params) -> UploadPart -# Responses - -Types: - -```python -from openai.types.responses import ( - ApplyPatchTool, - CompactedResponse, - ComputerTool, - ContainerAuto, - ContainerNetworkPolicyAllowlist, - ContainerNetworkPolicyDisabled, - ContainerNetworkPolicyDomainSecret, - ContainerReference, - CustomTool, - EasyInputMessage, - FileSearchTool, - FunctionShellTool, - FunctionTool, - InlineSkill, - InlineSkillSource, - LocalEnvironment, - LocalSkill, - Response, - ResponseApplyPatchToolCall, - ResponseApplyPatchToolCallOutput, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCodeInterpreterCallCodeDeltaEvent, - ResponseCodeInterpreterCallCodeDoneEvent, - ResponseCodeInterpreterCallCompletedEvent, - ResponseCodeInterpreterCallInProgressEvent, - ResponseCodeInterpreterCallInterpretingEvent, - ResponseCodeInterpreterToolCall, - ResponseCompactionItem, - ResponseCompactionItemParam, - ResponseCompletedEvent, - ResponseComputerToolCall, - ResponseComputerToolCallOutputItem, - ResponseComputerToolCallOutputScreenshot, - ResponseContainerReference, - ResponseContent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseConversationParam, - ResponseCreatedEvent, - ResponseCustomToolCall, - ResponseCustomToolCallInputDeltaEvent, - ResponseCustomToolCallInputDoneEvent, - ResponseCustomToolCallOutput, - ResponseError, - ResponseErrorEvent, - ResponseFailedEvent, - ResponseFileSearchCallCompletedEvent, - ResponseFileSearchCallInProgressEvent, - ResponseFileSearchCallSearchingEvent, - ResponseFileSearchToolCall, - ResponseFormatTextConfig, - ResponseFormatTextJSONSchemaConfig, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseFunctionCallOutputItem, - ResponseFunctionCallOutputItemList, - ResponseFunctionShellCallOutputContent, - ResponseFunctionShellToolCall, - ResponseFunctionShellToolCallOutput, - ResponseFunctionToolCall, - ResponseFunctionToolCallItem, - ResponseFunctionToolCallOutputItem, - ResponseFunctionWebSearch, - ResponseImageGenCallCompletedEvent, - ResponseImageGenCallGeneratingEvent, - ResponseImageGenCallInProgressEvent, - ResponseImageGenCallPartialImageEvent, - ResponseInProgressEvent, - ResponseIncludable, - ResponseIncompleteEvent, - ResponseInput, - ResponseInputAudio, - ResponseInputContent, - ResponseInputFile, - ResponseInputFileContent, - ResponseInputImage, - ResponseInputImageContent, - ResponseInputItem, - ResponseInputMessageContentList, - ResponseInputMessageItem, - ResponseInputText, - ResponseInputTextContent, - ResponseItem, - ResponseLocalEnvironment, - ResponseMcpCallArgumentsDeltaEvent, - ResponseMcpCallArgumentsDoneEvent, - ResponseMcpCallCompletedEvent, - ResponseMcpCallFailedEvent, - ResponseMcpCallInProgressEvent, - ResponseMcpListToolsCompletedEvent, - ResponseMcpListToolsFailedEvent, - ResponseMcpListToolsInProgressEvent, - ResponseOutputAudio, - ResponseOutputItem, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseOutputMessage, - ResponseOutputRefusal, - ResponseOutputText, - ResponseOutputTextAnnotationAddedEvent, - ResponsePrompt, - ResponseQueuedEvent, - ResponseReasoningItem, - ResponseReasoningSummaryPartAddedEvent, - ResponseReasoningSummaryPartDoneEvent, - ResponseReasoningSummaryTextDeltaEvent, - ResponseReasoningSummaryTextDoneEvent, - ResponseReasoningTextDeltaEvent, - ResponseReasoningTextDoneEvent, - ResponseRefusalDeltaEvent, - ResponseRefusalDoneEvent, - ResponseStatus, - ResponseStreamEvent, - ResponseTextConfig, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - ResponseUsage, - ResponseWebSearchCallCompletedEvent, - ResponseWebSearchCallInProgressEvent, - ResponseWebSearchCallSearchingEvent, - SkillReference, - Tool, - ToolChoiceAllowed, - ToolChoiceApplyPatch, - ToolChoiceCustom, - ToolChoiceFunction, - ToolChoiceMcp, - ToolChoiceOptions, - ToolChoiceShell, - ToolChoiceTypes, - WebSearchPreviewTool, - WebSearchTool, -) -``` - -Methods: - -- client.responses.create(\*\*params) -> Response -- client.responses.retrieve(response_id, \*\*params) -> Response -- client.responses.delete(response_id) -> None -- client.responses.cancel(response_id) -> Response -- client.responses.compact(\*\*params) -> CompactedResponse - -## InputItems - -Types: - -```python -from openai.types.responses import ResponseItemList -``` - -Methods: - -- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] - -## InputTokens - -Types: - -```python -from openai.types.responses import InputTokenCountResponse -``` - -Methods: - -- client.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse - -# Realtime - -Types: - -```python -from openai.types.realtime import ( - AudioTranscription, - ConversationCreatedEvent, - ConversationItem, - ConversationItemAdded, - ConversationItemCreateEvent, - ConversationItemCreatedEvent, - ConversationItemDeleteEvent, - ConversationItemDeletedEvent, - ConversationItemDone, - ConversationItemInputAudioTranscriptionCompletedEvent, - ConversationItemInputAudioTranscriptionDeltaEvent, - ConversationItemInputAudioTranscriptionFailedEvent, - ConversationItemInputAudioTranscriptionSegment, - ConversationItemRetrieveEvent, - ConversationItemTruncateEvent, - ConversationItemTruncatedEvent, - ConversationItemWithReference, - InputAudioBufferAppendEvent, - InputAudioBufferClearEvent, - InputAudioBufferClearedEvent, - InputAudioBufferCommitEvent, - InputAudioBufferCommittedEvent, - InputAudioBufferDtmfEventReceivedEvent, - InputAudioBufferSpeechStartedEvent, - InputAudioBufferSpeechStoppedEvent, - InputAudioBufferTimeoutTriggered, - LogProbProperties, - McpListToolsCompleted, - McpListToolsFailed, - McpListToolsInProgress, - NoiseReductionType, - OutputAudioBufferClearEvent, - RateLimitsUpdatedEvent, - RealtimeAudioConfig, - RealtimeAudioConfigInput, - RealtimeAudioConfigOutput, - RealtimeAudioFormats, - RealtimeAudioInputTurnDetection, - RealtimeClientEvent, - RealtimeConversationItemAssistantMessage, - RealtimeConversationItemFunctionCall, - RealtimeConversationItemFunctionCallOutput, - RealtimeConversationItemSystemMessage, - RealtimeConversationItemUserMessage, - RealtimeError, - RealtimeErrorEvent, - RealtimeFunctionTool, - RealtimeMcpApprovalRequest, - RealtimeMcpApprovalResponse, - RealtimeMcpListTools, - RealtimeMcpProtocolError, - RealtimeMcpToolCall, - RealtimeMcpToolExecutionError, - RealtimeMcphttpError, - RealtimeResponse, - RealtimeResponseCreateAudioOutput, - RealtimeResponseCreateMcpTool, - RealtimeResponseCreateParams, - RealtimeResponseStatus, - RealtimeResponseUsage, - RealtimeResponseUsageInputTokenDetails, - RealtimeResponseUsageOutputTokenDetails, - RealtimeServerEvent, - RealtimeSession, - RealtimeSessionCreateRequest, - RealtimeToolChoiceConfig, - RealtimeToolsConfig, - RealtimeToolsConfigUnion, - RealtimeTracingConfig, - RealtimeTranscriptionSessionAudio, - RealtimeTranscriptionSessionAudioInput, - RealtimeTranscriptionSessionAudioInputTurnDetection, - RealtimeTranscriptionSessionCreateRequest, - RealtimeTruncation, - RealtimeTruncationRetentionRatio, - ResponseAudioDeltaEvent, - ResponseAudioDoneEvent, - ResponseAudioTranscriptDeltaEvent, - ResponseAudioTranscriptDoneEvent, - ResponseCancelEvent, - ResponseContentPartAddedEvent, - ResponseContentPartDoneEvent, - ResponseCreateEvent, - ResponseCreatedEvent, - ResponseDoneEvent, - ResponseFunctionCallArgumentsDeltaEvent, - ResponseFunctionCallArgumentsDoneEvent, - ResponseMcpCallArgumentsDelta, - ResponseMcpCallArgumentsDone, - ResponseMcpCallCompleted, - ResponseMcpCallFailed, - ResponseMcpCallInProgress, - ResponseOutputItemAddedEvent, - ResponseOutputItemDoneEvent, - ResponseTextDeltaEvent, - ResponseTextDoneEvent, - SessionCreatedEvent, - SessionUpdateEvent, - SessionUpdatedEvent, - TranscriptionSessionUpdate, - TranscriptionSessionUpdatedEvent, -) -``` - -## ClientSecrets +# [Responses](src/openai/resources/responses/api.md) -Types: - -```python -from openai.types.realtime import ( - RealtimeSessionClientSecret, - RealtimeSessionCreateResponse, - RealtimeTranscriptionSessionCreateResponse, - RealtimeTranscriptionSessionTurnDetection, - ClientSecretCreateResponse, -) -``` - -Methods: - -- client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse - -## Calls - -Methods: - -- client.realtime.calls.create(\*\*params) -> HttpxBinaryResponseContent -- client.realtime.calls.accept(call_id, \*\*params) -> None -- client.realtime.calls.hangup(call_id) -> None -- client.realtime.calls.refer(call_id, \*\*params) -> None -- client.realtime.calls.reject(call_id, \*\*params) -> None - -# Conversations - -Types: - -```python -from openai.types.conversations import ( - ComputerScreenshotContent, - Conversation, - ConversationDeleted, - ConversationDeletedResource, - Message, - SummaryTextContent, - TextContent, - InputTextContent, - OutputTextContent, - RefusalContent, - InputImageContent, - InputFileContent, -) -``` - -Methods: - -- client.conversations.create(\*\*params) -> Conversation -- client.conversations.retrieve(conversation_id) -> Conversation -- client.conversations.update(conversation_id, \*\*params) -> Conversation -- client.conversations.delete(conversation_id) -> ConversationDeletedResource - -## Items - -Types: - -```python -from openai.types.conversations import ConversationItem, ConversationItemList -``` - -Methods: +# [Realtime](src/openai/resources/realtime/api.md) -- client.conversations.items.create(conversation_id, \*\*params) -> ConversationItemList -- client.conversations.items.retrieve(item_id, \*, conversation_id, \*\*params) -> ConversationItem -- client.conversations.items.list(conversation_id, \*\*params) -> SyncConversationCursorPage[ConversationItem] -- client.conversations.items.delete(item_id, \*, conversation_id) -> Conversation +# [Conversations](src/openai/resources/conversations/api.md) # Evals diff --git a/pyproject.toml b/pyproject.toml index 326c715f08..fe2e394592 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.20.0" +version = "2.21.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" @@ -84,7 +84,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ diff --git a/src/openai/_client.py b/src/openai/_client.py index 440a8a45c8..0399bbf742 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -63,7 +63,6 @@ from .resources.models import Models, AsyncModels from .resources.videos import Videos, AsyncVideos from .resources.batches import Batches, AsyncBatches - from .resources.webhooks import Webhooks, AsyncWebhooks from .resources.beta.beta import Beta, AsyncBeta from .resources.chat.chat import Chat, AsyncChat from .resources.embeddings import Embeddings, AsyncEmbeddings @@ -74,6 +73,7 @@ from .resources.skills.skills import Skills, AsyncSkills from .resources.uploads.uploads import Uploads, AsyncUploads from .resources.realtime.realtime import Realtime, AsyncRealtime + from .resources.webhooks.webhooks import Webhooks, AsyncWebhooks from .resources.responses.responses import Responses, AsyncResponses from .resources.containers.containers import Containers, AsyncContainers from .resources.fine_tuning.fine_tuning import FineTuning, AsyncFineTuning diff --git a/src/openai/_module_client.py b/src/openai/_module_client.py index 17bb9306aa..98901c0446 100644 --- a/src/openai/_module_client.py +++ b/src/openai/_module_client.py @@ -11,7 +11,6 @@ from .resources.models import Models from .resources.videos import Videos from .resources.batches import Batches - from .resources.webhooks import Webhooks from .resources.beta.beta import Beta from .resources.chat.chat import Chat from .resources.embeddings import Embeddings @@ -22,6 +21,7 @@ from .resources.skills.skills import Skills from .resources.uploads.uploads import Uploads from .resources.realtime.realtime import Realtime + from .resources.webhooks.webhooks import Webhooks from .resources.responses.responses import Responses from .resources.containers.containers import Containers from .resources.fine_tuning.fine_tuning import FineTuning diff --git a/src/openai/_utils/_compat.py b/src/openai/_utils/_compat.py index dd703233c5..2c70b299ce 100644 --- a/src/openai/_utils/_compat.py +++ b/src/openai/_utils/_compat.py @@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool: else: import types - return tp is Union or tp is types.UnionType + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] def is_typeddict(tp: Type[Any]) -> bool: diff --git a/src/openai/_version.py b/src/openai/_version.py index 4987d1ca18..0d4ef7b71c 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "openai" -__version__ = "2.20.0" # x-release-please-version +__version__ = "2.21.0" # x-release-please-version diff --git a/src/openai/lib/_parsing/__init__.py b/src/openai/lib/_parsing/__init__.py index 4d454c3a20..08591f43f4 100644 --- a/src/openai/lib/_parsing/__init__.py +++ b/src/openai/lib/_parsing/__init__.py @@ -6,7 +6,6 @@ validate_input_tools as validate_input_tools, parse_chat_completion as parse_chat_completion, get_input_tool_by_name as get_input_tool_by_name, - solve_response_format_t as solve_response_format_t, parse_function_tool_arguments as parse_function_tool_arguments, type_to_response_format_param as type_to_response_format_param, ) diff --git a/src/openai/lib/_parsing/_completions.py b/src/openai/lib/_parsing/_completions.py index 7903732a4a..7a1bded1de 100644 --- a/src/openai/lib/_parsing/_completions.py +++ b/src/openai/lib/_parsing/_completions.py @@ -138,7 +138,7 @@ def parse_chat_completion( choices.append( construct_type_unchecked( - type_=cast(Any, ParsedChoice)[solve_response_format_t(response_format)], + type_=ParsedChoice[ResponseFormatT], value={ **choice.to_dict(), "message": { @@ -153,15 +153,12 @@ def parse_chat_completion( ) ) - return cast( - ParsedChatCompletion[ResponseFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedChatCompletion)[solve_response_format_t(response_format)], - value={ - **chat_completion.to_dict(), - "choices": choices, - }, - ), + return construct_type_unchecked( + type_=ParsedChatCompletion[ResponseFormatT], + value={ + **chat_completion.to_dict(), + "choices": choices, + }, ) @@ -201,20 +198,6 @@ def maybe_parse_content( return None -def solve_response_format_t( - response_format: type[ResponseFormatT] | ResponseFormatParam | Omit, -) -> type[ResponseFormatT]: - """Return the runtime type for the given response format. - - If no response format is given, or if we won't auto-parse the response format - then we default to `None`. - """ - if has_rich_response_format(response_format): - return response_format - - return cast("type[ResponseFormatT]", _default_response_format) - - def has_parseable_input( *, response_format: type | ResponseFormatParam | Omit, diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 4bed171df7..5676eb0b63 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -1,7 +1,7 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any, List, Iterable, cast +from typing import TYPE_CHECKING, List, Iterable, cast from typing_extensions import TypeVar, assert_never import pydantic @@ -12,7 +12,7 @@ from ..._compat import PYDANTIC_V1, model_parse_json from ..._models import construct_type_unchecked from .._pydantic import is_basemodel_type, is_dataclass_like_type -from ._completions import solve_response_format_t, type_to_response_format_param +from ._completions import type_to_response_format_param from ...types.responses import ( Response, ToolParam, @@ -56,7 +56,6 @@ def parse_response( input_tools: Iterable[ToolParam] | Omit | None, response: Response | ParsedResponse[object], ) -> ParsedResponse[TextFormatT]: - solved_t = solve_response_format_t(text_format) output_list: List[ParsedResponseOutputItem[TextFormatT]] = [] for output in response.output: @@ -69,7 +68,7 @@ def parse_response( content_list.append( construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputText)[solved_t], + type_=ParsedResponseOutputText[TextFormatT], value={ **item.to_dict(), "parsed": parse_text(item.text, text_format=text_format), @@ -79,7 +78,7 @@ def parse_response( output_list.append( construct_type_unchecked( - type_=cast(Any, ParsedResponseOutputMessage)[solved_t], + type_=ParsedResponseOutputMessage[TextFormatT], value={ **output.to_dict(), "content": content_list, @@ -123,15 +122,12 @@ def parse_response( else: output_list.append(output) - return cast( - ParsedResponse[TextFormatT], - construct_type_unchecked( - type_=cast(Any, ParsedResponse)[solved_t], - value={ - **response.to_dict(), - "output": output_list, - }, - ), + return construct_type_unchecked( + type_=ParsedResponse[TextFormatT], + value={ + **response.to_dict(), + "output": output_list, + }, ) diff --git a/src/openai/lib/streaming/chat/_completions.py b/src/openai/lib/streaming/chat/_completions.py index c4610e2120..5f072cafbd 100644 --- a/src/openai/lib/streaming/chat/_completions.py +++ b/src/openai/lib/streaming/chat/_completions.py @@ -33,7 +33,6 @@ maybe_parse_content, parse_chat_completion, get_input_tool_by_name, - solve_response_format_t, parse_function_tool_arguments, ) from ...._streaming import Stream, AsyncStream @@ -663,7 +662,7 @@ def _content_done_events( # type variable, e.g. `ContentDoneEvent[MyModelType]` cast( # pyright: ignore[reportUnnecessaryCast] "type[ContentDoneEvent[ResponseFormatT]]", - cast(Any, ContentDoneEvent)[solve_response_format_t(response_format)], + cast(Any, ContentDoneEvent), ), type="content.done", content=choice_snapshot.message.content, diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py index 9c0b74b804..fb1887a7d5 100644 --- a/src/openai/resources/chat/completions/completions.py +++ b/src/openai/resources/chat/completions/completions.py @@ -1346,12 +1346,10 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. + metadata: + A list of metadata keys to filter the Chat Completions by. Example: - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` model: The model used to generate the Chat Completions. @@ -2832,12 +2830,10 @@ def list( limit: Number of Chat Completions to retrieve. - metadata: Set of 16 key-value pairs that can be attached to an object. This can be useful - for storing additional information about the object in a structured format, and - querying for objects via API or the dashboard. + metadata: + A list of metadata keys to filter the Chat Completions by. Example: - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` model: The model used to generate the Chat Completions. diff --git a/src/openai/resources/containers/containers.py b/src/openai/resources/containers/containers.py index 0cbb400d4a..216097d9c8 100644 --- a/src/openai/resources/containers/containers.py +++ b/src/openai/resources/containers/containers.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Iterable from typing_extensions import Literal import httpx @@ -61,6 +62,8 @@ def create( expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, + network_policy: container_create_params.NetworkPolicy | Omit = omit, + skills: Iterable[container_create_params.Skill] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -80,6 +83,10 @@ def create( memory_limit: Optional memory limit for the container. Defaults to "1g". + network_policy: Network access policy for the container. + + skills: An optional list of skills referenced by id or inline data. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -96,6 +103,8 @@ def create( "expires_after": expires_after, "file_ids": file_ids, "memory_limit": memory_limit, + "network_policy": network_policy, + "skills": skills, }, container_create_params.ContainerCreateParams, ), @@ -143,6 +152,7 @@ def list( *, after: str | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -164,6 +174,8 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + name: Filter results by container name. + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order. @@ -187,6 +199,7 @@ def list( { "after": after, "limit": limit, + "name": name, "order": order, }, container_list_params.ContainerListParams, @@ -261,6 +274,8 @@ async def create( expires_after: container_create_params.ExpiresAfter | Omit = omit, file_ids: SequenceNotStr[str] | Omit = omit, memory_limit: Literal["1g", "4g", "16g", "64g"] | Omit = omit, + network_policy: container_create_params.NetworkPolicy | Omit = omit, + skills: Iterable[container_create_params.Skill] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -280,6 +295,10 @@ async def create( memory_limit: Optional memory limit for the container. Defaults to "1g". + network_policy: Network access policy for the container. + + skills: An optional list of skills referenced by id or inline data. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -296,6 +315,8 @@ async def create( "expires_after": expires_after, "file_ids": file_ids, "memory_limit": memory_limit, + "network_policy": network_policy, + "skills": skills, }, container_create_params.ContainerCreateParams, ), @@ -343,6 +364,7 @@ def list( *, after: str | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, order: Literal["asc", "desc"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -364,6 +386,8 @@ def list( limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + name: Filter results by container name. + order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order. @@ -387,6 +411,7 @@ def list( { "after": after, "limit": limit, + "name": name, "order": order, }, container_list_params.ContainerListParams, diff --git a/src/openai/resources/containers/files/files.py b/src/openai/resources/containers/files/files.py index a472cfc9f3..62659a5c3d 100644 --- a/src/openai/resources/containers/files/files.py +++ b/src/openai/resources/containers/files/files.py @@ -96,10 +96,11 @@ def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return self._post( f"/containers/{container_id}/files", body=maybe_transform(body, file_create_params.FileCreateParams), @@ -309,10 +310,11 @@ async def create( } ) files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) - # It should be noted that the actual Content-Type header that will be - # sent to the server will contain a `boundary` parameter, e.g. - # multipart/form-data; boundary=---abc-- - extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + if files: + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} return await self._post( f"/containers/{container_id}/files", body=await async_maybe_transform(body, file_create_params.FileCreateParams), diff --git a/src/openai/resources/conversations/api.md b/src/openai/resources/conversations/api.md new file mode 100644 index 0000000000..9e9181a367 --- /dev/null +++ b/src/openai/resources/conversations/api.md @@ -0,0 +1,42 @@ +# Conversations + +Types: + +```python +from openai.types.conversations import ( + ComputerScreenshotContent, + Conversation, + ConversationDeleted, + ConversationDeletedResource, + Message, + SummaryTextContent, + TextContent, + InputTextContent, + OutputTextContent, + RefusalContent, + InputImageContent, + InputFileContent, +) +``` + +Methods: + +- client.conversations.create(\*\*params) -> Conversation +- client.conversations.retrieve(conversation_id) -> Conversation +- client.conversations.update(conversation_id, \*\*params) -> Conversation +- client.conversations.delete(conversation_id) -> ConversationDeletedResource + +## Items + +Types: + +```python +from openai.types.conversations import ConversationItem, ConversationItemList +``` + +Methods: + +- client.conversations.items.create(conversation_id, \*\*params) -> ConversationItemList +- client.conversations.items.retrieve(item_id, \*, conversation_id, \*\*params) -> ConversationItem +- client.conversations.items.list(conversation_id, \*\*params) -> SyncConversationCursorPage[ConversationItem] +- client.conversations.items.delete(item_id, \*, conversation_id) -> Conversation diff --git a/src/openai/resources/realtime/api.md b/src/openai/resources/realtime/api.md new file mode 100644 index 0000000000..1a178384db --- /dev/null +++ b/src/openai/resources/realtime/api.md @@ -0,0 +1,137 @@ +# Realtime + +Types: + +```python +from openai.types.realtime import ( + AudioTranscription, + ConversationCreatedEvent, + ConversationItem, + ConversationItemAdded, + ConversationItemCreateEvent, + ConversationItemCreatedEvent, + ConversationItemDeleteEvent, + ConversationItemDeletedEvent, + ConversationItemDone, + ConversationItemInputAudioTranscriptionCompletedEvent, + ConversationItemInputAudioTranscriptionDeltaEvent, + ConversationItemInputAudioTranscriptionFailedEvent, + ConversationItemInputAudioTranscriptionSegment, + ConversationItemRetrieveEvent, + ConversationItemTruncateEvent, + ConversationItemTruncatedEvent, + ConversationItemWithReference, + InputAudioBufferAppendEvent, + InputAudioBufferClearEvent, + InputAudioBufferClearedEvent, + InputAudioBufferCommitEvent, + InputAudioBufferCommittedEvent, + InputAudioBufferDtmfEventReceivedEvent, + InputAudioBufferSpeechStartedEvent, + InputAudioBufferSpeechStoppedEvent, + InputAudioBufferTimeoutTriggered, + LogProbProperties, + McpListToolsCompleted, + McpListToolsFailed, + McpListToolsInProgress, + NoiseReductionType, + OutputAudioBufferClearEvent, + RateLimitsUpdatedEvent, + RealtimeAudioConfig, + RealtimeAudioConfigInput, + RealtimeAudioConfigOutput, + RealtimeAudioFormats, + RealtimeAudioInputTurnDetection, + RealtimeClientEvent, + RealtimeConversationItemAssistantMessage, + RealtimeConversationItemFunctionCall, + RealtimeConversationItemFunctionCallOutput, + RealtimeConversationItemSystemMessage, + RealtimeConversationItemUserMessage, + RealtimeError, + RealtimeErrorEvent, + RealtimeFunctionTool, + RealtimeMcpApprovalRequest, + RealtimeMcpApprovalResponse, + RealtimeMcpListTools, + RealtimeMcpProtocolError, + RealtimeMcpToolCall, + RealtimeMcpToolExecutionError, + RealtimeMcphttpError, + RealtimeResponse, + RealtimeResponseCreateAudioOutput, + RealtimeResponseCreateMcpTool, + RealtimeResponseCreateParams, + RealtimeResponseStatus, + RealtimeResponseUsage, + RealtimeResponseUsageInputTokenDetails, + RealtimeResponseUsageOutputTokenDetails, + RealtimeServerEvent, + RealtimeSession, + RealtimeSessionCreateRequest, + RealtimeToolChoiceConfig, + RealtimeToolsConfig, + RealtimeToolsConfigUnion, + RealtimeTracingConfig, + RealtimeTranscriptionSessionAudio, + RealtimeTranscriptionSessionAudioInput, + RealtimeTranscriptionSessionAudioInputTurnDetection, + RealtimeTranscriptionSessionCreateRequest, + RealtimeTruncation, + RealtimeTruncationRetentionRatio, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCancelEvent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseCreateEvent, + ResponseCreatedEvent, + ResponseDoneEvent, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseMcpCallArgumentsDelta, + ResponseMcpCallArgumentsDone, + ResponseMcpCallCompleted, + ResponseMcpCallFailed, + ResponseMcpCallInProgress, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + SessionCreatedEvent, + SessionUpdateEvent, + SessionUpdatedEvent, + TranscriptionSessionUpdate, + TranscriptionSessionUpdatedEvent, +) +``` + +## ClientSecrets + +Types: + +```python +from openai.types.realtime import ( + RealtimeSessionClientSecret, + RealtimeSessionCreateResponse, + RealtimeTranscriptionSessionCreateResponse, + RealtimeTranscriptionSessionTurnDetection, + ClientSecretCreateResponse, +) +``` + +Methods: + +- client.realtime.client_secrets.create(\*\*params) -> ClientSecretCreateResponse + +## Calls + +Methods: + +- client.realtime.calls.create(\*\*params) -> HttpxBinaryResponseContent +- client.realtime.calls.accept(call_id, \*\*params) -> None +- client.realtime.calls.hangup(call_id) -> None +- client.realtime.calls.refer(call_id, \*\*params) -> None +- client.realtime.calls.reject(call_id, \*\*params) -> None diff --git a/src/openai/resources/responses/api.md b/src/openai/resources/responses/api.md new file mode 100644 index 0000000000..6eb1b999fa --- /dev/null +++ b/src/openai/resources/responses/api.md @@ -0,0 +1,175 @@ +# Responses + +Types: + +```python +from openai.types.responses import ( + ApplyPatchTool, + CompactedResponse, + ComputerTool, + ContainerAuto, + ContainerNetworkPolicyAllowlist, + ContainerNetworkPolicyDisabled, + ContainerNetworkPolicyDomainSecret, + ContainerReference, + CustomTool, + EasyInputMessage, + FileSearchTool, + FunctionShellTool, + FunctionTool, + InlineSkill, + InlineSkillSource, + LocalEnvironment, + LocalSkill, + Response, + ResponseApplyPatchToolCall, + ResponseApplyPatchToolCallOutput, + ResponseAudioDeltaEvent, + ResponseAudioDoneEvent, + ResponseAudioTranscriptDeltaEvent, + ResponseAudioTranscriptDoneEvent, + ResponseCodeInterpreterCallCodeDeltaEvent, + ResponseCodeInterpreterCallCodeDoneEvent, + ResponseCodeInterpreterCallCompletedEvent, + ResponseCodeInterpreterCallInProgressEvent, + ResponseCodeInterpreterCallInterpretingEvent, + ResponseCodeInterpreterToolCall, + ResponseCompactionItem, + ResponseCompactionItemParam, + ResponseCompletedEvent, + ResponseComputerToolCall, + ResponseComputerToolCallOutputItem, + ResponseComputerToolCallOutputScreenshot, + ResponseContainerReference, + ResponseContent, + ResponseContentPartAddedEvent, + ResponseContentPartDoneEvent, + ResponseConversationParam, + ResponseCreatedEvent, + ResponseCustomToolCall, + ResponseCustomToolCallInputDeltaEvent, + ResponseCustomToolCallInputDoneEvent, + ResponseCustomToolCallOutput, + ResponseError, + ResponseErrorEvent, + ResponseFailedEvent, + ResponseFileSearchCallCompletedEvent, + ResponseFileSearchCallInProgressEvent, + ResponseFileSearchCallSearchingEvent, + ResponseFileSearchToolCall, + ResponseFormatTextConfig, + ResponseFormatTextJSONSchemaConfig, + ResponseFunctionCallArgumentsDeltaEvent, + ResponseFunctionCallArgumentsDoneEvent, + ResponseFunctionCallOutputItem, + ResponseFunctionCallOutputItemList, + ResponseFunctionShellCallOutputContent, + ResponseFunctionShellToolCall, + ResponseFunctionShellToolCallOutput, + ResponseFunctionToolCall, + ResponseFunctionToolCallItem, + ResponseFunctionToolCallOutputItem, + ResponseFunctionWebSearch, + ResponseImageGenCallCompletedEvent, + ResponseImageGenCallGeneratingEvent, + ResponseImageGenCallInProgressEvent, + ResponseImageGenCallPartialImageEvent, + ResponseInProgressEvent, + ResponseIncludable, + ResponseIncompleteEvent, + ResponseInput, + ResponseInputAudio, + ResponseInputContent, + ResponseInputFile, + ResponseInputFileContent, + ResponseInputImage, + ResponseInputImageContent, + ResponseInputItem, + ResponseInputMessageContentList, + ResponseInputMessageItem, + ResponseInputText, + ResponseInputTextContent, + ResponseItem, + ResponseLocalEnvironment, + ResponseMcpCallArgumentsDeltaEvent, + ResponseMcpCallArgumentsDoneEvent, + ResponseMcpCallCompletedEvent, + ResponseMcpCallFailedEvent, + ResponseMcpCallInProgressEvent, + ResponseMcpListToolsCompletedEvent, + ResponseMcpListToolsFailedEvent, + ResponseMcpListToolsInProgressEvent, + ResponseOutputAudio, + ResponseOutputItem, + ResponseOutputItemAddedEvent, + ResponseOutputItemDoneEvent, + ResponseOutputMessage, + ResponseOutputRefusal, + ResponseOutputText, + ResponseOutputTextAnnotationAddedEvent, + ResponsePrompt, + ResponseQueuedEvent, + ResponseReasoningItem, + ResponseReasoningSummaryPartAddedEvent, + ResponseReasoningSummaryPartDoneEvent, + ResponseReasoningSummaryTextDeltaEvent, + ResponseReasoningSummaryTextDoneEvent, + ResponseReasoningTextDeltaEvent, + ResponseReasoningTextDoneEvent, + ResponseRefusalDeltaEvent, + ResponseRefusalDoneEvent, + ResponseStatus, + ResponseStreamEvent, + ResponseTextConfig, + ResponseTextDeltaEvent, + ResponseTextDoneEvent, + ResponseUsage, + ResponseWebSearchCallCompletedEvent, + ResponseWebSearchCallInProgressEvent, + ResponseWebSearchCallSearchingEvent, + SkillReference, + Tool, + ToolChoiceAllowed, + ToolChoiceApplyPatch, + ToolChoiceCustom, + ToolChoiceFunction, + ToolChoiceMcp, + ToolChoiceOptions, + ToolChoiceShell, + ToolChoiceTypes, + WebSearchPreviewTool, + WebSearchTool, +) +``` + +Methods: + +- client.responses.create(\*\*params) -> Response +- client.responses.retrieve(response_id, \*\*params) -> Response +- client.responses.delete(response_id) -> None +- client.responses.cancel(response_id) -> Response +- client.responses.compact(\*\*params) -> CompactedResponse + +## InputItems + +Types: + +```python +from openai.types.responses import ResponseItemList +``` + +Methods: + +- client.responses.input_items.list(response_id, \*\*params) -> SyncCursorPage[ResponseItem] + +## InputTokens + +Types: + +```python +from openai.types.responses import InputTokenCountResponse +``` + +Methods: + +- client.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse diff --git a/src/openai/resources/webhooks/__init__.py b/src/openai/resources/webhooks/__init__.py new file mode 100644 index 0000000000..371906299b --- /dev/null +++ b/src/openai/resources/webhooks/__init__.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .webhooks import Webhooks as _Webhooks, AsyncWebhooks as _AsyncWebhooks + + +class Webhooks(_Webhooks): + pass + + +class AsyncWebhooks(_AsyncWebhooks): + pass + +__all__ = ["Webhooks", "AsyncWebhooks"] diff --git a/src/openai/resources/webhooks/api.md b/src/openai/resources/webhooks/api.md new file mode 100644 index 0000000000..8e3c312eb0 --- /dev/null +++ b/src/openai/resources/webhooks/api.md @@ -0,0 +1,24 @@ +# Webhooks + +Types: + +```python +from openai.types.webhooks import ( + BatchCancelledWebhookEvent, + BatchCompletedWebhookEvent, + BatchExpiredWebhookEvent, + BatchFailedWebhookEvent, + EvalRunCanceledWebhookEvent, + EvalRunFailedWebhookEvent, + EvalRunSucceededWebhookEvent, + FineTuningJobCancelledWebhookEvent, + FineTuningJobFailedWebhookEvent, + FineTuningJobSucceededWebhookEvent, + RealtimeCallIncomingWebhookEvent, + ResponseCancelledWebhookEvent, + ResponseCompletedWebhookEvent, + ResponseFailedWebhookEvent, + ResponseIncompleteWebhookEvent, + UnwrapWebhookEvent, +) +``` diff --git a/src/openai/resources/webhooks.py b/src/openai/resources/webhooks/webhooks.py similarity index 96% rename from src/openai/resources/webhooks.py rename to src/openai/resources/webhooks/webhooks.py index 3e13d3faae..8d99568aad 100644 --- a/src/openai/resources/webhooks.py +++ b/src/openai/resources/webhooks/webhooks.py @@ -9,12 +9,12 @@ import hashlib from typing import cast -from .._types import HeadersLike -from .._utils import get_required_header -from .._models import construct_type -from .._resource import SyncAPIResource, AsyncAPIResource -from .._exceptions import InvalidWebhookSignatureError -from ..types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent +from ..._types import HeadersLike +from ..._utils import get_required_header +from ..._models import construct_type +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._exceptions import InvalidWebhookSignatureError +from ...types.webhooks.unwrap_webhook_event import UnwrapWebhookEvent __all__ = ["Webhooks", "AsyncWebhooks"] diff --git a/src/openai/types/chat/completion_list_params.py b/src/openai/types/chat/completion_list_params.py index 32bd3f5c0a..d93da834a3 100644 --- a/src/openai/types/chat/completion_list_params.py +++ b/src/openai/types/chat/completion_list_params.py @@ -18,13 +18,9 @@ class CompletionListParams(TypedDict, total=False): """Number of Chat Completions to retrieve.""" metadata: Optional[Metadata] - """Set of 16 key-value pairs that can be attached to an object. + """A list of metadata keys to filter the Chat Completions by. Example: - This can be useful for storing additional information about the object in a - structured format, and querying for objects via API or the dashboard. - - Keys are strings with a maximum length of 64 characters. Values are strings with - a maximum length of 512 characters. + `metadata[key1]=value1&metadata[key2]=value2` """ model: str diff --git a/src/openai/types/container_create_params.py b/src/openai/types/container_create_params.py index 47101ecdb6..63d28f3955 100644 --- a/src/openai/types/container_create_params.py +++ b/src/openai/types/container_create_params.py @@ -2,11 +2,16 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing import Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict from .._types import SequenceNotStr +from .responses.inline_skill_param import InlineSkillParam +from .responses.skill_reference_param import SkillReferenceParam +from .responses.container_network_policy_disabled_param import ContainerNetworkPolicyDisabledParam +from .responses.container_network_policy_allowlist_param import ContainerNetworkPolicyAllowlistParam -__all__ = ["ContainerCreateParams", "ExpiresAfter"] +__all__ = ["ContainerCreateParams", "ExpiresAfter", "NetworkPolicy", "Skill"] class ContainerCreateParams(TypedDict, total=False): @@ -22,6 +27,12 @@ class ContainerCreateParams(TypedDict, total=False): memory_limit: Literal["1g", "4g", "16g", "64g"] """Optional memory limit for the container. Defaults to "1g".""" + network_policy: NetworkPolicy + """Network access policy for the container.""" + + skills: Iterable[Skill] + """An optional list of skills referenced by id or inline data.""" + class ExpiresAfter(TypedDict, total=False): """Container expiration time in seconds relative to the 'anchor' time.""" @@ -33,3 +44,8 @@ class ExpiresAfter(TypedDict, total=False): """ minutes: Required[int] + + +NetworkPolicy: TypeAlias = Union[ContainerNetworkPolicyDisabledParam, ContainerNetworkPolicyAllowlistParam] + +Skill: TypeAlias = Union[SkillReferenceParam, InlineSkillParam] diff --git a/src/openai/types/container_create_response.py b/src/openai/types/container_create_response.py index 0ebcc04062..34bc56ad13 100644 --- a/src/openai/types/container_create_response.py +++ b/src/openai/types/container_create_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerCreateResponse", "ExpiresAfter"] +__all__ = ["ContainerCreateResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerCreateResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerCreateResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/src/openai/types/container_list_params.py b/src/openai/types/container_list_params.py index 4821a87d18..01ec43af32 100644 --- a/src/openai/types/container_list_params.py +++ b/src/openai/types/container_list_params.py @@ -23,6 +23,9 @@ class ContainerListParams(TypedDict, total=False): Limit can range between 1 and 100, and the default is 20. """ + name: str + """Filter results by container name.""" + order: Literal["asc", "desc"] """Sort order by the `created_at` timestamp of the objects. diff --git a/src/openai/types/container_list_response.py b/src/openai/types/container_list_response.py index 8f39548201..bf572acd6b 100644 --- a/src/openai/types/container_list_response.py +++ b/src/openai/types/container_list_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerListResponse", "ExpiresAfter"] +__all__ = ["ContainerListResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerListResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerListResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/src/openai/types/container_retrieve_response.py b/src/openai/types/container_retrieve_response.py index 9ba3e18c3a..b5a6d350ff 100644 --- a/src/openai/types/container_retrieve_response.py +++ b/src/openai/types/container_retrieve_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["ContainerRetrieveResponse", "ExpiresAfter"] +__all__ = ["ContainerRetrieveResponse", "ExpiresAfter", "NetworkPolicy"] class ExpiresAfter(BaseModel): @@ -22,6 +22,16 @@ class ExpiresAfter(BaseModel): """The number of minutes after the anchor before the container expires.""" +class NetworkPolicy(BaseModel): + """Network access policy for the container.""" + + type: Literal["allowlist", "disabled"] + """The network policy mode.""" + + allowed_domains: Optional[List[str]] = None + """Allowed outbound domains when `type` is `allowlist`.""" + + class ContainerRetrieveResponse(BaseModel): id: str """Unique identifier for the container.""" @@ -50,3 +60,6 @@ class ContainerRetrieveResponse(BaseModel): memory_limit: Optional[Literal["1g", "4g", "16g", "64g"]] = None """The memory limit configured for the container.""" + + network_policy: Optional[NetworkPolicy] = None + """Network access policy for the container.""" diff --git a/tests/api_resources/test_containers.py b/tests/api_resources/test_containers.py index cf173c7fd5..321d7778b0 100644 --- a/tests/api_resources/test_containers.py +++ b/tests/api_resources/test_containers.py @@ -39,6 +39,14 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: }, file_ids=["string"], memory_limit="1g", + network_policy={"type": "disabled"}, + skills=[ + { + "skill_id": "x", + "type": "skill_reference", + "version": "version", + } + ], ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) @@ -114,6 +122,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: container = client.containers.list( after="after", limit=0, + name="name", order="asc", ) assert_matches_type(SyncCursorPage[ContainerListResponse], container, path=["response"]) @@ -199,6 +208,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> }, file_ids=["string"], memory_limit="1g", + network_policy={"type": "disabled"}, + skills=[ + { + "skill_id": "x", + "type": "skill_reference", + "version": "version", + } + ], ) assert_matches_type(ContainerCreateResponse, container, path=["response"]) @@ -274,6 +291,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N container = await async_client.containers.list( after="after", limit=0, + name="name", order="asc", ) assert_matches_type(AsyncCursorPage[ContainerListResponse], container, path=["response"]) diff --git a/tests/api_resources/webhooks/__init__.py b/tests/api_resources/webhooks/__init__.py new file mode 100644 index 0000000000..fd8019a9a1 --- /dev/null +++ b/tests/api_resources/webhooks/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/lib/chat/test_completions.py b/tests/lib/chat/test_completions.py index afad5a1391..85bab4f095 100644 --- a/tests/lib/chat/test_completions.py +++ b/tests/lib/chat/test_completions.py @@ -50,13 +50,13 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[NoneType]( +ParsedChatCompletion( choices=[ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I @@ -120,13 +120,13 @@ class Location(BaseModel): assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -191,13 +191,13 @@ class Location(BaseModel): assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -266,11 +266,11 @@ class ColorDetection(BaseModel): assert print_obj(completion.choices[0], monkeypatch) == snapshot( """\ -ParsedChoice[ColorDetection]( +ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[ColorDetection]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"color":"red","hex_color_code":"#FF0000"}', @@ -317,11 +317,11 @@ class Location(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":64,"units":"f"}', @@ -332,11 +332,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=1, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -347,11 +347,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=2, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":63.0,"units":"f"}', @@ -397,13 +397,13 @@ class CalendarEvent: assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[CalendarEvent]( +ParsedChatCompletion( choices=[ - ParsedChoice[CalendarEvent]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[CalendarEvent]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"name":"Science Fair","date":"Friday","participants":["Alice","Bob"]}', @@ -462,11 +462,11 @@ def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, m assert print_obj(completion.choices[0], monkeypatch) == snapshot( """\ -ParsedChoice[Query]( +ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Query]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -576,11 +576,11 @@ class Location(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -627,11 +627,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -701,11 +701,11 @@ class GetStockPrice(BaseModel): assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -784,11 +784,11 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: assert print_obj(completion.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -866,13 +866,13 @@ class Location(BaseModel): assert isinstance(message.parsed.city, str) assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":58,"units":"f"}', @@ -943,13 +943,13 @@ class Location(BaseModel): assert isinstance(message.parsed.city, str) assert print_obj(completion, monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', diff --git a/tests/lib/chat/test_completions_streaming.py b/tests/lib/chat/test_completions_streaming.py index 548416dfe2..eb3a0973ac 100644 --- a/tests/lib/chat/test_completions_streaming.py +++ b/tests/lib/chat/test_completions_streaming.py @@ -63,11 +63,11 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I @@ -84,7 +84,7 @@ def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pyte ) assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ -ContentDoneEvent[NoneType]( +ContentDoneEvent( content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I recommend checking a reliable weather website or a weather app.", parsed=None, @@ -140,13 +140,13 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream assert print_obj(listener.stream.get_final_completion(), monkeypatch) == snapshot( """\ -ParsedChatCompletion[Location]( +ParsedChatCompletion( choices=[ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', @@ -181,7 +181,7 @@ def on_event(stream: ChatCompletionStream[Location], event: ChatCompletionStream ) assert print_obj(listener.get_event_by_type("content.done"), monkeypatch) == snapshot( """\ -ContentDoneEvent[Location]( +ContentDoneEvent( content='{"city":"San Francisco","temperature":61,"units":"f"}', parsed=Location(city='San Francisco', temperature=61.0, units='f'), type='content.done' @@ -320,11 +320,11 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":65,"units":"f"}', @@ -335,11 +335,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=1, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":61,"units":"f"}', @@ -350,11 +350,11 @@ class Location(BaseModel): tool_calls=None ) ), - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=2, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='{"city":"San Francisco","temperature":59,"units":"f"}', @@ -426,11 +426,11 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -495,7 +495,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot("""\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=ChoiceLogprobs( @@ -505,7 +505,7 @@ def test_content_logprobs_events(client: OpenAI, respx_mock: MockRouter, monkeyp ], refusal=None ), - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='Foo!', @@ -563,7 +563,7 @@ class Location(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot("""\ [ - ParsedChoice[Location]( + ParsedChoice( finish_reason='stop', index=0, logprobs=ChoiceLogprobs( @@ -617,7 +617,7 @@ class Location(BaseModel): ChatCompletionTokenLogprob(bytes=[46], logprob=-0.57687104, token='.', top_logprobs=[]) ] ), - message=ParsedChatCompletionMessage[Location]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -660,11 +660,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -693,11 +693,11 @@ class GetWeatherArgs(BaseModel): assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -765,11 +765,11 @@ class GetStockPrice(BaseModel): assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -874,11 +874,11 @@ def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: assert print_obj(listener.stream.current_completion_snapshot.choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[object]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[object]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -926,11 +926,11 @@ def test_non_pydantic_response_format(client: OpenAI, respx_mock: MockRouter, mo assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content='\\n {\\n "location": "San Francisco, CA",\\n "weather": {\\n "temperature": "18°C",\\n @@ -987,11 +987,11 @@ def test_allows_non_strict_tools_but_no_parsing( assert print_obj(listener.stream.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='tool_calls', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content=None, @@ -1047,11 +1047,11 @@ def streamer(client: OpenAI) -> Iterator[ChatCompletionChunk]: assert print_obj(state.get_final_completion().choices, monkeypatch) == snapshot( """\ [ - ParsedChoice[NoneType]( + ParsedChoice( finish_reason='stop', index=0, logprobs=None, - message=ParsedChatCompletionMessage[NoneType]( + message=ParsedChatCompletionMessage( annotations=None, audio=None, content="I'm unable to provide real-time weather updates. To get the current weather in San Francisco, I diff --git a/tests/lib/utils.py b/tests/lib/utils.py index e6b6a29434..0efdfca968 100644 --- a/tests/lib/utils.py +++ b/tests/lib/utils.py @@ -1,6 +1,6 @@ from __future__ import annotations -import inspect +import re from typing import Any, Iterable from typing_extensions import TypeAlias @@ -28,27 +28,7 @@ def __repr_args__(self: pydantic.BaseModel) -> ReprArgs: string = rich_print_str(obj) - # we remove all `fn_name..` occurrences - # so that we can share the same snapshots between - # pydantic v1 and pydantic v2 as their output for - # generic models differs, e.g. - # - # v2: `ParsedChatCompletion[test_parse_pydantic_model..Location]` - # v1: `ParsedChatCompletion[Location]` - return clear_locals(string, stacklevel=2) - - -def get_caller_name(*, stacklevel: int = 1) -> str: - frame = inspect.currentframe() - assert frame is not None - - for i in range(stacklevel): - frame = frame.f_back - assert frame is not None, f"no {i}th frame" - - return frame.f_code.co_name - - -def clear_locals(string: str, *, stacklevel: int) -> str: - caller = get_caller_name(stacklevel=stacklevel + 1) - return string.replace(f"{caller}..", "") + # Pydantic v1 and v2 have different implementations of __repr__ and print out + # generics differently, so we strip out generic type parameters to ensure + # consistent snapshot tests across both versions + return re.sub(r"([A-Za-z_]\w*)\[[^\[\]]+\](?=\()", r"\1", string)