openai 0.115.1 → 0.116.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 +19 -0
- data/README.md +1 -1
- data/lib/openai/helpers/responses_websocket/incremental.rb +500 -154
- data/lib/openai/helpers/responses_websocket/session.rb +75 -2
- data/lib/openai/models/live/responses_delegation_config.rb +999 -6
- data/lib/openai/models/live/responses_delegation_update_config.rb +1043 -6
- data/lib/openai/version.rb +1 -1
- data/rbi/openai/helpers/responses_websocket/incremental.rbi +4 -0
- data/rbi/openai/models/live/responses_delegation_config.rbi +2253 -24
- data/rbi/openai/models/live/responses_delegation_update_config.rbi +2327 -24
- data/responses-websocket.md +40 -2
- data/sig/openai/helpers/responses_websocket/incremental.rbs +1 -0
- data/sig/openai/models/live/responses_delegation_config.rbs +851 -0
- data/sig/openai/models/live/responses_delegation_update_config.rbs +871 -0
- metadata +1 -1
|
@@ -146,6 +146,7 @@ module OpenAI
|
|
|
146
146
|
@in_flight = false
|
|
147
147
|
@pending_steers = pending_steers
|
|
148
148
|
@response_id = nil
|
|
149
|
+
@required_input = {}
|
|
149
150
|
@changed = Async::Condition.new
|
|
150
151
|
@accumulator = SessionAccumulator.new(session.limits.max_response_bytes)
|
|
151
152
|
end
|
|
@@ -169,7 +170,9 @@ module OpenAI
|
|
|
169
170
|
end
|
|
170
171
|
|
|
171
172
|
pending = @pending_steers[@response_id]
|
|
172
|
-
if @in_flight ||
|
|
173
|
+
if @in_flight ||
|
|
174
|
+
queued_response ||
|
|
175
|
+
(pending && pending[:count].positive? && !required_input_continuation?(data))
|
|
173
176
|
raise SessionError, "Consume the current response before sending another create on this lane."
|
|
174
177
|
end
|
|
175
178
|
|
|
@@ -244,9 +247,15 @@ module OpenAI
|
|
|
244
247
|
@in_flight = true
|
|
245
248
|
@pending_steers.delete(@response_id) if @response_id != event.response.id
|
|
246
249
|
@response_id = event.response.id.dup.freeze
|
|
250
|
+
@required_input.clear
|
|
247
251
|
elsif %w[response.completed response.failed response.incomplete error].include?(event.type.to_s)
|
|
248
252
|
@in_flight = false
|
|
249
|
-
|
|
253
|
+
if event.type.to_s == "error"
|
|
254
|
+
@required_input.clear
|
|
255
|
+
else
|
|
256
|
+
@required_input = required_input_keys(@accumulator.final_response&.output || [])
|
|
257
|
+
@response_id = event.response.id.dup.freeze
|
|
258
|
+
end
|
|
250
259
|
end
|
|
251
260
|
end
|
|
252
261
|
|
|
@@ -262,6 +271,69 @@ module OpenAI
|
|
|
262
271
|
end
|
|
263
272
|
end
|
|
264
273
|
|
|
274
|
+
private def required_input_continuation?(data)
|
|
275
|
+
return false unless data[:previous_response_id] == @response_id
|
|
276
|
+
|
|
277
|
+
input = data[:input]
|
|
278
|
+
return false unless input.is_a?(Array) && !input.empty?
|
|
279
|
+
|
|
280
|
+
keys = input.map do |item|
|
|
281
|
+
return false unless item.is_a?(Hash)
|
|
282
|
+
|
|
283
|
+
required_input_key(item)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
keys.uniq.length == keys.length && keys.all? { |key| @required_input.key?(key) }
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
private def required_input_key(data)
|
|
290
|
+
type = data[:type].to_s
|
|
291
|
+
id = case type
|
|
292
|
+
when
|
|
293
|
+
"function_call_output",
|
|
294
|
+
"custom_tool_call_output",
|
|
295
|
+
"computer_call_output",
|
|
296
|
+
"shell_call_output",
|
|
297
|
+
"apply_patch_call_output"
|
|
298
|
+
data[:call_id]
|
|
299
|
+
when "tool_search_output"
|
|
300
|
+
data[:call_id] if data[:execution].to_s == "client"
|
|
301
|
+
when "mcp_approval_response"
|
|
302
|
+
data[:approval_request_id]
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
[type, id] if id.is_a?(String) && !id.empty?
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
private def required_input_keys(items)
|
|
309
|
+
required = {}
|
|
310
|
+
items.each do |item|
|
|
311
|
+
data = item.to_h
|
|
312
|
+
type = data[:type].to_s
|
|
313
|
+
next if type != "mcp_approval_request" && data[:status] && data[:status].to_s != "completed"
|
|
314
|
+
|
|
315
|
+
result_type = case type
|
|
316
|
+
when "function_call", "custom_tool_call", "computer_call", "apply_patch_call"
|
|
317
|
+
"#{type}_output"
|
|
318
|
+
when "shell_call"
|
|
319
|
+
"shell_call_output" if data[:environment].to_h[:type].to_s == "local"
|
|
320
|
+
when "tool_search_call"
|
|
321
|
+
"tool_search_output" if data[:execution].to_s == "client"
|
|
322
|
+
when "mcp_approval_request"
|
|
323
|
+
"mcp_approval_response"
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
next unless result_type
|
|
327
|
+
|
|
328
|
+
id = data[type == "mcp_approval_request" ? :id : :call_id]
|
|
329
|
+
# Retain only detached IDs when get_final_response releases its collector.
|
|
330
|
+
required[[result_type, id.dup.freeze]] = true if id.is_a?(String) && !id.empty?
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
items.each { |item| required.delete(required_input_key(item.to_h)) }
|
|
334
|
+
required
|
|
335
|
+
end
|
|
336
|
+
|
|
265
337
|
def get_final_response
|
|
266
338
|
@session.assert_owner!
|
|
267
339
|
loop do
|
|
@@ -306,6 +378,7 @@ module OpenAI
|
|
|
306
378
|
@queue.clear
|
|
307
379
|
@bytes = 0
|
|
308
380
|
@accumulator = SessionAccumulator.new(@session.limits.max_response_bytes)
|
|
381
|
+
@required_input.clear
|
|
309
382
|
@changed.signal
|
|
310
383
|
end
|
|
311
384
|
|