openai 0.77.0 → 0.78.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 +25 -0
- data/README.md +102 -4
- data/lib/openai/client.rb +7 -10
- data/lib/openai/http_client.rb +97 -0
- data/lib/openai/internal/read_io_adapter.rb +137 -0
- data/lib/openai/internal/transport/base_client.rb +84 -25
- data/lib/openai/internal/type/base_stream.rb +1 -1
- data/lib/openai/internal/util.rb +7 -85
- data/lib/openai/net_http_client.rb +281 -0
- data/lib/openai/version.rb +1 -1
- data/lib/openai.rb +2 -1
- data/rbi/openai/client.rbi +4 -2
- data/rbi/openai/http_client.rbi +63 -0
- data/rbi/openai/internal/read_io_adapter.rbi +47 -0
- data/rbi/openai/internal/transport/base_client.rbi +21 -5
- data/rbi/openai/internal/type/base_stream.rbi +1 -1
- data/rbi/openai/internal/util.rbi +0 -40
- data/rbi/openai/net_http_client.rbi +64 -0
- data/sig/openai/client.rbs +2 -1
- data/sig/openai/http_client.rbs +41 -0
- data/sig/openai/internal/read_io_adapter.rbs +21 -0
- data/sig/openai/internal/transport/base_client.rbs +10 -3
- data/sig/openai/internal/type/base_stream.rbs +1 -1
- data/sig/openai/internal/util.rbs +0 -16
- data/sig/openai/net_http_client.rbs +34 -0
- metadata +12 -6
- data/lib/openai/internal/transport/pooled_net_requester.rb +0 -210
- data/rbi/openai/internal/transport/pooled_net_requester.rbi +0 -82
- data/sig/openai/internal/transport/pooled_net_requester.rbs +0 -48
|
@@ -55,7 +55,7 @@ module OpenAI
|
|
|
55
55
|
# @param url [URI::Generic]
|
|
56
56
|
# @param status [Integer]
|
|
57
57
|
# @param headers [Hash{String=>String}]
|
|
58
|
-
# @param response [
|
|
58
|
+
# @param response [OpenAI::HTTPClient::Response]
|
|
59
59
|
# @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc]
|
|
60
60
|
# @param stream [Enumerable<Object>]
|
|
61
61
|
def initialize(model:, url:, status:, headers:, response:, unwrap:, stream:)
|
data/lib/openai/internal/util.rb
CHANGED
|
@@ -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]
|
|
@@ -397,90 +402,6 @@ module OpenAI
|
|
|
397
402
|
end
|
|
398
403
|
end
|
|
399
404
|
|
|
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
|
|
458
|
-
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
|
-
end
|
|
482
|
-
end
|
|
483
|
-
|
|
484
405
|
class << self
|
|
485
406
|
# @param blk [Proc]
|
|
486
407
|
#
|
|
@@ -768,6 +689,7 @@ module OpenAI
|
|
|
768
689
|
close&.call
|
|
769
690
|
close = nil
|
|
770
691
|
end
|
|
692
|
+
iter.extend(FusedEnumerator)
|
|
771
693
|
|
|
772
694
|
iter.define_singleton_method(:rewind) do
|
|
773
695
|
fused = true
|
|
@@ -780,7 +702,7 @@ module OpenAI
|
|
|
780
702
|
#
|
|
781
703
|
# @param enum [Enumerable<Object>, nil]
|
|
782
704
|
def close_fused!(enum)
|
|
783
|
-
return unless enum.is_a?(
|
|
705
|
+
return unless enum.is_a?(FusedEnumerator)
|
|
784
706
|
|
|
785
707
|
# rubocop:disable Lint/UnreachableLoop
|
|
786
708
|
enum.rewind.each { break }
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "internal/read_io_adapter"
|
|
4
|
+
|
|
5
|
+
module OpenAI
|
|
6
|
+
# The SDK's pooled Net::HTTP implementation.
|
|
7
|
+
#
|
|
8
|
+
# Pass a block to configure each SDK-created connection before it is pooled
|
|
9
|
+
# and started.
|
|
10
|
+
class NetHTTPClient < HTTPClient
|
|
11
|
+
# from the golang stdlib
|
|
12
|
+
# https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49
|
|
13
|
+
KEEP_ALIVE_TIMEOUT = 30
|
|
14
|
+
|
|
15
|
+
DEFAULT_MAX_CONNECTIONS = [Etc.nprocessors, 99].max
|
|
16
|
+
|
|
17
|
+
NETWORK_ERRORS = [
|
|
18
|
+
EOFError,
|
|
19
|
+
IOError,
|
|
20
|
+
SocketError,
|
|
21
|
+
SystemCallError,
|
|
22
|
+
OpenSSL::SSL::SSLError,
|
|
23
|
+
Net::HTTPBadResponse,
|
|
24
|
+
Net::HTTPHeaderSyntaxError,
|
|
25
|
+
Net::ProtocolError,
|
|
26
|
+
(defined?(Zlib::Error) ? Zlib::Error : nil),
|
|
27
|
+
ConnectionPool::PoolShuttingDownError
|
|
28
|
+
].compact.freeze
|
|
29
|
+
private_constant :NETWORK_ERRORS
|
|
30
|
+
|
|
31
|
+
class ConnectionConfigurationError < StandardError
|
|
32
|
+
attr_reader :original
|
|
33
|
+
|
|
34
|
+
def initialize(original)
|
|
35
|
+
@original = original
|
|
36
|
+
super()
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
private_constant :ConnectionConfigurationError
|
|
40
|
+
|
|
41
|
+
# @api private
|
|
42
|
+
#
|
|
43
|
+
# @param url [URI::Generic]
|
|
44
|
+
#
|
|
45
|
+
# @return [Net::HTTP]
|
|
46
|
+
private def connect(url:)
|
|
47
|
+
port =
|
|
48
|
+
case [url.port, url.scheme]
|
|
49
|
+
in [Integer, _]
|
|
50
|
+
url.port
|
|
51
|
+
in [nil, "http" | "ws"]
|
|
52
|
+
Net::HTTP.http_default_port
|
|
53
|
+
in [nil, "https" | "wss"]
|
|
54
|
+
Net::HTTP.https_default_port
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
Net::HTTP.new(url.host, port).tap do
|
|
58
|
+
_1.use_ssl = %w[https wss].include?(url.scheme)
|
|
59
|
+
_1.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
|
|
60
|
+
_1.max_retries = 0
|
|
61
|
+
|
|
62
|
+
(_1.cert_store = @cert_store) if _1.use_ssl?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
#
|
|
68
|
+
# @param conn [Net::HTTP]
|
|
69
|
+
# @param deadline [Float]
|
|
70
|
+
private def calibrate_socket_timeout(conn, deadline)
|
|
71
|
+
timeout = remaining_timeout(deadline)
|
|
72
|
+
conn.open_timeout = conn.read_timeout = conn.write_timeout = conn.continue_timeout = timeout
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @api private
|
|
76
|
+
#
|
|
77
|
+
# @param deadline [Float]
|
|
78
|
+
# @return [Float]
|
|
79
|
+
# @raise [Timeout::Error]
|
|
80
|
+
private def remaining_timeout(deadline)
|
|
81
|
+
timeout = deadline - OpenAI::Internal::Util.monotonic_secs
|
|
82
|
+
raise Timeout::Error, "request timed out" unless timeout.positive?
|
|
83
|
+
|
|
84
|
+
timeout
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @api private
|
|
88
|
+
#
|
|
89
|
+
# @param request [OpenAI::HTTPClient::Request]
|
|
90
|
+
# @param blk [Proc]
|
|
91
|
+
#
|
|
92
|
+
# @yieldparam [String]
|
|
93
|
+
# @return [Array(Net::HTTPGenericRequest, Proc)]
|
|
94
|
+
private def build_request(request, &blk)
|
|
95
|
+
method = request.method
|
|
96
|
+
body = request.body
|
|
97
|
+
req = Net::HTTPGenericRequest.new(
|
|
98
|
+
method.to_s.upcase,
|
|
99
|
+
!body.nil?,
|
|
100
|
+
method != :head,
|
|
101
|
+
URI(request.url.to_s)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
request.headers.each { req[_1] = _2 }
|
|
105
|
+
|
|
106
|
+
case body
|
|
107
|
+
in nil
|
|
108
|
+
req["content-length"] ||= 0 unless req["transfer-encoding"]
|
|
109
|
+
in String
|
|
110
|
+
req["content-length"] ||= body.bytesize.to_s unless req["transfer-encoding"]
|
|
111
|
+
req.body_stream = OpenAI::Internal::Util::ReadIOAdapter.new(body, &blk)
|
|
112
|
+
in StringIO
|
|
113
|
+
req["content-length"] ||= body.size.to_s unless req["transfer-encoding"]
|
|
114
|
+
req.body_stream = OpenAI::Internal::Util::ReadIOAdapter.new(body, &blk)
|
|
115
|
+
in Pathname | IO | Enumerator
|
|
116
|
+
req["transfer-encoding"] ||= "chunked" unless req["content-length"]
|
|
117
|
+
req.body_stream = OpenAI::Internal::Util::ReadIOAdapter.new(body, &blk)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
[req, req.body_stream&.method(:close)]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# @api private
|
|
124
|
+
#
|
|
125
|
+
# @param url [URI::Generic]
|
|
126
|
+
# @param deadline [Float]
|
|
127
|
+
# @param blk [Proc]
|
|
128
|
+
#
|
|
129
|
+
# @raise [Timeout::Error]
|
|
130
|
+
# @yieldparam [Net::HTTP]
|
|
131
|
+
private def with_pool(url, deadline:, &blk)
|
|
132
|
+
origin = OpenAI::Internal::Util.uri_origin(url)
|
|
133
|
+
timeout = remaining_timeout(deadline)
|
|
134
|
+
pool =
|
|
135
|
+
@mutex.synchronize do
|
|
136
|
+
@pools[origin] ||= ConnectionPool.new(size: @size) do
|
|
137
|
+
configured_connection(url)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
pool.with(timeout: timeout, &blk)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @api private
|
|
145
|
+
#
|
|
146
|
+
# @param url [URI::Generic]
|
|
147
|
+
#
|
|
148
|
+
# @return [Net::HTTP]
|
|
149
|
+
private def configured_connection(url)
|
|
150
|
+
connection = nil
|
|
151
|
+
connection = connect(url: url)
|
|
152
|
+
begin
|
|
153
|
+
@connection_configurator&.call(connection)
|
|
154
|
+
rescue StandardError => e
|
|
155
|
+
raise ConnectionConfigurationError.new(e)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
if connection.started?
|
|
159
|
+
raise ArgumentError, "connection configuration must leave the connection unstarted"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
expected_ssl = %w[https wss].include?(url.scheme)
|
|
163
|
+
unless connection.use_ssl? == expected_ssl
|
|
164
|
+
raise ArgumentError, "connection configuration must preserve TLS for the requested URL"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
connection.max_retries = 0
|
|
168
|
+
connection
|
|
169
|
+
rescue StandardError
|
|
170
|
+
begin
|
|
171
|
+
connection.finish if connection&.started?
|
|
172
|
+
rescue StandardError
|
|
173
|
+
nil
|
|
174
|
+
end
|
|
175
|
+
raise
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Closes current pooled connections. The client remains reusable and will
|
|
179
|
+
# create fresh pools on subsequent requests.
|
|
180
|
+
#
|
|
181
|
+
# In-flight requests are allowed to finish before their connection closes.
|
|
182
|
+
#
|
|
183
|
+
# @return [void]
|
|
184
|
+
def close
|
|
185
|
+
pools =
|
|
186
|
+
@mutex.synchronize do
|
|
187
|
+
current_pools = @pools
|
|
188
|
+
@pools = {}
|
|
189
|
+
current_pools
|
|
190
|
+
end
|
|
191
|
+
pools.each_value do |pool|
|
|
192
|
+
pool.shutdown { |connection| connection.finish if connection.started? }
|
|
193
|
+
end
|
|
194
|
+
nil
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Executes a request using a pooled Net::HTTP connection.
|
|
198
|
+
#
|
|
199
|
+
# @param request [OpenAI::HTTPClient::Request]
|
|
200
|
+
# @return [OpenAI::HTTPClient::Response]
|
|
201
|
+
def execute(request)
|
|
202
|
+
url = request.url
|
|
203
|
+
deadline = OpenAI::Internal::Util.monotonic_secs + request.timeout
|
|
204
|
+
|
|
205
|
+
req = nil
|
|
206
|
+
finished = false
|
|
207
|
+
|
|
208
|
+
# rubocop:disable Metrics/BlockLength
|
|
209
|
+
enum = Enumerator.new do |y|
|
|
210
|
+
next if finished
|
|
211
|
+
|
|
212
|
+
with_pool(url, deadline: deadline) do |conn|
|
|
213
|
+
eof = false
|
|
214
|
+
closing = nil
|
|
215
|
+
::Thread.handle_interrupt(Object => :never) do
|
|
216
|
+
::Thread.handle_interrupt(Object => :immediate) do
|
|
217
|
+
req, closing = build_request(request) do
|
|
218
|
+
calibrate_socket_timeout(conn, deadline)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
calibrate_socket_timeout(conn, deadline)
|
|
222
|
+
conn.start unless conn.started?
|
|
223
|
+
|
|
224
|
+
calibrate_socket_timeout(conn, deadline)
|
|
225
|
+
::Kernel.catch(:jump) do
|
|
226
|
+
conn.request(req) do |rsp|
|
|
227
|
+
y << [req, rsp]
|
|
228
|
+
::Kernel.throw(:jump) if finished
|
|
229
|
+
|
|
230
|
+
rsp.read_body do |bytes|
|
|
231
|
+
y << bytes.force_encoding(Encoding::BINARY)
|
|
232
|
+
::Kernel.throw(:jump) if finished
|
|
233
|
+
|
|
234
|
+
calibrate_socket_timeout(conn, deadline)
|
|
235
|
+
end
|
|
236
|
+
eof = true
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
ensure
|
|
241
|
+
begin
|
|
242
|
+
conn.finish if !eof && conn&.started?
|
|
243
|
+
ensure
|
|
244
|
+
closing&.call
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
rescue ConnectionConfigurationError => e
|
|
249
|
+
raise e.original, cause: e.original.cause
|
|
250
|
+
rescue Timeout::Error
|
|
251
|
+
raise OpenAI::Errors::APITimeoutError.new(url: url, request: req)
|
|
252
|
+
rescue *NETWORK_ERRORS
|
|
253
|
+
raise OpenAI::Errors::APIConnectionError.new(url: url, request: req)
|
|
254
|
+
end
|
|
255
|
+
# rubocop:enable Metrics/BlockLength
|
|
256
|
+
|
|
257
|
+
_, response = enum.next
|
|
258
|
+
body = OpenAI::Internal::Util.fused_enum(enum, external: true) do
|
|
259
|
+
finished = true
|
|
260
|
+
loop { enum.next }
|
|
261
|
+
end
|
|
262
|
+
OpenAI::HTTPClient::Response.new(
|
|
263
|
+
status: Integer(response.code),
|
|
264
|
+
headers: response.each_header.to_h,
|
|
265
|
+
body: body
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# @param size [Integer]
|
|
270
|
+
# @param connection_configurator [#call, nil] A block that configures every
|
|
271
|
+
# SDK-created Net::HTTP connection before it is pooled and started.
|
|
272
|
+
def initialize(size: self.class::DEFAULT_MAX_CONNECTIONS, &connection_configurator)
|
|
273
|
+
super()
|
|
274
|
+
@mutex = Mutex.new
|
|
275
|
+
@size = size
|
|
276
|
+
@cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
|
|
277
|
+
@connection_configurator = connection_configurator
|
|
278
|
+
@pools = {}
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
data/lib/openai/version.rb
CHANGED
data/lib/openai.rb
CHANGED
|
@@ -53,11 +53,12 @@ require_relative "openai/internal"
|
|
|
53
53
|
require_relative "openai/request_options"
|
|
54
54
|
require_relative "openai/file_part"
|
|
55
55
|
require_relative "openai/errors"
|
|
56
|
+
require_relative "openai/http_client"
|
|
57
|
+
require_relative "openai/net_http_client"
|
|
56
58
|
require_relative "openai/provider"
|
|
57
59
|
require_relative "openai/internal/provider"
|
|
58
60
|
require_relative "openai/providers/bedrock"
|
|
59
61
|
require_relative "openai/internal/transport/base_client"
|
|
60
|
-
require_relative "openai/internal/transport/pooled_net_requester"
|
|
61
62
|
require_relative "openai/client"
|
|
62
63
|
require_relative "openai/internal/stream"
|
|
63
64
|
require_relative "openai/internal/conversation_cursor_page"
|
data/rbi/openai/client.rbi
CHANGED
|
@@ -162,7 +162,8 @@ module OpenAI
|
|
|
162
162
|
max_retries: Integer,
|
|
163
163
|
timeout: Float,
|
|
164
164
|
initial_retry_delay: Float,
|
|
165
|
-
max_retry_delay: Float
|
|
165
|
+
max_retry_delay: Float,
|
|
166
|
+
http_client: T.untyped
|
|
166
167
|
).returns(T.attached_class)
|
|
167
168
|
end
|
|
168
169
|
def self.new(
|
|
@@ -185,7 +186,8 @@ module OpenAI
|
|
|
185
186
|
max_retries: OpenAI::Client::DEFAULT_MAX_RETRIES,
|
|
186
187
|
timeout: OpenAI::Client::DEFAULT_TIMEOUT_IN_SECONDS,
|
|
187
188
|
initial_retry_delay: OpenAI::Client::DEFAULT_INITIAL_RETRY_DELAY,
|
|
188
|
-
max_retry_delay: OpenAI::Client::DEFAULT_MAX_RETRY_DELAY
|
|
189
|
+
max_retry_delay: OpenAI::Client::DEFAULT_MAX_RETRY_DELAY,
|
|
190
|
+
http_client: nil
|
|
189
191
|
)
|
|
190
192
|
end
|
|
191
193
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
|
|
3
|
+
module OpenAI
|
|
4
|
+
class HTTPClient
|
|
5
|
+
class Request
|
|
6
|
+
sig { returns(Symbol) }
|
|
7
|
+
attr_reader :method
|
|
8
|
+
|
|
9
|
+
sig { returns(URI::Generic) }
|
|
10
|
+
attr_reader :url
|
|
11
|
+
|
|
12
|
+
sig { returns(T::Hash[String, String]) }
|
|
13
|
+
attr_reader :headers
|
|
14
|
+
|
|
15
|
+
sig { returns(T.anything) }
|
|
16
|
+
attr_reader :body
|
|
17
|
+
|
|
18
|
+
sig { returns(Float) }
|
|
19
|
+
attr_reader :timeout
|
|
20
|
+
|
|
21
|
+
sig do
|
|
22
|
+
params(
|
|
23
|
+
method: Symbol,
|
|
24
|
+
url: URI::Generic,
|
|
25
|
+
headers: T::Hash[String, String],
|
|
26
|
+
body: T.anything,
|
|
27
|
+
timeout: Float
|
|
28
|
+
).returns(T.attached_class)
|
|
29
|
+
end
|
|
30
|
+
def self.new(method:, url:, headers:, body:, timeout:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class Response
|
|
35
|
+
sig { returns(Integer) }
|
|
36
|
+
attr_reader :status
|
|
37
|
+
|
|
38
|
+
sig { returns(T::Hash[String, String]) }
|
|
39
|
+
attr_reader :headers
|
|
40
|
+
|
|
41
|
+
sig { returns(T::Enumerable[String]) }
|
|
42
|
+
attr_reader :body
|
|
43
|
+
|
|
44
|
+
sig do
|
|
45
|
+
params(
|
|
46
|
+
status: Integer,
|
|
47
|
+
headers: T::Hash[String, String],
|
|
48
|
+
body: T.any(String, T::Enumerable[String])
|
|
49
|
+
).returns(T.attached_class)
|
|
50
|
+
end
|
|
51
|
+
def self.new(status:, headers:, body:)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
sig do
|
|
56
|
+
params(request: OpenAI::HTTPClient::Request).returns(
|
|
57
|
+
OpenAI::HTTPClient::Response
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
def execute(request)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
|
|
3
|
+
module OpenAI
|
|
4
|
+
module Internal
|
|
5
|
+
module Util
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# An adapter that satisfies the IO interface required by `::IO.copy_stream`
|
|
9
|
+
class ReadIOAdapter
|
|
10
|
+
# @api private
|
|
11
|
+
sig { returns(T.nilable(T::Boolean)) }
|
|
12
|
+
def close?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @api private
|
|
16
|
+
sig { void }
|
|
17
|
+
def close
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @api private
|
|
21
|
+
sig { params(max_len: T.nilable(Integer)).returns(String) }
|
|
22
|
+
private def read_enum(max_len)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @api private
|
|
26
|
+
sig do
|
|
27
|
+
params(
|
|
28
|
+
max_len: T.nilable(Integer),
|
|
29
|
+
out_string: T.nilable(String)
|
|
30
|
+
).returns(T.nilable(String))
|
|
31
|
+
end
|
|
32
|
+
def read(max_len = nil, out_string = nil)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @api private
|
|
36
|
+
sig do
|
|
37
|
+
params(
|
|
38
|
+
src: T.any(String, Pathname, StringIO, T::Enumerable[String]),
|
|
39
|
+
blk: T.proc.params(arg0: String).void
|
|
40
|
+
).returns(T.attached_class)
|
|
41
|
+
end
|
|
42
|
+
def self.new(src, &blk)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -103,6 +103,11 @@ module OpenAI
|
|
|
103
103
|
def should_retry?(status, headers:)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
+
# @api private
|
|
107
|
+
sig { params(body: T.untyped).returns(T::Boolean) }
|
|
108
|
+
def request_body_replayable?(body)
|
|
109
|
+
end
|
|
110
|
+
|
|
106
111
|
# @api private
|
|
107
112
|
sig do
|
|
108
113
|
params(
|
|
@@ -147,7 +152,7 @@ module OpenAI
|
|
|
147
152
|
attr_reader :idempotency_header
|
|
148
153
|
|
|
149
154
|
# @api private
|
|
150
|
-
sig { returns(
|
|
155
|
+
sig { returns(T.untyped) }
|
|
151
156
|
attr_reader :requester
|
|
152
157
|
|
|
153
158
|
# @api private
|
|
@@ -169,7 +174,8 @@ module OpenAI
|
|
|
169
174
|
)
|
|
170
175
|
)
|
|
171
176
|
],
|
|
172
|
-
idempotency_header: T.nilable(String)
|
|
177
|
+
idempotency_header: T.nilable(String),
|
|
178
|
+
http_client: T.untyped
|
|
173
179
|
).returns(T.attached_class)
|
|
174
180
|
end
|
|
175
181
|
def self.new(
|
|
@@ -179,7 +185,8 @@ module OpenAI
|
|
|
179
185
|
initial_retry_delay: 0.0,
|
|
180
186
|
max_retry_delay: 0.0,
|
|
181
187
|
headers: {},
|
|
182
|
-
idempotency_header: nil
|
|
188
|
+
idempotency_header: nil,
|
|
189
|
+
http_client: nil
|
|
183
190
|
)
|
|
184
191
|
end
|
|
185
192
|
|
|
@@ -223,6 +230,15 @@ module OpenAI
|
|
|
223
230
|
private def build_request(req, opts)
|
|
224
231
|
end
|
|
225
232
|
|
|
233
|
+
# @api private
|
|
234
|
+
sig do
|
|
235
|
+
params(
|
|
236
|
+
request: OpenAI::Internal::Transport::BaseClient::RequestInput
|
|
237
|
+
).returns(T::Boolean)
|
|
238
|
+
end
|
|
239
|
+
private def request_replayable?(request)
|
|
240
|
+
end
|
|
241
|
+
|
|
226
242
|
# @api private
|
|
227
243
|
sig do
|
|
228
244
|
params(
|
|
@@ -239,7 +255,7 @@ module OpenAI
|
|
|
239
255
|
url: URI::Generic,
|
|
240
256
|
status: Integer,
|
|
241
257
|
headers: T::Hash[String, String],
|
|
242
|
-
response:
|
|
258
|
+
response: OpenAI::HTTPClient::Response,
|
|
243
259
|
stream: T::Enumerable[String]
|
|
244
260
|
).returns(T.noreturn)
|
|
245
261
|
end
|
|
@@ -259,7 +275,7 @@ module OpenAI
|
|
|
259
275
|
redirect_count: Integer,
|
|
260
276
|
retry_count: Integer,
|
|
261
277
|
send_retry_header: T::Boolean
|
|
262
|
-
).returns(
|
|
278
|
+
).returns(OpenAI::HTTPClient::Response)
|
|
263
279
|
end
|
|
264
280
|
def send_request(
|
|
265
281
|
request,
|
|
@@ -253,46 +253,6 @@ module OpenAI
|
|
|
253
253
|
end
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
-
# @api private
|
|
257
|
-
#
|
|
258
|
-
# An adapter that satisfies the IO interface required by `::IO.copy_stream`
|
|
259
|
-
class ReadIOAdapter
|
|
260
|
-
# @api private
|
|
261
|
-
sig { returns(T.nilable(T::Boolean)) }
|
|
262
|
-
def close?
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
# @api private
|
|
266
|
-
sig { void }
|
|
267
|
-
def close
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# @api private
|
|
271
|
-
sig { params(max_len: T.nilable(Integer)).returns(String) }
|
|
272
|
-
private def read_enum(max_len)
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
# @api private
|
|
276
|
-
sig do
|
|
277
|
-
params(
|
|
278
|
-
max_len: T.nilable(Integer),
|
|
279
|
-
out_string: T.nilable(String)
|
|
280
|
-
).returns(T.nilable(String))
|
|
281
|
-
end
|
|
282
|
-
def read(max_len = nil, out_string = nil)
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
# @api private
|
|
286
|
-
sig do
|
|
287
|
-
params(
|
|
288
|
-
src: T.any(String, Pathname, StringIO, T::Enumerable[String]),
|
|
289
|
-
blk: T.proc.params(arg0: String).void
|
|
290
|
-
).returns(T.attached_class)
|
|
291
|
-
end
|
|
292
|
-
def self.new(src, &blk)
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
256
|
class << self
|
|
297
257
|
sig do
|
|
298
258
|
params(blk: T.proc.params(y: Enumerator::Yielder).void).returns(
|