openai 0.77.1 → 0.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +98 -0
  3. data/README.md +341 -10
  4. data/SECURITY.md +6 -22
  5. data/azure.md +110 -0
  6. data/bedrock.md +132 -0
  7. data/examples/mtls_custom_http_client.rb +61 -0
  8. data/lib/openai/auth/workload_identity.rb +13 -2
  9. data/lib/openai/auth/workload_identity_auth.rb +2 -1
  10. data/lib/openai/client.rb +34 -14
  11. data/lib/openai/errors.rb +11 -1
  12. data/lib/openai/helpers/streaming/chat_completion_stream.rb +3 -3
  13. data/lib/openai/helpers/streaming/response_stream.rb +5 -6
  14. data/lib/openai/helpers/structured_output/base_model.rb +20 -19
  15. data/lib/openai/helpers/structured_output/json_schema_converter.rb +12 -5
  16. data/lib/openai/http_client.rb +189 -0
  17. data/lib/openai/internal/conversation_cursor_page.rb +5 -6
  18. data/lib/openai/internal/cursor_page.rb +3 -3
  19. data/lib/openai/internal/logging.rb +419 -0
  20. data/lib/openai/internal/next_cursor_page.rb +5 -6
  21. data/lib/openai/internal/page.rb +2 -2
  22. data/lib/openai/internal/provider.rb +7 -1
  23. data/lib/openai/internal/read_io_adapter.rb +161 -0
  24. data/lib/openai/internal/stream.rb +2 -2
  25. data/lib/openai/internal/transport/base_client.rb +216 -57
  26. data/lib/openai/internal/type/array_of.rb +6 -4
  27. data/lib/openai/internal/type/base_model.rb +39 -1
  28. data/lib/openai/internal/type/base_page.rb +19 -2
  29. data/lib/openai/internal/type/base_stream.rb +40 -8
  30. data/lib/openai/internal/type/hash_of.rb +3 -3
  31. data/lib/openai/internal/util.rb +59 -112
  32. data/lib/openai/models/admin/organization/audit_log_list_params.rb +3 -1
  33. data/lib/openai/models/admin/organization/audit_log_list_response.rb +33 -11
  34. data/lib/openai/models/admin/organization/groups/role_list_response.rb +5 -1
  35. data/lib/openai/models/admin/organization/groups/role_retrieve_response.rb +5 -1
  36. data/lib/openai/models/admin/organization/projects/groups/role_list_response.rb +6 -1
  37. data/lib/openai/models/admin/organization/projects/groups/role_retrieve_response.rb +6 -1
  38. data/lib/openai/models/admin/organization/projects/service_account_create_response.rb +3 -1
  39. data/lib/openai/models/admin/organization/projects/users/role_list_response.rb +6 -1
  40. data/lib/openai/models/admin/organization/projects/users/role_retrieve_response.rb +6 -1
  41. data/lib/openai/models/admin/organization/users/role_list_response.rb +5 -1
  42. data/lib/openai/models/admin/organization/users/role_retrieve_response.rb +5 -1
  43. data/lib/openai/models/all_models.rb +3 -0
  44. data/lib/openai/models/audio/transcription_create_params.rb +7 -1
  45. data/lib/openai/models/audio/translation_create_params.rb +7 -1
  46. data/lib/openai/models/beta/beta_response.rb +9 -0
  47. data/lib/openai/models/beta/beta_response_stream_event.rb +1 -1
  48. data/lib/openai/models/beta/beta_responses_client_event.rb +28 -3
  49. data/lib/openai/models/beta/beta_responses_server_event.rb +1037 -61
  50. data/lib/openai/models/beta/response_compact_params.rb +9 -0
  51. data/lib/openai/models/beta/response_create_params.rb +9 -0
  52. data/lib/openai/models/containers/file_create_params.rb +4 -0
  53. data/lib/openai/models/content_provenance_check_create_params.rb +4 -0
  54. data/lib/openai/models/file_create_params.rb +4 -0
  55. data/lib/openai/models/image_create_variation_params.rb +4 -0
  56. data/lib/openai/models/image_edit_params.rb +8 -0
  57. data/lib/openai/models/responses/response_compact_params.rb +9 -0
  58. data/lib/openai/models/responses/response_stream_event.rb +1 -1
  59. data/lib/openai/models/responses/responses_client_event.rb +13 -1
  60. data/lib/openai/models/responses/responses_server_event.rb +1027 -54
  61. data/lib/openai/models/responses_model.rb +3 -0
  62. data/lib/openai/models/skill_create_params.rb +4 -0
  63. data/lib/openai/models/skills/version_create_params.rb +4 -0
  64. data/lib/openai/models/uploads/part_create_params.rb +4 -0
  65. data/lib/openai/models/vector_store_search_response.rb +3 -1
  66. data/lib/openai/models/video_create_character_params.rb +4 -0
  67. data/lib/openai/models/video_create_params.rb +4 -0
  68. data/lib/openai/models/video_edit_params.rb +4 -0
  69. data/lib/openai/models/video_extend_params.rb +4 -0
  70. data/lib/openai/models.rb +9 -1
  71. data/lib/openai/net_http_client.rb +295 -0
  72. data/lib/openai/providers/azure.rb +216 -0
  73. data/lib/openai/providers/bedrock.rb +3 -1
  74. data/lib/openai/resources/admin/organization/projects/groups/roles.rb +1 -1
  75. data/lib/openai/resources/admin/organization/projects/groups.rb +1 -1
  76. data/lib/openai/resources/admin/organization/projects/users/roles.rb +1 -1
  77. data/lib/openai/resources/admin/organization/projects.rb +4 -2
  78. data/lib/openai/resources/audio/transcriptions.rb +8 -0
  79. data/lib/openai/resources/audio/translations.rb +4 -0
  80. data/lib/openai/resources/beta/responses.rb +1 -1
  81. data/lib/openai/resources/beta/threads/runs/steps.rb +2 -2
  82. data/lib/openai/resources/containers/files.rb +4 -0
  83. data/lib/openai/resources/content_provenance_checks.rb +4 -0
  84. data/lib/openai/resources/conversations/items.rb +1 -1
  85. data/lib/openai/resources/evals/runs/output_items.rb +1 -1
  86. data/lib/openai/resources/files.rb +4 -0
  87. data/lib/openai/resources/images.rb +12 -0
  88. data/lib/openai/resources/responses.rb +3 -2
  89. data/lib/openai/resources/skills/versions.rb +4 -0
  90. data/lib/openai/resources/skills.rb +4 -0
  91. data/lib/openai/resources/uploads/parts.rb +4 -0
  92. data/lib/openai/resources/vector_stores/file_batches.rb +1 -1
  93. data/lib/openai/resources/videos.rb +38 -0
  94. data/lib/openai/resources/webhooks.rb +18 -6
  95. data/lib/openai/version.rb +1 -1
  96. data/lib/openai.rb +113 -108
  97. data/rbi/openai/auth.rbi +4 -4
  98. data/rbi/openai/client.rbi +15 -3
  99. data/rbi/openai/errors.rbi +7 -0
  100. data/rbi/openai/helpers/streaming/events.rbi +12 -0
  101. data/rbi/openai/http_client.rbi +123 -0
  102. data/rbi/openai/internal/logging.rbi +192 -0
  103. data/rbi/openai/internal/provider.rbi +3 -0
  104. data/rbi/openai/internal/read_io_adapter.rbi +52 -0
  105. data/rbi/openai/internal/transport/base_client.rbi +80 -10
  106. data/rbi/openai/internal/type/base_model.rbi +24 -1
  107. data/rbi/openai/internal/type/base_page.rbi +13 -2
  108. data/rbi/openai/internal/type/base_stream.rbi +16 -5
  109. data/rbi/openai/internal/util.rbi +26 -42
  110. data/rbi/openai/models/admin/organization/audit_log_list_params.rbi +5 -0
  111. data/rbi/openai/models/admin/organization/audit_log_list_response.rbi +5 -0
  112. data/rbi/openai/models/all_models.rbi +15 -0
  113. data/rbi/openai/models/audio/transcription_create_params.rbi +14 -2
  114. data/rbi/openai/models/audio/translation_create_params.rbi +14 -2
  115. data/rbi/openai/models/beta/beta_response.rbi +15 -0
  116. data/rbi/openai/models/beta/beta_response_stream_event.rbi +1 -1
  117. data/rbi/openai/models/beta/beta_responses_client_event.rbi +37 -1
  118. data/rbi/openai/models/beta/beta_responses_server_event.rbi +3791 -54
  119. data/rbi/openai/models/beta/response_compact_params.rbi +15 -0
  120. data/rbi/openai/models/beta/response_create_params.rbi +15 -0
  121. data/rbi/openai/models/containers/file_create_params.rbi +8 -0
  122. data/rbi/openai/models/content_provenance_check_create_params.rbi +8 -0
  123. data/rbi/openai/models/file_create_params.rbi +8 -0
  124. data/rbi/openai/models/image_create_variation_params.rbi +8 -0
  125. data/rbi/openai/models/image_edit_params.rbi +16 -0
  126. data/rbi/openai/models/responses/response_compact_params.rbi +15 -0
  127. data/rbi/openai/models/responses/response_stream_event.rbi +1 -1
  128. data/rbi/openai/models/responses/responses_client_event.rbi +19 -0
  129. data/rbi/openai/models/responses/responses_server_event.rbi +3282 -53
  130. data/rbi/openai/models/responses_model.rbi +15 -0
  131. data/rbi/openai/models/skill_create_params.rbi +8 -0
  132. data/rbi/openai/models/skills/version_create_params.rbi +8 -0
  133. data/rbi/openai/models/uploads/part_create_params.rbi +8 -0
  134. data/rbi/openai/models/video_create_character_params.rbi +8 -0
  135. data/rbi/openai/models/video_create_params.rbi +8 -0
  136. data/rbi/openai/models/video_edit_params.rbi +8 -0
  137. data/rbi/openai/models/video_extend_params.rbi +8 -0
  138. data/rbi/openai/net_http_client.rbi +64 -0
  139. data/rbi/openai/providers.rbi +9 -0
  140. data/rbi/openai/resources/audio/transcriptions.rbi +14 -2
  141. data/rbi/openai/resources/audio/translations.rbi +7 -1
  142. data/rbi/openai/resources/containers/files.rbi +4 -0
  143. data/rbi/openai/resources/content_provenance_checks.rbi +4 -0
  144. data/rbi/openai/resources/files.rbi +4 -0
  145. data/rbi/openai/resources/images.rbi +20 -0
  146. data/rbi/openai/resources/skills/versions.rbi +4 -0
  147. data/rbi/openai/resources/skills.rbi +4 -0
  148. data/rbi/openai/resources/uploads/parts.rbi +4 -0
  149. data/rbi/openai/resources/videos.rbi +16 -0
  150. data/sig/openai/client.rbs +7 -2
  151. data/sig/openai/errors.rbs +5 -0
  152. data/sig/openai/http_client.rbs +76 -0
  153. data/sig/openai/internal/logging.rbs +88 -0
  154. data/sig/openai/internal/provider.rbs +3 -1
  155. data/sig/openai/internal/read_io_adapter.rbs +23 -0
  156. data/sig/openai/internal/transport/base_client.rbs +41 -6
  157. data/sig/openai/internal/type/base_model.rbs +13 -0
  158. data/sig/openai/internal/type/base_page.rbs +8 -1
  159. data/sig/openai/internal/type/base_stream.rbs +9 -3
  160. data/sig/openai/internal/util.rbs +12 -16
  161. data/sig/openai/models/admin/organization/audit_log_list_params.rbs +2 -0
  162. data/sig/openai/models/admin/organization/audit_log_list_response.rbs +2 -0
  163. data/sig/openai/models/all_models.rbs +6 -0
  164. data/sig/openai/models/beta/beta_response.rbs +6 -0
  165. data/sig/openai/models/beta/beta_responses_client_event.rbs +13 -0
  166. data/sig/openai/models/beta/beta_responses_server_event.rbs +1946 -54
  167. data/sig/openai/models/beta/response_compact_params.rbs +6 -0
  168. data/sig/openai/models/beta/response_create_params.rbs +6 -0
  169. data/sig/openai/models/responses/response_compact_params.rbs +6 -0
  170. data/sig/openai/models/responses/responses_client_event.rbs +7 -0
  171. data/sig/openai/models/responses/responses_server_event.rbs +1786 -53
  172. data/sig/openai/models/responses_model.rbs +6 -0
  173. data/sig/openai/net_http_client.rbs +34 -0
  174. data/sig/openai/providers.rbs +6 -0
  175. metadata +33 -4
  176. data/lib/openai/internal/transport/pooled_net_requester.rb +0 -210
  177. data/rbi/openai/internal/transport/pooled_net_requester.rbi +0 -82
  178. data/sig/openai/internal/transport/pooled_net_requester.rbs +0 -48
@@ -226,6 +226,32 @@ module OpenAI
226
226
  # @return [Integer]
227
227
  def hash = [self.class, @data].hash
228
228
 
229
+ # The ID of the API request, returned via the `x-request-id` response
230
+ # header. This is only populated on top-level response objects returned
231
+ # by the client.
232
+ #
233
+ # @api public
234
+ #
235
+ # @return [String, nil]
236
+ def _request_id = @last_response&.request_id
237
+
238
+ # Metadata from the HTTP response that produced this model. This is
239
+ # only populated on top-level response objects returned by the client.
240
+ #
241
+ # @api public
242
+ #
243
+ # @return [OpenAI::ResponseMetadata, nil]
244
+ attr_reader :last_response
245
+
246
+ # @api private
247
+ #
248
+ # @param response [OpenAI::ResponseMetadata]
249
+ # @return [self]
250
+ def _set_last_response(response)
251
+ @last_response = response
252
+ self
253
+ end
254
+
229
255
  class << self
230
256
  # @api private
231
257
  #
@@ -247,7 +273,7 @@ module OpenAI
247
273
  def coerce(value, state:)
248
274
  exactness = state.fetch(:exactness)
249
275
 
250
- if value.is_a?(self.class)
276
+ if value.is_a?(self)
251
277
  exactness[:yes] += 1
252
278
  return value
253
279
  end
@@ -470,12 +496,24 @@ module OpenAI
470
496
  # @return [String]
471
497
  def to_yaml(*a) = OpenAI::Internal::Type::Converter.dump(self.class, self).to_yaml(*a)
472
498
 
499
+ # Keep transport metadata outside Psych's object serialization path.
500
+ #
501
+ # @api private
502
+ #
503
+ # @param coder [Psych::Coder]
504
+ # @return [void]
505
+ def encode_with(coder)
506
+ coder["data"] = @data
507
+ coder["coerced"] = @coerced
508
+ end
509
+
473
510
  # Create a new instance of a model.
474
511
  #
475
512
  # @param data [Hash{Symbol=>Object}, self]
476
513
  def initialize(data = {})
477
514
  @data = {}
478
515
  @coerced = {}
516
+ @last_response = nil
479
517
  OpenAI::Internal::Util.coerce_hash!(data).each do
480
518
  if self.class.known_fields.key?(_1)
481
519
  public_send(:"#{_1}=", _2)
@@ -11,6 +11,22 @@ module OpenAI
11
11
  module BasePage
12
12
  # rubocop:disable Lint/UnusedMethodArgument
13
13
 
14
+ # The ID of the API request, returned via the `x-request-id` response
15
+ # header. This is only populated on top-level response objects returned
16
+ # by the client.
17
+ #
18
+ # @api public
19
+ #
20
+ # @return [String, nil]
21
+ def _request_id = last_response.request_id
22
+
23
+ # Metadata from the HTTP response that produced this page.
24
+ #
25
+ # @api public
26
+ #
27
+ # @return [OpenAI::ResponseMetadata]
28
+ attr_reader :last_response
29
+
14
30
  # @api public
15
31
  #
16
32
  # @return [Boolean]
@@ -39,12 +55,13 @@ module OpenAI
39
55
  #
40
56
  # @param client [OpenAI::Internal::Transport::BaseClient]
41
57
  # @param req [Hash{Symbol=>Object}]
42
- # @param headers [Hash{String=>String}]
58
+ # @param response_metadata [OpenAI::ResponseMetadata]
43
59
  # @param page_data [Object]
44
- def initialize(client:, req:, headers:, page_data:)
60
+ def initialize(client:, req:, response_metadata:, page_data:)
45
61
  @client = client
46
62
  @req = req
47
63
  @model = req.fetch(:model)
64
+ @last_response = response_metadata
48
65
  super()
49
66
  end
50
67
 
@@ -14,16 +14,50 @@ module OpenAI
14
14
  include Enumerable
15
15
 
16
16
  # @return [Integer]
17
- attr_reader :status
17
+ def status = last_response.status
18
18
 
19
19
  # @return [Hash{String=>String}]
20
- attr_reader :headers
20
+ def headers = last_response.headers
21
+
22
+ # Metadata from the HTTP response that opened this stream.
23
+ #
24
+ # @api public
25
+ #
26
+ # @return [OpenAI::ResponseMetadata]
27
+ attr_reader :last_response
21
28
 
22
29
  # @api public
23
30
  #
24
31
  # @return [void]
25
32
  def close = OpenAI::Internal::Util.close_fused!(@iterator)
26
33
 
34
+ # Attach request lifecycle logging without changing the stream's identity.
35
+ #
36
+ # @api private
37
+ #
38
+ # @param context [OpenAI::Internal::Logging::Context]
39
+ # @param response [OpenAI::HTTPClient::Response]
40
+ # @return [self]
41
+ def observe(context:, response:)
42
+ source = @iterator
43
+ @iterator = OpenAI::Internal::Util.chain_fused(source) do |yielder|
44
+ loop do
45
+ event =
46
+ begin
47
+ source.next
48
+ rescue StopIteration
49
+ context.completed(response)
50
+ break
51
+ rescue StandardError => e
52
+ context.request_failed(e)
53
+ raise
54
+ end
55
+ yielder << event
56
+ end
57
+ end
58
+ self
59
+ end
60
+
27
61
  # @api private
28
62
  #
29
63
  # @return [Enumerable<generic<Elem>>]
@@ -53,16 +87,14 @@ module OpenAI
53
87
  #
54
88
  # @param model [Class, OpenAI::Internal::Type::Converter]
55
89
  # @param url [URI::Generic]
56
- # @param status [Integer]
57
- # @param headers [Hash{String=>String}]
58
- # @param response [Net::HTTPResponse]
90
+ # @param response_metadata [OpenAI::ResponseMetadata]
91
+ # @param response [OpenAI::HTTPClient::Response]
59
92
  # @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc]
60
93
  # @param stream [Enumerable<Object>]
61
- def initialize(model:, url:, status:, headers:, response:, unwrap:, stream:)
94
+ def initialize(model:, url:, response_metadata:, response:, unwrap:, stream:)
62
95
  @model = model
63
96
  @url = url
64
- @status = status
65
- @headers = headers
97
+ @last_response = response_metadata
66
98
  @response = response
67
99
  @unwrap = unwrap
68
100
  @stream = stream
@@ -61,9 +61,9 @@ module OpenAI
61
61
  #
62
62
  # @return [Boolean]
63
63
  def ==(other)
64
- # rubocop:disable Layout/LineLength
65
- other.is_a?(OpenAI::Internal::Type::HashOf) && other.nilable? == nilable? && other.item_type == item_type
66
- # rubocop:enable Layout/LineLength
64
+ other.is_a?(OpenAI::Internal::Type::HashOf) &&
65
+ other.nilable? == nilable? &&
66
+ other.item_type == item_type
67
67
  end
68
68
 
69
69
  # @api public
@@ -4,6 +4,11 @@ module OpenAI
4
4
  module Internal
5
5
  # @api private
6
6
  module Util
7
+ # Marks enumerators whose overridden rewind safely closes the iterator.
8
+ module FusedEnumerator
9
+ end
10
+ private_constant :FusedEnumerator
11
+
7
12
  # @api private
8
13
  #
9
14
  # @return [Float]
@@ -256,9 +261,13 @@ module OpenAI
256
261
  #
257
262
  # @param path [String, Integer]
258
263
  #
264
+ # @raise [ArgumentError]
259
265
  # @return [String]
260
266
  def encode_path(path)
261
- path.to_s.gsub(OpenAI::Internal::Util::RFC_3986_NOT_PCHARS) { ERB::Util.url_encode(_1) }
267
+ path = path.to_s
268
+ raise ArgumentError, "path segment cannot be '.' or '..'" if path == "." || path == ".."
269
+
270
+ path.gsub(OpenAI::Internal::Util::RFC_3986_NOT_PCHARS) { ERB::Util.url_encode(_1) }
262
271
  end
263
272
 
264
273
  # @api private
@@ -384,7 +393,7 @@ module OpenAI
384
393
  #
385
394
  # @return [Hash{String=>String}]
386
395
  def normalized_headers(*headers)
387
- {}.merge(*headers.compact).to_h do |key, val|
396
+ headers.compact.flat_map(&:to_a).to_h do |key, val|
388
397
  value =
389
398
  case val
390
399
  in Array
@@ -392,92 +401,8 @@ module OpenAI
392
401
  else
393
402
  val&.to_s&.strip
394
403
  end
395
- [key.downcase, value]
396
- end
397
- end
398
- end
399
-
400
- # @api private
401
- #
402
- # An adapter that satisfies the IO interface required by `::IO.copy_stream`
403
- class ReadIOAdapter
404
- # @api private
405
- #
406
- # @return [Boolean, nil]
407
- def close? = @closing
408
-
409
- # @api private
410
- def close
411
- case @stream
412
- in Enumerator
413
- OpenAI::Internal::Util.close_fused!(@stream)
414
- in IO if close?
415
- @stream.close
416
- else
417
- end
418
- end
419
-
420
- # @api private
421
- #
422
- # @param max_len [Integer, nil]
423
- #
424
- # @return [String]
425
- private def read_enum(max_len)
426
- case max_len
427
- in nil
428
- @stream.to_a.join
429
- in Integer
430
- @buf << @stream.next while @buf.length < max_len
431
- @buf.slice!(..max_len)
432
- end
433
- rescue StopIteration
434
- @stream = nil
435
- @buf.slice!(0..)
436
- end
437
-
438
- # @api private
439
- #
440
- # @param max_len [Integer, nil]
441
- # @param out_string [String, nil]
442
- #
443
- # @return [String, nil]
444
- def read(max_len = nil, out_string = nil)
445
- case @stream
446
- in nil
447
- nil
448
- in IO | StringIO
449
- @stream.read(max_len, out_string)
450
- in Enumerator
451
- read = read_enum(max_len)
452
- case out_string
453
- in String
454
- out_string.replace(read)
455
- in nil
456
- read
457
- end
404
+ [key.to_s.downcase, value]
458
405
  end
459
- .tap(&@blk)
460
- end
461
-
462
- # @api private
463
- #
464
- # @param src [String, Pathname, StringIO, Enumerable<String>]
465
- # @param blk [Proc]
466
- #
467
- # @yieldparam [String]
468
- def initialize(src, &blk)
469
- @stream =
470
- case src
471
- in String
472
- StringIO.new(src)
473
- in Pathname
474
- @closing = true
475
- src.open(binmode: true)
476
- else
477
- src
478
- end
479
- @buf = String.new
480
- @blk = blk
481
406
  end
482
407
  end
483
408
 
@@ -499,9 +424,9 @@ module OpenAI
499
424
  end
500
425
 
501
426
  # @type [Regexp]
502
- JSON_CONTENT = %r{^application/(?:[a-zA-Z0-9.-]+\+)?json(?!l)}
427
+ JSON_CONTENT = %r{\Aapplication/(?:[a-z0-9.-]+\+)?json[ \t]*(?:;|\z)}i
503
428
  # @type [Regexp]
504
- JSONL_CONTENT = %r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)}
429
+ JSONL_CONTENT = %r{\Aapplication/(?:x-[nl]djson|(?:x-)?jsonl)[ \t]*(?:;|\z)}i
505
430
 
506
431
  class << self
507
432
  # @api private
@@ -575,14 +500,14 @@ module OpenAI
575
500
 
576
501
  # @api private
577
502
  #
578
- # Multipart filenames are quoted-strings, not URI path segments. Escape header
579
- # delimiters and remove CR/LF without encoding ordinary filename characters.
503
+ # Multipart disposition parameters are quoted-strings, not URI path segments.
504
+ # Escape header delimiters and remove CR/LF without encoding ordinary characters.
580
505
  #
581
- # @param filename [Pathname, String]
506
+ # @param value [Pathname, String, Symbol]
582
507
  #
583
508
  # @return [String]
584
- private def escape_multipart_filename(filename)
585
- filename.to_s.gsub(/["\\]/) { "\\#{_1}" }.delete("\r\n").b
509
+ private def escape_multipart_header_param(value)
510
+ value.to_s.gsub(/["\\]/) { "\\#{_1}" }.delete("\r\n").b
586
511
  end
587
512
 
588
513
  # @api private
@@ -597,15 +522,16 @@ module OpenAI
597
522
  y << "Content-Disposition: form-data"
598
523
 
599
524
  unless key.nil?
600
- y << "; name=\"#{key}\""
525
+ name = escape_multipart_header_param(key)
526
+ y << "; name=\"#{name}\""
601
527
  end
602
528
 
603
529
  case val
604
530
  in OpenAI::FilePart unless val.filename.nil?
605
- filename = escape_multipart_filename(val.filename)
531
+ filename = escape_multipart_header_param(val.filename)
606
532
  y << "; filename=\"#{filename}\""
607
533
  in Pathname | IO
608
- filename = escape_multipart_filename(::File.basename(val.to_path))
534
+ filename = escape_multipart_header_param(::File.basename(val.to_path))
609
535
  y << "; filename=\"#{filename}\""
610
536
  else
611
537
  end
@@ -614,6 +540,34 @@ module OpenAI
614
540
  write_multipart_content(y, val: val, closing: closing)
615
541
  end
616
542
 
543
+ # @api private
544
+ #
545
+ # @param y [Enumerator::Yielder]
546
+ # @param boundary [String]
547
+ # @param key [Symbol, String]
548
+ # @param val [Object]
549
+ # @param closing [Array<Proc>]
550
+ private def write_multipart_value(y, boundary:, key:, val:, closing:)
551
+ case val
552
+ in Hash
553
+ val.each do |name, value|
554
+ write_multipart_value(
555
+ y,
556
+ boundary: boundary,
557
+ key: "#{key}[#{name}]",
558
+ val: value,
559
+ closing: closing
560
+ )
561
+ end
562
+ in Array
563
+ val.each do |value|
564
+ write_multipart_value(y, boundary: boundary, key: "#{key}[]", val: value, closing: closing)
565
+ end
566
+ else
567
+ write_multipart_chunk(y, boundary: boundary, key: key, val: val, closing: closing)
568
+ end
569
+ end
570
+
617
571
  # @api private
618
572
  #
619
573
  # https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#special-considerations-for-multipart-content
@@ -622,7 +576,6 @@ module OpenAI
622
576
  #
623
577
  # @return [Array(String, Enumerable<String>)]
624
578
  private def encode_multipart_streaming(body)
625
- # rubocop:disable Style/CaseEquality
626
579
  # RFC 1521 Section 7.2.1 says we should have 70 char maximum for boundary length
627
580
  boundary = SecureRandom.urlsafe_base64(46)
628
581
 
@@ -631,14 +584,7 @@ module OpenAI
631
584
  case body
632
585
  in Hash
633
586
  body.each do |key, val|
634
- case val
635
- in Array if val.all? { primitive?(_1) || OpenAI::Internal::Type::FileInput === _1 }
636
- val.each do |v|
637
- write_multipart_chunk(y, boundary: boundary, key: key, val: v, closing: closing)
638
- end
639
- else
640
- write_multipart_chunk(y, boundary: boundary, key: key, val: val, closing: closing)
641
- end
587
+ write_multipart_value(y, boundary: boundary, key: key, val: val, closing: closing)
642
588
  end
643
589
  else
644
590
  write_multipart_chunk(y, boundary: boundary, key: nil, val: body, closing: closing)
@@ -648,7 +594,6 @@ module OpenAI
648
594
 
649
595
  fused_io = fused_enum(strio) { closing.each(&:call) }
650
596
  [boundary, fused_io]
651
- # rubocop:enable Style/CaseEquality
652
597
  end
653
598
 
654
599
  # @api private
@@ -659,12 +604,14 @@ module OpenAI
659
604
  # @return [Object]
660
605
  def encode_content(headers, body)
661
606
  # rubocop:disable Style/CaseEquality
662
- # rubocop:disable Layout/LineLength
663
607
  content_type = headers["content-type"]
664
608
  case [content_type, body]
665
609
  in [OpenAI::Internal::Util::JSON_CONTENT, Hash | Array | -> { primitive?(_1) }]
666
610
  [headers, JSON.generate(body)]
667
- in [OpenAI::Internal::Util::JSONL_CONTENT, Enumerable] unless OpenAI::Internal::Type::FileInput === body
611
+ in [
612
+ OpenAI::Internal::Util::JSONL_CONTENT,
613
+ Enumerable
614
+ ] unless OpenAI::Internal::Type::FileInput === body
668
615
  [headers, body.lazy.map { JSON.generate(_1) }]
669
616
  in [%r{^multipart/form-data}, Hash | OpenAI::Internal::Type::FileInput]
670
617
  boundary, strio = encode_multipart_streaming(body)
@@ -679,7 +626,6 @@ module OpenAI
679
626
  else
680
627
  [headers, body]
681
628
  end
682
- # rubocop:enable Layout/LineLength
683
629
  # rubocop:enable Style/CaseEquality
684
630
  end
685
631
 
@@ -732,7 +678,7 @@ module OpenAI
732
678
  y << JSON.parse(_1, symbolize_names: true)
733
679
  end
734
680
  end
735
- in %r{^text/event-stream}
681
+ in %r{\Atext/event-stream[ \t]*(?:;|\z)}i
736
682
  lines = decode_lines(stream)
737
683
  decode_sse(lines)
738
684
  else
@@ -768,6 +714,7 @@ module OpenAI
768
714
  close&.call
769
715
  close = nil
770
716
  end
717
+ iter.extend(FusedEnumerator)
771
718
 
772
719
  iter.define_singleton_method(:rewind) do
773
720
  fused = true
@@ -780,7 +727,7 @@ module OpenAI
780
727
  #
781
728
  # @param enum [Enumerable<Object>, nil]
782
729
  def close_fused!(enum)
783
- return unless enum.is_a?(Enumerator)
730
+ return unless enum.is_a?(FusedEnumerator)
784
731
 
785
732
  # rubocop:disable Lint/UnreachableLoop
786
733
  enum.rewind.each { break }
@@ -229,6 +229,7 @@ module OpenAI
229
229
  TENANT_WORKLOAD_IDENTITY_MAPPING_ARCHIVED = :"tenant.workload_identity.mapping.archived"
230
230
  TENANT_WORKLOAD_IDENTITY_BINDING_CREATED = :"tenant.workload_identity.binding.created"
231
231
  TENANT_WORKLOAD_IDENTITY_PRINCIPAL_PROVISIONED = :"tenant.workload_identity.principal.provisioned"
232
+ TENANT_WORKLOAD_IDENTITY_ACCESS_TOKEN_ISSUED = :"tenant.workload_identity.access_token.issued"
232
233
  TENANT_ADMIN_API_KEY_CREATED = :"tenant.admin_api_key.created"
233
234
  TENANT_ADMIN_API_KEY_UPDATED = :"tenant.admin_api_key.updated"
234
235
  TENANT_ADMIN_API_KEY_DELETED = :"tenant.admin_api_key.deleted"
@@ -246,7 +247,8 @@ module OpenAI
246
247
  TENANT_POLICY_DELETED = :"tenant.policy.deleted"
247
248
  TENANT_POLICY_ATTACHED = :"tenant.policy.attached"
248
249
  TENANT_POLICY_DETACHED = :"tenant.policy.detached"
249
- TENANT_PRINCIPAL_AUTHENTICATION_POLICY_RESOLVED = :"tenant.principal_authentication_policy.resolved"
250
+ TENANT_PRINCIPAL_AUTHENTICATION_POLICY_RESOLVED =
251
+ :"tenant.principal_authentication_policy.resolved"
250
252
  TENANT_SCIM_SETUP_STARTED = :"tenant.scim.setup.started"
251
253
  TENANT_SCIM_DELETION_REQUESTED = :"tenant.scim.deletion.requested"
252
254
  TENANT_SCIM_DIRECTORY_CREATED = :"tenant.scim.directory.created"
@@ -100,7 +100,9 @@ module OpenAI
100
100
  #
101
101
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionCreated, nil]
102
102
  optional :checkpoint_permission_created,
103
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionCreated },
103
+ -> {
104
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionCreated
105
+ },
104
106
  api_name: :"checkpoint.permission.created"
105
107
 
106
108
  # @!attribute checkpoint_permission_deleted
@@ -108,7 +110,9 @@ module OpenAI
108
110
  #
109
111
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionDeleted, nil]
110
112
  optional :checkpoint_permission_deleted,
111
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionDeleted },
113
+ -> {
114
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::CheckpointPermissionDeleted
115
+ },
112
116
  api_name: :"checkpoint.permission.deleted"
113
117
 
114
118
  # @!attribute external_key_registered
@@ -180,7 +184,9 @@ module OpenAI
180
184
  #
181
185
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigActivated, nil]
182
186
  optional :ip_allowlist_config_activated,
183
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigActivated },
187
+ -> {
188
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigActivated
189
+ },
184
190
  api_name: :"ip_allowlist.config.activated"
185
191
 
186
192
  # @!attribute ip_allowlist_config_deactivated
@@ -188,7 +194,9 @@ module OpenAI
188
194
  #
189
195
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigDeactivated, nil]
190
196
  optional :ip_allowlist_config_deactivated,
191
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigDeactivated },
197
+ -> {
198
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::IPAllowlistConfigDeactivated
199
+ },
192
200
  api_name: :"ip_allowlist.config.deactivated"
193
201
 
194
202
  # @!attribute ip_allowlist_created
@@ -432,7 +440,9 @@ module OpenAI
432
440
  #
433
441
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingCreated, nil]
434
442
  optional :workload_identity_provider_mapping_created,
435
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingCreated },
443
+ -> {
444
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingCreated
445
+ },
436
446
  api_name: :"workload_identity_provider_mapping.created"
437
447
 
438
448
  # @!attribute workload_identity_provider_mapping_deleted
@@ -440,7 +450,9 @@ module OpenAI
440
450
  #
441
451
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingDeleted, nil]
442
452
  optional :workload_identity_provider_mapping_deleted,
443
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingDeleted },
453
+ -> {
454
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingDeleted
455
+ },
444
456
  api_name: :"workload_identity_provider_mapping.deleted"
445
457
 
446
458
  # @!attribute workload_identity_provider_mapping_updated
@@ -448,7 +460,9 @@ module OpenAI
448
460
  #
449
461
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingUpdated, nil]
450
462
  optional :workload_identity_provider_mapping_updated,
451
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingUpdated },
463
+ -> {
464
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderMappingUpdated
465
+ },
452
466
  api_name: :"workload_identity_provider_mapping.updated"
453
467
 
454
468
  # @!attribute workload_identity_provider_created
@@ -456,7 +470,9 @@ module OpenAI
456
470
  #
457
471
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderCreated, nil]
458
472
  optional :workload_identity_provider_created,
459
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderCreated },
473
+ -> {
474
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderCreated
475
+ },
460
476
  api_name: :"workload_identity_provider.created"
461
477
 
462
478
  # @!attribute workload_identity_provider_deleted
@@ -464,7 +480,9 @@ module OpenAI
464
480
  #
465
481
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderDeleted, nil]
466
482
  optional :workload_identity_provider_deleted,
467
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderDeleted },
483
+ -> {
484
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderDeleted
485
+ },
468
486
  api_name: :"workload_identity_provider.deleted"
469
487
 
470
488
  # @!attribute workload_identity_provider_updated
@@ -472,7 +490,9 @@ module OpenAI
472
490
  #
473
491
  # @return [OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderUpdated, nil]
474
492
  optional :workload_identity_provider_updated,
475
- -> { OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderUpdated },
493
+ -> {
494
+ OpenAI::Models::Admin::Organization::AuditLogListResponse::WorkloadIdentityProviderUpdated
495
+ },
476
496
  api_name: :"workload_identity_provider.updated"
477
497
 
478
498
  # @!method initialize(id:, effective_at:, type:, actor: nil, api_key_created: nil, api_key_deleted: nil, api_key_updated: nil, certificate_created: nil, certificate_deleted: nil, certificate_updated: nil, certificates_activated: nil, certificates_deactivated: nil, checkpoint_permission_created: nil, checkpoint_permission_deleted: nil, external_key_registered: nil, external_key_removed: nil, group_created: nil, group_deleted: nil, group_updated: nil, invite_accepted: nil, invite_deleted: nil, invite_sent: nil, ip_allowlist_config_activated: nil, ip_allowlist_config_deactivated: nil, ip_allowlist_created: nil, ip_allowlist_deleted: nil, ip_allowlist_updated: nil, login_failed: nil, login_succeeded: nil, logout_failed: nil, logout_succeeded: nil, organization_updated: nil, project: nil, project_archived: nil, project_created: nil, project_deleted: nil, project_updated: nil, rate_limit_deleted: nil, rate_limit_updated: nil, role_assignment_created: nil, role_assignment_deleted: nil, role_bound_to_resource: nil, role_created: nil, role_deleted: nil, role_unbound_from_resource: nil, role_updated: nil, scim_disabled: nil, scim_enabled: nil, service_account_created: nil, service_account_deleted: nil, service_account_updated: nil, user_added: nil, user_deleted: nil, user_updated: nil, workload_identity_provider_mapping_created: nil, workload_identity_provider_mapping_deleted: nil, workload_identity_provider_mapping_updated: nil, workload_identity_provider_created: nil, workload_identity_provider_deleted: nil, workload_identity_provider_updated: nil)
@@ -677,6 +697,7 @@ module OpenAI
677
697
  TENANT_WORKLOAD_IDENTITY_MAPPING_ARCHIVED = :"tenant.workload_identity.mapping.archived"
678
698
  TENANT_WORKLOAD_IDENTITY_BINDING_CREATED = :"tenant.workload_identity.binding.created"
679
699
  TENANT_WORKLOAD_IDENTITY_PRINCIPAL_PROVISIONED = :"tenant.workload_identity.principal.provisioned"
700
+ TENANT_WORKLOAD_IDENTITY_ACCESS_TOKEN_ISSUED = :"tenant.workload_identity.access_token.issued"
680
701
  TENANT_ADMIN_API_KEY_CREATED = :"tenant.admin_api_key.created"
681
702
  TENANT_ADMIN_API_KEY_UPDATED = :"tenant.admin_api_key.updated"
682
703
  TENANT_ADMIN_API_KEY_DELETED = :"tenant.admin_api_key.deleted"
@@ -694,7 +715,8 @@ module OpenAI
694
715
  TENANT_POLICY_DELETED = :"tenant.policy.deleted"
695
716
  TENANT_POLICY_ATTACHED = :"tenant.policy.attached"
696
717
  TENANT_POLICY_DETACHED = :"tenant.policy.detached"
697
- TENANT_PRINCIPAL_AUTHENTICATION_POLICY_RESOLVED = :"tenant.principal_authentication_policy.resolved"
718
+ TENANT_PRINCIPAL_AUTHENTICATION_POLICY_RESOLVED =
719
+ :"tenant.principal_authentication_policy.resolved"
698
720
  TENANT_SCIM_SETUP_STARTED = :"tenant.scim.setup.started"
699
721
  TENANT_SCIM_DELETION_REQUESTED = :"tenant.scim.deletion.requested"
700
722
  TENANT_SCIM_DIRECTORY_CREATED = :"tenant.scim.directory.created"
@@ -18,7 +18,11 @@ module OpenAI
18
18
  #
19
19
  # @return [Array<OpenAI::Models::Admin::Organization::Groups::RoleListResponse::AssignmentSource>, nil]
20
20
  required :assignment_sources,
21
- -> { OpenAI::Internal::Type::ArrayOf[OpenAI::Models::Admin::Organization::Groups::RoleListResponse::AssignmentSource] },
21
+ -> do
22
+ OpenAI::Internal::Type::ArrayOf[
23
+ OpenAI::Models::Admin::Organization::Groups::RoleListResponse::AssignmentSource
24
+ ]
25
+ end,
22
26
  nil?: true
23
27
 
24
28
  # @!attribute created_at
@@ -18,7 +18,11 @@ module OpenAI
18
18
  #
19
19
  # @return [Array<OpenAI::Models::Admin::Organization::Groups::RoleRetrieveResponse::AssignmentSource>, nil]
20
20
  required :assignment_sources,
21
- -> { OpenAI::Internal::Type::ArrayOf[OpenAI::Models::Admin::Organization::Groups::RoleRetrieveResponse::AssignmentSource] },
21
+ -> do
22
+ OpenAI::Internal::Type::ArrayOf[
23
+ OpenAI::Models::Admin::Organization::Groups::RoleRetrieveResponse::AssignmentSource
24
+ ]
25
+ end,
22
26
  nil?: true
23
27
 
24
28
  # @!attribute created_at
@@ -19,7 +19,12 @@ module OpenAI
19
19
  #
20
20
  # @return [Array<OpenAI::Models::Admin::Organization::Projects::Groups::RoleListResponse::AssignmentSource>, nil]
21
21
  required :assignment_sources,
22
- -> { OpenAI::Internal::Type::ArrayOf[OpenAI::Models::Admin::Organization::Projects::Groups::RoleListResponse::AssignmentSource] },
22
+ -> do
23
+ OpenAI::Internal::Type::ArrayOf[
24
+ OpenAI::Models::Admin::Organization::Projects::Groups::RoleListResponse::
25
+ AssignmentSource
26
+ ]
27
+ end,
23
28
  nil?: true
24
29
 
25
30
  # @!attribute created_at