From 7015158c3119acf57af6c20903587cef928530a9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 19:55:23 +0000 Subject: [PATCH 1/6] feat(api): update OpenAPI spec or Stainless config --- .stats.yml | 4 +- .../admin/organization/admin_api_keys.py | 24 ++++- .../admin/organization/audit_logs.py | 24 ++++- .../types/admin/organization/admin_api_key.py | 3 + .../admin_api_key_create_params.py | 6 ++ .../organization/audit_log_list_params.py | 14 ++- .../organization/audit_log_list_response.py | 96 +++++++++++++++++++ src/openai/types/responses/response.py | 24 +++-- src/openai/types/shared/reasoning.py | 7 ++ src/openai/types/shared_params/reasoning.py | 7 ++ src/openai/types/video_edit_params.py | 2 +- .../admin/organization/test_admin_api_keys.py | 16 ++++ .../admin/organization/test_audit_logs.py | 2 + .../responses/test_input_tokens.py | 2 + tests/api_resources/test_responses.py | 4 + 15 files changed, 221 insertions(+), 14 deletions(-) diff --git a/.stats.yml b/.stats.yml index a62e7b979c..ea980d413b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 262 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-0161cb2a0faadedfc17ff59c7fcad9671962dbd170f83811003c23702148cf36.yml -openapi_spec_hash: 1023c7442d0e2e7e213e8b3a253921c5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-e00ba6273043ec67eab4c213e30df144731fc5ae51d7c820ea647990c552b60b.yml +openapi_spec_hash: 9168743f8e60b63630e679583b29a840 config_hash: e02ca1082421dfe55b145c45e95d6126 diff --git a/src/openai/resources/admin/organization/admin_api_keys.py b/src/openai/resources/admin/organization/admin_api_keys.py index 80ddc39b49..fe10e236f5 100644 --- a/src/openai/resources/admin/organization/admin_api_keys.py +++ b/src/openai/resources/admin/organization/admin_api_keys.py @@ -47,6 +47,7 @@ def create( self, *, name: str, + expires_in_seconds: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -58,6 +59,9 @@ def create( Create an organization admin API key Args: + expires_in_seconds: The number of seconds until the API key expires. Omit this field for a key that + does not expire. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -68,7 +72,13 @@ def create( """ return self._post( "/organization/admin_api_keys", - body=maybe_transform({"name": name}, admin_api_key_create_params.AdminAPIKeyCreateParams), + body=maybe_transform( + { + "name": name, + "expires_in_seconds": expires_in_seconds, + }, + admin_api_key_create_params.AdminAPIKeyCreateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -234,6 +244,7 @@ async def create( self, *, name: str, + expires_in_seconds: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -245,6 +256,9 @@ async def create( Create an organization admin API key Args: + expires_in_seconds: The number of seconds until the API key expires. Omit this field for a key that + does not expire. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -255,7 +269,13 @@ async def create( """ return await self._post( "/organization/admin_api_keys", - body=await async_maybe_transform({"name": name}, admin_api_key_create_params.AdminAPIKeyCreateParams), + body=await async_maybe_transform( + { + "name": name, + "expires_in_seconds": expires_in_seconds, + }, + admin_api_key_create_params.AdminAPIKeyCreateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/openai/resources/admin/organization/audit_logs.py b/src/openai/resources/admin/organization/audit_logs.py index 760fb4b034..1774a80aed 100644 --- a/src/openai/resources/admin/organization/audit_logs.py +++ b/src/openai/resources/admin/organization/audit_logs.py @@ -102,6 +102,8 @@ def list( "role.deleted", "role.assignment.created", "role.assignment.deleted", + "role.bound_to_resource", + "role.unbound_from_resource", "scim.enabled", "scim.disabled", "service_account.created", @@ -116,6 +118,7 @@ def list( limit: int | Omit = omit, project_ids: SequenceNotStr[str] | Omit = omit, resource_ids: SequenceNotStr[str] | Omit = omit, + tenant_only: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -154,7 +157,13 @@ def list( project_ids: Return only events for these projects. resource_ids: Return only events performed on these targets. For example, a project ID - updated. + updated. For ChatGPT connector role events, use the workspace connector resource + ID shown in `details.id`, such as `__`. + + tenant_only: Return only tenant-scoped events associated with this organization. Required for + tenant-scoped events such as `role.bound_to_resource` and + `role.unbound_from_resource`. When `true`, all supplied event types must be + tenant-scoped. extra_headers: Send extra headers @@ -183,6 +192,7 @@ def list( "limit": limit, "project_ids": project_ids, "resource_ids": resource_ids, + "tenant_only": tenant_only, }, audit_log_list_params.AuditLogListParams, ), @@ -273,6 +283,8 @@ def list( "role.deleted", "role.assignment.created", "role.assignment.deleted", + "role.bound_to_resource", + "role.unbound_from_resource", "scim.enabled", "scim.disabled", "service_account.created", @@ -287,6 +299,7 @@ def list( limit: int | Omit = omit, project_ids: SequenceNotStr[str] | Omit = omit, resource_ids: SequenceNotStr[str] | Omit = omit, + tenant_only: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -325,7 +338,13 @@ def list( project_ids: Return only events for these projects. resource_ids: Return only events performed on these targets. For example, a project ID - updated. + updated. For ChatGPT connector role events, use the workspace connector resource + ID shown in `details.id`, such as `__`. + + tenant_only: Return only tenant-scoped events associated with this organization. Required for + tenant-scoped events such as `role.bound_to_resource` and + `role.unbound_from_resource`. When `true`, all supplied event types must be + tenant-scoped. extra_headers: Send extra headers @@ -354,6 +373,7 @@ def list( "limit": limit, "project_ids": project_ids, "resource_ids": resource_ids, + "tenant_only": tenant_only, }, audit_log_list_params.AuditLogListParams, ), diff --git a/src/openai/types/admin/organization/admin_api_key.py b/src/openai/types/admin/organization/admin_api_key.py index 5d2e5840f9..b9323dd465 100644 --- a/src/openai/types/admin/organization/admin_api_key.py +++ b/src/openai/types/admin/organization/admin_api_key.py @@ -37,6 +37,9 @@ class AdminAPIKey(BaseModel): created_at: int """The Unix timestamp (in seconds) of when the API key was created""" + expires_at: Optional[int] = None + """The Unix timestamp (in seconds) of when the API key expires""" + object: Literal["organization.admin_api_key"] """The object type, which is always `organization.admin_api_key`""" diff --git a/src/openai/types/admin/organization/admin_api_key_create_params.py b/src/openai/types/admin/organization/admin_api_key_create_params.py index dccdfb8a75..ac7b22ea30 100644 --- a/src/openai/types/admin/organization/admin_api_key_create_params.py +++ b/src/openai/types/admin/organization/admin_api_key_create_params.py @@ -9,3 +9,9 @@ class AdminAPIKeyCreateParams(TypedDict, total=False): name: Required[str] + + expires_in_seconds: int + """The number of seconds until the API key expires. + + Omit this field for a key that does not expire. + """ diff --git a/src/openai/types/admin/organization/audit_log_list_params.py b/src/openai/types/admin/organization/audit_log_list_params.py index 25224d47dc..e77e1c8d96 100644 --- a/src/openai/types/admin/organization/audit_log_list_params.py +++ b/src/openai/types/admin/organization/audit_log_list_params.py @@ -92,6 +92,8 @@ class AuditLogListParams(TypedDict, total=False): "role.deleted", "role.assignment.created", "role.assignment.deleted", + "role.bound_to_resource", + "role.unbound_from_resource", "scim.enabled", "scim.disabled", "service_account.created", @@ -120,7 +122,17 @@ class AuditLogListParams(TypedDict, total=False): resource_ids: SequenceNotStr[str] """Return only events performed on these targets. - For example, a project ID updated. + For example, a project ID updated. For ChatGPT connector role events, use the + workspace connector resource ID shown in `details.id`, such as + `__`. + """ + + tenant_only: bool + """Return only tenant-scoped events associated with this organization. + + Required for tenant-scoped events such as `role.bound_to_resource` and + `role.unbound_from_resource`. When `true`, all supplied event types must be + tenant-scoped. """ diff --git a/src/openai/types/admin/organization/audit_log_list_response.py b/src/openai/types/admin/organization/audit_log_list_response.py index 9fa99bd677..f2f63c2e74 100644 --- a/src/openai/types/admin/organization/audit_log_list_response.py +++ b/src/openai/types/admin/organization/audit_log_list_response.py @@ -64,8 +64,10 @@ "RateLimitUpdatedChangesRequested", "RoleAssignmentCreated", "RoleAssignmentDeleted", + "RoleBoundToResource", "RoleCreated", "RoleDeleted", + "RoleUnboundFromResource", "RoleUpdated", "RoleUpdatedChangesRequested", "ScimDisabled", @@ -653,6 +655,48 @@ class RoleAssignmentDeleted(BaseModel): """The type of resource the role assignment was scoped to.""" +class RoleBoundToResource(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the resource the role was bound to. + + ChatGPT workspace connector resources use `__`. + """ + + connector_id: Optional[str] = None + """The connector ID for a ChatGPT workspace connector resource.""" + + connector_name: Optional[str] = None + """ + The connector display name for a ChatGPT workspace connector resource, or the + connector ID when the display name could not be resolved. + """ + + enabled: Optional[bool] = None + """Whether the connector is enabled for the role.""" + + permissions: Optional[List[str]] = None + """The permissions granted to the role for the resource.""" + + resource_id: Optional[str] = None + """The ID of the resource the role was bound to.""" + + resource_type: Optional[str] = None + """The type of resource the role was bound to.""" + + role_id: Optional[str] = None + """The ID of the role that was bound to the resource.""" + + source: Optional[ + Literal["role_toggle", "role_connector_update", "role_delete", "workspace_permissions", "connector_publish"] + ] = None + """The connector role mutation path that produced the event.""" + + workspace_id: Optional[str] = None + """The workspace ID for a ChatGPT workspace connector resource.""" + + class RoleCreated(BaseModel): """The details for events with this `type`.""" @@ -679,6 +723,48 @@ class RoleDeleted(BaseModel): """The role ID.""" +class RoleUnboundFromResource(BaseModel): + """The details for events with this `type`.""" + + id: Optional[str] = None + """The ID of the resource the role was unbound from. + + ChatGPT workspace connector resources use `__`. + """ + + connector_id: Optional[str] = None + """The connector ID for a ChatGPT workspace connector resource.""" + + connector_name: Optional[str] = None + """ + The connector display name for a ChatGPT workspace connector resource, or the + connector ID when the display name could not be resolved. + """ + + enabled: Optional[bool] = None + """Whether the connector is enabled for the role.""" + + permissions: Optional[List[str]] = None + """The permissions remaining for the role after the change.""" + + resource_id: Optional[str] = None + """The ID of the resource the role was unbound from.""" + + resource_type: Optional[str] = None + """The type of resource the role was unbound from.""" + + role_id: Optional[str] = None + """The ID of the role that was unbound from the resource.""" + + source: Optional[ + Literal["role_toggle", "role_connector_update", "role_delete", "workspace_permissions", "connector_publish"] + ] = None + """The connector role mutation path that produced the event.""" + + workspace_id: Optional[str] = None + """The workspace ID for a ChatGPT workspace connector resource.""" + + class RoleUpdatedChangesRequested(BaseModel): """The payload used to update the role.""" @@ -941,6 +1027,8 @@ class AuditLogListResponse(BaseModel): "role.deleted", "role.assignment.created", "role.assignment.deleted", + "role.bound_to_resource", + "role.unbound_from_resource", "scim.enabled", "scim.disabled", "service_account.created", @@ -1083,12 +1171,20 @@ class AuditLogListResponse(BaseModel): role_assignment_deleted: Optional[RoleAssignmentDeleted] = FieldInfo(alias="role.assignment.deleted", default=None) """The details for events with this `type`.""" + role_bound_to_resource: Optional[RoleBoundToResource] = FieldInfo(alias="role.bound_to_resource", default=None) + """The details for events with this `type`.""" + role_created: Optional[RoleCreated] = FieldInfo(alias="role.created", default=None) """The details for events with this `type`.""" role_deleted: Optional[RoleDeleted] = FieldInfo(alias="role.deleted", default=None) """The details for events with this `type`.""" + role_unbound_from_resource: Optional[RoleUnboundFromResource] = FieldInfo( + alias="role.unbound_from_resource", default=None + ) + """The details for events with this `type`.""" + role_updated: Optional[RoleUpdated] = FieldInfo(alias="role.updated", default=None) """The details for events with this `type`.""" diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index 67102d2628..e69aae9ad4 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -12,7 +12,6 @@ from .response_status import ResponseStatus from .tool_choice_mcp import ToolChoiceMcp from ..shared.metadata import Metadata -from ..shared.reasoning import Reasoning from .tool_choice_shell import ToolChoiceShell from .tool_choice_types import ToolChoiceTypes from .tool_choice_custom import ToolChoiceCustom @@ -37,6 +36,7 @@ "ModerationOutput", "ModerationOutputModerationResult", "ModerationOutputError", + "Reasoning", ] @@ -173,6 +173,22 @@ class Moderation(BaseModel): """Moderation for the response output.""" +class Reasoning(BaseModel): + """Reasoning configuration and metadata that were used for the response.""" + + context: Optional[Literal["current_turn", "all_turns"]] = None + """The effective reasoning context mode used for the response.""" + + effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = None + """The reasoning effort that was requested for the model, if specified.""" + + summary: Optional[Literal["concise", "detailed", "auto"]] = None + """A model-generated summary of its reasoning that was produced, if available.""" + + generate_summary: Optional[Literal["concise", "detailed", "auto"]] = None + """Deprecated. `summary` was used instead.""" + + class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -354,11 +370,7 @@ class Response(BaseModel): """ reasoning: Optional[Reasoning] = None - """**gpt-5 and o-series models only** - - Configuration options for - [reasoning models](https://platform.openai.com/docs/guides/reasoning). - """ + """Reasoning configuration and metadata that were used for the response.""" safety_identifier: Optional[str] = None """ diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py index 14f56a04cd..6a7b3e4b7d 100644 --- a/src/openai/types/shared/reasoning.py +++ b/src/openai/types/shared/reasoning.py @@ -16,6 +16,13 @@ class Reasoning(BaseModel): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + context: Optional[Literal["auto", "current_turn", "all_turns"]] = None + """ + Controls which reasoning items are rendered back to the model on later turns. + When returned on a response, this is the effective reasoning context mode used + for the response. + """ + effort: Optional[ReasoningEffort] = None """ Constrains effort on reasoning for diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py index 2bd7ce7268..86ebc259f1 100644 --- a/src/openai/types/shared_params/reasoning.py +++ b/src/openai/types/shared_params/reasoning.py @@ -17,6 +17,13 @@ class Reasoning(TypedDict, total=False): [reasoning models](https://platform.openai.com/docs/guides/reasoning). """ + context: Optional[Literal["auto", "current_turn", "all_turns"]] + """ + Controls which reasoning items are rendered back to the model on later turns. + When returned on a response, this is the effective reasoning context mode used + for the response. + """ + effort: Optional[ReasoningEffort] """ Constrains effort on reasoning for diff --git a/src/openai/types/video_edit_params.py b/src/openai/types/video_edit_params.py index 8d3b15fc6f..44e8c35d7f 100644 --- a/src/openai/types/video_edit_params.py +++ b/src/openai/types/video_edit_params.py @@ -19,7 +19,7 @@ class VideoEditParams(TypedDict, total=False): class VideoVideoReferenceInputParam(TypedDict, total=False): - """Reference to the completed video.""" + """Reference to the completed video to edit.""" id: Required[str] """The identifier of the completed video.""" diff --git a/tests/api_resources/admin/organization/test_admin_api_keys.py b/tests/api_resources/admin/organization/test_admin_api_keys.py index 59eed910e8..3384ee32df 100644 --- a/tests/api_resources/admin/organization/test_admin_api_keys.py +++ b/tests/api_resources/admin/organization/test_admin_api_keys.py @@ -29,6 +29,14 @@ def test_method_create(self, client: OpenAI) -> None: ) assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) + @parametrize + def test_method_create_with_all_params(self, client: OpenAI) -> None: + admin_api_key = client.admin.organization.admin_api_keys.create( + name="New Admin Key", + expires_in_seconds=2592000, + ) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) + @parametrize def test_raw_response_create(self, client: OpenAI) -> None: response = client.admin.organization.admin_api_keys.with_raw_response.create( @@ -176,6 +184,14 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: ) assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: + admin_api_key = await async_client.admin.organization.admin_api_keys.create( + name="New Admin Key", + expires_in_seconds=2592000, + ) + assert_matches_type(AdminAPIKeyCreateResponse, admin_api_key, path=["response"]) + @parametrize async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: response = await async_client.admin.organization.admin_api_keys.with_raw_response.create( diff --git a/tests/api_resources/admin/organization/test_audit_logs.py b/tests/api_resources/admin/organization/test_audit_logs.py index 5e696461fa..cf60c407b3 100644 --- a/tests/api_resources/admin/organization/test_audit_logs.py +++ b/tests/api_resources/admin/organization/test_audit_logs.py @@ -40,6 +40,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: limit=0, project_ids=["string"], resource_ids=["string"], + tenant_only=True, ) assert_matches_type(SyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) @@ -91,6 +92,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N limit=0, project_ids=["string"], resource_ids=["string"], + tenant_only=True, ) assert_matches_type(AsyncConversationCursorPage[AuditLogListResponse], audit_log, path=["response"]) diff --git a/tests/api_resources/responses/test_input_tokens.py b/tests/api_resources/responses/test_input_tokens.py index 04c0bb698e..59ff4252b9 100644 --- a/tests/api_resources/responses/test_input_tokens.py +++ b/tests/api_resources/responses/test_input_tokens.py @@ -33,6 +33,7 @@ def test_method_count_with_all_params(self, client: OpenAI) -> None: personality="friendly", previous_response_id="resp_123", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", @@ -98,6 +99,7 @@ async def test_method_count_with_all_params(self, async_client: AsyncOpenAI) -> personality="friendly", previous_response_id="resp_123", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", diff --git a/tests/api_resources/test_responses.py b/tests/api_resources/test_responses.py index dc6083e78c..761b410943 100644 --- a/tests/api_resources/test_responses.py +++ b/tests/api_resources/test_responses.py @@ -55,6 +55,7 @@ def test_method_create_with_all_params_overload_1(self, client: OpenAI) -> None: prompt_cache_key="prompt-cache-key-1234", prompt_cache_retention="in_memory", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", @@ -144,6 +145,7 @@ def test_method_create_with_all_params_overload_2(self, client: OpenAI) -> None: prompt_cache_key="prompt-cache-key-1234", prompt_cache_retention="in_memory", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", @@ -470,6 +472,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn prompt_cache_key="prompt-cache-key-1234", prompt_cache_retention="in_memory", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", @@ -559,6 +562,7 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn prompt_cache_key="prompt-cache-key-1234", prompt_cache_retention="in_memory", reasoning={ + "context": "auto", "effort": "none", "generate_summary": "auto", "summary": "auto", From 6134198a488996c4ff6fca4551afd55fb3294fdc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:28:25 +0000 Subject: [PATCH 2/6] feat(api): admin spend_alerts --- .stats.yml | 8 +- api.md | 2 + .../organization/projects/spend_alerts.py | 96 +++++++++++++++++++ .../admin/organization/spend_alerts.py | 86 +++++++++++++++++ src/openai/types/responses/response.py | 24 ++--- .../projects/test_spend_alerts.py | 96 +++++++++++++++++++ .../admin/organization/test_spend_alerts.py | 76 +++++++++++++++ 7 files changed, 366 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index ea980d413b..b1a3597bc6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 262 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-e00ba6273043ec67eab4c213e30df144731fc5ae51d7c820ea647990c552b60b.yml -openapi_spec_hash: 9168743f8e60b63630e679583b29a840 -config_hash: e02ca1082421dfe55b145c45e95d6126 +configured_endpoints: 264 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-c16aadb4992b72ce2391b8db90427e6be355e6c5f3f372bad3bfad7de5b8c8ed.yml +openapi_spec_hash: 310aad77be43c413a991e659beedc1a8 +config_hash: c60fedbe1462084139674a3c34bbbc95 diff --git a/api.md b/api.md index 10a729d995..56e01254dc 100644 --- a/api.md +++ b/api.md @@ -922,6 +922,7 @@ from openai.types.admin.organization import OrganizationSpendAlert, Organization Methods: - client.admin.organization.spend_alerts.create(\*\*params) -> OrganizationSpendAlert +- client.admin.organization.spend_alerts.retrieve(alert_id) -> OrganizationSpendAlert - client.admin.organization.spend_alerts.update(alert_id, \*\*params) -> OrganizationSpendAlert - client.admin.organization.spend_alerts.list(\*\*params) -> SyncConversationCursorPage[OrganizationSpendAlert] - client.admin.organization.spend_alerts.delete(alert_id) -> OrganizationSpendAlertDeleted @@ -1154,6 +1155,7 @@ from openai.types.admin.organization.projects import ProjectSpendAlert, ProjectS Methods: - client.admin.organization.projects.spend_alerts.create(project_id, \*\*params) -> ProjectSpendAlert +- client.admin.organization.projects.spend_alerts.retrieve(alert_id, \*, project_id) -> ProjectSpendAlert - client.admin.organization.projects.spend_alerts.update(alert_id, \*, project_id, \*\*params) -> ProjectSpendAlert - client.admin.organization.projects.spend_alerts.list(project_id, \*\*params) -> SyncConversationCursorPage[ProjectSpendAlert] - client.admin.organization.projects.spend_alerts.delete(alert_id, \*, project_id) -> ProjectSpendAlertDeleted diff --git a/src/openai/resources/admin/organization/projects/spend_alerts.py b/src/openai/resources/admin/organization/projects/spend_alerts.py index 3bc5d0c1f9..9eb0922df5 100644 --- a/src/openai/resources/admin/organization/projects/spend_alerts.py +++ b/src/openai/resources/admin/organization/projects/spend_alerts.py @@ -103,6 +103,48 @@ def create( cast_to=ProjectSpendAlert, ) + def retrieve( + self, + alert_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Retrieves a project spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._get( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + def update( self, alert_id: str, @@ -349,6 +391,48 @@ async def create( cast_to=ProjectSpendAlert, ) + async def retrieve( + self, + alert_id: str, + *, + project_id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectSpendAlert: + """ + Retrieves a project spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._get( + path_template( + "/organization/projects/{project_id}/spend_alerts/{alert_id}", project_id=project_id, alert_id=alert_id + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=ProjectSpendAlert, + ) + async def update( self, alert_id: str, @@ -524,6 +608,9 @@ def __init__(self, spend_alerts: SpendAlerts) -> None: self.create = _legacy_response.to_raw_response_wrapper( spend_alerts.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + spend_alerts.retrieve, + ) self.update = _legacy_response.to_raw_response_wrapper( spend_alerts.update, ) @@ -542,6 +629,9 @@ def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( spend_alerts.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.retrieve, + ) self.update = _legacy_response.async_to_raw_response_wrapper( spend_alerts.update, ) @@ -560,6 +650,9 @@ def __init__(self, spend_alerts: SpendAlerts) -> None: self.create = to_streamed_response_wrapper( spend_alerts.create, ) + self.retrieve = to_streamed_response_wrapper( + spend_alerts.retrieve, + ) self.update = to_streamed_response_wrapper( spend_alerts.update, ) @@ -578,6 +671,9 @@ def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: self.create = async_to_streamed_response_wrapper( spend_alerts.create, ) + self.retrieve = async_to_streamed_response_wrapper( + spend_alerts.retrieve, + ) self.update = async_to_streamed_response_wrapper( spend_alerts.update, ) diff --git a/src/openai/resources/admin/organization/spend_alerts.py b/src/openai/resources/admin/organization/spend_alerts.py index 4f3e223269..0da46176b6 100644 --- a/src/openai/resources/admin/organization/spend_alerts.py +++ b/src/openai/resources/admin/organization/spend_alerts.py @@ -96,6 +96,43 @@ def create( cast_to=OrganizationSpendAlert, ) + def retrieve( + self, + alert_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Retrieves an organization spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return self._get( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + def update( self, alert_id: str, @@ -326,6 +363,43 @@ async def create( cast_to=OrganizationSpendAlert, ) + async def retrieve( + self, + alert_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> OrganizationSpendAlert: + """ + Retrieves an organization spend alert. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not alert_id: + raise ValueError(f"Expected a non-empty value for `alert_id` but received {alert_id!r}") + return await self._get( + path_template("/organization/spend_alerts/{alert_id}", alert_id=alert_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + security={"admin_api_key_auth": True}, + ), + cast_to=OrganizationSpendAlert, + ) + async def update( self, alert_id: str, @@ -488,6 +562,9 @@ def __init__(self, spend_alerts: SpendAlerts) -> None: self.create = _legacy_response.to_raw_response_wrapper( spend_alerts.create, ) + self.retrieve = _legacy_response.to_raw_response_wrapper( + spend_alerts.retrieve, + ) self.update = _legacy_response.to_raw_response_wrapper( spend_alerts.update, ) @@ -506,6 +583,9 @@ def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: self.create = _legacy_response.async_to_raw_response_wrapper( spend_alerts.create, ) + self.retrieve = _legacy_response.async_to_raw_response_wrapper( + spend_alerts.retrieve, + ) self.update = _legacy_response.async_to_raw_response_wrapper( spend_alerts.update, ) @@ -524,6 +604,9 @@ def __init__(self, spend_alerts: SpendAlerts) -> None: self.create = to_streamed_response_wrapper( spend_alerts.create, ) + self.retrieve = to_streamed_response_wrapper( + spend_alerts.retrieve, + ) self.update = to_streamed_response_wrapper( spend_alerts.update, ) @@ -542,6 +625,9 @@ def __init__(self, spend_alerts: AsyncSpendAlerts) -> None: self.create = async_to_streamed_response_wrapper( spend_alerts.create, ) + self.retrieve = async_to_streamed_response_wrapper( + spend_alerts.retrieve, + ) self.update = async_to_streamed_response_wrapper( spend_alerts.update, ) diff --git a/src/openai/types/responses/response.py b/src/openai/types/responses/response.py index e69aae9ad4..67102d2628 100644 --- a/src/openai/types/responses/response.py +++ b/src/openai/types/responses/response.py @@ -12,6 +12,7 @@ from .response_status import ResponseStatus from .tool_choice_mcp import ToolChoiceMcp from ..shared.metadata import Metadata +from ..shared.reasoning import Reasoning from .tool_choice_shell import ToolChoiceShell from .tool_choice_types import ToolChoiceTypes from .tool_choice_custom import ToolChoiceCustom @@ -36,7 +37,6 @@ "ModerationOutput", "ModerationOutputModerationResult", "ModerationOutputError", - "Reasoning", ] @@ -173,22 +173,6 @@ class Moderation(BaseModel): """Moderation for the response output.""" -class Reasoning(BaseModel): - """Reasoning configuration and metadata that were used for the response.""" - - context: Optional[Literal["current_turn", "all_turns"]] = None - """The effective reasoning context mode used for the response.""" - - effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] = None - """The reasoning effort that was requested for the model, if specified.""" - - summary: Optional[Literal["concise", "detailed", "auto"]] = None - """A model-generated summary of its reasoning that was produced, if available.""" - - generate_summary: Optional[Literal["concise", "detailed", "auto"]] = None - """Deprecated. `summary` was used instead.""" - - class Response(BaseModel): id: str """Unique identifier for this Response.""" @@ -370,7 +354,11 @@ class Response(BaseModel): """ reasoning: Optional[Reasoning] = None - """Reasoning configuration and metadata that were used for the response.""" + """**gpt-5 and o-series models only** + + Configuration options for + [reasoning models](https://platform.openai.com/docs/guides/reasoning). + """ safety_identifier: Optional[str] = None """ diff --git a/tests/api_resources/admin/organization/projects/test_spend_alerts.py b/tests/api_resources/admin/organization/projects/test_spend_alerts.py index c763401af3..ee53d014dd 100644 --- a/tests/api_resources/admin/organization/projects/test_spend_alerts.py +++ b/tests/api_resources/admin/organization/projects/test_spend_alerts.py @@ -102,6 +102,54 @@ def test_path_params_create(self, client: OpenAI) -> None: threshold_amount=0, ) + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.projects.spend_alerts.retrieve( + alert_id="alert_id", + project_id="project_id", + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="alert_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.projects.spend_alerts.with_streaming_response.retrieve( + alert_id="alert_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="alert_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="", + project_id="project_id", + ) + @parametrize def test_method_update(self, client: OpenAI) -> None: spend_alert = client.admin.organization.projects.spend_alerts.update( @@ -385,6 +433,54 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: threshold_amount=0, ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.projects.spend_alerts.retrieve( + alert_id="alert_id", + project_id="project_id", + ) + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="alert_id", + project_id="project_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.projects.spend_alerts.with_streaming_response.retrieve( + alert_id="alert_id", + project_id="project_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(ProjectSpendAlert, spend_alert, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="alert_id", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `alert_id` but received ''"): + await async_client.admin.organization.projects.spend_alerts.with_raw_response.retrieve( + alert_id="", + project_id="project_id", + ) + @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: spend_alert = await async_client.admin.organization.projects.spend_alerts.update( diff --git a/tests/api_resources/admin/organization/test_spend_alerts.py b/tests/api_resources/admin/organization/test_spend_alerts.py index 08a3c445c3..13e80d7afa 100644 --- a/tests/api_resources/admin/organization/test_spend_alerts.py +++ b/tests/api_resources/admin/organization/test_spend_alerts.py @@ -84,6 +84,44 @@ def test_streaming_response_create(self, client: OpenAI) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_retrieve(self, client: OpenAI) -> None: + spend_alert = client.admin.organization.spend_alerts.retrieve( + "alert_id", + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: OpenAI) -> None: + response = client.admin.organization.spend_alerts.with_raw_response.retrieve( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: OpenAI) -> None: + with client.admin.organization.spend_alerts.with_streaming_response.retrieve( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, 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 `alert_id` but received ''"): + client.admin.organization.spend_alerts.with_raw_response.retrieve( + "", + ) + @parametrize def test_method_update(self, client: OpenAI) -> None: spend_alert = client.admin.organization.spend_alerts.update( @@ -307,6 +345,44 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None: + spend_alert = await async_client.admin.organization.spend_alerts.retrieve( + "alert_id", + ) + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None: + response = await async_client.admin.organization.spend_alerts.with_raw_response.retrieve( + "alert_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + spend_alert = response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None: + async with async_client.admin.organization.spend_alerts.with_streaming_response.retrieve( + "alert_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + spend_alert = await response.parse() + assert_matches_type(OrganizationSpendAlert, spend_alert, 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 `alert_id` but received ''"): + await async_client.admin.organization.spend_alerts.with_raw_response.retrieve( + "", + ) + @parametrize async def test_method_update(self, async_client: AsyncOpenAI) -> None: spend_alert = await async_client.admin.organization.spend_alerts.update( From 775912df1bb4683cec8f02c6cdbc36c802695110 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:30:11 +0000 Subject: [PATCH 3/6] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b1a3597bc6..db5da516b8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 264 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-c16aadb4992b72ce2391b8db90427e6be355e6c5f3f372bad3bfad7de5b8c8ed.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-3b6617316ec90f4c2426d20b137184a090adf479265d36613222b5f58b4faa97.yml openapi_spec_hash: 310aad77be43c413a991e659beedc1a8 -config_hash: c60fedbe1462084139674a3c34bbbc95 +config_hash: bb963cf2eb4f9a31afd86839949ac24c From f337bf43276c880d2daf09a5d7f9fc9a886c4bf2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:38:30 +0000 Subject: [PATCH 4/6] feat(api): manual updates --- .stats.yml | 6 +++--- src/openai/types/video_edit_params.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index db5da516b8..fef3ddfe2f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 264 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-3b6617316ec90f4c2426d20b137184a090adf479265d36613222b5f58b4faa97.yml -openapi_spec_hash: 310aad77be43c413a991e659beedc1a8 -config_hash: bb963cf2eb4f9a31afd86839949ac24c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-1d7b3ad7ffe7acee54d8097b85de7f335b8dec979e10ed1780ba07da7fbe78c0.yml +openapi_spec_hash: 2466f6ad496b27334217999202e185c0 +config_hash: 2895eaa2c8a5cb56f29eb33e5feaac1a diff --git a/src/openai/types/video_edit_params.py b/src/openai/types/video_edit_params.py index 44e8c35d7f..8d3b15fc6f 100644 --- a/src/openai/types/video_edit_params.py +++ b/src/openai/types/video_edit_params.py @@ -19,7 +19,7 @@ class VideoEditParams(TypedDict, total=False): class VideoVideoReferenceInputParam(TypedDict, total=False): - """Reference to the completed video to edit.""" + """Reference to the completed video.""" id: Required[str] """The identifier of the completed video.""" From 6a2736f28566c3aabb4d5a4f00e2094a29ec8a3b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:44:29 +0000 Subject: [PATCH 5/6] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index fef3ddfe2f..693dbe3631 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 264 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-1d7b3ad7ffe7acee54d8097b85de7f335b8dec979e10ed1780ba07da7fbe78c0.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-4db8edc05bd5503d4aaad74e8b9c783aa1f4d40382a8075c53355bd18dfaf68c.yml openapi_spec_hash: 2466f6ad496b27334217999202e185c0 -config_hash: 2895eaa2c8a5cb56f29eb33e5feaac1a +config_hash: ef3ce17315a31703e7af0567b3e9738c From 03230cc09db511e455c61893cbd2fd903cbbea36 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:45:23 +0000 Subject: [PATCH 6/6] release: 2.42.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 25d9dabb53..c33eb8cbe1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.41.1" + ".": "2.42.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a2a2e0b16..ed57a6ca21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 2.42.0 (2026-06-16) + +Full Changelog: [v2.41.1...v2.42.0](https://github.com/openai/openai-python/compare/v2.41.1...v2.42.0) + +### Features + +* **api:** admin spend_alerts ([6134198](https://github.com/openai/openai-python/commit/6134198a488996c4ff6fca4551afd55fb3294fdc)) +* **api:** manual updates ([f337bf4](https://github.com/openai/openai-python/commit/f337bf43276c880d2daf09a5d7f9fc9a886c4bf2)) +* **api:** update OpenAPI spec or Stainless config ([7015158](https://github.com/openai/openai-python/commit/7015158c3119acf57af6c20903587cef928530a9)) + + +### Build System + +* fix release workflow permissions ([#3389](https://github.com/openai/openai-python/issues/3389)) ([a526ee8](https://github.com/openai/openai-python/commit/a526ee813f085318fe3c6923ac3fa10c1cf56420)) +* Use CI environment for examples API key ([#3394](https://github.com/openai/openai-python/issues/3394)) ([d64d811](https://github.com/openai/openai-python/commit/d64d811e82aff724397e32d593e50657fee3f905)) + ## 2.41.1 (2026-06-05) Full Changelog: [v2.41.0...v2.41.1](https://github.com/openai/openai-python/compare/v2.41.0...v2.41.1) diff --git a/pyproject.toml b/pyproject.toml index 75d0d5e246..f3d0b5edf2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "2.41.1" +version = "2.42.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index 55f1df75a9..aeadf9ba57 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.41.1" # x-release-please-version +__version__ = "2.42.0" # x-release-please-version