module RubyLLM::Providers::OpenRouter::Chat
Chat methods of the OpenRouter API integration
Public Instance Methods
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 131 def build_reasoning(thinking) return nil unless thinking&.enabled? reasoning = {} reasoning[:effort] = thinking.effort if thinking.respond_to?(:effort) && thinking.effort reasoning[:max_tokens] = thinking.budget if thinking.respond_to?(:budget) && thinking.budget reasoning[:enabled] = true if reasoning.empty? reasoning end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 95 def cache_read_tokens(usage) usage.dig('prompt_tokens_details', 'cached_tokens') || usage['prompt_cache_hit_tokens'] end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 99 def cache_write_tokens(usage) usage.dig('prompt_tokens_details', 'cache_write_tokens') || 0 end
# File lib/ruby_llm/providers/openrouter/chat.rb, line 181 def extract_thinking_signature(message_data) details = message_data['reasoning_details'] return nil unless details.is_a?(Array) signature = details.filter_map do |detail| detail['signature'] if detail['signature'].is_a?(String) end.first return signature if signature encrypted = details.find { |detail| detail['type'] == 'reasoning.encrypted' && detail['data'].is_a?(String) } encrypted&.dig('data') end
# File lib/ruby_llm/providers/openrouter/chat.rb, line 162 def extract_thinking_text(message_data) candidate = message_data['reasoning'] return candidate if candidate.is_a?(String) details = message_data['reasoning_details'] return nil unless details.is_a?(Array) text = details.filter_map do |detail| case detail['type'] when 'reasoning.text' detail['text'] when 'reasoning.summary' detail['summary'] end end.join text.empty? ? nil : text end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 118 def format_content(content) OpenAI::Media.format_content(content) end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 107 def format_messages(messages) messages.map do |msg| { role: format_role(msg.role), content: format_content(msg.content), tool_calls: OpenAI::Tools.format_tool_calls(msg.tool_calls), tool_call_id: msg.tool_call_id }.compact.merge(format_thinking(msg)) end end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 122 def format_role(role) case role when :system @config.openai_use_system_role ? 'system' : 'developer' else role.to_s end end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 141 def format_thinking(msg) thinking = msg.thinking return {} unless thinking && msg.role == :assistant details = [] if thinking.text details << { type: 'reasoning.text', text: thinking.text, signature: thinking.signature }.compact elsif thinking.signature details << { type: 'reasoning.encrypted', data: thinking.signature } end details.empty? ? {} : { reasoning_details: details } end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 82 def input_tokens(usage) return usage['prompt_cache_miss_tokens'] if usage['prompt_cache_miss_tokens'] prompt_tokens = usage['prompt_tokens'] return unless prompt_tokens [prompt_tokens.to_i - cache_read_tokens(usage).to_i - cache_write_tokens(usage).to_i, 0].max end
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 91 def output_tokens(usage) OpenAI::Chat.output_tokens(usage) end
# File lib/ruby_llm/providers/openrouter/chat.rb, line 53 def parse_completion_response(response) data = response.body return if data.nil? || data.empty? raise Error.new(response, data.dig('error', 'message')) if data.dig('error', 'message') message_data = data.dig('choices', 0, 'message') return unless message_data usage = data['usage'] || {} thinking_tokens = thinking_tokens(usage) thinking_text = extract_thinking_text(message_data) thinking_signature = extract_thinking_signature(message_data) Message.new( role: :assistant, content: message_data['content'], thinking: Thinking.build(text: thinking_text, signature: thinking_signature), tool_calls: OpenAI::Tools.parse_tool_calls(message_data['tool_calls']), input_tokens: input_tokens(usage), output_tokens: output_tokens(usage), cached_tokens: cache_read_tokens(usage), cache_creation_tokens: cache_write_tokens(usage), thinking_tokens: thinking_tokens, model_id: data['model'], raw: response ) end
rubocop:enable Metrics/ParameterLists,Metrics/PerceivedComplexity
# File lib/ruby_llm/providers/openrouter/chat.rb, line 11 def render_payload(messages, tools:, temperature:, model:, stream: false, schema: nil, thinking: nil, tool_prefs: nil) tool_prefs ||= {} payload = { model: model.id, messages: format_messages(messages), stream: stream } payload[:temperature] = temperature unless temperature.nil? if tools.any? payload[:tools] = tools.map { |_, tool| OpenAI::Tools.tool_for(tool) } payload[:tool_choice] = OpenAI::Tools.build_tool_choice(tool_prefs[:choice]) unless tool_prefs[:choice].nil? payload[:parallel_tool_calls] = tool_prefs[:calls] == :many unless tool_prefs[:calls].nil? end if schema schema_name = schema[:name] schema_def = RubyLLM::Utils.deep_dup(schema[:schema]) if schema_def.is_a?(Hash) schema_def.delete(:strict) schema_def.delete('strict') end strict = schema[:strict] payload[:response_format] = { type: 'json_schema', json_schema: { name: schema_name, schema: schema_def, strict: strict } } end reasoning = build_reasoning(thinking) payload[:reasoning] = reasoning if reasoning payload[:stream_options] = { include_usage: true } if stream payload end
rubocop:disable Metrics/ParameterLists,Metrics/PerceivedComplexity
Source
# File lib/ruby_llm/providers/openrouter/chat.rb, line 103 def thinking_tokens(usage) OpenAI::Chat.thinking_tokens(usage) end