openai 0.78.0 → 0.80.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -0
- data/README.md +241 -8
- data/SECURITY.md +6 -22
- data/azure.md +110 -0
- data/bedrock.md +197 -0
- data/examples/mtls_custom_http_client.rb +61 -0
- data/lib/openai/auth/workload_identity.rb +13 -2
- data/lib/openai/auth/workload_identity_auth.rb +2 -1
- data/lib/openai/client.rb +29 -6
- data/lib/openai/errors.rb +11 -1
- data/lib/openai/helpers/streaming/chat_completion_stream.rb +3 -3
- data/lib/openai/helpers/streaming/response_stream.rb +5 -6
- data/lib/openai/helpers/structured_output/base_model.rb +20 -19
- data/lib/openai/helpers/structured_output/json_schema_converter.rb +12 -5
- data/lib/openai/http_client.rb +99 -7
- data/lib/openai/internal/conversation_cursor_page.rb +5 -6
- data/lib/openai/internal/cursor_page.rb +3 -3
- data/lib/openai/internal/logging.rb +419 -0
- data/lib/openai/internal/next_cursor_page.rb +5 -6
- data/lib/openai/internal/page.rb +2 -2
- data/lib/openai/internal/provider.rb +7 -1
- data/lib/openai/internal/read_io_adapter.rb +42 -18
- data/lib/openai/internal/stream.rb +2 -2
- data/lib/openai/internal/transport/base_client.rb +137 -37
- data/lib/openai/internal/type/array_of.rb +6 -4
- data/lib/openai/internal/type/base_model.rb +39 -1
- data/lib/openai/internal/type/base_page.rb +19 -2
- data/lib/openai/internal/type/base_stream.rb +39 -7
- data/lib/openai/internal/type/hash_of.rb +3 -3
- data/lib/openai/internal/util.rb +52 -27
- data/lib/openai/models/admin/organization/audit_log_list_params.rb +3 -1
- data/lib/openai/models/admin/organization/audit_log_list_response.rb +33 -11
- data/lib/openai/models/admin/organization/groups/role_list_response.rb +5 -1
- data/lib/openai/models/admin/organization/groups/role_retrieve_response.rb +5 -1
- data/lib/openai/models/admin/organization/projects/groups/role_list_response.rb +6 -1
- data/lib/openai/models/admin/organization/projects/groups/role_retrieve_response.rb +6 -1
- data/lib/openai/models/admin/organization/projects/service_account_create_response.rb +3 -1
- data/lib/openai/models/admin/organization/projects/users/role_list_response.rb +6 -1
- data/lib/openai/models/admin/organization/projects/users/role_retrieve_response.rb +6 -1
- data/lib/openai/models/admin/organization/users/role_list_response.rb +5 -1
- data/lib/openai/models/admin/organization/users/role_retrieve_response.rb +5 -1
- data/lib/openai/models/all_models.rb +5 -0
- data/lib/openai/models/audio/transcription_create_params.rb +7 -1
- data/lib/openai/models/audio/translation_create_params.rb +7 -1
- data/lib/openai/models/beta/beta_mcp_tool_call_error.rb +84 -0
- data/lib/openai/models/beta/beta_response.rb +27 -0
- data/lib/openai/models/beta/beta_response_input_item.rb +3 -3
- data/lib/openai/models/beta/beta_response_item.rb +3 -3
- data/lib/openai/models/beta/beta_response_output_item.rb +3 -3
- data/lib/openai/models/beta/beta_response_output_item_added_event.rb +5 -2
- data/lib/openai/models/beta/beta_response_output_text_annotation_added_event.rb +201 -4
- data/lib/openai/models/beta/beta_response_reasoning_item.rb +5 -0
- data/lib/openai/models/beta/beta_response_stream_event.rb +1 -1
- data/lib/openai/models/beta/beta_responses_client_event.rb +46 -3
- data/lib/openai/models/beta/beta_responses_server_event.rb +1143 -63
- data/lib/openai/models/beta/beta_web_search_tool.rb +11 -1
- data/lib/openai/models/beta/response_compact_params.rb +18 -0
- data/lib/openai/models/beta/response_create_params.rb +27 -0
- data/lib/openai/models/chat_model.rb +1 -0
- data/lib/openai/models/completion_usage.rb +26 -2
- data/lib/openai/models/containers/file_create_params.rb +4 -0
- data/lib/openai/models/content_provenance_check_create_params.rb +4 -0
- data/lib/openai/models/conversations/conversation_item.rb +3 -3
- data/lib/openai/models/file_create_params.rb +4 -0
- data/lib/openai/models/image_create_variation_params.rb +4 -0
- data/lib/openai/models/image_edit_params.rb +8 -0
- data/lib/openai/models/model.rb +9 -1
- data/lib/openai/models/responses/mcp_tool_call_error.rb +82 -0
- data/lib/openai/models/responses/response.rb +9 -0
- data/lib/openai/models/responses/response_compact_params.rb +18 -0
- data/lib/openai/models/responses/response_create_params.rb +9 -0
- data/lib/openai/models/responses/response_input_item.rb +3 -3
- data/lib/openai/models/responses/response_item.rb +3 -3
- data/lib/openai/models/responses/response_output_item.rb +3 -3
- data/lib/openai/models/responses/response_output_item_added_event.rb +5 -2
- data/lib/openai/models/responses/response_output_text_annotation_added_event.rb +201 -4
- data/lib/openai/models/responses/response_reasoning_item.rb +5 -0
- data/lib/openai/models/responses/response_stream_event.rb +1 -1
- data/lib/openai/models/responses/responses_client_event.rb +22 -1
- data/lib/openai/models/responses/responses_server_event.rb +1107 -56
- data/lib/openai/models/responses/web_search_tool.rb +11 -1
- data/lib/openai/models/responses_model.rb +5 -0
- data/lib/openai/models/skill_create_params.rb +4 -0
- data/lib/openai/models/skills/version_create_params.rb +4 -0
- data/lib/openai/models/uploads/part_create_params.rb +4 -0
- data/lib/openai/models/vector_store_search_response.rb +3 -1
- data/lib/openai/models/video_create_character_params.rb +4 -0
- data/lib/openai/models/video_create_params.rb +4 -0
- data/lib/openai/models/video_edit_params.rb +4 -0
- data/lib/openai/models/video_extend_params.rb +4 -0
- data/lib/openai/models.rb +9 -1
- data/lib/openai/net_http_client.rb +20 -6
- data/lib/openai/providers/azure.rb +216 -0
- data/lib/openai/providers/bedrock.rb +130 -17
- data/lib/openai/resources/admin/organization/projects/groups/roles.rb +1 -1
- data/lib/openai/resources/admin/organization/projects/groups.rb +1 -1
- data/lib/openai/resources/admin/organization/projects/users/roles.rb +1 -1
- data/lib/openai/resources/admin/organization/projects.rb +4 -2
- data/lib/openai/resources/audio/transcriptions.rb +8 -0
- data/lib/openai/resources/audio/translations.rb +4 -0
- data/lib/openai/resources/beta/responses.rb +1 -1
- data/lib/openai/resources/beta/threads/runs/steps.rb +2 -2
- data/lib/openai/resources/containers/files.rb +4 -0
- data/lib/openai/resources/content_provenance_checks.rb +4 -0
- data/lib/openai/resources/conversations/items.rb +1 -1
- data/lib/openai/resources/evals/runs/output_items.rb +1 -1
- data/lib/openai/resources/files.rb +5 -1
- data/lib/openai/resources/images.rb +12 -0
- data/lib/openai/resources/responses.rb +3 -2
- data/lib/openai/resources/skills/versions.rb +4 -0
- data/lib/openai/resources/skills.rb +4 -0
- data/lib/openai/resources/uploads/parts.rb +4 -0
- data/lib/openai/resources/vector_stores/file_batches.rb +1 -1
- data/lib/openai/resources/videos.rb +38 -0
- data/lib/openai/resources/webhooks.rb +18 -6
- data/lib/openai/version.rb +1 -1
- data/lib/openai.rb +111 -105
- data/rbi/openai/auth.rbi +4 -4
- data/rbi/openai/client.rbi +13 -3
- data/rbi/openai/errors.rbi +7 -0
- data/rbi/openai/helpers/streaming/events.rbi +12 -0
- data/rbi/openai/http_client.rbi +62 -2
- data/rbi/openai/internal/logging.rbi +192 -0
- data/rbi/openai/internal/provider.rbi +3 -0
- data/rbi/openai/internal/read_io_adapter.rbi +6 -1
- data/rbi/openai/internal/transport/base_client.rbi +61 -7
- data/rbi/openai/internal/type/base_model.rbi +24 -1
- data/rbi/openai/internal/type/base_page.rbi +13 -2
- data/rbi/openai/internal/type/base_stream.rbi +15 -4
- data/rbi/openai/internal/util.rbi +26 -2
- data/rbi/openai/models/admin/organization/audit_log_list_params.rbi +5 -0
- data/rbi/openai/models/admin/organization/audit_log_list_response.rbi +5 -0
- data/rbi/openai/models/all_models.rbi +25 -0
- data/rbi/openai/models/audio/transcription_create_params.rbi +14 -2
- data/rbi/openai/models/audio/translation_create_params.rbi +14 -2
- data/rbi/openai/models/beta/beta_mcp_tool_call_error.rbi +122 -0
- data/rbi/openai/models/beta/beta_response.rbi +47 -0
- data/rbi/openai/models/beta/beta_response_input_item.rbi +27 -3
- data/rbi/openai/models/beta/beta_response_item.rbi +27 -3
- data/rbi/openai/models/beta/beta_response_output_item.rbi +27 -3
- data/rbi/openai/models/beta/beta_response_output_item_added_event.rbi +8 -2
- data/rbi/openai/models/beta/beta_response_output_text_annotation_added_event.rbi +297 -5
- data/rbi/openai/models/beta/beta_response_reasoning_item.rbi +10 -0
- data/rbi/openai/models/beta/beta_response_stream_event.rbi +1 -1
- data/rbi/openai/models/beta/beta_responses_client_event.rbi +69 -1
- data/rbi/openai/models/beta/beta_responses_server_event.rbi +3945 -54
- data/rbi/openai/models/beta/beta_web_search_tool.rbi +15 -0
- data/rbi/openai/models/beta/response_compact_params.rbi +30 -0
- data/rbi/openai/models/beta/response_create_params.rbi +47 -0
- data/rbi/openai/models/chat_model.rbi +2 -0
- data/rbi/openai/models/completion_usage.rbi +39 -6
- data/rbi/openai/models/containers/file_create_params.rbi +8 -0
- data/rbi/openai/models/content_provenance_check_create_params.rbi +8 -0
- data/rbi/openai/models/conversations/conversation_item.rbi +12 -3
- data/rbi/openai/models/file_create_params.rbi +8 -0
- data/rbi/openai/models/image_create_variation_params.rbi +8 -0
- data/rbi/openai/models/image_edit_params.rbi +16 -0
- data/rbi/openai/models/model.rbi +14 -1
- data/rbi/openai/models/responses/mcp_tool_call_error.rbi +120 -0
- data/rbi/openai/models/responses/response.rbi +17 -0
- data/rbi/openai/models/responses/response_compact_params.rbi +30 -0
- data/rbi/openai/models/responses/response_create_params.rbi +17 -0
- data/rbi/openai/models/responses/response_input_item.rbi +27 -3
- data/rbi/openai/models/responses/response_item.rbi +27 -3
- data/rbi/openai/models/responses/response_output_item.rbi +27 -3
- data/rbi/openai/models/responses/response_output_item_added_event.rbi +8 -2
- data/rbi/openai/models/responses/response_output_text_annotation_added_event.rbi +297 -5
- data/rbi/openai/models/responses/response_reasoning_item.rbi +10 -0
- data/rbi/openai/models/responses/response_stream_event.rbi +1 -1
- data/rbi/openai/models/responses/responses_client_event.rbi +36 -0
- data/rbi/openai/models/responses/responses_server_event.rbi +3385 -53
- data/rbi/openai/models/responses/web_search_tool.rbi +15 -0
- data/rbi/openai/models/responses_model.rbi +25 -0
- data/rbi/openai/models/skill_create_params.rbi +8 -0
- data/rbi/openai/models/skills/version_create_params.rbi +8 -0
- data/rbi/openai/models/uploads/part_create_params.rbi +8 -0
- data/rbi/openai/models/video_create_character_params.rbi +8 -0
- data/rbi/openai/models/video_create_params.rbi +8 -0
- data/rbi/openai/models/video_edit_params.rbi +8 -0
- data/rbi/openai/models/video_extend_params.rbi +8 -0
- data/rbi/openai/net_http_client.rbi +2 -2
- data/rbi/openai/providers.rbi +11 -0
- data/rbi/openai/resources/audio/transcriptions.rbi +14 -2
- data/rbi/openai/resources/audio/translations.rbi +7 -1
- data/rbi/openai/resources/beta/responses.rbi +8 -0
- data/rbi/openai/resources/containers/files.rbi +4 -0
- data/rbi/openai/resources/content_provenance_checks.rbi +4 -0
- data/rbi/openai/resources/files.rbi +5 -1
- data/rbi/openai/resources/images.rbi +20 -0
- data/rbi/openai/resources/responses.rbi +8 -0
- data/rbi/openai/resources/skills/versions.rbi +4 -0
- data/rbi/openai/resources/skills.rbi +4 -0
- data/rbi/openai/resources/uploads/parts.rbi +4 -0
- data/rbi/openai/resources/videos.rbi +16 -0
- data/sig/openai/client.rbs +6 -2
- data/sig/openai/errors.rbs +5 -0
- data/sig/openai/http_client.rbs +37 -2
- data/sig/openai/internal/logging.rbs +88 -0
- data/sig/openai/internal/provider.rbs +3 -1
- data/sig/openai/internal/read_io_adapter.rbs +3 -1
- data/sig/openai/internal/transport/base_client.rbs +33 -5
- data/sig/openai/internal/type/base_model.rbs +13 -0
- data/sig/openai/internal/type/base_page.rbs +8 -1
- data/sig/openai/internal/type/base_stream.rbs +8 -2
- data/sig/openai/internal/util.rbs +12 -0
- data/sig/openai/models/admin/organization/audit_log_list_params.rbs +2 -0
- data/sig/openai/models/admin/organization/audit_log_list_response.rbs +2 -0
- data/sig/openai/models/all_models.rbs +10 -0
- data/sig/openai/models/beta/beta_mcp_tool_call_error.rbs +75 -0
- data/sig/openai/models/beta/beta_response.rbs +14 -1
- data/sig/openai/models/beta/beta_response_input_item.rbs +4 -4
- data/sig/openai/models/beta/beta_response_item.rbs +4 -4
- data/sig/openai/models/beta/beta_response_output_item.rbs +4 -4
- data/sig/openai/models/beta/beta_response_output_text_annotation_added_event.rbs +149 -4
- data/sig/openai/models/beta/beta_responses_client_event.rbs +21 -1
- data/sig/openai/models/beta/beta_responses_server_event.rbs +2005 -53
- data/sig/openai/models/beta/beta_web_search_tool.rbs +7 -0
- data/sig/openai/models/beta/response_compact_params.rbs +12 -0
- data/sig/openai/models/beta/response_create_params.rbs +14 -1
- data/sig/openai/models/chat_model.rbs +2 -0
- data/sig/openai/models/completion_usage.rbs +27 -6
- data/sig/openai/models/conversations/conversation_item.rbs +4 -4
- data/sig/openai/models/model.rbs +12 -2
- data/sig/openai/models/responses/mcp_tool_call_error.rbs +73 -0
- data/sig/openai/models/responses/response.rbs +2 -1
- data/sig/openai/models/responses/response_compact_params.rbs +12 -0
- data/sig/openai/models/responses/response_create_params.rbs +2 -1
- data/sig/openai/models/responses/response_input_item.rbs +4 -4
- data/sig/openai/models/responses/response_item.rbs +4 -4
- data/sig/openai/models/responses/response_output_item.rbs +4 -4
- data/sig/openai/models/responses/response_output_text_annotation_added_event.rbs +149 -4
- data/sig/openai/models/responses/responses_client_event.rbs +9 -1
- data/sig/openai/models/responses/responses_server_event.rbs +1834 -53
- data/sig/openai/models/responses/web_search_tool.rbs +7 -0
- data/sig/openai/models/responses_model.rbs +10 -0
- data/sig/openai/net_http_client.rbs +2 -2
- data/sig/openai/providers.rbs +7 -0
- metadata +30 -1
data/lib/openai/http_client.rb
CHANGED
|
@@ -1,6 +1,95 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
3
5
|
module OpenAI
|
|
6
|
+
# Metadata from the HTTP response backing a top-level SDK value.
|
|
7
|
+
class ResponseMetadata
|
|
8
|
+
# The HTTP response status code.
|
|
9
|
+
#
|
|
10
|
+
# @return [Integer]
|
|
11
|
+
attr_reader :status
|
|
12
|
+
|
|
13
|
+
# Immutable response headers with lowercase String keys.
|
|
14
|
+
#
|
|
15
|
+
# @return [Hash{String=>String}]
|
|
16
|
+
attr_reader :headers
|
|
17
|
+
|
|
18
|
+
# The request ID returned in the `x-request-id` response header.
|
|
19
|
+
#
|
|
20
|
+
# @return [String, nil]
|
|
21
|
+
attr_reader :request_id
|
|
22
|
+
|
|
23
|
+
# @api private
|
|
24
|
+
#
|
|
25
|
+
# @param status [Integer]
|
|
26
|
+
# @param headers [Hash{String=>String}]
|
|
27
|
+
def initialize(status:, headers:)
|
|
28
|
+
@status = Integer(status)
|
|
29
|
+
@headers =
|
|
30
|
+
headers.to_h do |name, value|
|
|
31
|
+
[name.to_s.downcase.freeze, value.to_s.dup.freeze]
|
|
32
|
+
end.freeze
|
|
33
|
+
@request_id = @headers["x-request-id"]
|
|
34
|
+
freeze
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Details about an API request retry that is about to run.
|
|
39
|
+
class RetryEvent
|
|
40
|
+
# The one-based number of the attempt that will run after the delay.
|
|
41
|
+
#
|
|
42
|
+
# @return [Integer]
|
|
43
|
+
attr_reader :attempt
|
|
44
|
+
|
|
45
|
+
# The maximum number of attempts, including the initial request.
|
|
46
|
+
#
|
|
47
|
+
# @return [Integer]
|
|
48
|
+
attr_reader :max_attempts
|
|
49
|
+
|
|
50
|
+
# The number of seconds the SDK will wait before the next attempt.
|
|
51
|
+
#
|
|
52
|
+
# @return [Float]
|
|
53
|
+
attr_reader :delay
|
|
54
|
+
|
|
55
|
+
# Metadata from the retryable HTTP response, if one was received.
|
|
56
|
+
#
|
|
57
|
+
# @return [OpenAI::ResponseMetadata, nil]
|
|
58
|
+
attr_reader :response
|
|
59
|
+
|
|
60
|
+
# The connection error that caused the retry, if the request failed before
|
|
61
|
+
# an HTTP response was received.
|
|
62
|
+
#
|
|
63
|
+
# @return [OpenAI::Errors::APIConnectionError, nil]
|
|
64
|
+
attr_reader :error
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
#
|
|
68
|
+
# @param attempt [Integer]
|
|
69
|
+
# @param max_attempts [Integer]
|
|
70
|
+
# @param delay [Float]
|
|
71
|
+
# @param response [OpenAI::ResponseMetadata, nil]
|
|
72
|
+
# @param error [OpenAI::Errors::APIConnectionError, nil]
|
|
73
|
+
def initialize(attempt:, max_attempts:, delay:, response:, error:)
|
|
74
|
+
@attempt = Integer(attempt)
|
|
75
|
+
@max_attempts = Integer(max_attempts)
|
|
76
|
+
@delay = Float(delay)
|
|
77
|
+
@response = response
|
|
78
|
+
@error = error
|
|
79
|
+
freeze
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The status of the retryable response, if one was received.
|
|
83
|
+
#
|
|
84
|
+
# @return [Integer, nil]
|
|
85
|
+
def status = @response&.status
|
|
86
|
+
|
|
87
|
+
# The request ID of the retryable response, if one was received.
|
|
88
|
+
#
|
|
89
|
+
# @return [String, nil]
|
|
90
|
+
def request_id = @response&.request_id
|
|
91
|
+
end
|
|
92
|
+
|
|
4
93
|
# The transport boundary used by {OpenAI::Client}.
|
|
5
94
|
#
|
|
6
95
|
# Implement {#execute} to replace the SDK's HTTP transport. Subclassing this
|
|
@@ -21,14 +110,14 @@ module OpenAI
|
|
|
21
110
|
# @return [Object, nil]
|
|
22
111
|
attr_reader :body
|
|
23
112
|
|
|
24
|
-
# @return [Float]
|
|
113
|
+
# @return [Float, nil]
|
|
25
114
|
attr_reader :timeout
|
|
26
115
|
|
|
27
116
|
# @param method [Symbol]
|
|
28
117
|
# @param url [URI::Generic]
|
|
29
118
|
# @param headers [Hash{String=>String}]
|
|
30
119
|
# @param body [Object, nil]
|
|
31
|
-
# @param timeout [Float]
|
|
120
|
+
# @param timeout [Float, nil]
|
|
32
121
|
def initialize(method:, url:, headers:, body:, timeout:)
|
|
33
122
|
@method = method
|
|
34
123
|
@url = url
|
|
@@ -54,6 +143,11 @@ module OpenAI
|
|
|
54
143
|
# @return [Enumerable<String>]
|
|
55
144
|
attr_reader :body
|
|
56
145
|
|
|
146
|
+
# Immutable metadata safe to retain after the response body is consumed.
|
|
147
|
+
#
|
|
148
|
+
# @return [OpenAI::ResponseMetadata]
|
|
149
|
+
attr_reader :metadata
|
|
150
|
+
|
|
57
151
|
# @param status [Integer]
|
|
58
152
|
# @param headers [Hash{String=>String}]
|
|
59
153
|
# @param body [String, Enumerable<String>]
|
|
@@ -62,11 +156,9 @@ module OpenAI
|
|
|
62
156
|
raise ArgumentError, "`body` must be a String or respond to `each`"
|
|
63
157
|
end
|
|
64
158
|
|
|
65
|
-
@
|
|
66
|
-
@
|
|
67
|
-
|
|
68
|
-
[name.to_s.downcase, value.to_s]
|
|
69
|
-
end.freeze
|
|
159
|
+
@metadata = OpenAI::ResponseMetadata.new(status: status, headers: headers)
|
|
160
|
+
@status = @metadata.status
|
|
161
|
+
@headers = @metadata.headers
|
|
70
162
|
source = body.is_a?(String) ? [body].freeze : body
|
|
71
163
|
@body = OpenAI::Internal::Util.fused_enum(source) do
|
|
72
164
|
if source.respond_to?(:close)
|
|
@@ -35,7 +35,7 @@ module OpenAI
|
|
|
35
35
|
def next_page
|
|
36
36
|
unless next_page?
|
|
37
37
|
message = "No more pages available. Please check #next_page? before calling ##{__method__}"
|
|
38
|
-
raise
|
|
38
|
+
raise message
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
req = OpenAI::Internal::Util.deep_merge(@req, {query: {after: last_id}})
|
|
@@ -63,9 +63,9 @@ module OpenAI
|
|
|
63
63
|
#
|
|
64
64
|
# @param client [OpenAI::Internal::Transport::BaseClient]
|
|
65
65
|
# @param req [Hash{Symbol=>Object}]
|
|
66
|
-
# @param
|
|
66
|
+
# @param response_metadata [OpenAI::ResponseMetadata]
|
|
67
67
|
# @param page_data [Hash{Symbol=>Object}]
|
|
68
|
-
def initialize(client:, req:,
|
|
68
|
+
def initialize(client:, req:, response_metadata:, page_data:)
|
|
69
69
|
super
|
|
70
70
|
|
|
71
71
|
case page_data
|
|
@@ -81,11 +81,10 @@ module OpenAI
|
|
|
81
81
|
#
|
|
82
82
|
# @return [String]
|
|
83
83
|
def inspect
|
|
84
|
-
# rubocop:disable Layout/LineLength
|
|
85
84
|
model = OpenAI::Internal::Type::Converter.inspect(@model, depth: 1)
|
|
86
85
|
|
|
87
|
-
"#<#{self.class}[#{model}]:0x#{object_id.to_s(16)}
|
|
88
|
-
|
|
86
|
+
"#<#{self.class}[#{model}]:0x#{object_id.to_s(16)} " \
|
|
87
|
+
"has_more=#{has_more.inspect} last_id=#{last_id.inspect}>"
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
90
|
end
|
|
@@ -32,7 +32,7 @@ module OpenAI
|
|
|
32
32
|
def next_page
|
|
33
33
|
unless next_page?
|
|
34
34
|
message = "No more pages available. Please check #next_page? before calling ##{__method__}"
|
|
35
|
-
raise
|
|
35
|
+
raise message
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
req = OpenAI::Internal::Util.deep_merge(@req, {query: {after: data&.last&.id}})
|
|
@@ -60,9 +60,9 @@ module OpenAI
|
|
|
60
60
|
#
|
|
61
61
|
# @param client [OpenAI::Internal::Transport::BaseClient]
|
|
62
62
|
# @param req [Hash{Symbol=>Object}]
|
|
63
|
-
# @param
|
|
63
|
+
# @param response_metadata [OpenAI::ResponseMetadata]
|
|
64
64
|
# @param page_data [Hash{Symbol=>Object}]
|
|
65
|
-
def initialize(client:, req:,
|
|
65
|
+
def initialize(client:, req:, response_metadata:, page_data:)
|
|
66
66
|
super
|
|
67
67
|
|
|
68
68
|
case page_data
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenAI
|
|
4
|
+
module Internal
|
|
5
|
+
# Request logging helpers shared by generated clients.
|
|
6
|
+
#
|
|
7
|
+
# @api private
|
|
8
|
+
module Logging
|
|
9
|
+
LOG_LEVELS = {off: 0, error: 1, warn: 2, info: 3, debug: 4}.freeze
|
|
10
|
+
REDACTED_HEADERS = %w[
|
|
11
|
+
api-key
|
|
12
|
+
authorization
|
|
13
|
+
cookie
|
|
14
|
+
proxy-authorization
|
|
15
|
+
set-cookie
|
|
16
|
+
x-amz-security-token
|
|
17
|
+
x-api-key
|
|
18
|
+
].freeze
|
|
19
|
+
MAX_BODY_BYTES = 16 * 1024
|
|
20
|
+
MAX_ARRAY_ITEMS = 100
|
|
21
|
+
OPAQUE_STRING_BYTES = 1_024
|
|
22
|
+
SENSITIVE_BODY_KEY = /(?:api[-_]?key|authorization|credential|password|secret|signature|token)/i
|
|
23
|
+
SENSITIVE_QUERY_KEY = /
|
|
24
|
+
(?:
|
|
25
|
+
(?:\A|[-_\[])(?:key|sig)
|
|
26
|
+
| (?-i:K)ey
|
|
27
|
+
| api[-_]?key
|
|
28
|
+
| authorization
|
|
29
|
+
| credentials?
|
|
30
|
+
| password
|
|
31
|
+
| secret
|
|
32
|
+
| signature
|
|
33
|
+
| token
|
|
34
|
+
)
|
|
35
|
+
(?:\[|\]|\z)
|
|
36
|
+
/ix
|
|
37
|
+
URL_HEADER_KEY = /(?:\A|[-_])(?:location|url|uri)\z|\A(?:link|refresh)\z/i
|
|
38
|
+
|
|
39
|
+
class Context
|
|
40
|
+
def initialize(logger:, log_level:, on_retry:, method:, url:)
|
|
41
|
+
@logger = logger
|
|
42
|
+
@log_level = log_level
|
|
43
|
+
@on_retry = on_retry
|
|
44
|
+
@id = nil
|
|
45
|
+
@method = method.to_s.upcase
|
|
46
|
+
@url = url
|
|
47
|
+
@started_at = OpenAI::Internal::Util.monotonic_secs
|
|
48
|
+
@attempt_started_at = @started_at
|
|
49
|
+
@attempts = 0
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def request_started(request, redirect_count:)
|
|
53
|
+
@attempts += 1
|
|
54
|
+
log(:debug) do
|
|
55
|
+
"[openai] request started log_id=#{id} attempt=#{@attempts} " \
|
|
56
|
+
"redirect=#{redirect_count} method=#{request.method.to_s.upcase} " \
|
|
57
|
+
"url=#{OpenAI::Internal::Logging.safe_url(request.url)} " \
|
|
58
|
+
"headers=#{OpenAI::Internal::Logging.format_headers(request.headers)} " \
|
|
59
|
+
"body=#{OpenAI::Internal::Logging.format_body(request.body, headers: request.headers)}"
|
|
60
|
+
end
|
|
61
|
+
@attempt_started_at = OpenAI::Internal::Util.monotonic_secs
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def response_received(response)
|
|
65
|
+
log(:debug) do
|
|
66
|
+
"[openai] response received log_id=#{id} attempt=#{@attempts} " \
|
|
67
|
+
"status=#{response.status} request_id=#{safe_field(response.headers['x-request-id'])} " \
|
|
68
|
+
"duration_ms=#{attempt_duration_ms} " \
|
|
69
|
+
"headers=#{OpenAI::Internal::Logging.format_headers(response.headers)}"
|
|
70
|
+
end
|
|
71
|
+
return response unless enabled?(:debug)
|
|
72
|
+
|
|
73
|
+
observed = ObservedBody.new(
|
|
74
|
+
body: response.body,
|
|
75
|
+
headers: response.headers,
|
|
76
|
+
context: self,
|
|
77
|
+
attempt: @attempts
|
|
78
|
+
)
|
|
79
|
+
OpenAI::HTTPClient::Response.new(
|
|
80
|
+
status: response.status,
|
|
81
|
+
headers: response.headers,
|
|
82
|
+
body: observed
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def attempt_failed(error)
|
|
87
|
+
log(:debug) do
|
|
88
|
+
"[openai] request attempt failed log_id=#{id} attempt=#{@attempts} " \
|
|
89
|
+
"error=#{error.class} duration_ms=#{attempt_duration_ms}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def retry_scheduled(cause, delay:, response:, retry_count:, max_retries:)
|
|
94
|
+
reason = cause.is_a?(Integer) ? "status=#{cause}" : "error=#{cause.class}"
|
|
95
|
+
log(:warn) do
|
|
96
|
+
"[openai] request retry log_id=#{id} attempt=#{@attempts} " \
|
|
97
|
+
"#{reason} delay_seconds=#{delay}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
event = OpenAI::RetryEvent.new(
|
|
101
|
+
attempt: retry_count + 2,
|
|
102
|
+
max_attempts: max_retries + 1,
|
|
103
|
+
delay: delay,
|
|
104
|
+
response: response,
|
|
105
|
+
error: cause.is_a?(OpenAI::Errors::APIConnectionError) ? cause : nil
|
|
106
|
+
)
|
|
107
|
+
@on_retry&.call(event)
|
|
108
|
+
rescue StandardError
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def completed(response)
|
|
113
|
+
log(:info) do
|
|
114
|
+
"[openai] request complete log_id=#{id} method=#{@method} " \
|
|
115
|
+
"path=#{OpenAI::Internal::Logging.safe_path(@url)} " \
|
|
116
|
+
"status=#{response.status} request_id=#{safe_field(response.headers['x-request-id'])} " \
|
|
117
|
+
"attempts=#{@attempts} duration_ms=#{duration_ms}"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def observe_stream(stream, response:)
|
|
122
|
+
return stream unless enabled?(:error)
|
|
123
|
+
|
|
124
|
+
stream.observe(context: self, response: response)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def request_failed(error)
|
|
128
|
+
status = error.is_a?(OpenAI::Errors::APIError) ? error.status : nil
|
|
129
|
+
request_id = error.is_a?(OpenAI::Errors::APIError) ? error.request_id : nil
|
|
130
|
+
log(:error) do
|
|
131
|
+
"[openai] request failed log_id=#{id} method=#{@method} " \
|
|
132
|
+
"path=#{OpenAI::Internal::Logging.safe_path(@url)} " \
|
|
133
|
+
"status=#{status || 'none'} request_id=#{safe_field(request_id)} " \
|
|
134
|
+
"error=#{error.class} attempts=#{@attempts} duration_ms=#{duration_ms}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def response_body(body, headers:, complete:, total_bytes:, attempt:)
|
|
139
|
+
log(:debug) do
|
|
140
|
+
formatted = OpenAI::Internal::Logging.format_observed_body(
|
|
141
|
+
body,
|
|
142
|
+
headers: headers,
|
|
143
|
+
complete: complete,
|
|
144
|
+
total_bytes: total_bytes
|
|
145
|
+
)
|
|
146
|
+
"[openai] response body log_id=#{id} " \
|
|
147
|
+
"attempt=#{attempt} duration_ms=#{duration_ms} body=#{formatted}"
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private def duration_ms
|
|
152
|
+
((OpenAI::Internal::Util.monotonic_secs - @started_at) * 1_000).round(2)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private def id = @id ||= "log_#{SecureRandom.hex(6)}"
|
|
156
|
+
|
|
157
|
+
private def attempt_duration_ms
|
|
158
|
+
((OpenAI::Internal::Util.monotonic_secs - @attempt_started_at) * 1_000).round(2)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private def enabled?(event_level)
|
|
162
|
+
!@logger.nil? && OpenAI::Internal::Logging.enabled?(@log_level, event_level)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private def safe_field(value) = OpenAI::Internal::Logging.safe_field(value)
|
|
166
|
+
|
|
167
|
+
private def log(event_level)
|
|
168
|
+
return unless enabled?(event_level)
|
|
169
|
+
|
|
170
|
+
message = yield
|
|
171
|
+
case event_level
|
|
172
|
+
in :debug
|
|
173
|
+
@logger.debug(message)
|
|
174
|
+
in :info
|
|
175
|
+
@logger.info(message)
|
|
176
|
+
in :warn
|
|
177
|
+
@logger.warn(message)
|
|
178
|
+
in :error
|
|
179
|
+
@logger.error(message)
|
|
180
|
+
end
|
|
181
|
+
rescue StandardError
|
|
182
|
+
nil
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class ObservedBody
|
|
187
|
+
include Enumerable
|
|
188
|
+
|
|
189
|
+
def initialize(body:, headers:, context:, attempt:)
|
|
190
|
+
@body = body
|
|
191
|
+
@headers = headers
|
|
192
|
+
@context = context
|
|
193
|
+
@attempt = attempt
|
|
194
|
+
@captured = String.new(encoding: Encoding::BINARY)
|
|
195
|
+
@capture_body = OpenAI::Internal::Logging.capture_response_body?(headers)
|
|
196
|
+
@bytes = 0
|
|
197
|
+
@complete = false
|
|
198
|
+
@closed = false
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def each
|
|
202
|
+
return enum_for unless block_given?
|
|
203
|
+
return if @closed
|
|
204
|
+
|
|
205
|
+
begin
|
|
206
|
+
@body.each do |chunk|
|
|
207
|
+
capture(chunk)
|
|
208
|
+
yield(chunk)
|
|
209
|
+
end
|
|
210
|
+
@complete = true
|
|
211
|
+
ensure
|
|
212
|
+
close
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def close
|
|
217
|
+
return if @closed
|
|
218
|
+
|
|
219
|
+
@closed = true
|
|
220
|
+
OpenAI::Internal::Util.close_fused!(@body)
|
|
221
|
+
@context.response_body(
|
|
222
|
+
@captured,
|
|
223
|
+
headers: @headers,
|
|
224
|
+
complete: @complete,
|
|
225
|
+
total_bytes: @bytes,
|
|
226
|
+
attempt: @attempt
|
|
227
|
+
)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private def capture(chunk)
|
|
231
|
+
@bytes += chunk.bytesize
|
|
232
|
+
return unless @capture_body
|
|
233
|
+
|
|
234
|
+
remaining = OpenAI::Internal::Logging::MAX_BODY_BYTES - @captured.bytesize
|
|
235
|
+
@captured << chunk.byteslice(0, remaining) if remaining.positive?
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
class << self
|
|
240
|
+
def normalize_level(value)
|
|
241
|
+
level = value.to_s.downcase.to_sym if value.is_a?(String) || value.is_a?(Symbol)
|
|
242
|
+
return level if LOG_LEVELS.key?(level)
|
|
243
|
+
|
|
244
|
+
raise ArgumentError, "`log_level` must be one of :off, :error, :warn, :info, or :debug"
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def validate_logger!(logger)
|
|
248
|
+
return if logger.nil?
|
|
249
|
+
|
|
250
|
+
methods = [:debug, :info, :warn, :error]
|
|
251
|
+
return if methods.all? { logger.respond_to?(_1) }
|
|
252
|
+
|
|
253
|
+
raise ArgumentError, "`logger` must respond to `debug`, `info`, `warn`, and `error`"
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def default_logger = ::Logger.new($stderr)
|
|
257
|
+
|
|
258
|
+
def enabled?(configured_level, event_level)
|
|
259
|
+
LOG_LEVELS.fetch(configured_level) >= LOG_LEVELS.fetch(event_level)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def safe_path(url)
|
|
263
|
+
uri = sanitized_uri(url)
|
|
264
|
+
path = uri.path.to_s.empty? ? "/" : uri.path
|
|
265
|
+
uri.query.nil? ? path : "#{path}?#{uri.query}"
|
|
266
|
+
rescue ArgumentError, URI::Error
|
|
267
|
+
"[URL OMITTED]"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def safe_url(url)
|
|
271
|
+
sanitized_uri(url).to_s
|
|
272
|
+
rescue ArgumentError, URI::Error
|
|
273
|
+
"[URL OMITTED]"
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def safe_field(value)
|
|
277
|
+
return "none" if value.nil?
|
|
278
|
+
|
|
279
|
+
value.to_s.dump.delete_prefix('"').delete_suffix('"')
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# @api private
|
|
283
|
+
def sensitive_header?(name)
|
|
284
|
+
normalized_name = name.to_s.downcase
|
|
285
|
+
REDACTED_HEADERS.include?(normalized_name) || SENSITIVE_QUERY_KEY.match?(normalized_name)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# @api private
|
|
289
|
+
def credential_header?(name)
|
|
290
|
+
normalized_name = name.to_s.downcase
|
|
291
|
+
idempotency = normalized_name.match(/(?:\A|[-_])idempotency[-_]key\z/)
|
|
292
|
+
return sensitive_header?(normalized_name) unless idempotency
|
|
293
|
+
|
|
294
|
+
prefix = normalized_name[...idempotency.begin(0)]
|
|
295
|
+
prefix.split(/[-_]/).any? { sensitive_header?(_1) }
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def format_headers(headers)
|
|
299
|
+
redacted =
|
|
300
|
+
headers.sort.to_h do |name, value|
|
|
301
|
+
normalized_name = name.to_s.downcase
|
|
302
|
+
rendered =
|
|
303
|
+
if sensitive_header?(normalized_name)
|
|
304
|
+
"[REDACTED]"
|
|
305
|
+
elsif URL_HEADER_KEY.match?(normalized_name)
|
|
306
|
+
sanitized_header_url(value)
|
|
307
|
+
else
|
|
308
|
+
value
|
|
309
|
+
end
|
|
310
|
+
[name, rendered]
|
|
311
|
+
end
|
|
312
|
+
JSON.generate(redacted)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def format_body(body, headers:)
|
|
316
|
+
content_type = headers["content-type"].to_s
|
|
317
|
+
return "[NO BODY]" if body.nil?
|
|
318
|
+
return "[MULTIPART BODY OMITTED]" if content_type.match?(%r{\Amultipart/}i)
|
|
319
|
+
return "[STREAMING BODY OMITTED]" unless body.is_a?(String)
|
|
320
|
+
return "[BINARY BODY OMITTED] bytes=#{body.bytesize}" unless textual_content_type?(content_type)
|
|
321
|
+
|
|
322
|
+
format_text_body(body, content_type: content_type, total_bytes: body.bytesize)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def capture_response_body?(headers)
|
|
326
|
+
content_type = headers["content-type"].to_s
|
|
327
|
+
textual_content_type?(content_type) && !content_type.match?(%r{\Atext/event-stream}i)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def format_observed_body(body, headers:, complete:, total_bytes:)
|
|
331
|
+
content_type = headers["content-type"].to_s
|
|
332
|
+
return "[STREAM BODY OMITTED] bytes=#{total_bytes}" if content_type.match?(%r{\Atext/event-stream}i)
|
|
333
|
+
return "[BODY CLOSED EARLY] bytes=#{total_bytes}" unless complete
|
|
334
|
+
unless textual_content_type?(content_type)
|
|
335
|
+
return "[BINARY BODY OMITTED] bytes=#{total_bytes}"
|
|
336
|
+
end
|
|
337
|
+
if total_bytes > MAX_BODY_BYTES && json_content_type?(content_type)
|
|
338
|
+
return "[JSON BODY OMITTED] bytes=#{total_bytes} reason=too_large"
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
format_text_body(body, content_type: content_type, total_bytes: total_bytes)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
private def sanitized_uri(url)
|
|
345
|
+
uri = url.dup
|
|
346
|
+
uri.user = nil
|
|
347
|
+
uri.password = nil
|
|
348
|
+
return uri if uri.query.nil?
|
|
349
|
+
|
|
350
|
+
uri.query = sanitized_query(uri.query)
|
|
351
|
+
uri
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
private def sanitized_query(query)
|
|
355
|
+
pairs = URI.decode_www_form(query).map do |name, value|
|
|
356
|
+
[name, SENSITIVE_QUERY_KEY.match?(name) ? "[REDACTED]" : value]
|
|
357
|
+
end
|
|
358
|
+
URI.encode_www_form(pairs)
|
|
359
|
+
rescue ArgumentError
|
|
360
|
+
nil
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
private def sanitized_header_url(value)
|
|
364
|
+
safe_url(URI(value.to_s))
|
|
365
|
+
rescue URI::InvalidURIError
|
|
366
|
+
"[URL OMITTED]"
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
private def textual_content_type?(content_type)
|
|
370
|
+
content_type.empty? ||
|
|
371
|
+
content_type.match?(%r{\Atext/}i) ||
|
|
372
|
+
content_type.match?(/(?:json|xml|x-www-form-urlencoded)/i)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
private def json_content_type?(content_type) = content_type.match?(%r{(?:\A|[+/])json(?:;|\z)}i)
|
|
376
|
+
|
|
377
|
+
private def format_text_body(body, content_type:, total_bytes:)
|
|
378
|
+
if json_content_type?(content_type)
|
|
379
|
+
return "[JSON BODY OMITTED] bytes=#{total_bytes} reason=too_large" if total_bytes > MAX_BODY_BYTES
|
|
380
|
+
|
|
381
|
+
parsed = JSON.parse(body)
|
|
382
|
+
return summarize_json_body(parsed, total_bytes: total_bytes)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
unless content_type.match?(%r{\Aapplication/x-www-form-urlencoded(?:;|\z)}i)
|
|
386
|
+
return "[TEXT BODY OMITTED] bytes=#{total_bytes}"
|
|
387
|
+
end
|
|
388
|
+
return "[FORM BODY OMITTED] bytes=#{total_bytes} reason=too_large" if total_bytes > MAX_BODY_BYTES
|
|
389
|
+
|
|
390
|
+
fields = URI.decode_www_form(body).length
|
|
391
|
+
"[FORM BODY] bytes=#{total_bytes} fields=#{fields}"
|
|
392
|
+
rescue JSON::ParserError
|
|
393
|
+
"[INVALID JSON BODY OMITTED] bytes=#{total_bytes}"
|
|
394
|
+
rescue ArgumentError
|
|
395
|
+
"[INVALID FORM BODY OMITTED] bytes=#{total_bytes}"
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
private def summarize_json_body(value, total_bytes:)
|
|
399
|
+
shape =
|
|
400
|
+
case value
|
|
401
|
+
in Hash
|
|
402
|
+
"object fields=#{value.length}"
|
|
403
|
+
in Array
|
|
404
|
+
"array items=#{value.length}"
|
|
405
|
+
in String
|
|
406
|
+
"string"
|
|
407
|
+
in Integer | Float
|
|
408
|
+
"number"
|
|
409
|
+
in true | false
|
|
410
|
+
"boolean"
|
|
411
|
+
in nil
|
|
412
|
+
"null"
|
|
413
|
+
end
|
|
414
|
+
"[JSON BODY] bytes=#{total_bytes} type=#{shape}"
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
@@ -35,7 +35,7 @@ module OpenAI
|
|
|
35
35
|
def next_page
|
|
36
36
|
unless next_page?
|
|
37
37
|
message = "No more pages available. Please check #next_page? before calling ##{__method__}"
|
|
38
|
-
raise
|
|
38
|
+
raise message
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
req = OpenAI::Internal::Util.deep_merge(@req, {query: {after: next_}})
|
|
@@ -63,9 +63,9 @@ module OpenAI
|
|
|
63
63
|
#
|
|
64
64
|
# @param client [OpenAI::Internal::Transport::BaseClient]
|
|
65
65
|
# @param req [Hash{Symbol=>Object}]
|
|
66
|
-
# @param
|
|
66
|
+
# @param response_metadata [OpenAI::ResponseMetadata]
|
|
67
67
|
# @param page_data [Hash{Symbol=>Object}]
|
|
68
|
-
def initialize(client:, req:,
|
|
68
|
+
def initialize(client:, req:, response_metadata:, page_data:)
|
|
69
69
|
super
|
|
70
70
|
|
|
71
71
|
case page_data
|
|
@@ -81,11 +81,10 @@ module OpenAI
|
|
|
81
81
|
#
|
|
82
82
|
# @return [String]
|
|
83
83
|
def inspect
|
|
84
|
-
# rubocop:disable Layout/LineLength
|
|
85
84
|
model = OpenAI::Internal::Type::Converter.inspect(@model, depth: 1)
|
|
86
85
|
|
|
87
|
-
"#<#{self.class}[#{model}]:0x#{object_id.to_s(16)}
|
|
88
|
-
|
|
86
|
+
"#<#{self.class}[#{model}]:0x#{object_id.to_s(16)} " \
|
|
87
|
+
"has_more=#{has_more.inspect} next_=#{next_.inspect}>"
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
90
|
end
|
data/lib/openai/internal/page.rb
CHANGED
|
@@ -54,9 +54,9 @@ module OpenAI
|
|
|
54
54
|
#
|
|
55
55
|
# @param client [OpenAI::Internal::Transport::BaseClient]
|
|
56
56
|
# @param req [Hash{Symbol=>Object}]
|
|
57
|
-
# @param
|
|
57
|
+
# @param response_metadata [OpenAI::ResponseMetadata]
|
|
58
58
|
# @param page_data [Array<Object>]
|
|
59
|
-
def initialize(client:, req:,
|
|
59
|
+
def initialize(client:, req:, response_metadata:, page_data:)
|
|
60
60
|
super
|
|
61
61
|
|
|
62
62
|
case page_data
|
|
@@ -7,7 +7,13 @@ module OpenAI
|
|
|
7
7
|
# Provider factories return opaque OpenAI::Provider instances whose public
|
|
8
8
|
# representation does not expose their definition.
|
|
9
9
|
module Provider
|
|
10
|
-
Runtime = Struct.new(
|
|
10
|
+
Runtime = Struct.new(
|
|
11
|
+
:name,
|
|
12
|
+
:base_url,
|
|
13
|
+
:prepare_request,
|
|
14
|
+
:authentication_headers,
|
|
15
|
+
keyword_init: true
|
|
16
|
+
)
|
|
11
17
|
|
|
12
18
|
class << self
|
|
13
19
|
# @api private
|