Class: OpenRouter::Client

Inherits:
Object
  • Object
show all
Includes:
HTTP
Defined in:
lib/open_router/client.rb

Direct Known Subclasses

StreamingClient

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HTTP

#delete, #get, #multipart_post, #post

Constructor Details

#initialize(access_token: nil, request_timeout: nil, uri_base: nil, extra_headers: {}, track_usage: true) {|OpenRouter.configuration| ... } ⇒ Client

Initializes the client with optional configurations.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/open_router/client.rb', line 18

def initialize(access_token: nil, request_timeout: nil, uri_base: nil, extra_headers: {}, track_usage: true)
  OpenRouter.configuration.access_token = access_token if access_token
  OpenRouter.configuration.request_timeout = request_timeout if request_timeout
  OpenRouter.configuration.uri_base = uri_base if uri_base
  OpenRouter.configuration.extra_headers = extra_headers if extra_headers.any?
  yield(OpenRouter.configuration) if block_given?

  # Instance-level tracking of capability warnings to avoid memory leaks
  @capability_warnings_shown = Set.new

  # Initialize callback system
  @callbacks = {
    before_request: [],
    after_response: [],
    on_tool_call: [],
    on_error: [],
    on_stream_chunk: [],
    on_healing: []
  }

  # Initialize usage tracking
  @track_usage = track_usage
  @usage_tracker = UsageTracker.new if @track_usage
end

Instance Attribute Details

#callbacksObject (readonly)

Returns the value of attribute callbacks.



15
16
17
# File 'lib/open_router/client.rb', line 15

def callbacks
  @callbacks
end

#usage_trackerObject (readonly)

Returns the value of attribute usage_tracker.



15
16
17
# File 'lib/open_router/client.rb', line 15

def usage_tracker
  @usage_tracker
end

Instance Method Details

#clear_callbacks(event = nil) ⇒ self

Remove all callbacks for a specific event

Parameters:

  • event (Symbol) (defaults to: nil)

    The event to clear callbacks for

Returns:

  • (self)

    Returns self for method chaining



70
71
72
73
74
75
76
77
# File 'lib/open_router/client.rb', line 70

def clear_callbacks(event = nil)
  if event
    @callbacks[event] = [] if @callbacks.key?(event)
  else
    @callbacks.each_key { |key| @callbacks[key] = [] }
  end
  self
end

#complete(messages, model: "openrouter/auto", providers: [], transforms: [], tools: [], tool_choice: nil, response_format: nil, force_structured_output: nil, extras: {}, stream: nil) ⇒ Response

Performs a chat completion request to the OpenRouter API.

Parameters:

  • messages (Array<Hash>)

    Array of message hashes with role and content, like [“user”, content: “What is the meaning of life?”]

  • model (String|Array) (defaults to: "openrouter/auto")

    Model identifier, or array of model identifiers if you want to fallback to the next model in case of failure

  • providers (Array<String>) (defaults to: [])

    Optional array of provider identifiers, ordered by priority

  • transforms (Array<String>) (defaults to: [])

    Optional array of strings that tell OpenRouter to apply a series of transformations to the prompt before sending it to the model. Transformations are applied in-order

  • tools (Array<Tool>) (defaults to: [])

    Optional array of Tool objects or tool definition hashes for function calling

  • tool_choice (String|Hash) (defaults to: nil)

    Optional tool choice: “auto”, “none”, “required”, or specific tool selection

  • response_format (Hash) (defaults to: nil)

    Optional response format for structured outputs

  • extras (Hash) (defaults to: {})

    Optional hash of model-specific parameters to send to the OpenRouter API

  • stream (Proc, nil) (defaults to: nil)

    Optional callable object for streaming

Returns:

  • (Response)

    The completion response wrapped in a Response object.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/open_router/client.rb', line 104

def complete(messages, model: "openrouter/auto", providers: [], transforms: [], tools: [], tool_choice: nil,
             response_format: nil, force_structured_output: nil, extras: {}, stream: nil)
  parameters = prepare_base_parameters(messages, model, providers, transforms, stream, extras)
  forced_extraction = configure_tools_and_structured_outputs!(parameters, model, tools, tool_choice,
                                                              response_format, force_structured_output)
  validate_vision_support(model, messages)

  # Trigger before_request callbacks
  trigger_callbacks(:before_request, parameters)

  raw_response = execute_request(parameters)
  validate_response!(raw_response, stream)

  response = build_response(raw_response, response_format, forced_extraction)

  # Track usage if enabled
  @usage_tracker&.track(response, model: model.is_a?(String) ? model : model.first)

  # Trigger after_response callbacks
  trigger_callbacks(:after_response, response)

  # Trigger on_tool_call callbacks if tool calls are present
  trigger_callbacks(:on_tool_call, response.tool_calls) if response.has_tool_calls?

  response
end

#configurationObject



43
44
45
# File 'lib/open_router/client.rb', line 43

def configuration
  OpenRouter.configuration
end

#modelsArray<Hash>

Fetches the list of available models from the OpenRouter API.

Returns:

  • (Array<Hash>)

    The list of models.



133
134
135
# File 'lib/open_router/client.rb', line 133

def models
  get(path: "/models")["data"]
end

#on(event, &block) ⇒ self

Register a callback for a specific event

Examples:

client.on(:after_response) do |response|
  puts "Used #{response.total_tokens} tokens"
end

Parameters:

  • event (Symbol)

    The event to register for (:before_request, :after_response, :on_tool_call, :on_error, :on_stream_chunk, :on_healing)

  • block (Proc)

    The callback to execute

Returns:

  • (self)

    Returns self for method chaining



57
58
59
60
61
62
63
64
# File 'lib/open_router/client.rb', line 57

def on(event, &block)
  unless @callbacks.key?(event)
    raise ArgumentError, "Invalid event: #{event}. Valid events are: #{@callbacks.keys.join(", ")}"
  end

  @callbacks[event] << block
  self
end

#query_generation_stats(generation_id) ⇒ Hash

Queries the generation stats for a given id.

Parameters:

  • generation_id (String)

    The generation id returned from a previous request.

Returns:

  • (Hash)

    The stats including token counts and cost.



140
141
142
143
# File 'lib/open_router/client.rb', line 140

def query_generation_stats(generation_id)
  response = get(path: "/generation?id=#{generation_id}")
  response["data"]
end

#select_modelModelSelector

Create a new ModelSelector for intelligent model selection

Examples:

client = OpenRouter::Client.new
model = client.select_model.optimize_for(:cost).require(:function_calling).choose

Returns:



151
152
153
# File 'lib/open_router/client.rb', line 151

def select_model
  ModelSelector.new
end

#smart_complete(messages, requirements: {}, optimization: :cost, **extras) ⇒ Response

Smart completion that automatically selects the best model based on requirements

Examples:

response = client.smart_complete(
  messages: [{ role: "user", content: "Analyze this data" }],
  requirements: { capabilities: [:function_calling], max_input_cost: 0.01 },
  optimization: :cost
)

Parameters:

  • messages (Array<Hash>)

    Array of message hashes

  • requirements (Hash) (defaults to: {})

    Model selection requirements

  • optimization (Symbol) (defaults to: :cost)

    Optimization strategy (:cost, :performance, :latest, :context)

  • extras (Hash)

    Additional parameters for the completion request

Returns:

  • (Response)

    The completion response

Raises:



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/open_router/client.rb', line 170

def smart_complete(messages, requirements: {}, optimization: :cost, **extras)
  selector = ModelSelector.new.optimize_for(optimization)

  # Apply requirements using fluent interface
  selector = selector.require(*requirements[:capabilities]) if requirements[:capabilities]

  if requirements[:max_cost] || requirements[:max_input_cost]
    cost_opts = {}
    cost_opts[:max_cost] = requirements[:max_cost] || requirements[:max_input_cost]
    cost_opts[:max_output_cost] = requirements[:max_output_cost] if requirements[:max_output_cost]
    selector = selector.within_budget(**cost_opts)
  end

  selector = selector.min_context(requirements[:min_context_length]) if requirements[:min_context_length]

  if requirements[:providers]
    case requirements[:providers]
    when Hash
      selector = selector.prefer_providers(*requirements[:providers][:prefer]) if requirements[:providers][:prefer]
      if requirements[:providers][:require]
        selector = selector.require_providers(*requirements[:providers][:require])
      end
      selector = selector.avoid_providers(*requirements[:providers][:avoid]) if requirements[:providers][:avoid]
    when Array
      selector = selector.prefer_providers(*requirements[:providers])
    end
  end

  # Select the best model
  model = selector.choose
  raise ModelSelectionError, "No model found matching requirements: #{requirements}" unless model

  # Perform the completion with the selected model
  complete(messages, model:, **extras)
end

#smart_complete_with_fallback(messages, requirements: {}, optimization: :cost, max_retries: 3, **extras) ⇒ Response

Smart completion with automatic fallback to alternative models

Examples:

response = client.smart_complete_with_fallback(
  messages: [{ role: "user", content: "Hello" }],
  requirements: { capabilities: [:function_calling] },
  max_retries: 3
)

Parameters:

  • messages (Array<Hash>)

    Array of message hashes

  • requirements (Hash) (defaults to: {})

    Model selection requirements

  • optimization (Symbol) (defaults to: :cost)

    Optimization strategy

  • max_retries (Integer) (defaults to: 3)

    Maximum number of fallback attempts

  • extras (Hash)

    Additional parameters for the completion request

Returns:

  • (Response)

    The completion response

Raises:



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/open_router/client.rb', line 222

def smart_complete_with_fallback(messages, requirements: {}, optimization: :cost, max_retries: 3, **extras)
  selector = ModelSelector.new.optimize_for(optimization)

  # Apply requirements (same logic as smart_complete)
  selector = selector.require(*requirements[:capabilities]) if requirements[:capabilities]

  if requirements[:max_cost] || requirements[:max_input_cost]
    cost_opts = {}
    cost_opts[:max_cost] = requirements[:max_cost] || requirements[:max_input_cost]
    cost_opts[:max_output_cost] = requirements[:max_output_cost] if requirements[:max_output_cost]
    selector = selector.within_budget(**cost_opts)
  end

  selector = selector.min_context(requirements[:min_context_length]) if requirements[:min_context_length]

  if requirements[:providers]
    case requirements[:providers]
    when Hash
      selector = selector.prefer_providers(*requirements[:providers][:prefer]) if requirements[:providers][:prefer]
      if requirements[:providers][:require]
        selector = selector.require_providers(*requirements[:providers][:require])
      end
      selector = selector.avoid_providers(*requirements[:providers][:avoid]) if requirements[:providers][:avoid]
    when Array
      selector = selector.prefer_providers(*requirements[:providers])
    end
  end

  # Get fallback models
  fallback_models = selector.choose_with_fallbacks(limit: max_retries + 1)
  raise ModelSelectionError, "No models found matching requirements: #{requirements}" if fallback_models.empty?

  last_error = nil

  fallback_models.each do |model|
    return complete(messages, model:, **extras)
  rescue StandardError => e
    last_error = e
    # Continue to next model in fallback list
  end

  # If we get here, all models failed
  raise ModelSelectionError, "All fallback models failed. Last error: #{last_error&.message}"
end

#trigger_callbacks(event, data = nil) ⇒ Object

Trigger callbacks for a specific event

Parameters:

  • event (Symbol)

    The event to trigger

  • data (Object) (defaults to: nil)

    Data to pass to the callbacks



83
84
85
86
87
88
89
90
91
# File 'lib/open_router/client.rb', line 83

def trigger_callbacks(event, data = nil)
  return unless @callbacks[event]

  @callbacks[event].each do |callback|
    callback.call(data)
  rescue StandardError => e
    warn "[OpenRouter] Callback error for #{event}: #{e.message}"
  end
end