openai 0.78.0 → 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 (175) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -0
  3. data/README.md +241 -8
  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 +29 -6
  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 +99 -7
  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 +42 -18
  24. data/lib/openai/internal/stream.rb +2 -2
  25. data/lib/openai/internal/transport/base_client.rb +137 -37
  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 +39 -7
  30. data/lib/openai/internal/type/hash_of.rb +3 -3
  31. data/lib/openai/internal/util.rb +52 -27
  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 +20 -6
  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 +111 -107
  97. data/rbi/openai/auth.rbi +4 -4
  98. data/rbi/openai/client.rbi +13 -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 +62 -2
  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 +6 -1
  105. data/rbi/openai/internal/transport/base_client.rbi +61 -7
  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 +15 -4
  109. data/rbi/openai/internal/util.rbi +26 -2
  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 +2 -2
  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 +6 -2
  151. data/sig/openai/errors.rbs +5 -0
  152. data/sig/openai/http_client.rbs +37 -2
  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 +3 -1
  156. data/sig/openai/internal/transport/base_client.rbs +33 -5
  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 +8 -2
  160. data/sig/openai/internal/util.rbs +12 -0
  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 +2 -2
  174. data/sig/openai/providers.rbs +6 -0
  175. metadata +24 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf3def8aaf6807cfdd1d5df8ed41e2eaf6513c703e9f8baa77db8c145637147a
4
- data.tar.gz: 49a15beeb6bda9ba47e71cff822aa4eb0778c400b3a891ae15b2b7ade46f28ad
3
+ metadata.gz: c91ec0ec5334f72006f30c1c9287f4175038c146c2ae5361447e99159dd4940e
4
+ data.tar.gz: 9f34b2932f7aa72d19b1e313f1fc37941fd85aa00232a395362a738619e6d8c2
5
5
  SHA512:
6
- metadata.gz: 7335e2cf29373c855d5f5866bb41ad0317ee0ba1df4ade67a9bfbddce0cd0befa3fb3910baa852bb2e95c8298b86a7c84de9a8cfe2c6324709ebf1ab47b4c17b
7
- data.tar.gz: e596b1723939ef042457f1a9b7275cbb6f4d26fb6fe9f3a31bdbdc47d398f963da59b82217a4f626463a25596c6e0702193b95f4c3b2160c94a5340e7ef5971a
6
+ metadata.gz: e90ca693f7e19f02b668b5e35facaead8a83da5dd7cd9b14a527e613572241f3e5086b5e8d7f29bff089e1a6ce02ac5657c4181feb02c4374f8368b68d7325d6
7
+ data.tar.gz: 2ac6392091a4b4a46b07272a29e16fac51a7dca2f36d6bdf2be356d34e3424d2e49c0a922d72a9edf4badafaf6b2b04682d37e4e66f4e5dc197958a4f7191c58
data/CHANGELOG.md CHANGED
@@ -1,5 +1,85 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.79.0](https://github.com/openai/openai-ruby/compare/v0.78.0...v0.79.0) (2026-08-14)
4
+
5
+
6
+ ### Features
7
+
8
+ * add HTTP response observability ([#365](https://github.com/openai/openai-ruby/issues/365)) ([48d36b7](https://github.com/openai/openai-ruby/commit/48d36b70883a446a8062dca50fbc2d419fbe1fb9))
9
+ * add Tapioca typing for structured outputs ([#364](https://github.com/openai/openai-ruby/issues/364)) ([738e2b4](https://github.com/openai/openai-ruby/commit/738e2b4de4f991e594f9d319c4d17f0955cd8edd))
10
+ * **api:** Add new model identifiers and remove audit log source ([e0a4bc5](https://github.com/openai/openai-ruby/commit/e0a4bc56d5280c45a12e44adc49b6c34e182b33f))
11
+ * **api:** add WebSocket stream IDs ([#387](https://github.com/openai/openai-ruby/issues/387)) ([5880287](https://github.com/openai/openai-ruby/commit/588028770b493f2ad55b1b9acfe6ad3164c1cddc))
12
+ * **api:** add workload identity access token issued event ([#372](https://github.com/openai/openai-ruby/issues/372)) ([9199779](https://github.com/openai/openai-ruby/commit/919977919667da8b0764a7134d646e9cac24e709))
13
+ * **api:** deprecate Sora video APIs ([#386](https://github.com/openai/openai-ruby/issues/386)) ([0664456](https://github.com/openai/openai-ruby/commit/0664456735e3eccc8dd15041a45528f59df3787d))
14
+ * **client:** add default headers ([#369](https://github.com/openai/openai-ruby/issues/369)) ([d516874](https://github.com/openai/openai-ruby/commit/d516874ebca3ac142ecbc9d829367ab97ae685f2))
15
+ * expose request IDs ([#352](https://github.com/openai/openai-ruby/issues/352)) ([c15fb7b](https://github.com/openai/openai-ruby/commit/c15fb7b5d3f15de8ffc1404dba870752175415af))
16
+ * support Azure OpenAI v1 ([#355](https://github.com/openai/openai-ruby/issues/355)) ([c1d223e](https://github.com/openai/openai-ruby/commit/c1d223e2253450cee2631f875b968baa7cbcdc2e))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * **api:** Add new model identifiers and remove audit log source ([#360](https://github.com/openai/openai-ruby/issues/360)) ([e0a4bc5](https://github.com/openai/openai-ruby/commit/e0a4bc56d5280c45a12e44adc49b6c34e182b33f))
22
+ * **api:** allow nil timeout in client signatures ([#363](https://github.com/openai/openai-ruby/issues/363)) ([e52ca61](https://github.com/openai/openai-ruby/commit/e52ca61a116f7a49e98f903c28337232608264d7))
23
+ * **api:** document file upload metadata defaults ([#361](https://github.com/openai/openai-ruby/issues/361)) ([b4bc1ea](https://github.com/openai/openai-ruby/commit/b4bc1eaf8dd8edcc10700b3d29669816176839a3))
24
+ * coerce nested BaseModel fields ([#295](https://github.com/openai/openai-ruby/issues/295)) ([e5152a9](https://github.com/openai/openai-ruby/commit/e5152a92962251ce76ceb3d89ec0b6b37fa4efdb))
25
+ * enable streaming when retrieving responses ([#413](https://github.com/openai/openai-ruby/issues/413)) ([fd85182](https://github.com/openai/openai-ruby/commit/fd8518235b16089b03733040f22e51f3fb043ed4))
26
+ * encode multipart array and nested fields ([#348](https://github.com/openai/openai-ruby/issues/348)) ([1c71a1e](https://github.com/openai/openai-ruby/commit/1c71a1eccdee36a1e8dc8ab974ad1437396bd6e6))
27
+ * honor workload identity environment defaults ([#398](https://github.com/openai/openai-ruby/issues/398)) ([f4afea1](https://github.com/openai/openai-ruby/commit/f4afea1057ebfa5447fbbef0d89f62943473efdc))
28
+ * keep required path parameters out of resource query strings ([#402](https://github.com/openai/openai-ruby/issues/402)) ([6768a7c](https://github.com/openai/openai-ruby/commit/6768a7c29664fc9edce4f4da261920da8bb1959d))
29
+ * loading after ActiveSupport 6 subclass extensions ([#346](https://github.com/openai/openai-ruby/issues/346)) ([20fbb09](https://github.com/openai/openai-ruby/commit/20fbb0942991888e618e5b5a86531e58fff65626))
30
+ * make SDK debug body logging fail closed ([#411](https://github.com/openai/openai-ruby/issues/411)) ([c4f7284](https://github.com/openai/openai-ruby/commit/c4f72846e6f2bddc280f0723f880130ad27d2b71))
31
+ * package every README-linked guide and example ([#382](https://github.com/openai/openai-ruby/issues/382)) ([ddecd0f](https://github.com/openai/openai-ruby/commit/ddecd0f75fc2a9e33e5fb6caf3f7531f7868fb90))
32
+ * preserve binary multipart stream reads ([#354](https://github.com/openai/openai-ruby/issues/354)) ([b3a1ba7](https://github.com/openai/openai-ruby/commit/b3a1ba7f3dc561ac28d2768e619e46da75177c3c))
33
+ * preserve existing BaseModel instances during coercion ([#400](https://github.com/openai/openai-ruby/issues/400)) ([fbd8560](https://github.com/openai/openai-ruby/commit/fbd8560ff986774acb4c3af849eba048232a8da3))
34
+ * preserve prefixed idempotency headers on redirects ([#404](https://github.com/openai/openai-ruby/issues/404)) ([c380e13](https://github.com/openai/openai-ruby/commit/c380e13d1f866d591add5b32cc7e414de0ac85f2))
35
+ * preserve stream identity with HTTP logging ([#384](https://github.com/openai/openai-ruby/issues/384)) ([640a1fe](https://github.com/openai/openai-ruby/commit/640a1fed33e57194cf4241001d171b75bc3b7638))
36
+ * prevent symbol-keyed headers from bypassing security filters ([#383](https://github.com/openai/openai-ruby/issues/383)) ([b8165af](https://github.com/openai/openai-ruby/commit/b8165afa3065ee01e1440bc7e5339a9c5a7d7123))
37
+ * redact sensitive query and form logging ([#389](https://github.com/openai/openai-ruby/issues/389)) ([7aa54e4](https://github.com/openai/openai-ruby/commit/7aa54e43aba381c33639a8f697348d0620ced5d0))
38
+ * reject invalid webhook signing secrets ([#403](https://github.com/openai/openai-ruby/issues/403)) ([ad12458](https://github.com/openai/openai-ruby/commit/ad1245832fd18c7830becc2375c9fa7deadca88f))
39
+ * remove unsound structured-output Tapioca compiler ([#405](https://github.com/openai/openai-ruby/issues/405)) ([826769a](https://github.com/openai/openai-ruby/commit/826769a5169eb659042fbfcb9259ad61f04d20a5))
40
+ * restore RuboCop coverage for RBI files ([#388](https://github.com/openai/openai-ruby/issues/388)) ([d2d4b5d](https://github.com/openai/openai-ruby/commit/d2d4b5d1308e21703724b2f2561da2d328be5c46))
41
+ * return values from interruptible enumerator ([#350](https://github.com/openai/openai-ruby/issues/350)) ([327dad7](https://github.com/openai/openai-ruby/commit/327dad76d434b8ea56401efb1312e9b499cc8e71))
42
+ * strip credential headers on cross-origin redirects ([#391](https://github.com/openai/openai-ruby/issues/391)) ([f50f08c](https://github.com/openai/openai-ruby/commit/f50f08c15f373e956c0013d519c6d69c2484e562))
43
+ * tighten JSON, JSONL, and SSE content type matching ([#277](https://github.com/openai/openai-ruby/issues/277)) ([66359a0](https://github.com/openai/openai-ruby/commit/66359a09076711315bed0c8aceea8db89bc4bd42))
44
+ * use API field names in structured output schemas ([#390](https://github.com/openai/openai-ruby/issues/390)) ([d1e3cf3](https://github.com/openai/openai-ruby/commit/d1e3cf3cd2793d18e98394cd5e66da766c686557))
45
+ * validate and bound retry delays ([#392](https://github.com/openai/openai-ruby/issues/392)) ([fff94e7](https://github.com/openai/openai-ruby/commit/fff94e789a9d750913306fe3c52973bd3e730916))
46
+ * **webhooks:** support Rack and case-insensitive HTTP headers ([#401](https://github.com/openai/openai-ruby/issues/401)) ([37de980](https://github.com/openai/openai-ruby/commit/37de98099af70d8e97f50f8dc02ce5166c081d38))
47
+
48
+
49
+ ### Reverts
50
+
51
+ * nested BaseModel coercion ([#295](https://github.com/openai/openai-ruby/issues/295)) ([#375](https://github.com/openai/openai-ruby/issues/375)) ([65fa76e](https://github.com/openai/openai-ruby/commit/65fa76e57881804908bc4d1753ee7d60cff1f875))
52
+
53
+
54
+ ### Chores
55
+
56
+ * Cover Ruby files at the SDK root ([#362](https://github.com/openai/openai-ruby/issues/362)) ([d11f25b](https://github.com/openai/openai-ruby/commit/d11f25b28044e618849cd430c63946a306ede32c))
57
+ * enforce boolean symbol lint ([#395](https://github.com/openai/openai-ruby/issues/395)) ([fafdf2e](https://github.com/openai/openai-ruby/commit/fafdf2e86e2736b79212189dee07aa83ba912945))
58
+ * enforce deprecated constant lint ([#379](https://github.com/openai/openai-ruby/issues/379)) ([0def912](https://github.com/openai/openai-ruby/commit/0def9124cadee946879f2f66a5018ee986972509))
59
+ * enforce duplicate match pattern lint ([#380](https://github.com/openai/openai-ruby/issues/380)) ([7a8f2fb](https://github.com/openai/openai-ruby/commit/7a8f2fb4ac9d1176bb5e8eac88cccc9766e3fd6c))
60
+ * enforce empty else lint ([#396](https://github.com/openai/openai-ruby/issues/396)) ([1e073c1](https://github.com/openai/openai-ruby/commit/1e073c14a657e93ea0394fba29f9a059b3bf9b09))
61
+ * enforce line length lint ([#406](https://github.com/openai/openai-ruby/issues/406)) ([4592061](https://github.com/openai/openai-ruby/commit/459206126267209930640d25eae0fada7177bff0))
62
+ * enforce line length on base models ([#416](https://github.com/openai/openai-ruby/issues/416)) ([aef1e33](https://github.com/openai/openai-ruby/commit/aef1e333cae9c72379b3230a35d0274917999f82))
63
+ * enforce line length on requires ([#415](https://github.com/openai/openai-ruby/issues/415)) ([c24e045](https://github.com/openai/openai-ruby/commit/c24e045bc1a194a0935a36ed48a17841f5309718))
64
+ * enforce missing RuboCop enable directives ([#368](https://github.com/openai/openai-ruby/issues/368)) ([50046bf](https://github.com/openai/openai-ruby/commit/50046bf02497984d46377b9e9f1f6cc1370ee776))
65
+ * enforce missing super lint ([#393](https://github.com/openai/openai-ruby/issues/393)) ([2a42bd0](https://github.com/openai/openai-ruby/commit/2a42bd0531f0c16e2d61d55b2dee80e541111812))
66
+ * enforce nonempty pattern branches ([#409](https://github.com/openai/openai-ruby/issues/409)) ([9d22d5c](https://github.com/openai/openai-ruby/commit/9d22d5c63a9f68f1839de6f6b20f92d767eec80b))
67
+ * enforce redundant directive lint ([#366](https://github.com/openai/openai-ruby/issues/366)) ([8448a4c](https://github.com/openai/openai-ruby/commit/8448a4cb1551fb47a28205556e0bce320eb82c99))
68
+ * enforce redundant exception lint ([#397](https://github.com/openai/openai-ruby/issues/397)) ([cbda8bc](https://github.com/openai/openai-ruby/commit/cbda8bc0e6e3b2b8d0b96dfe3021d4557b713400))
69
+ * enforce symbol conversion lint ([#381](https://github.com/openai/openai-ruby/issues/381)) ([0531498](https://github.com/openai/openai-ruby/commit/0531498c5498804408381dcef3ddec1228196ecd))
70
+ * enforce useless assignment lint ([#394](https://github.com/openai/openai-ruby/issues/394)) ([9688836](https://github.com/openai/openai-ruby/commit/96888367ae757d119c90f2d9a81f4000d21745c2))
71
+ * guard RuboCop suppression directives ([#408](https://github.com/openai/openai-ruby/issues/408)) ([5b6e0dc](https://github.com/openai/openai-ruby/commit/5b6e0dcc325f0f5a6a0fc6df8d9aea4999c90cf5))
72
+ * lint Ruby files repository-wide ([#377](https://github.com/openai/openai-ruby/issues/377)) ([8ca8426](https://github.com/openai/openai-ruby/commit/8ca842693f441f19b18fda7190de4d68b2f7f9d9))
73
+ * remove Stainless attribution and infrastructure ([#371](https://github.com/openai/openai-ruby/issues/371)) ([33d2c86](https://github.com/openai/openai-ruby/commit/33d2c864e1f3c2a683f1b826838b2bfd2e380a26))
74
+ * require MFA for gem releases ([#378](https://github.com/openai/openai-ruby/issues/378)) ([71798ec](https://github.com/openai/openai-ruby/commit/71798ecb840a3feb8574efae3dd94af577717d64))
75
+
76
+
77
+ ### Documentation
78
+
79
+ * **api:** describe response stream event unions ([#412](https://github.com/openai/openai-ruby/issues/412)) ([87d18ef](https://github.com/openai/openai-ruby/commit/87d18efc19445d0080344f6ebd5bc95dc8aed5cb))
80
+ * clarify file upload metadata ([#358](https://github.com/openai/openai-ruby/issues/358)) ([698ac65](https://github.com/openai/openai-ruby/commit/698ac65d948f07edf30255c621abaac6437f0bcf)), closes [#243](https://github.com/openai/openai-ruby/issues/243)
81
+ * document fiber scheduler concurrency ([#357](https://github.com/openai/openai-ruby/issues/357)) ([25a7bbc](https://github.com/openai/openai-ruby/commit/25a7bbcdc93c3331dc199e4cfe1da6037ef43bb2))
82
+
3
83
  ## [0.78.0](https://github.com/openai/openai-ruby/compare/v0.77.1...v0.78.0) (2026-08-07)
4
84
 
5
85
 
data/README.md CHANGED
@@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application
15
15
  <!-- x-release-please-start-version -->
16
16
 
17
17
  ```ruby
18
- gem "openai", "~> 0.78.0"
18
+ gem "openai", "~> 0.79.0"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -82,6 +82,8 @@ end
82
82
 
83
83
  Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.3/o/pathname) instance, [`StringIO`](https://rubyapi.org/3.3/o/stringio), or more.
84
84
 
85
+ Raw `String` and `StringIO` values, and `IO` objects without a path, do not carry format-identifying metadata. The SDK sends them using the fallback filename `upload`; raw `String` values default to `text/plain`, while `StringIO` and pathless `IO` values default to `application/octet-stream`. For format-sensitive endpoints, such as audio transcriptions, wrap each value in `OpenAI::FilePart` and provide an extension-bearing filename and content type.
86
+
85
87
  ```ruby
86
88
  require "pathname"
87
89
 
@@ -93,12 +95,25 @@ file_object = openai.files.create(file: File.read("input.jsonl"), purpose: "fine
93
95
 
94
96
  puts(file_object.id)
95
97
 
96
- # Or, to control the filename and/or content type:
97
- image = OpenAI::FilePart.new(Pathname('dog.jpg'), content_type: 'image/jpeg')
98
+ # For format-sensitive uploads, provide the filename and content type:
99
+ audio_data = StringIO.new(File.binread("audio.wav"))
100
+ audio = OpenAI::FilePart.new(
101
+ audio_data,
102
+ filename: "audio.wav",
103
+ content_type: "audio/wav"
104
+ )
105
+ transcription = openai.audio.transcriptions.create(
106
+ model: "gpt-4o-transcribe",
107
+ file: audio
108
+ )
109
+ puts(transcription.text)
110
+
111
+ # FilePart also accepts a Pathname:
112
+ image = OpenAI::FilePart.new(Pathname("dog.jpg"), content_type: "image/jpeg")
98
113
  edited = openai.images.edit(
99
114
  prompt: "make this image look like a painting",
100
115
  model: "gpt-image-1",
101
- size: '1024x1024',
116
+ size: "1024x1024",
102
117
  image: image
103
118
  )
104
119
 
@@ -205,6 +220,49 @@ rotation, build and atomically swap in new `OpenAI::NetHTTPClient` and
205
220
  in-flight work finishes. See the complete [custom HTTP client mTLS
206
221
  example](examples/mtls_custom_http_client.rb).
207
222
 
223
+ ## Microsoft Azure OpenAI
224
+
225
+ Use the standard client with the Azure provider to call model deployments through
226
+ the Azure OpenAI v1 API. The provider accepts an Azure resource endpoint and
227
+ adds `/openai/v1` when needed:
228
+
229
+ ```ruby
230
+ require "openai"
231
+
232
+ client = OpenAI::Client.new(
233
+ provider: OpenAI::Providers.azure(
234
+ endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
235
+ api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
236
+ )
237
+ )
238
+
239
+ response = client.responses.create(
240
+ model: ENV.fetch("AZURE_OPENAI_DEPLOYMENT"),
241
+ input: "Say hello!"
242
+ )
243
+
244
+ puts(response.output_text)
245
+ ```
246
+
247
+ Omit `endpoint` and `api_key` to use `AZURE_OPENAI_ENDPOINT` and
248
+ `AZURE_OPENAI_API_KEY`. For Microsoft Entra authentication, pass a callable
249
+ that returns a current bearer token. The provider invokes it before every
250
+ request attempt, including retries:
251
+
252
+ ```ruby
253
+ client = OpenAI::Client.new(
254
+ provider: OpenAI::Providers.azure(
255
+ endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
256
+ token_provider: -> { fetch_azure_openai_token }
257
+ )
258
+ )
259
+ ```
260
+
261
+ This integration targets the Azure OpenAI v1 API. It does not add dated
262
+ `api-version` query parameters or rewrite requests to legacy
263
+ `/deployments/{deployment}` paths. See [azure.md](azure.md) for configuration,
264
+ authentication precedence, and endpoint security details.
265
+
208
266
  ## Amazon Bedrock
209
267
 
210
268
  Use the standard client with the Bedrock provider to call OpenAI models through Amazon Bedrock's OpenAI-compatible API. Add `aws-sdk-core` to your application for AWS credential discovery and SigV4 signing:
@@ -365,8 +423,11 @@ Note that the `body` parameter must be the raw JSON string sent from the server
365
423
  require 'sinatra'
366
424
  require 'openai'
367
425
 
368
- # Set up the client with webhook secret from environment variable
369
- client = OpenAI::Client.new(webhook_secret: ENV['OPENAI_WEBHOOK_SECRET'])
426
+ # Set up the client with API credentials and the webhook secret
427
+ client = OpenAI::Client.new(
428
+ api_key: ENV.fetch('OPENAI_API_KEY'),
429
+ webhook_secret: ENV.fetch('OPENAI_WEBHOOK_SECRET')
430
+ )
370
431
 
371
432
  post '/webhook' do
372
433
  request_body = request.body.read
@@ -404,8 +465,11 @@ require 'sinatra'
404
465
  require 'json'
405
466
  require 'openai'
406
467
 
407
- # Set up the client with webhook secret from environment variable
408
- client = OpenAI::Client.new(webhook_secret: ENV['OPENAI_WEBHOOK_SECRET'])
468
+ # Set up the client with API credentials and the webhook secret
469
+ client = OpenAI::Client.new(
470
+ api_key: ENV.fetch('OPENAI_API_KEY'),
471
+ webhook_secret: ENV.fetch('OPENAI_WEBHOOK_SECRET')
472
+ )
409
473
 
410
474
  post '/webhook' do
411
475
  request_body = request.body.read
@@ -565,6 +629,108 @@ Error codes are as follows:
565
629
  | Timeout | `APITimeoutError` |
566
630
  | Network error | `APIConnectionError` |
567
631
 
632
+ ### Request logging
633
+
634
+ Request logging is disabled by default. Enable it with a standard Ruby logger
635
+ when creating the client:
636
+
637
+ ```ruby
638
+ client = OpenAI::Client.new(
639
+ api_key: ENV.fetch("OPENAI_API_KEY"),
640
+ logger: Rails.logger,
641
+ log_level: :info
642
+ )
643
+ ```
644
+
645
+ The logger can be any object that responds to `debug`, `info`, `warn`, and
646
+ `error`; the SDK does not depend on Rails. Supplying a logger enables `:info`
647
+ logging by default. When logging is enabled without a custom logger, the SDK
648
+ uses a standard-library `Logger` that writes to stderr. Use `log_level: :off`
649
+ when you only need retry notifications.
650
+
651
+ You can instead set `OPENAI_LOG=info` or `OPENAI_LOG=debug`. An explicit
652
+ `log_level:` takes precedence over the environment variable.
653
+
654
+ For example, to use the stderr logger for one process:
655
+
656
+ ```sh
657
+ OPENAI_LOG=info bundle exec ruby app.rb
658
+ ```
659
+
660
+ A completion message includes the logical request and retry context:
661
+
662
+ ```text
663
+ [openai] request complete log_id=log_a1b2c3d4e5f6 method=POST path=/v1/responses status=200 request_id=req_123 attempts=1 duration_ms=42.7
664
+ ```
665
+
666
+ | Level | Behavior |
667
+ | --- | --- |
668
+ | `:off` | No SDK request logs (default) |
669
+ | `:error` | Terminal request failures after retries are exhausted |
670
+ | `:warn` | Error events plus retry reason and delay |
671
+ | `:info` | Safe request completion summaries |
672
+ | `:debug` | Per-attempt headers and bounded structural body diagnostics |
673
+
674
+ Info, warning, and error logs include operational fields such as the HTTP
675
+ method, sanitized path, status, request ID, duration, and attempt count. They
676
+ never include headers or bodies. Debug logs redact credential-bearing headers
677
+ and query parameters, including authorization, API-key, cookie, token,
678
+ credential, and signature values.
679
+
680
+ Debug body diagnostics never include customer-controlled object keys, string
681
+ values, prompts, model responses, tool arguments, form fields, or signed URLs.
682
+ JSON bodies report only their byte size, top-level type, and object-field or
683
+ array-item count; form bodies report only their byte size and field count. The
684
+ built-in logger omits uploaded file contents, multipart bodies, binary bodies,
685
+ server-sent event contents, unsupported text bodies, oversized bodies, and
686
+ incomplete bodies. Response bodies are observed only as the application consumes
687
+ them and are never read eagerly for logging.
688
+
689
+ SDK log messages are intended for human diagnostics. Their text format is not
690
+ a stable structured-event API and may change between releases. Exceptions from
691
+ a supplied logger are isolated and never replace an API result or API error.
692
+
693
+ ### Response metadata and request IDs
694
+
695
+ OpenAI recommends logging request IDs in production so requests can be traced
696
+ during troubleshooting. Top-level models and pages returned by the client expose
697
+ immutable HTTP response metadata through `last_response`:
698
+
699
+ ```ruby
700
+ response = openai.responses.create(model: "gpt-5.2", input: "Say 'this is a test'.")
701
+ puts(response.last_response.status) # 200
702
+ puts(response.last_response.headers["x-request-id"]) # req_123
703
+ puts(response.last_response.request_id) # req_123
704
+ puts(response._request_id) # req_123
705
+ ```
706
+
707
+ Header names and values are normalized to strings, header names are lowercase,
708
+ and the metadata and header map are frozen. Streams expose the metadata for the
709
+ HTTP response that opened the stream. Higher-level streaming helpers expose the
710
+ same metadata as their underlying stream; models assembled from stream events
711
+ do not.
712
+
713
+ `last_response` and `_request_id` are only populated on top-level typed models
714
+ and pages returned by the client. They are `nil` on constructed or nested models
715
+ and are not included in `to_h`, JSON, or YAML output. Endpoints returning raw
716
+ primitives, binary data, or `nil` do not expose this metadata. Unlike other
717
+ properties that begin with an underscore, `_request_id` is public.
718
+
719
+ For failed HTTP requests, catch `OpenAI::Errors::APIStatusError` and use
720
+ `request_id`:
721
+
722
+ ```ruby
723
+ begin
724
+ openai.responses.create(model: "gpt-5.2", input: "Say 'this is a test'.")
725
+ rescue OpenAI::Errors::APIStatusError => e
726
+ puts(e.request_id) # req_123
727
+ raise
728
+ end
729
+ ```
730
+
731
+ See the [official OpenAI request debugging documentation](https://developers.openai.com/api/reference/overview#debugging-requests)
732
+ for more information.
733
+
568
734
  ### Retries
569
735
 
570
736
  Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
@@ -587,6 +753,27 @@ openai.chat.completions.create(
587
753
  )
588
754
  ```
589
755
 
756
+ To observe retries as they happen, supply an `on_retry` callback when creating
757
+ the client. The callback runs immediately before the retry delay and receives
758
+ an immutable `OpenAI::RetryEvent`:
759
+
760
+ ```ruby
761
+ openai = OpenAI::Client.new(
762
+ log_level: :off,
763
+ on_retry: lambda do |event|
764
+ Rails.logger.warn(
765
+ "OpenAI retry #{event.attempt}/#{event.max_attempts} " \
766
+ "status=#{event.status.inspect} request_id=#{event.request_id.inspect}"
767
+ )
768
+ end
769
+ )
770
+ ```
771
+
772
+ For response-triggered retries, `event.response` contains the same immutable
773
+ status, headers, and request ID shape as `last_response`. For connection errors,
774
+ `event.error` is populated instead. Exceptions raised by the callback are
775
+ isolated and do not replace the API result or error.
776
+
590
777
  ### Timeouts
591
778
 
592
779
  By default, requests will time out after 600 seconds. You can use the timeout option to configure or disable this:
@@ -611,6 +798,20 @@ Note that requests that time out are retried by default.
611
798
 
612
799
  ## Advanced concepts
613
800
 
801
+ ### Default request headers
802
+
803
+ Use `default_headers` to send the same custom headers with every request made by a client:
804
+
805
+ ```ruby
806
+ finance = OpenAI::Client.new(
807
+ default_headers: {"x-cost-center" => "finance"}
808
+ )
809
+ ```
810
+
811
+ Explicit `default_headers` override values from `OPENAI_CUSTOM_HEADERS`. For a single request,
812
+ `request_options[:extra_headers]` can override a client default or remove it by assigning `nil`.
813
+ Authentication and endpoint-specific headers also take precedence over client defaults.
814
+
614
815
  ### BaseModel
615
816
 
616
817
  All parameter and response objects inherit from `OpenAI::Internal::Type::BaseModel`, which provides several conveniences, including:
@@ -668,6 +869,38 @@ response = client.request(
668
869
 
669
870
  `OpenAI::Client` instances using the default `OpenAI::NetHTTPClient` are threadsafe, but are only fork-safe when there are no in-flight HTTP requests. Injected HTTP clients are responsible for documenting and enforcing their own concurrency guarantees.
670
871
 
872
+ #### Asynchronous requests with a fiber scheduler
873
+
874
+ The default HTTP client also cooperates with Ruby's fiber scheduler interface
875
+ (`Fiber.scheduler`). When a request runs inside a non-blocking fiber managed by
876
+ an active scheduler, network operations, streaming reads, retry delays, and
877
+ waits for a pooled connection yield to other fibers instead of blocking the
878
+ thread. Resource methods keep their normal return types; schedule each complete
879
+ request or stream operation as a task using the scheduler implementation your
880
+ application already uses.
881
+
882
+ For example, with the [`async`](https://github.com/socketry/async) gem:
883
+
884
+ ```ruby
885
+ require "async"
886
+
887
+ prompts = ["Summarize the incident report.", "Draft the follow-up actions."]
888
+
889
+ responses = Async do |task|
890
+ prompts.map do |prompt|
891
+ task.async do
892
+ openai.responses.create(model: "gpt-5.2", input: prompt)
893
+ end
894
+ end.map(&:wait)
895
+ end.wait
896
+ ```
897
+
898
+ Outside a non-blocking fiber managed by an active scheduler, calls block the
899
+ current thread as usual. The SDK does not install a scheduler or depend on a
900
+ particular scheduler gem.
901
+
902
+ #### Connection pooling
903
+
671
904
  By default, each `OpenAI::Client` creates its own HTTP connection pool with a size of at least 99 connections. As such, we recommend instantiating the client once per application in most settings. An injected HTTP client may instead share its pool across multiple SDK clients; the caller owns that HTTP client's lifecycle.
672
905
 
673
906
  When all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.
data/SECURITY.md CHANGED
@@ -2,28 +2,12 @@
2
2
 
3
3
  ## Reporting Security Issues
4
4
 
5
- This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
6
-
7
- To report a security issue, please contact the Stainless team at security@stainless.com.
5
+ Please report potential security vulnerabilities through OpenAI's
6
+ [coordinated vulnerability disclosure process](https://openai.com/policies/coordinated-vulnerability-disclosure-policy).
7
+ For questions about that process, contact disclosure@openai.com.
8
8
 
9
9
  ## Responsible Disclosure
10
10
 
11
- We appreciate the efforts of security researchers and individuals who help us maintain the security of
12
- SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible
13
- disclosure practices by allowing us a reasonable amount of time to investigate and address the issue
14
- before making any information public.
15
-
16
- ## Reporting Non-SDK Related Security Issues
17
-
18
- If you encounter security issues that are not directly related to SDKs but pertain to the services
19
- or products provided by OpenAI, please follow the respective company's security reporting guidelines.
20
-
21
- ### OpenAI Terms and Policies
22
-
23
- Our Security Policy can be found at [Security Policy URL](https://openai.com/policies/coordinated-vulnerability-disclosure-policy).
24
-
25
- Please contact disclosure@openai.com for any questions or concerns regarding the security of our services.
26
-
27
- ---
28
-
29
- Thank you for helping us keep the SDKs and systems they interact with secure.
11
+ Please allow OpenAI a reasonable amount of time to investigate and address the
12
+ issue before making information public. Thank you for helping us keep this SDK
13
+ and the systems it interacts with secure.
data/azure.md ADDED
@@ -0,0 +1,110 @@
1
+ # Microsoft Azure OpenAI
2
+
3
+ Configure the standard `OpenAI::Client` with the Azure provider to use the
4
+ [Azure OpenAI v1 API](https://learn.microsoft.com/azure/foundry/openai/api-version-lifecycle):
5
+
6
+ ```ruby
7
+ require "openai"
8
+
9
+ client = OpenAI::Client.new(
10
+ provider: OpenAI::Providers.azure(
11
+ endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
12
+ api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
13
+ )
14
+ )
15
+
16
+ response = client.responses.create(
17
+ model: ENV.fetch("AZURE_OPENAI_DEPLOYMENT"),
18
+ input: "Say hello!"
19
+ )
20
+
21
+ puts(response.output_text)
22
+ ```
23
+
24
+ The `model` parameter is the Azure model deployment name. The provider exposes
25
+ the normal Ruby SDK resources, request and response models, retries, pagination,
26
+ streaming helpers, and custom HTTP transport. Azure controls which resources and
27
+ features are available for a deployment; unsupported calls surface as normal API
28
+ errors.
29
+
30
+ ## Endpoint configuration
31
+
32
+ Pass the Azure resource endpoint or set `AZURE_OPENAI_ENDPOINT`:
33
+
34
+ ```ruby
35
+ provider = OpenAI::Providers.azure(
36
+ endpoint: "https://my-resource.openai.azure.com",
37
+ api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
38
+ )
39
+ ```
40
+
41
+ The provider appends `/openai/v1` when it is absent. These values therefore
42
+ configure the same base URL:
43
+
44
+ ```text
45
+ https://my-resource.openai.azure.com
46
+ https://my-resource.openai.azure.com/openai
47
+ https://my-resource.openai.azure.com/openai/v1/
48
+ ```
49
+
50
+ The endpoint must be an absolute HTTP or HTTPS URL without user information, a
51
+ query string, or a fragment. Use HTTPS outside local testing. A path prefix is
52
+ preserved for gateways and private routing, for example
53
+ `https://gateway.example.com/azure` becomes
54
+ `https://gateway.example.com/azure/openai/v1`.
55
+
56
+ ## Authentication
57
+
58
+ Configure exactly one authentication mode explicitly. If neither is explicit,
59
+ the provider uses `AZURE_OPENAI_API_KEY`.
60
+
61
+ ### Azure API key
62
+
63
+ Pass `api_key` or set `AZURE_OPENAI_API_KEY`. The provider sends it in Azure's
64
+ `api-key` header:
65
+
66
+ ```ruby
67
+ provider = OpenAI::Providers.azure(
68
+ endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
69
+ api_key: ENV.fetch("AZURE_OPENAI_API_KEY")
70
+ )
71
+ ```
72
+
73
+ Passing `api_key: nil` explicitly skips the environment fallback.
74
+
75
+ ### Microsoft Entra bearer token
76
+
77
+ Pass a callable that returns a current access token for Azure OpenAI. Credential
78
+ acquisition stays with the application, so the SDK does not require an Azure
79
+ identity package:
80
+
81
+ ```ruby
82
+ provider = OpenAI::Providers.azure(
83
+ endpoint: ENV.fetch("AZURE_OPENAI_ENDPOINT"),
84
+ token_provider: -> {
85
+ credential.get_token("https://cognitiveservices.azure.com/.default").token
86
+ }
87
+ )
88
+ ```
89
+
90
+ An explicit `token_provider` takes precedence over an ambient
91
+ `AZURE_OPENAI_API_KEY`. It is invoked immediately before every request attempt,
92
+ including API retries, so applications can refresh short-lived tokens without
93
+ rebuilding the client.
94
+
95
+ ## Security
96
+
97
+ The provider validates the request origin before attaching an API key or bearer
98
+ token. It refuses to authenticate redirects or custom requests whose origin
99
+ differs from the configured Azure endpoint. Custom `Authorization` and `api-key`
100
+ headers cannot be combined with provider-owned authentication.
101
+
102
+ Keep credentials out of source control and logs. Prefer short-lived Microsoft
103
+ Entra tokens to long-lived API keys for production workloads.
104
+
105
+ ## Dated Azure APIs
106
+
107
+ This provider targets the GA Azure OpenAI v1 API. It does not support dated API
108
+ versions such as `2025-04-01-preview`, inject `api-version` query parameters, or
109
+ rewrite generated resource paths to `/deployments/{deployment}`. Use the v1 API
110
+ for new integrations.