Class: OpenRouter::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/open_router/response.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw_response, response_format: nil, forced_extraction: false) ⇒ Response

Returns a new instance of Response.



13
14
15
16
17
18
# File 'lib/open_router/response.rb', line 13

def initialize(raw_response, response_format: nil, forced_extraction: false)
  @raw_response = raw_response.is_a?(Hash) ? raw_response.with_indifferent_access : {}
  @response_format = response_format
  @forced_extraction = forced_extraction
  @client = nil
end

Instance Attribute Details

#clientObject

Returns the value of attribute client.



11
12
13
# File 'lib/open_router/response.rb', line 11

def client
  @client
end

#forced_extractionObject (readonly)

Returns the value of attribute forced_extraction.



10
11
12
# File 'lib/open_router/response.rb', line 10

def forced_extraction
  @forced_extraction
end

#raw_responseObject (readonly)

Returns the value of attribute raw_response.



10
11
12
# File 'lib/open_router/response.rb', line 10

def raw_response
  @raw_response
end

#response_formatObject (readonly)

Returns the value of attribute response_format.



10
11
12
# File 'lib/open_router/response.rb', line 10

def response_format
  @response_format
end

Instance Method Details

#[](key) ⇒ Object

Delegate common hash methods to raw_response for backward compatibility



21
22
23
# File 'lib/open_router/response.rb', line 21

def [](key)
  @raw_response[key]
end

#cached_tokensObject

Cached tokens (tokens served from cache)



209
210
211
# File 'lib/open_router/response.rb', line 209

def cached_tokens
  usage&.dig("prompt_tokens_details", "cached_tokens") || 0
end

#choicesObject



164
165
166
# File 'lib/open_router/response.rb', line 164

def choices
  @raw_response["choices"] || []
end

#completion_tokensObject

Total completion tokens



219
220
221
# File 'lib/open_router/response.rb', line 219

def completion_tokens
  usage&.dig("completion_tokens") || 0
end

#contentObject

Content accessors



160
161
162
# File 'lib/open_router/response.rb', line 160

def content
  choices.first&.dig("message", "content")
end

#cost_estimateObject

Get estimated cost for this response Note: This requires an additional API call to /generation endpoint



230
231
232
233
234
235
236
# File 'lib/open_router/response.rb', line 230

def cost_estimate
  return nil unless id && client

  @cost_estimate ||= client.query_generation_stats(id)&.dig("cost")
rescue StandardError
  nil
end

#createdObject



180
181
182
# File 'lib/open_router/response.rb', line 180

def created
  @raw_response["created"]
end

#dig(*keys) ⇒ Object



25
26
27
# File 'lib/open_router/response.rb', line 25

def dig(*keys)
  @raw_response.dig(*keys)
end

#error?Boolean

Convenience method to check if response indicates an error

Returns:

  • (Boolean)


244
245
246
# File 'lib/open_router/response.rb', line 244

def error?
  @raw_response.key?("error")
end

#error_messageObject



248
249
250
# File 'lib/open_router/response.rb', line 248

def error_message
  @raw_response.dig("error", "message")
end

#fetch(key, default = nil) ⇒ Object



29
30
31
# File 'lib/open_router/response.rb', line 29

def fetch(key, default = nil)
  @raw_response.fetch(key, default)
end

#finish_reasonObject

Finish reason (standard OpenRouter format)



204
205
206
# File 'lib/open_router/response.rb', line 204

def finish_reason
  choices.first&.dig("finish_reason")
end

#has_content?Boolean

Convenience method to check if response has content

Returns:

  • (Boolean)


239
240
241
# File 'lib/open_router/response.rb', line 239

def has_content?
  !content.nil? && !content.empty?
end

#has_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/open_router/response.rb', line 41

def has_key?(key)
  @raw_response.key?(key)
end

#has_tool_calls?Boolean

Returns:

  • (Boolean)


58
59
60
# File 'lib/open_router/response.rb', line 58

def has_tool_calls?
  !tool_calls.empty?
end

#idObject



172
173
174
# File 'lib/open_router/response.rb', line 172

def id
  @raw_response["id"]
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/open_router/response.rb', line 33

def key?(key)
  @raw_response.key?(key)
end

#keysObject



37
38
39
# File 'lib/open_router/response.rb', line 37

def keys
  @raw_response.keys
end

#modelObject



176
177
178
# File 'lib/open_router/response.rb', line 176

def model
  @raw_response["model"]
end

#native_finish_reasonObject

Native finish reason from the provider



199
200
201
# File 'lib/open_router/response.rb', line 199

def native_finish_reason
  choices.first&.dig("native_finish_reason")
end

#objectObject



184
185
186
# File 'lib/open_router/response.rb', line 184

def object
  @raw_response["object"]
end

#prompt_tokensObject

Total prompt tokens



214
215
216
# File 'lib/open_router/response.rb', line 214

def prompt_tokens
  usage&.dig("prompt_tokens") || 0
end

#providerObject

Provider information



189
190
191
# File 'lib/open_router/response.rb', line 189

def provider
  @raw_response["provider"]
end

#structured_output(mode: nil, auto_heal: nil) ⇒ Object

Structured output methods

Raises:

  • (ArgumentError)


79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/open_router/response.rb', line 79

def structured_output(mode: nil, auto_heal: nil)
  # Use global default mode if not specified
  if mode.nil?
    mode = if @client&.configuration.respond_to?(:default_structured_output_mode)
             @client.configuration.default_structured_output_mode || :strict
           else
             :strict
           end
  end
  # Validate mode parameter
  raise ArgumentError, "Invalid mode: #{mode}. Must be :strict or :gentle." unless %i[strict gentle].include?(mode)

  return nil unless structured_output_expected? && has_content?

  case mode
  when :strict
    # The existing logic for strict parsing and healing
    should_heal = if auto_heal.nil?
                    @client&.configuration&.auto_heal_responses
                  else
                    auto_heal
                  end

    result = parse_and_heal_structured_output(auto_heal: should_heal)

    # Only validate after parsing if healing is disabled (healing handles its own validation)
    if result && !should_heal
      schema_obj = extract_schema_from_response_format
      if schema_obj && !schema_obj.validate(result)
        validation_errors = schema_obj.validation_errors(result)
        raise StructuredOutputError, "Schema validation failed: #{validation_errors.join(", ")}"
      end
    end

    @structured_output ||= result
  when :gentle
    # New gentle mode: best-effort parsing, no healing, no validation
    content_to_parse = @forced_extraction ? extract_json_from_text(content) : content
    return nil if content_to_parse.nil?

    begin
      JSON.parse(content_to_parse)
    rescue JSON::ParserError
      nil # Return nil on failure instead of raising an error
    end
  end
end

#system_fingerprintObject

System fingerprint (model version identifier)



194
195
196
# File 'lib/open_router/response.rb', line 194

def system_fingerprint
  @raw_response["system_fingerprint"]
end

#to_hObject



45
46
47
# File 'lib/open_router/response.rb', line 45

def to_h
  @raw_response.to_h
end

#to_json(*args) ⇒ Object



49
50
51
# File 'lib/open_router/response.rb', line 49

def to_json(*args)
  @raw_response.to_json(*args)
end

#to_messageObject

Convert response to message format for conversation continuation



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/open_router/response.rb', line 63

def to_message
  if has_tool_calls?
    {
      role: "assistant",
      content: content,
      tool_calls: raw_tool_calls
    }
  else
    {
      role: "assistant",
      content: content
    }
  end
end

#tool_callsObject

Tool calling methods



54
55
56
# File 'lib/open_router/response.rb', line 54

def tool_calls
  @tool_calls ||= parse_tool_calls
end

#total_tokensObject

Total tokens (prompt + completion)



224
225
226
# File 'lib/open_router/response.rb', line 224

def total_tokens
  usage&.dig("total_tokens") || 0
end

#usageObject



168
169
170
# File 'lib/open_router/response.rb', line 168

def usage
  @raw_response["usage"]
end

#valid_structured_output?Boolean

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/open_router/response.rb', line 127

def valid_structured_output?
  return true unless structured_output_expected?

  schema_obj = extract_schema_from_response_format
  return true unless schema_obj

  begin
    parsed_output = structured_output
    return false unless parsed_output

    schema_obj.validate(parsed_output)
  rescue StructuredOutputError
    false
  end
end

#validation_errorsObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/open_router/response.rb', line 143

def validation_errors
  return [] unless structured_output_expected?

  schema_obj = extract_schema_from_response_format
  return [] unless schema_obj

  begin
    parsed_output = structured_output
    return [] unless parsed_output

    schema_obj.validation_errors(parsed_output)
  rescue StructuredOutputError
    ["Failed to parse structured output"]
  end
end