diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fdce8724..3cb6257c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.62.0" + ".": "0.63.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index ff6b8935..6359ad06 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 232 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-371f497afe4d6070f6e252e5febbe8f453c7058a8dff0c26a01b4d88442a4ac2.yml -openapi_spec_hash: d39f46e8fda45f77096448105efd175a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-50d816559ef0935e64d07789ff936a2b762e26ab0714a2fa6bc06d06d4484294.yml +openapi_spec_hash: c5d8f37edbf66c1fef627d787b4c54fd config_hash: b64135fff1fe9cf4069b9ecf59ae8b07 diff --git a/CHANGELOG.md b/CHANGELOG.md index e6b669e8..812bd395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.63.0 (2026-05-13) + +Full Changelog: [v0.62.0...v0.63.0](https://github.com/openai/openai-ruby/compare/v0.62.0...v0.63.0) + +### Features + +* **api:** add service_tier parameter to responses compact method ([b0ed0cb](https://github.com/openai/openai-ruby/commit/b0ed0cbce8afbf6a2d099dbfed4c4d734ac10d0d)) + ## 0.62.0 (2026-05-07) Full Changelog: [v0.61.0...v0.62.0](https://github.com/openai/openai-ruby/compare/v0.61.0...v0.62.0) diff --git a/Gemfile.lock b/Gemfile.lock index d0ebeb70..33c3e46e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - openai (0.62.0) + openai (0.63.0) base64 cgi connection_pool diff --git a/README.md b/README.md index 916c1753..27260e3c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application ```ruby -gem "openai", "~> 0.62.0" +gem "openai", "~> 0.63.0" ``` @@ -111,6 +111,7 @@ Note that you can also pass a raw `IO` descriptor, but this disables retries, as For secure, automated environments like cloud-managed Kubernetes, Azure, and GCP, you can use workload identity authentication with short-lived tokens from cloud identity providers instead of long-lived API keys. +`client_id` remains available as an optional parameter for token exchange setups that require an explicit OAuth client ID. ### Kubernetes Service Account @@ -121,7 +122,6 @@ require "openai" provider = OpenAI::Auth::SubjectTokenProviders::K8sServiceAccountTokenProvider.new workload_identity = OpenAI::Auth::WorkloadIdentity.new( - client_id: ENV["OAUTH_CLIENT_ID"], # This is the default and can be omitted identity_provider_id: ENV["IDENTITY_PROVIDER_ID"], # This is the default and can be omitted service_account_id: ENV["SERVICE_ACCOUNT_ID"], # This is the default and can be omitted provider: provider @@ -143,7 +143,6 @@ response = client.chat.completions.create( provider = OpenAI::Auth::SubjectTokenProviders::AzureManagedIdentityTokenProvider.new workload_identity = OpenAI::Auth::WorkloadIdentity.new( - client_id: ENV["OAUTH_CLIENT_ID"], # This is the default and can be omitted identity_provider_id: ENV["IDENTITY_PROVIDER_ID"], # This is the default and can be omitted service_account_id: ENV["SERVICE_ACCOUNT_ID"], # This is the default and can be omitted provider: provider @@ -160,7 +159,6 @@ client = OpenAI::Client.new( provider = OpenAI::Auth::SubjectTokenProviders::GCPIDTokenProvider.new workload_identity = OpenAI::Auth::WorkloadIdentity.new( - client_id: ENV["OAUTH_CLIENT_ID"], # This is the default and can be omitted identity_provider_id: ENV["IDENTITY_PROVIDER_ID"], # This is the default and can be omitted service_account_id: ENV["SERVICE_ACCOUNT_ID"], # This is the default and can be omitted provider: provider @@ -191,7 +189,6 @@ end provider = CustomProvider.new workload_identity = OpenAI::Auth::WorkloadIdentity.new( - client_id: ENV["OAUTH_CLIENT_ID"], # This is the default and can be omitted identity_provider_id: ENV["IDENTITY_PROVIDER_ID"], # This is the default and can be omitted service_account_id: ENV["SERVICE_ACCOUNT_ID"], # This is the default and can be omitted provider: provider diff --git a/lib/openai/auth/workload_identity.rb b/lib/openai/auth/workload_identity.rb index c05a1e9b..87a645f9 100644 --- a/lib/openai/auth/workload_identity.rb +++ b/lib/openai/auth/workload_identity.rb @@ -6,13 +6,13 @@ class WorkloadIdentity attr_reader :client_id, :identity_provider_id, :service_account_id, :provider, :refresh_buffer_seconds def initialize( - client_id:, identity_provider_id:, service_account_id:, provider:, + client_id: nil, refresh_buffer_seconds: 1200 ) - @client_id = client_id.to_s + @client_id = client_id&.to_s @identity_provider_id = identity_provider_id.to_s @service_account_id = service_account_id.to_s @provider = provider diff --git a/lib/openai/auth/workload_identity_auth.rb b/lib/openai/auth/workload_identity_auth.rb index 22a08d10..c5c257f0 100644 --- a/lib/openai/auth/workload_identity_auth.rb +++ b/lib/openai/auth/workload_identity_auth.rb @@ -92,14 +92,15 @@ def fetch_token_from_exchange request = Net::HTTP::Post.new(@token_exchange_url) request["Content-Type"] = "application/json" - request.body = JSON.generate( + body = { grant_type: TOKEN_EXCHANGE_GRANT_TYPE, - client_id: @config.client_id, subject_token: subject_token, subject_token_type: subject_token_type, identity_provider_id: @config.identity_provider_id, service_account_id: @config.service_account_id - ) + } + body[:client_id] = @config.client_id unless @config.client_id.nil? + request.body = JSON.generate(body) response = Net::HTTP.start( @token_exchange_url.hostname, diff --git a/lib/openai/models/responses/response_compact_params.rb b/lib/openai/models/responses/response_compact_params.rb index a30231d6..62f97f11 100644 --- a/lib/openai/models/responses/response_compact_params.rb +++ b/lib/openai/models/responses/response_compact_params.rb @@ -56,7 +56,13 @@ class ResponseCompactParams < OpenAI::Internal::Type::BaseModel enum: -> { OpenAI::Responses::ResponseCompactParams::PromptCacheRetention }, nil?: true - # @!method initialize(model:, input: nil, instructions: nil, previous_response_id: nil, prompt_cache_key: nil, prompt_cache_retention: nil, request_options: {}) + # @!attribute service_tier + # The service tier to use for this request. + # + # @return [Symbol, OpenAI::Models::Responses::ResponseCompactParams::ServiceTier, nil] + optional :service_tier, enum: -> { OpenAI::Responses::ResponseCompactParams::ServiceTier }, nil?: true + + # @!method initialize(model:, input: nil, instructions: nil, previous_response_id: nil, prompt_cache_key: nil, prompt_cache_retention: nil, service_tier: nil, request_options: {}) # Some parameter documentations has been truncated, see # {OpenAI::Models::Responses::ResponseCompactParams} for more details. # @@ -72,6 +78,8 @@ class ResponseCompactParams < OpenAI::Internal::Type::BaseModel # # @param prompt_cache_retention [Symbol, OpenAI::Models::Responses::ResponseCompactParams::PromptCacheRetention, nil] How long to retain a prompt cache entry created by this request. # + # @param service_tier [Symbol, OpenAI::Models::Responses::ResponseCompactParams::ServiceTier, nil] The service tier to use for this request. + # # @param request_options [OpenAI::RequestOptions, Hash{Symbol=>Object}] # Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a @@ -401,6 +409,19 @@ module PromptCacheRetention # @!method self.values # @return [Array] end + + # The service tier to use for this request. + module ServiceTier + extend OpenAI::Internal::Type::Enum + + AUTO = :auto + DEFAULT = :default + FLEX = :flex + PRIORITY = :priority + + # @!method self.values + # @return [Array] + end end end end diff --git a/lib/openai/resources/responses.rb b/lib/openai/resources/responses.rb index cd4e73e8..2e4afd34 100644 --- a/lib/openai/resources/responses.rb +++ b/lib/openai/resources/responses.rb @@ -483,7 +483,7 @@ def cancel(response_id, params = {}) # For ZDR-compatible compaction details, see # [Compaction (advanced)](https://platform.openai.com/docs/guides/conversation-state#compaction-advanced). # - # @overload compact(model:, input: nil, instructions: nil, previous_response_id: nil, prompt_cache_key: nil, prompt_cache_retention: nil, request_options: {}) + # @overload compact(model:, input: nil, instructions: nil, previous_response_id: nil, prompt_cache_key: nil, prompt_cache_retention: nil, service_tier: nil, request_options: {}) # # @param model [Symbol, String, OpenAI::Models::Responses::ResponseCompactParams::Model, nil] Model ID used to generate the response, like `gpt-5` or `o3`. OpenAI offers a wi # @@ -497,6 +497,8 @@ def cancel(response_id, params = {}) # # @param prompt_cache_retention [Symbol, OpenAI::Models::Responses::ResponseCompactParams::PromptCacheRetention, nil] How long to retain a prompt cache entry created by this request. # + # @param service_tier [Symbol, OpenAI::Models::Responses::ResponseCompactParams::ServiceTier, nil] The service tier to use for this request. + # # @param request_options [OpenAI::RequestOptions, Hash{Symbol=>Object}, nil] # # @return [OpenAI::Models::Responses::CompactedResponse] diff --git a/lib/openai/version.rb b/lib/openai/version.rb index 74b41238..2d5c6103 100644 --- a/lib/openai/version.rb +++ b/lib/openai/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module OpenAI - VERSION = "0.62.0" + VERSION = "0.63.0" end diff --git a/rbi/openai/auth.rbi b/rbi/openai/auth.rbi index f3d217c2..e8f7fbdb 100644 --- a/rbi/openai/auth.rbi +++ b/rbi/openai/auth.rbi @@ -18,7 +18,7 @@ module OpenAI end class WorkloadIdentity - sig { returns(String) } + sig { returns(T.nilable(String)) } attr_reader :client_id sig { returns(String) } @@ -35,18 +35,18 @@ module OpenAI sig do params( - client_id: T.any(String, Symbol), identity_provider_id: T.any(String, Symbol), service_account_id: T.any(String, Symbol), provider: SubjectTokenProvider, + client_id: T.nilable(T.any(String, Symbol)), refresh_buffer_seconds: Integer ).void end def initialize( - client_id:, identity_provider_id:, service_account_id:, provider:, + client_id: nil, refresh_buffer_seconds: 1200 ) end diff --git a/rbi/openai/models/responses/response_compact_params.rbi b/rbi/openai/models/responses/response_compact_params.rbi index 46564650..395bcb96 100644 --- a/rbi/openai/models/responses/response_compact_params.rbi +++ b/rbi/openai/models/responses/response_compact_params.rbi @@ -68,6 +68,16 @@ module OpenAI end attr_accessor :prompt_cache_retention + # The service tier to use for this request. + sig do + returns( + T.nilable( + OpenAI::Responses::ResponseCompactParams::ServiceTier::OrSymbol + ) + ) + end + attr_accessor :service_tier + sig do params( model: @@ -88,6 +98,10 @@ module OpenAI T.nilable( OpenAI::Responses::ResponseCompactParams::PromptCacheRetention::OrSymbol ), + service_tier: + T.nilable( + OpenAI::Responses::ResponseCompactParams::ServiceTier::OrSymbol + ), request_options: OpenAI::RequestOptions::OrHash ).returns(T.attached_class) end @@ -114,6 +128,8 @@ module OpenAI prompt_cache_key: nil, # How long to retain a prompt cache entry created by this request. prompt_cache_retention: nil, + # The service tier to use for this request. + service_tier: nil, request_options: {} ) end @@ -139,6 +155,10 @@ module OpenAI T.nilable( OpenAI::Responses::ResponseCompactParams::PromptCacheRetention::OrSymbol ), + service_tier: + T.nilable( + OpenAI::Responses::ResponseCompactParams::ServiceTier::OrSymbol + ), request_options: OpenAI::RequestOptions } ) @@ -705,6 +725,51 @@ module OpenAI def self.values end end + + # The service tier to use for this request. + module ServiceTier + extend OpenAI::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + OpenAI::Responses::ResponseCompactParams::ServiceTier + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + AUTO = + T.let( + :auto, + OpenAI::Responses::ResponseCompactParams::ServiceTier::TaggedSymbol + ) + DEFAULT = + T.let( + :default, + OpenAI::Responses::ResponseCompactParams::ServiceTier::TaggedSymbol + ) + FLEX = + T.let( + :flex, + OpenAI::Responses::ResponseCompactParams::ServiceTier::TaggedSymbol + ) + PRIORITY = + T.let( + :priority, + OpenAI::Responses::ResponseCompactParams::ServiceTier::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + OpenAI::Responses::ResponseCompactParams::ServiceTier::TaggedSymbol + ] + ) + end + def self.values + end + end end end end diff --git a/rbi/openai/resources/responses.rbi b/rbi/openai/resources/responses.rbi index 6542cb5a..167d04b2 100644 --- a/rbi/openai/resources/responses.rbi +++ b/rbi/openai/resources/responses.rbi @@ -994,6 +994,10 @@ module OpenAI T.nilable( OpenAI::Responses::ResponseCompactParams::PromptCacheRetention::OrSymbol ), + service_tier: + T.nilable( + OpenAI::Responses::ResponseCompactParams::ServiceTier::OrSymbol + ), request_options: OpenAI::RequestOptions::OrHash ).returns(OpenAI::Responses::CompactedResponse) end @@ -1020,6 +1024,8 @@ module OpenAI prompt_cache_key: nil, # How long to retain a prompt cache entry created by this request. prompt_cache_retention: nil, + # The service tier to use for this request. + service_tier: nil, request_options: {} ) end diff --git a/sig/openai/models/responses/response_compact_params.rbs b/sig/openai/models/responses/response_compact_params.rbs index 14c59c83..226c79e2 100644 --- a/sig/openai/models/responses/response_compact_params.rbs +++ b/sig/openai/models/responses/response_compact_params.rbs @@ -8,7 +8,8 @@ module OpenAI instructions: String?, previous_response_id: String?, prompt_cache_key: String?, - prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention? + prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention?, + service_tier: OpenAI::Models::Responses::ResponseCompactParams::service_tier? } & OpenAI::Internal::Type::request_parameters @@ -28,6 +29,8 @@ module OpenAI attr_accessor prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention? + attr_accessor service_tier: OpenAI::Models::Responses::ResponseCompactParams::service_tier? + def initialize: ( model: OpenAI::Models::Responses::ResponseCompactParams::model?, ?input: OpenAI::Models::Responses::ResponseCompactParams::input?, @@ -35,6 +38,7 @@ module OpenAI ?previous_response_id: String?, ?prompt_cache_key: String?, ?prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention?, + ?service_tier: OpenAI::Models::Responses::ResponseCompactParams::service_tier?, ?request_options: OpenAI::request_opts ) -> void @@ -45,6 +49,7 @@ module OpenAI previous_response_id: String?, prompt_cache_key: String?, prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention?, + service_tier: OpenAI::Models::Responses::ResponseCompactParams::service_tier?, request_options: OpenAI::RequestOptions } @@ -263,6 +268,19 @@ module OpenAI def self?.values: -> ::Array[OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention] end + + type service_tier = :auto | :default | :flex | :priority + + module ServiceTier + extend OpenAI::Internal::Type::Enum + + AUTO: :auto + DEFAULT: :default + FLEX: :flex + PRIORITY: :priority + + def self?.values: -> ::Array[OpenAI::Models::Responses::ResponseCompactParams::service_tier] + end end end end diff --git a/sig/openai/resources/responses.rbs b/sig/openai/resources/responses.rbs index 88fa787f..de05b4b1 100644 --- a/sig/openai/resources/responses.rbs +++ b/sig/openai/resources/responses.rbs @@ -130,6 +130,7 @@ module OpenAI ?previous_response_id: String?, ?prompt_cache_key: String?, ?prompt_cache_retention: OpenAI::Models::Responses::ResponseCompactParams::prompt_cache_retention?, + ?service_tier: OpenAI::Models::Responses::ResponseCompactParams::service_tier?, ?request_options: OpenAI::request_opts ) -> OpenAI::Responses::CompactedResponse diff --git a/test/openai/auth/workload_identity_test.rb b/test/openai/auth/workload_identity_test.rb index 0731284a..78d55fb4 100644 --- a/test/openai/auth/workload_identity_test.rb +++ b/test/openai/auth/workload_identity_test.rb @@ -119,6 +119,39 @@ def test_workload_identity_auth_token_exchange token_path: @token_path ) + stub_request(:post, "https://auth.openai.com/oauth/token") + .with do |request| + JSON.parse(request.body) == { + "grant_type" => "urn:ietf:params:oauth:grant-type:token-exchange", + "subject_token" => "k8s-jwt-token", + "subject_token_type" => "urn:ietf:params:oauth:token-type:jwt", + "identity_provider_id" => "idp-123", + "service_account_id" => "sa-456" + } + end + .to_return( + status: 200, + body: JSON.generate({"access_token" => "oauth-access-token", "expires_in" => 3600}) + ) + + config = OpenAI::Auth::WorkloadIdentity.new( + identity_provider_id: "idp-123", + service_account_id: "sa-456", + provider: provider + ) + + auth = OpenAI::Auth::WorkloadIdentityAuth.new(config, "org-123") + token = auth.get_token + + assert_equal("oauth-access-token", token) + end + + def test_workload_identity_auth_token_exchange_with_optional_client_id + File.write(@token_path, "k8s-jwt-token") + provider = OpenAI::Auth::SubjectTokenProviders::K8sServiceAccountTokenProvider.new( + token_path: @token_path + ) + stub_request(:post, "https://auth.openai.com/oauth/token") .with( body: hash_including( @@ -136,10 +169,10 @@ def test_workload_identity_auth_token_exchange ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", - provider: provider + provider: provider, + client_id: "test-client" ) auth = OpenAI::Auth::WorkloadIdentityAuth.new(config, "org-123") @@ -166,7 +199,6 @@ def test_workload_identity_auth_oauth_error ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "bad-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider @@ -190,7 +222,6 @@ def test_workload_identity_client_initialization ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider @@ -210,7 +241,6 @@ def test_workload_identity_client_initialization def test_workload_identity_mutually_exclusive_with_api_key provider = OpenAI::Auth::SubjectTokenProviders::K8sServiceAccountTokenProvider.new config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider @@ -233,7 +263,6 @@ def test_workload_identity_preserves_admin_auth_requests token_path: @token_path ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider @@ -316,7 +345,6 @@ def test_401_retry_with_token_invalidation ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider @@ -379,7 +407,6 @@ def test_workload_identity_token_caching ) config = OpenAI::Auth::WorkloadIdentity.new( - client_id: "test-client", identity_provider_id: "idp-123", service_account_id: "sa-456", provider: provider