ruby_llm-responses_api 0.6.0 → 1.0.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 (26) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/MIGRATION.md +276 -0
  4. data/README.md +42 -32
  5. data/lib/ruby_llm/providers/openai_responses/active_record_extension.rb +12 -109
  6. data/lib/ruby_llm/providers/openai_responses/base.rb +2 -7
  7. data/lib/ruby_llm/providers/openai_responses/batch.rb +8 -8
  8. data/lib/ruby_llm/providers/openai_responses/batches.rb +6 -14
  9. data/lib/ruby_llm/providers/openai_responses/built_in_tools.rb +1 -1
  10. data/lib/ruby_llm/providers/openai_responses/chat_extension.rb +3 -12
  11. data/lib/ruby_llm/providers/openai_responses/compaction.rb +1 -1
  12. data/lib/ruby_llm/providers/openai_responses/message_extension.rb +11 -21
  13. data/lib/ruby_llm/providers/openai_responses/model_registry.rb +17 -261
  14. data/lib/ruby_llm/providers/openai_responses/protocol.rb +103 -0
  15. data/lib/ruby_llm/providers/openai_responses/stream_accumulator.rb +48 -0
  16. data/lib/ruby_llm/providers/openai_responses/web_socket.rb +51 -77
  17. data/lib/ruby_llm/providers/openai_responses.rb +29 -65
  18. data/lib/rubyllm_responses_api.rb +13 -46
  19. metadata +17 -18
  20. data/lib/ruby_llm/providers/openai_responses/capabilities.rb +0 -263
  21. data/lib/ruby_llm/providers/openai_responses/chat.rb +0 -273
  22. data/lib/ruby_llm/providers/openai_responses/media.rb +0 -95
  23. data/lib/ruby_llm/providers/openai_responses/models.rb +0 -48
  24. data/lib/ruby_llm/providers/openai_responses/stream_accumulator_extension.rb +0 -39
  25. data/lib/ruby_llm/providers/openai_responses/streaming.rb +0 -137
  26. data/lib/ruby_llm/providers/openai_responses/tools.rb +0 -222
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ class OpenAIResponses
6
+ # Native Responses rendering/parsing, with state scoped to this provider.
7
+ class Protocol < OpenAI::Responses
8
+ def render(messages, provider_options: {}, **)
9
+ @response_options = RubyLLM::Support::Utils.deep_symbolize_keys(provider_options)
10
+ payload = super(messages, provider_options: @response_options.except(:transport), **)
11
+ @store_response = payload[:store] != false
12
+ payload
13
+ end
14
+
15
+ def render_payload(messages, **)
16
+ state = @response_options || {}
17
+ parent = if state.key?(:previous_response_id)
18
+ state[:previous_response_id]
19
+ elsif state[:store] != false
20
+ messages.rfind { |message| message.role == :assistant && message.response_id }&.response_id
21
+ end
22
+ payload = super(new_messages(messages, parent), **)
23
+ payload[:store] = state.fetch(:store, true)
24
+ payload[:previous_response_id] = parent if parent
25
+ payload
26
+ end
27
+
28
+ def apply_compaction(payload, compaction)
29
+ warn_ignored_compaction_options(compaction)
30
+ entry = { type: 'compaction' }
31
+ entry[:compact_threshold] = compaction[:at] if compaction[:at]
32
+ payload.merge(context_management: [entry])
33
+ end
34
+
35
+ def apply_end_user(payload, identifier)
36
+ payload.merge(safety_identifier: identifier)
37
+ end
38
+
39
+ def supports_provider_file_references?
40
+ true
41
+ end
42
+
43
+ def parse_completion_body(data, raw:)
44
+ decorate_message(super, data)
45
+ end
46
+
47
+ def build_final_chunk(data)
48
+ decorate_message(super, data.fetch('response', {}))
49
+ end
50
+
51
+ # Public event entry point for the standalone WebSocket client.
52
+ def parse_event(data)
53
+ build_chunk(data)
54
+ end
55
+
56
+ def stream_response(payload, additional_headers = {})
57
+ accumulator = StreamAccumulator.new
58
+ response = stream_events(stream_url, payload, additional_headers) do |data|
59
+ chunk = build_chunk(data)
60
+ accumulator.add(chunk)
61
+ yield chunk
62
+ end
63
+ accumulator.to_message(response)
64
+ end
65
+
66
+ def stream_events(url, payload, additional_headers = {}, &)
67
+ return super unless websocket?
68
+
69
+ @usage_tracker&.start
70
+ @provider.responses_websocket(additional_headers).stream_events(payload, &)
71
+ end
72
+
73
+ def sync_response(payload, additional_headers = {})
74
+ return super unless websocket?
75
+
76
+ stream_response(payload, additional_headers) { |chunk| @usage_tracker&.observe(chunk) }
77
+ end
78
+
79
+ private
80
+
81
+ def websocket?
82
+ @response_options && @response_options[:transport]&.to_sym == :websocket
83
+ end
84
+
85
+ def new_messages(messages, parent)
86
+ return messages unless parent
87
+
88
+ anchor = messages.rindex { |message| message.role == :assistant && message.response_id == parent }
89
+ return messages unless anchor
90
+
91
+ messages.each_with_index.filter_map { |message, index| message if message.role == :system || index > anchor }
92
+ end
93
+
94
+ def decorate_message(message, data)
95
+ message.response_id = data['id'] unless @store_response == false || data['store'] == false
96
+ message.built_in_tool_events = BuiltInTools.extract_events(data['output'] || [])
97
+ message.responses_api_body = data
98
+ message
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ class OpenAIResponses
6
+ # Extends the native stream accumulator to carry built_in_tool_events and
7
+ # response_id from chunks through to the final assembled Message.
8
+ # Without this the accumulator drops everything off the Chunk it does
9
+ # not know about — including response_id, which breaks
10
+ # previous_response_id chaining on the next turn for any streamed chat.
11
+ class StreamAccumulator < RubyLLM::Protocol::StreamAccumulator
12
+ def add(chunk)
13
+ super
14
+ @response_id = chunk.response_id if chunk.respond_to?(:response_id) && chunk.response_id
15
+
16
+ @responses_api_body = chunk.responses_api_body if chunk.responses_api_body
17
+ events = chunk_built_in_events(chunk)
18
+ return if events.nil? || events.empty?
19
+
20
+ @built_in_tool_events ||= []
21
+ @built_in_tool_events.concat(events)
22
+ end
23
+
24
+ def to_message(response)
25
+ if @responses_api_body
26
+ # A completed stream supplies the same response object as a sync call.
27
+ response = Faraday::Response.new(status: response&.status || 200,
28
+ response_headers: response&.headers || {}, body: @responses_api_body)
29
+ end
30
+ message = super
31
+ if @built_in_tool_events && !@built_in_tool_events.empty? && message.respond_to?(:built_in_tool_events=)
32
+ message.built_in_tool_events = @built_in_tool_events
33
+ end
34
+ message.response_id = @response_id if @response_id && message.respond_to?(:response_id=)
35
+ message
36
+ end
37
+
38
+ private
39
+
40
+ def chunk_built_in_events(chunk)
41
+ return nil unless chunk.respond_to?(:built_in_tool_events)
42
+
43
+ chunk.built_in_tool_events
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -13,7 +13,7 @@ module RubyLLM
13
13
  #
14
14
  # Integrated usage (recommended):
15
15
  # chat = RubyLLM.chat(model: 'gpt-4o', provider: :openai_responses)
16
- # chat.with_params(transport: :websocket)
16
+ # chat.with_provider_options(transport: :websocket)
17
17
  # chat.ask("Hello!")
18
18
  #
19
19
  # Standalone usage (advanced):
@@ -34,15 +34,16 @@ module RubyLLM
34
34
  # @param project_id [String, nil] OpenAI project ID
35
35
  # @param client_class [#connect, nil] WebSocket client class (for testing)
36
36
  # @param response_timeout [Numeric] seconds to wait for a response event
37
- # rubocop:disable Metrics/ParameterLists
37
+ # rubocop:disable-next Metrics/ParameterLists
38
38
  def initialize(api_key:, api_base: 'https://api.openai.com/v1', organization_id: nil, project_id: nil,
39
- client_class: nil, response_timeout: 60)
39
+ client_class: nil, response_timeout: 60, headers: {})
40
40
  @api_key = api_key
41
41
  @api_base = api_base
42
42
  @organization_id = organization_id
43
43
  @project_id = project_id
44
44
  @client_class = client_class
45
45
  @response_timeout = response_timeout
46
+ @headers = headers
46
47
 
47
48
  @ws = nil
48
49
  @mutex = Mutex.new
@@ -51,7 +52,6 @@ module RubyLLM
51
52
  @last_response_id = nil
52
53
  @message_queue = nil
53
54
  end
54
- # rubocop:enable Metrics/ParameterLists
55
55
 
56
56
  # Open the WebSocket connection. Blocks until the connection is established.
57
57
  # @param timeout [Numeric] seconds to wait for the connection (default: 10)
@@ -96,19 +96,43 @@ module RubyLLM
96
96
  # @param payload [Hash] Responses API payload (model, input, tools, etc.)
97
97
  # @yield [RubyLLM::Chunk] each streamed chunk
98
98
  # @return [RubyLLM::Message] the assembled final message
99
- def call(payload, &)
99
+ def call(payload)
100
+ config = RubyLLM.config.dup
101
+ config.openai_api_key = @api_key
102
+ provider = OpenAIResponses.new(config)
103
+ protocol = Protocol.new(provider)
104
+ accumulator = StreamAccumulator.new
105
+ stream_events(payload) do |data|
106
+ chunk = protocol.parse_event(data)
107
+ chunk.response_id = nil if payload[:store] == false
108
+ accumulator.add(chunk)
109
+ yield chunk if block_given?
110
+ end
111
+ accumulator.to_message(nil)
112
+ end
113
+
114
+ # Shared by the standalone client and the native RubyLLM protocol.
115
+ def stream_events(payload)
100
116
  ensure_connected!
101
117
  acquire_flight!
102
-
118
+ acquired = true
103
119
  queue = Queue.new
104
120
  @mutex.synchronize { @message_queue = queue }
121
+ send_json({ type: 'response.create' }.merge(payload.except(:stream)))
122
+
123
+ loop do
124
+ data = next_event(queue)
125
+ yield data
126
+ next unless %w[response.completed response.incomplete].include?(data['type'])
105
127
 
106
- envelope = { type: 'response.create' }.merge(payload.except(:stream))
107
- send_json(envelope)
108
- accumulate_response(queue, &)
128
+ @last_response_id = payload[:store] == false ? nil : data.dig('response', 'id')
129
+ return nil
130
+ end
109
131
  ensure
110
- @mutex.synchronize { @message_queue = nil }
111
- release_flight!
132
+ if acquired
133
+ @mutex.synchronize { @message_queue = nil }
134
+ release_flight!
135
+ end
112
136
  end
113
137
 
114
138
  # Send a response.create request using raw Responses API format.
@@ -122,14 +146,14 @@ module RubyLLM
122
146
  # @param extra [Hash] additional fields forwarded to the API
123
147
  # @yield [RubyLLM::Chunk] each streamed chunk
124
148
  # @return [RubyLLM::Message] the assembled final message
125
- def create_response(model:, input:, tools: nil, previous_response_id: nil, instructions: nil, **extra, &block) # rubocop:disable Metrics/ParameterLists
149
+ def create_response(model:, input:, tools: nil, previous_response_id: nil, instructions: nil, **extra, &) # rubocop:disable Metrics/ParameterLists
126
150
  payload = build_standalone_payload(
127
151
  model: model, input: input, tools: tools,
128
152
  previous_response_id: previous_response_id,
129
153
  instructions: instructions, **extra
130
154
  )
131
155
 
132
- call(payload, &block)
156
+ call(payload, &)
133
157
  end
134
158
 
135
159
  # Warm up the connection by sending a response.create with generate: false.
@@ -138,33 +162,7 @@ module RubyLLM
138
162
  # @param extra [Hash] additional fields
139
163
  # @return [void]
140
164
  def warmup(model:, **extra)
141
- ensure_connected!
142
- acquire_flight!
143
-
144
- queue = Queue.new
145
- @mutex.synchronize { @message_queue = queue }
146
-
147
- payload = { type: 'response.create', model: model, generate: false }.merge(extra)
148
-
149
- send_json(payload)
150
-
151
- loop do
152
- data = queue.pop
153
- break if data.nil?
154
-
155
- parsed = JSON.parse(data)
156
- event_type = parsed['type']
157
-
158
- if event_type == 'error'
159
- error_msg = parsed.dig('error', 'message') || 'Warmup error'
160
- raise ResponseError, error_msg
161
- end
162
-
163
- break if event_type == 'response.completed'
164
- end
165
- ensure
166
- @mutex.synchronize { @message_queue = nil }
167
- release_flight!
165
+ stream_events({ model: model, generate: false }.merge(extra)) { |_event| nil }
168
166
  end
169
167
 
170
168
  # Disconnect the WebSocket.
@@ -226,13 +224,13 @@ module RubyLLM
226
224
  }
227
225
  headers['OpenAI-Organization'] = @organization_id if @organization_id
228
226
  headers['OpenAI-Project'] = @project_id if @project_id
229
- headers
227
+ headers.merge(@headers)
230
228
  end
231
229
 
232
230
  def build_standalone_payload(model:, input:, tools: nil, previous_response_id: nil, instructions: nil, **extra) # rubocop:disable Metrics/ParameterLists
233
- prev_id = previous_response_id || @last_response_id
231
+ prev_id = previous_response_id || (@last_response_id unless extra[:store] == false)
234
232
  response = { model: model, input: input }
235
- response[:tools] = tools.map { |t| Tools.tool_for(t) } if tools&.any?
233
+ response[:tools] = tools if tools&.any?
236
234
  response[:previous_response_id] = prev_id if prev_id
237
235
  response[:instructions] = instructions if instructions
238
236
 
@@ -247,43 +245,19 @@ module RubyLLM
247
245
  @ws.send(JSON.generate(payload))
248
246
  end
249
247
 
250
- def accumulate_response(queue, &block)
251
- accumulator = StreamAccumulator.new
252
- built_in_events = []
253
-
254
- loop do
255
- raw = pop_response_event(queue)
256
- if raw == RESPONSE_TIMEOUT
257
- raise ConnectionError, "Timed out waiting for WebSocket response after #{@response_timeout} seconds"
258
- end
259
-
260
- break if raw.nil?
261
-
262
- data = JSON.parse(raw)
263
- event_type = data['type']
264
-
265
- chunk = Streaming.build_chunk(data)
266
- accumulator.add(chunk)
267
- block&.call(chunk)
268
-
269
- next unless event_type == 'response.completed'
270
-
271
- track_response_id(data)
272
- built_in_events.concat(BuiltInTools.extract_events(data.dig('response', 'output') || []))
273
- break
248
+ def next_event(queue)
249
+ raw = pop_response_event(queue)
250
+ if raw == RESPONSE_TIMEOUT
251
+ raise ConnectionError, "Timed out waiting for WebSocket response after #{@response_timeout} seconds"
274
252
  end
253
+ raise ConnectionError, 'WebSocket closed before the response completed' if raw.nil?
275
254
 
276
- message = accumulator.to_message(nil)
277
- message.response_id = @last_response_id
278
- if message.respond_to?(:built_in_tool_events=) && built_in_events.any?
279
- message.built_in_tool_events = built_in_events
255
+ data = JSON.parse(raw)
256
+ if %w[error response.failed].include?(data['type'])
257
+ error = data['error'] || data.dig('response', 'error') || data
258
+ raise RubyLLM::Error, error['message'] || 'WebSocket response failed'
280
259
  end
281
- message
282
- end
283
-
284
- def track_response_id(data)
285
- resp_id = data.dig('response', 'id')
286
- @mutex.synchronize { @last_response_id = resp_id } if resp_id
260
+ data
287
261
  end
288
262
 
289
263
  def ensure_connected!
@@ -6,36 +6,11 @@ module RubyLLM
6
6
  # Implements the new Responses API which provides built-in tools,
7
7
  # stateful conversations, background mode, and MCP support.
8
8
  class OpenAIResponses
9
- include OpenAIResponses::Chat
10
- include OpenAIResponses::Streaming
11
- include OpenAIResponses::Tools
12
- include OpenAIResponses::Models
13
- include OpenAIResponses::Media
14
-
15
- def api_base
16
- @config.openai_api_base || 'https://api.openai.com/v1'
17
- end
18
-
19
- # Override to support WebSocket transport via with_params(transport: :websocket).
20
- # rubocop:disable Metrics/ParameterLists
21
- def complete(messages, tools:, temperature:, model:, params: {}, headers: {},
22
- schema: nil, thinking: nil, tool_prefs: nil, &block)
23
- if params[:transport]&.to_sym == :websocket
24
- ws_complete(messages, tools: tools, temperature: temperature, model: model,
25
- params: params.except(:transport), schema: schema,
26
- thinking: thinking, &block)
27
- else
28
- super
29
- end
30
- end
31
- # rubocop:enable Metrics/ParameterLists
9
+ protocol :responses, OpenAIResponses::Protocol, batches: Protocols::Responses::Batches
10
+ protocol :files, Protocols::OpenAI::Files
32
11
 
33
- def headers
34
- {
35
- 'Authorization' => "Bearer #{@config.openai_api_key}",
36
- 'OpenAI-Organization' => @config.openai_organization_id,
37
- 'OpenAI-Project' => @config.openai_project_id
38
- }.compact
12
+ def protocol_for(_model, **)
13
+ protocols.fetch(:responses)
39
14
  end
40
15
 
41
16
  # Retrieve a stored response by ID
@@ -185,56 +160,45 @@ module RubyLLM
185
160
  response.body
186
161
  end
187
162
 
188
- private
189
-
190
- def ws_complete(messages, tools:, temperature:, model:, params:, schema:, thinking:, &block) # rubocop:disable Metrics/ParameterLists
191
- normalized_temperature = maybe_normalize_temperature(temperature, model)
192
-
193
- payload = Utils.deep_merge(
194
- render_payload(
195
- messages,
196
- tools: tools,
197
- temperature: normalized_temperature,
198
- model: model,
199
- stream: true,
200
- schema: schema,
201
- thinking: thinking
202
- ),
203
- params
204
- )
205
-
206
- ws_connection.connect unless ws_connection.connected?
207
- ws_connection.call(payload, &block)
208
- end
209
-
210
- def ws_connection
163
+ # Headers are part of the handshake, so a changed set uses a new connection.
164
+ def responses_websocket(additional_headers = {})
165
+ if @ws_connection && @ws_headers != additional_headers
166
+ @ws_connection.disconnect
167
+ @ws_connection = nil
168
+ end
169
+ @ws_headers = additional_headers.dup
211
170
  @ws_connection ||= WebSocket.new(
212
- api_key: @config.openai_api_key,
213
- api_base: api_base,
214
- organization_id: @config.openai_organization_id,
215
- project_id: @config.openai_project_id
171
+ api_key: @config.openai_api_key, api_base: api_base,
172
+ organization_id: @config.openai_organization_id, project_id: @config.openai_project_id,
173
+ headers: additional_headers
216
174
  )
175
+ @ws_connection.connect unless @ws_connection.connected?
176
+ @ws_connection
217
177
  end
218
178
 
219
- # DELETE request via the underlying Faraday connection
220
- # RubyLLM::Connection only exposes get/post, so we use Faraday directly
179
+ private
180
+
221
181
  def delete_request(url)
222
- @connection.connection.delete(url) do |req|
223
- req.headers.merge!(headers)
224
- end
182
+ @connection.delete(url)
225
183
  end
226
184
 
227
185
  class << self
228
- def capabilities
229
- OpenAIResponses::Capabilities
186
+ def configuration_options
187
+ %i[
188
+ openai_api_key
189
+ openai_api_base
190
+ openai_organization_id
191
+ openai_project_id
192
+ ]
230
193
  end
231
194
 
232
195
  def configuration_requirements
233
196
  %i[openai_api_key]
234
197
  end
235
198
 
236
- def slug
237
- 'openai_responses'
199
+ def models_dev_alias(model_id, models, provider_model = nil)
200
+ source = models["openai:#{model_id}"] || super
201
+ source && RubyLLM::Model.new(source.to_h.merge(provider: 'openai_responses'))
238
202
  end
239
203
  end
240
204
  end
@@ -1,49 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ruby_llm'
4
-
5
- # Provider class must be loaded first to define the class
6
4
  require_relative 'ruby_llm/providers/openai_responses/base'
7
5
 
8
- # Core modules
9
- require_relative 'ruby_llm/providers/openai_responses/capabilities'
10
- require_relative 'ruby_llm/providers/openai_responses/media'
11
- require_relative 'ruby_llm/providers/openai_responses/tools'
12
- require_relative 'ruby_llm/providers/openai_responses/models'
13
- require_relative 'ruby_llm/providers/openai_responses/streaming'
14
- require_relative 'ruby_llm/providers/openai_responses/chat'
15
-
16
- # Advanced features
17
- require_relative 'ruby_llm/providers/openai_responses/built_in_tools'
18
- require_relative 'ruby_llm/providers/openai_responses/state'
19
- require_relative 'ruby_llm/providers/openai_responses/background'
20
- require_relative 'ruby_llm/providers/openai_responses/compaction'
21
- require_relative 'ruby_llm/providers/openai_responses/containers'
22
- require_relative 'ruby_llm/providers/openai_responses/batches'
23
- require_relative 'ruby_llm/providers/openai_responses/batch'
24
- require_relative 'ruby_llm/providers/openai_responses/message_extension'
25
- require_relative 'ruby_llm/providers/openai_responses/stream_accumulator_extension'
26
- require_relative 'ruby_llm/providers/openai_responses/chat_extension'
27
- require_relative 'ruby_llm/providers/openai_responses/model_registry'
28
- require_relative 'ruby_llm/providers/openai_responses/active_record_extension'
29
- require_relative 'ruby_llm/providers/openai_responses/web_socket'
30
-
31
- # Include all modules in the provider class
6
+ %w[
7
+ built_in_tools state background compaction containers message_extension
8
+ stream_accumulator chat_extension model_registry active_record_extension
9
+ protocol web_socket batches batch
10
+ ].each { |name| require_relative "ruby_llm/providers/openai_responses/#{name}" }
32
11
  require_relative 'ruby_llm/providers/openai_responses'
33
12
 
34
- # Register the provider
35
13
  RubyLLM::Provider.register :openai_responses, RubyLLM::Providers::OpenAIResponses
36
14
 
37
- # Register models for this provider
38
- RubyLLM::Providers::OpenAIResponses::ModelRegistry.register_all!
39
-
40
- # Extend RubyLLM module with ResponsesAPI namespace
41
15
  module RubyLLM
42
- # ResponsesAPI namespace for direct access to helpers and version
16
+ # Responses-specific helpers. RubyLLM's native batch factory is unchanged.
43
17
  module ResponsesAPI
44
- VERSION = '0.6.0'
18
+ VERSION = '1.0.0'
45
19
 
46
- # Shorthand access to built-in tool helpers
47
20
  BuiltInTools = Providers::OpenAIResponses::BuiltInTools
48
21
  State = Providers::OpenAIResponses::State
49
22
  Background = Providers::OpenAIResponses::Background
@@ -52,19 +25,13 @@ module RubyLLM
52
25
  Batches = Providers::OpenAIResponses::Batches
53
26
  Batch = Providers::OpenAIResponses::Batch
54
27
  WebSocket = Providers::OpenAIResponses::WebSocket
55
- end
56
-
57
- # Create a new Batch for bulk request processing
58
- def self.batch(...)
59
- Providers::OpenAIResponses::Batch.new(...)
60
- end
61
28
 
62
- # List existing batches
63
- def self.batches(provider: :openai_responses, **kwargs)
64
- slug = provider.to_sym
65
- provider_class = Provider.providers[slug]
66
- raise Error.new(nil, "Unknown provider: #{slug}") unless provider_class
29
+ def self.batch(...)
30
+ Batch.new(...)
31
+ end
67
32
 
68
- provider_class.new(config).list_batches(**kwargs)
33
+ def self.batches(provider: :openai_responses, **)
34
+ RubyLLM::Provider.resolve!(provider).new(RubyLLM.config).list_batches(**)
35
+ end
69
36
  end
70
37
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm-responses_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hasinski
@@ -13,16 +13,16 @@ dependencies:
13
13
  name: ruby_llm
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
16
+ - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.13'
18
+ version: 2.1.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - ">="
23
+ - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.13'
25
+ version: 2.1.1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activerecord
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -83,16 +83,16 @@ dependencies:
83
83
  name: sqlite3
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '1.4'
88
+ version: 2.9.5
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: '1.4'
95
+ version: 2.9.5
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: vcr
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -147,6 +147,7 @@ extra_rdoc_files: []
147
147
  files:
148
148
  - CHANGELOG.md
149
149
  - LICENSE.txt
150
+ - MIGRATION.md
150
151
  - README.md
151
152
  - lib/ruby_llm-responses_api.rb
152
153
  - lib/ruby_llm/providers/openai_responses.rb
@@ -156,19 +157,14 @@ files:
156
157
  - lib/ruby_llm/providers/openai_responses/batch.rb
157
158
  - lib/ruby_llm/providers/openai_responses/batches.rb
158
159
  - lib/ruby_llm/providers/openai_responses/built_in_tools.rb
159
- - lib/ruby_llm/providers/openai_responses/capabilities.rb
160
- - lib/ruby_llm/providers/openai_responses/chat.rb
161
160
  - lib/ruby_llm/providers/openai_responses/chat_extension.rb
162
161
  - lib/ruby_llm/providers/openai_responses/compaction.rb
163
162
  - lib/ruby_llm/providers/openai_responses/containers.rb
164
- - lib/ruby_llm/providers/openai_responses/media.rb
165
163
  - lib/ruby_llm/providers/openai_responses/message_extension.rb
166
164
  - lib/ruby_llm/providers/openai_responses/model_registry.rb
167
- - lib/ruby_llm/providers/openai_responses/models.rb
165
+ - lib/ruby_llm/providers/openai_responses/protocol.rb
168
166
  - lib/ruby_llm/providers/openai_responses/state.rb
169
- - lib/ruby_llm/providers/openai_responses/stream_accumulator_extension.rb
170
- - lib/ruby_llm/providers/openai_responses/streaming.rb
171
- - lib/ruby_llm/providers/openai_responses/tools.rb
167
+ - lib/ruby_llm/providers/openai_responses/stream_accumulator.rb
172
168
  - lib/ruby_llm/providers/openai_responses/web_socket.rb
173
169
  - lib/rubyllm_responses_api.rb
174
170
  homepage: https://github.com/khasinski/ruby_llm-responses_api
@@ -186,14 +182,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
182
  requirements:
187
183
  - - ">="
188
184
  - !ruby/object:Gem::Version
189
- version: 3.1.0
185
+ version: '4.0'
186
+ - - "<"
187
+ - !ruby/object:Gem::Version
188
+ version: '5.0'
190
189
  required_rubygems_version: !ruby/object:Gem::Requirement
191
190
  requirements:
192
191
  - - ">="
193
192
  - !ruby/object:Gem::Version
194
193
  version: '0'
195
194
  requirements: []
196
- rubygems_version: 3.6.9
195
+ rubygems_version: 4.0.20
197
196
  specification_version: 4
198
197
  summary: OpenAI Responses API provider for RubyLLM
199
198
  test_files: []