Skip to content

Commit 658be64

Browse files
authored
Merge pull request openai#3213 from openai/release-please--branches--main--changes--next
release: 2.37.0
2 parents 38d75d7 + 8a7cac3 commit 658be64

15 files changed

Lines changed: 171 additions & 26 deletions

File tree

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "2.36.0"
2+
".": "2.37.0"
33
}

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 233
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-371f497afe4d6070f6e252e5febbe8f453c7058a8dff0c26a01b4d88442a4ac2.yml
3-
openapi_spec_hash: d39f46e8fda45f77096448105efd175a
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-50d816559ef0935e64d07789ff936a2b762e26ab0714a2fa6bc06d06d4484294.yml
3+
openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd
44
config_hash: b64135fff1fe9cf4069b9ecf59ae8b07

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## 2.37.0 (2026-05-13)
4+
5+
Full Changelog: [v2.36.0...v2.37.0](https://github.com/openai/openai-python/compare/v2.36.0...v2.37.0)
6+
7+
### Features
8+
9+
* **api:** add service_tier parameter to responses compact method ([625827c](https://github.com/openai/openai-python/commit/625827c5509ece3c40e5002be37a9bd9d91b5374))
10+
* **internal/types:** support eagerly validating pydantic iterators ([7e527bc](https://github.com/openai/openai-python/commit/7e527bc927cc58b74d7619abf7f1fbcfff8bddfa))
11+
* Remove unnecessary client_id when using workload identity provider for auth ([c39ea8d](https://github.com/openai/openai-python/commit/c39ea8d12a010052d7f02cebe8daabd2d1f89597))
12+
13+
14+
### Bug Fixes
15+
16+
* **client:** add missing f-string prefix in file type error message ([c85ebd9](https://github.com/openai/openai-python/commit/c85ebd935cb4b80e7e97ce255437684f6411fb00))
17+
318
## 2.36.0 (2026-05-07)
419

520
Full Changelog: [v2.35.1...v2.36.0](https://github.com/openai/openai-python/compare/v2.35.1...v2.36.0)

README.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,12 @@ from openai.auth import k8s_service_account_token_provider
8383

8484
client = OpenAI(
8585
workload_identity={
86-
"client_id": "your-client-id",
8786
"identity_provider_id": "idp-123",
8887
"service_account_id": "sa-456",
8988
"provider": k8s_service_account_token_provider(
9089
"/var/run/secrets/kubernetes.io/serviceaccount/token"
9190
),
9291
},
93-
organization="org-xyz",
94-
project="proj-abc",
9592
)
9693

9794
response = client.chat.completions.create(
@@ -108,7 +105,6 @@ from openai.auth import azure_managed_identity_token_provider
108105

109106
client = OpenAI(
110107
workload_identity={
111-
"client_id": "your-client-id",
112108
"identity_provider_id": "idp-123",
113109
"service_account_id": "sa-456",
114110
"provider": azure_managed_identity_token_provider(
@@ -126,7 +122,6 @@ from openai.auth import gcp_id_token_provider
126122

127123
client = OpenAI(
128124
workload_identity={
129-
"client_id": "your-client-id",
130125
"identity_provider_id": "idp-123",
131126
"service_account_id": "sa-456",
132127
"provider": gcp_id_token_provider(audience="https://api.openai.com/v1"),
@@ -146,7 +141,6 @@ def get_custom_token() -> str:
146141

147142
client = OpenAI(
148143
workload_identity={
149-
"client_id": "your-client-id",
150144
"identity_provider_id": "idp-123",
151145
"service_account_id": "sa-456",
152146
"provider": {
@@ -165,7 +159,6 @@ from openai.auth import k8s_service_account_token_provider
165159

166160
client = OpenAI(
167161
workload_identity={
168-
"client_id": "your-client-id",
169162
"identity_provider_id": "idp-123",
170163
"service_account_id": "sa-456",
171164
"provider": k8s_service_account_token_provider("/var/token"),

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "openai"
3-
version = "2.36.0"
3+
version = "2.37.0"
44
description = "The official Python library for the openai API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"

src/openai/_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
9999
elif is_sequence_t(files):
100100
files = [(key, await _async_transform_file(file)) for key, file in files]
101101
else:
102-
raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
102+
raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")
103103

104104
return files
105105

src/openai/_models.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
Protocol,
2828
Required,
2929
Sequence,
30+
Annotated,
3031
ParamSpec,
32+
TypeAlias,
3133
TypedDict,
3234
TypeGuard,
3335
final,
@@ -81,7 +83,15 @@
8183
from ._constants import RAW_RESPONSE_HEADER
8284

8385
if TYPE_CHECKING:
86+
from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler
87+
from pydantic_core import CoreSchema, core_schema
8488
from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
89+
else:
90+
try:
91+
from pydantic_core import CoreSchema, core_schema
92+
except ImportError:
93+
CoreSchema = None
94+
core_schema = None
8595

8696
__all__ = ["BaseModel", "GenericModel"]
8797

@@ -422,6 +432,76 @@ def model_dump_json(
422432
)
423433

424434

435+
class _EagerIterable(list[_T], Generic[_T]):
436+
"""
437+
Accepts any Iterable[T] input (including generators), consumes it
438+
eagerly, and validates all items upfront.
439+
440+
Validation preserves the original container type where possible
441+
(e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON)
442+
always emits a list — round-tripping through model_dump() will not
443+
restore the original container type.
444+
"""
445+
446+
@classmethod
447+
def __get_pydantic_core_schema__(
448+
cls,
449+
source_type: Any,
450+
handler: GetCoreSchemaHandler,
451+
) -> CoreSchema:
452+
(item_type,) = get_args(source_type) or (Any,)
453+
item_schema: CoreSchema = handler.generate_schema(item_type)
454+
list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema)
455+
456+
return core_schema.no_info_wrap_validator_function(
457+
cls._validate,
458+
list_of_items_schema,
459+
serialization=core_schema.plain_serializer_function_ser_schema(
460+
cls._serialize,
461+
info_arg=False,
462+
),
463+
)
464+
465+
@staticmethod
466+
def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any:
467+
original_type: type[Any] = type(v)
468+
469+
# Normalize to list so list_schema can validate each item
470+
if isinstance(v, list):
471+
items: list[_T] = v
472+
else:
473+
try:
474+
items = list(v)
475+
except TypeError as e:
476+
raise TypeError("Value is not iterable") from e
477+
478+
# Validate items against the inner schema
479+
validated: list[_T] = handler(items)
480+
481+
# Reconstruct original container type
482+
if original_type is list:
483+
return validated
484+
# str(list) produces the list's repr, not a string built from items,
485+
# so skip reconstruction for str and its subclasses.
486+
if issubclass(original_type, str):
487+
return validated
488+
try:
489+
return original_type(validated)
490+
except (TypeError, ValueError):
491+
# If the type cannot be reconstructed, just return the validated list
492+
return validated
493+
494+
@staticmethod
495+
def _serialize(v: Iterable[_T]) -> list[_T]:
496+
"""Always serialize as a list so Pydantic's JSON encoder is happy."""
497+
if isinstance(v, list):
498+
return v
499+
return list(v)
500+
501+
502+
EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable]
503+
504+
425505
def _construct_field(value: object, field: FieldInfo, key: str) -> object:
426506
if value is None:
427507
return field_get_default(field)

src/openai/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "openai"
4-
__version__ = "2.36.0" # x-release-please-version
4+
__version__ = "2.37.0" # x-release-please-version

src/openai/auth/_workload.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ class SubjectTokenProvider(TypedDict):
2727

2828

2929
class WorkloadIdentity(TypedDict):
30-
"""A unique string that identifies the client."""
31-
32-
client_id: str
33-
3430
"""Identity provider resource id in WIFAPI."""
3531
identity_provider_id: str
3632

@@ -253,7 +249,6 @@ def _fetch_token_from_exchange(self) -> dict[str, Any]:
253249
self.token_exchange_url,
254250
json={
255251
"grant_type": TOKEN_EXCHANGE_GRANT_TYPE,
256-
"client_id": self.workload_identity["client_id"],
257252
"subject_token": subject_token,
258253
"subject_token_type": subject_token_type,
259254
"identity_provider_id": self.workload_identity["identity_provider_id"],

src/openai/resources/responses/responses.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,7 @@ def compact(
17041704
previous_response_id: Optional[str] | Omit = omit,
17051705
prompt_cache_key: Optional[str] | Omit = omit,
17061706
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
1707+
service_tier: Optional[Literal["auto", "default", "flex", "priority"]] | Omit = omit,
17071708
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
17081709
# The extra values given here take precedence over values defined on the client or passed to this method.
17091710
extra_headers: Headers | None = None,
@@ -1743,6 +1744,8 @@ def compact(
17431744
17441745
prompt_cache_retention: How long to retain a prompt cache entry created by this request.
17451746
1747+
service_tier: The service tier to use for this request.
1748+
17461749
extra_headers: Send extra headers
17471750
17481751
extra_query: Add additional query parameters to the request
@@ -1761,6 +1764,7 @@ def compact(
17611764
"previous_response_id": previous_response_id,
17621765
"prompt_cache_key": prompt_cache_key,
17631766
"prompt_cache_retention": prompt_cache_retention,
1767+
"service_tier": service_tier,
17641768
},
17651769
response_compact_params.ResponseCompactParams,
17661770
),
@@ -3410,6 +3414,7 @@ async def compact(
34103414
previous_response_id: Optional[str] | Omit = omit,
34113415
prompt_cache_key: Optional[str] | Omit = omit,
34123416
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
3417+
service_tier: Optional[Literal["auto", "default", "flex", "priority"]] | Omit = omit,
34133418
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
34143419
# The extra values given here take precedence over values defined on the client or passed to this method.
34153420
extra_headers: Headers | None = None,
@@ -3449,6 +3454,8 @@ async def compact(
34493454
34503455
prompt_cache_retention: How long to retain a prompt cache entry created by this request.
34513456
3457+
service_tier: The service tier to use for this request.
3458+
34523459
extra_headers: Send extra headers
34533460
34543461
extra_query: Add additional query parameters to the request
@@ -3467,6 +3474,7 @@ async def compact(
34673474
"previous_response_id": previous_response_id,
34683475
"prompt_cache_key": prompt_cache_key,
34693476
"prompt_cache_retention": prompt_cache_retention,
3477+
"service_tier": service_tier,
34703478
},
34713479
response_compact_params.ResponseCompactParams,
34723480
),

0 commit comments

Comments
 (0)