Skip to content

Commit 623098d

Browse files
committed
Support per-instance configuration
1 parent eb1e87e commit 623098d

File tree

5 files changed

+47
-28
lines changed

5 files changed

+47
-28
lines changed

lib/ruby_llm.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ module RubyLLM
2828
class Error < StandardError; end
2929

3030
class << self
31-
def chat(model: nil, provider: nil)
32-
Chat.new(model: model, provider: provider)
31+
def chat(model: nil, provider: nil, config: configuration)
32+
Chat.new(model: model, provider: provider, config: config)
3333
end
3434

3535
def embed(...)
@@ -56,6 +56,8 @@ def config
5656
@config ||= Configuration.new
5757
end
5858

59+
alias configuration config
60+
5961
def logger
6062
@logger ||= Logger.new(
6163
$stdout,

lib/ruby_llm/chat.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ module RubyLLM
1111
class Chat
1212
include Enumerable
1313

14-
attr_reader :model, :messages, :tools
14+
attr_reader :model, :messages, :tools, :config
1515

16-
def initialize(model: nil, provider: nil)
16+
def initialize(model: nil, provider: nil, config: nil)
1717
model_id = model || RubyLLM.config.default_model
1818
with_model(model_id, provider: provider)
1919
@temperature = 0.7
2020
@messages = []
2121
@tools = {}
22+
@config = config
2223
@on = {
2324
new_message: nil,
2425
end_message: nil
@@ -58,6 +59,12 @@ def with_temperature(temperature)
5859
self
5960
end
6061

62+
def with_config(&block)
63+
@config = config.dup
64+
yield @config if block
65+
self
66+
end
67+
6168
def on_new_message(&block)
6269
@on[:new_message] = block
6370
self
@@ -74,7 +81,7 @@ def each(&)
7481

7582
def complete(&)
7683
@on[:new_message]&.call
77-
response = @provider.complete(messages, tools: @tools, temperature: @temperature, model: @model.id, &)
84+
response = @provider.complete(messages, tools: @tools, temperature: @temperature, model: @model.id, config: @config, &)
7885
@on[:end_message]&.call(response)
7986

8087
add_message response

lib/ruby_llm/configuration.rb

+9
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,14 @@ def initialize
2727
@default_embedding_model = 'text-embedding-3-small'
2828
@default_image_model = 'dall-e-3'
2929
end
30+
31+
def dup
32+
config = self.class.new
33+
instance_variables.each do |var|
34+
value = instance_variable_get(var)
35+
config.instance_variable_set(var, value)
36+
end
37+
config
38+
end
3039
end
3140
end

lib/ruby_llm/provider.rb

+22-21
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Provider
1010
module Methods
1111
extend Streaming
1212

13-
def complete(messages, tools:, temperature:, model:, &block) # rubocop:disable Metrics/MethodLength
13+
def complete(messages, tools:, temperature:, model:, config:, &block) # rubocop:disable Metrics/MethodLength
1414
normalized_temperature = if capabilities.respond_to?(:normalize_temperature)
1515
capabilities.normalize_temperature(temperature, model)
1616
else
@@ -24,9 +24,9 @@ def complete(messages, tools:, temperature:, model:, &block) # rubocop:disable M
2424
stream: block_given?)
2525

2626
if block_given?
27-
stream_response payload, &block
27+
stream_response(payload, config, &block)
2828
else
29-
sync_response payload
29+
sync_response(payload, config)
3030
end
3131
end
3232

@@ -51,49 +51,50 @@ def paint(prompt, model:, size:)
5151
parse_image_response(response)
5252
end
5353

54-
def configured?
55-
missing_configs.empty?
54+
def configured?(config = nil)
55+
config ||= RubyLLM.config
56+
missing_configs(config).empty?
5657
end
5758

5859
private
5960

60-
def missing_configs
61+
def missing_configs(config)
6162
configuration_requirements.select do |key|
62-
value = RubyLLM.config.send(key)
63+
value = config.send(key)
6364
value.nil? || value.empty?
6465
end
6566
end
6667

67-
def ensure_configured!
68-
return if configured?
68+
def ensure_configured!(config)
69+
return if configured?(config)
6970

7071
config_block = <<~RUBY
71-
RubyLLM.configure do |config|
72-
#{missing_configs.map { |key| "config.#{key} = ENV['#{key.to_s.upcase}']" }.join("\n ")}
72+
RubyLLM.configure do |c|
73+
#{missing_configs(config).map { |key| "c.#{key} = ENV['#{key.to_s.upcase}']" }.join("\n ")}
7374
end
7475
RUBY
7576

7677
raise ConfigurationError,
7778
"#{slug} provider is not configured. Add this to your initialization:\n\n#{config_block}"
7879
end
7980

80-
def sync_response(payload)
81-
response = post completion_url, payload
82-
parse_completion_response response
81+
def sync_response(payload, config)
82+
response = post(completion_url, payload, config)
83+
parse_completion_response(response)
8384
end
8485

85-
def post(url, payload)
86-
connection.post url, payload do |req|
87-
req.headers.merge! headers
86+
def post(url, payload, config)
87+
connection(config).post(url, payload) do |req|
88+
req.headers.merge! headers(config)
8889
yield req if block_given?
8990
end
9091
end
9192

92-
def connection # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
93-
ensure_configured!
93+
def connection(config) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
94+
ensure_configured!(config)
9495

9596
@connection ||= Faraday.new(api_base) do |f| # rubocop:disable Metrics/BlockLength
96-
f.options.timeout = RubyLLM.config.request_timeout
97+
f.options.timeout = config.request_timeout
9798

9899
f.response :logger,
99100
RubyLLM.logger,
@@ -107,7 +108,7 @@ def connection # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
107108
end
108109

109110
f.request :retry, {
110-
max: RubyLLM.config.max_retries,
111+
max: config.max_retries,
111112
interval: 0.05,
112113
interval_randomness: 0.5,
113114
backoff_factor: 2,

lib/ruby_llm/providers/anthropic.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ def api_base
1919
'https://api.anthropic.com'
2020
end
2121

22-
def headers
22+
def headers(config)
2323
{
24-
'x-api-key' => RubyLLM.config.anthropic_api_key,
24+
'x-api-key' => config.anthropic_api_key,
2525
'anthropic-version' => '2023-06-01'
2626
}
2727
end

0 commit comments

Comments
 (0)