Skip to content

Commit 696e779

Browse files
committed
Add the ability to configure OpenRouter provider settings
1 parent 516e7b1 commit 696e779

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

lib/ruby_llm/configuration.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,18 @@ class Configuration
2020
:bedrock_secret_key,
2121
:bedrock_region,
2222
:bedrock_session_token,
23+
:ollama_api_base,
24+
# OpenRouter-specific configuration
2325
:openrouter_api_key,
2426
:openrouter_referer,
2527
:openrouter_title,
26-
:ollama_api_base,
28+
:openrouter_order,
29+
:openrouter_allow_fallbacks,
30+
:openrouter_require_parameters,
31+
:openrouter_data_collection,
32+
:openrouter_ignore,
33+
:openrouter_quantizations,
34+
:openrouter_sort,
2735
# Default models
2836
:default_model,
2937
:default_embedding_model,

lib/ruby_llm/providers/openrouter.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Providers
55
# OpenRouter API integration.
66
module OpenRouter
77
extend OpenAI
8+
extend OpenRouter::Chat
89
extend OpenRouter::Models
910
extend OpenRouter::Media
1011

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
3+
module RubyLLM
4+
module Providers
5+
module OpenRouter
6+
# Chat methods of the OpenRouter API integration
7+
module Chat
8+
def completion_url
9+
'chat/completions'
10+
end
11+
12+
module_function
13+
14+
def render_payload(messages, tools:, temperature:, model:, stream: false) # rubocop:disable Metrics/MethodLength
15+
{
16+
model: model,
17+
messages: format_messages(messages),
18+
temperature: temperature,
19+
stream: stream,
20+
provider: format_provider_options # @todo Allow for assistant overriding
21+
}.tap do |payload|
22+
if tools.any?
23+
payload[:tools] = tools.map { |_, tool| tool_for(tool) }
24+
payload[:tool_choice] = 'auto'
25+
end
26+
payload[:stream_options] = { include_usage: true } if stream
27+
end
28+
end
29+
30+
def parse_completion_response(response) # rubocop:disable Metrics/MethodLength
31+
data = response.body
32+
return if data.empty?
33+
34+
raise Error.new(response, data.dig('error', 'message')) if data.dig('error', 'message')
35+
36+
message_data = data.dig('choices', 0, 'message')
37+
return unless message_data
38+
39+
Message.new(
40+
role: :assistant,
41+
content: message_data['content'],
42+
tool_calls: parse_tool_calls(message_data['tool_calls']),
43+
input_tokens: data['usage']['prompt_tokens'],
44+
output_tokens: data['usage']['completion_tokens'],
45+
model_id: data['model']
46+
)
47+
end
48+
49+
def format_messages(messages)
50+
messages.map do |msg|
51+
{
52+
role: format_role(msg.role),
53+
content: self::Media.format_content(msg.content),
54+
tool_calls: format_tool_calls(msg.tool_calls),
55+
tool_call_id: msg.tool_call_id
56+
}.compact
57+
end
58+
end
59+
60+
def format_role(role)
61+
case role
62+
when :system
63+
'developer'
64+
else
65+
role.to_s
66+
end
67+
end
68+
69+
def format_provider_options
70+
{
71+
order: @connection.config.openrouter_order,
72+
allow_fallbacks: @connection.config.openrouter_allow_fallbacks,
73+
require_parameters: @connection.config.openrouter_require_parameters,
74+
data_collection: @connection.config.openrouter_data_collection,
75+
ignore: @connection.config.openrouter_ignore,
76+
quantizations: @connection.config.openrouter_quantizations,
77+
sort: @connection.config.openrouter_sort
78+
}.compact
79+
end
80+
end
81+
end
82+
end
83+
end

0 commit comments

Comments
 (0)