ruby_llm 0.1.0.pre25 → 0.1.0.pre26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -3
- data/Rakefile +3 -0
- data/bin/console +2 -0
- data/lib/ruby_llm/configuration.rb +2 -0
- data/lib/ruby_llm/error.rb +12 -2
- data/lib/ruby_llm/model_capabilities/anthropic.rb +1 -3
- data/lib/ruby_llm/model_capabilities/deepseek.rb +93 -0
- data/lib/ruby_llm/model_capabilities/gemini.rb +132 -0
- data/lib/ruby_llm/model_capabilities/openai.rb +35 -11
- data/lib/ruby_llm/model_info.rb +6 -10
- data/lib/ruby_llm/models.json +2068 -686
- data/lib/ruby_llm/models.rb +4 -2
- data/lib/ruby_llm/provider.rb +11 -4
- data/lib/ruby_llm/providers/anthropic.rb +8 -5
- data/lib/ruby_llm/providers/deepseek.rb +20 -0
- data/lib/ruby_llm/providers/gemini.rb +28 -0
- data/lib/ruby_llm/providers/openai.rb +12 -7
- data/lib/ruby_llm/stream_accumulator.rb +7 -4
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +8 -1
- data/lib/tasks/models.rake +7 -3
- metadata +6 -2
data/lib/ruby_llm/models.rb
CHANGED
@@ -18,7 +18,7 @@ module RubyLLM
|
|
18
18
|
def all
|
19
19
|
@all ||= begin
|
20
20
|
data = JSON.parse(File.read(File.expand_path('models.json', __dir__)))
|
21
|
-
data
|
21
|
+
data.map { |model| ModelInfo.new(model.transform_keys(&:to_sym)) }
|
22
22
|
end
|
23
23
|
rescue Errno::ENOENT
|
24
24
|
[] # Return empty array if file doesn't exist yet
|
@@ -53,7 +53,9 @@ module RubyLLM
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def refresh!
|
56
|
-
@all =
|
56
|
+
@all = RubyLLM.providers.flat_map do |provider|
|
57
|
+
provider.new.list_models
|
58
|
+
end
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -46,7 +46,7 @@ module RubyLLM
|
|
46
46
|
def stream_response(payload, &block)
|
47
47
|
accumulator = StreamAccumulator.new
|
48
48
|
|
49
|
-
post
|
49
|
+
post stream_url, payload do |req|
|
50
50
|
req.options.on_data = handle_stream do |chunk|
|
51
51
|
accumulator.add chunk
|
52
52
|
block.call chunk
|
@@ -104,13 +104,22 @@ module RubyLLM
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def try_parse_json(maybe_json)
|
107
|
-
return maybe_json
|
107
|
+
return maybe_json unless maybe_json.is_a?(String)
|
108
108
|
|
109
109
|
JSON.parse(maybe_json)
|
110
110
|
rescue JSON::ParserError
|
111
111
|
maybe_json
|
112
112
|
end
|
113
113
|
|
114
|
+
def capabilities
|
115
|
+
provider_name = self.class.name.split('::').last
|
116
|
+
RubyLLM.const_get "ModelCapabilities::#{provider_name}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def slug
|
120
|
+
self.class.name.split('::').last.downcase
|
121
|
+
end
|
122
|
+
|
114
123
|
class << self
|
115
124
|
def register(name, provider_class)
|
116
125
|
providers[name.to_sym] = provider_class
|
@@ -123,8 +132,6 @@ module RubyLLM
|
|
123
132
|
provider_class.new
|
124
133
|
end
|
125
134
|
|
126
|
-
private
|
127
|
-
|
128
135
|
def providers
|
129
136
|
@providers ||= {}
|
130
137
|
end
|
@@ -31,6 +31,10 @@ module RubyLLM
|
|
31
31
|
'/v1/messages'
|
32
32
|
end
|
33
33
|
|
34
|
+
def stream_url
|
35
|
+
completion_url
|
36
|
+
end
|
37
|
+
|
34
38
|
def models_url
|
35
39
|
'/v1/models'
|
36
40
|
end
|
@@ -77,16 +81,15 @@ module RubyLLM
|
|
77
81
|
)
|
78
82
|
end
|
79
83
|
|
80
|
-
def
|
81
|
-
capabilities = ModelCapabilities::Anthropic.new
|
82
|
-
|
84
|
+
def parse_list_models_response(response) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
83
85
|
(response.body['data'] || []).map do |model|
|
84
86
|
ModelInfo.new(
|
85
87
|
id: model['id'],
|
86
88
|
created_at: Time.parse(model['created_at']),
|
87
89
|
display_name: model['display_name'],
|
88
|
-
provider:
|
89
|
-
|
90
|
+
provider: slug,
|
91
|
+
type: model['type'],
|
92
|
+
family: capabilities.model_family(model['id']),
|
90
93
|
context_window: capabilities.determine_context_window(model['id']),
|
91
94
|
max_tokens: capabilities.determine_max_tokens(model['id']),
|
92
95
|
supports_vision: capabilities.supports_vision?(model['id']),
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
# DeepSeek API integration.
|
6
|
+
class DeepSeek < OpenAI
|
7
|
+
private
|
8
|
+
|
9
|
+
def api_base
|
10
|
+
'https://api.deepseek.com'
|
11
|
+
end
|
12
|
+
|
13
|
+
def headers
|
14
|
+
{
|
15
|
+
'Authorization' => "Bearer #{RubyLLM.config.deepseek_api_key}"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
module Providers
|
5
|
+
# Gemini API integration.
|
6
|
+
class Gemini < OpenAI
|
7
|
+
private
|
8
|
+
|
9
|
+
def api_base
|
10
|
+
'https://generativelanguage.googleapis.com/v1beta/openai'
|
11
|
+
end
|
12
|
+
|
13
|
+
def headers
|
14
|
+
{
|
15
|
+
'Authorization' => "Bearer #{RubyLLM.config.gemini_api_key}"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_list_models_response(response)
|
20
|
+
response.body['data']&.each do |model|
|
21
|
+
model['id'] = model['id'].delete_prefix('models/')
|
22
|
+
end
|
23
|
+
|
24
|
+
super(response)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -18,7 +18,7 @@ module RubyLLM
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def api_base
|
21
|
-
'https://api.openai.com'
|
21
|
+
'https://api.openai.com/v1'
|
22
22
|
end
|
23
23
|
|
24
24
|
def headers
|
@@ -28,15 +28,19 @@ module RubyLLM
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def completion_url
|
31
|
-
'
|
31
|
+
'chat/completions'
|
32
|
+
end
|
33
|
+
|
34
|
+
def stream_url
|
35
|
+
completion_url
|
32
36
|
end
|
33
37
|
|
34
38
|
def models_url
|
35
|
-
'
|
39
|
+
'models'
|
36
40
|
end
|
37
41
|
|
38
42
|
def embedding_url
|
39
|
-
'
|
43
|
+
'embeddings'
|
40
44
|
end
|
41
45
|
|
42
46
|
def build_payload(messages, tools:, temperature:, model:, stream: false) # rubocop:disable Metrics/MethodLength
|
@@ -189,13 +193,14 @@ module RubyLLM
|
|
189
193
|
end
|
190
194
|
|
191
195
|
def parse_list_models_response(response) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
192
|
-
capabilities = ModelCapabilities::OpenAI
|
193
196
|
(response.body['data'] || []).map do |model|
|
194
197
|
ModelInfo.new(
|
195
198
|
id: model['id'],
|
196
|
-
created_at: Time.at(model['created']),
|
199
|
+
created_at: model['created'] ? Time.at(model['created']) : nil,
|
197
200
|
display_name: capabilities.format_display_name(model['id']),
|
198
|
-
provider:
|
201
|
+
provider: slug,
|
202
|
+
type: capabilities.model_type(model['id']),
|
203
|
+
family: capabilities.model_family(model['id']),
|
199
204
|
metadata: {
|
200
205
|
object: model['object'],
|
201
206
|
owned_by: model['owned_by']
|
@@ -32,7 +32,7 @@ module RubyLLM
|
|
32
32
|
def to_message
|
33
33
|
Message.new(
|
34
34
|
role: :assistant,
|
35
|
-
content: content,
|
35
|
+
content: content.empty? ? nil : content,
|
36
36
|
model_id: model_id,
|
37
37
|
tool_calls: tool_calls_from_stream,
|
38
38
|
input_tokens: @input_tokens.positive? ? @input_tokens : nil,
|
@@ -52,13 +52,16 @@ module RubyLLM
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def accumulate_tool_calls(new_tool_calls) # rubocop:disable Metrics/MethodLength
|
55
|
+
def accumulate_tool_calls(new_tool_calls) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
56
|
+
RubyLLM.logger.debug "Accumulating tool calls: #{new_tool_calls}"
|
56
57
|
new_tool_calls.each_value do |tool_call|
|
57
58
|
if tool_call.id
|
59
|
+
tool_call_id = tool_call.id.empty? ? SecureRandom.uuid : tool_call.id
|
60
|
+
tool_call_arguments = tool_call.arguments.empty? ? String.new : tool_call.arguments
|
58
61
|
@tool_calls[tool_call.id] = ToolCall.new(
|
59
|
-
id:
|
62
|
+
id: tool_call_id,
|
60
63
|
name: tool_call.name,
|
61
|
-
arguments:
|
64
|
+
arguments: tool_call_arguments
|
62
65
|
)
|
63
66
|
@latest_tool_call_id = tool_call.id
|
64
67
|
else
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
@@ -12,7 +12,8 @@ loader.inflector.inflect(
|
|
12
12
|
'ruby_llm' => 'RubyLLM',
|
13
13
|
'llm' => 'LLM',
|
14
14
|
'openai' => 'OpenAI',
|
15
|
-
'api' => 'API'
|
15
|
+
'api' => 'API',
|
16
|
+
'deepseek' => 'DeepSeek'
|
16
17
|
)
|
17
18
|
loader.setup
|
18
19
|
|
@@ -35,6 +36,10 @@ module RubyLLM
|
|
35
36
|
Models
|
36
37
|
end
|
37
38
|
|
39
|
+
def providers
|
40
|
+
Provider.providers.values
|
41
|
+
end
|
42
|
+
|
38
43
|
def configure
|
39
44
|
yield config
|
40
45
|
end
|
@@ -55,6 +60,8 @@ end
|
|
55
60
|
|
56
61
|
RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
|
57
62
|
RubyLLM::Provider.register :anthropic, RubyLLM::Providers::Anthropic
|
63
|
+
RubyLLM::Provider.register :gemini, RubyLLM::Providers::Gemini
|
64
|
+
RubyLLM::Provider.register :deepseek, RubyLLM::Providers::DeepSeek
|
58
65
|
|
59
66
|
if defined?(Rails::Railtie)
|
60
67
|
require 'ruby_llm/railtie'
|
data/lib/tasks/models.rake
CHANGED
@@ -9,17 +9,21 @@ namespace :ruby_llm do
|
|
9
9
|
RubyLLM.configure do |config|
|
10
10
|
config.openai_api_key = ENV.fetch('OPENAI_API_KEY')
|
11
11
|
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY')
|
12
|
+
config.gemini_api_key = ENV['GEMINI_API_KEY']
|
13
|
+
config.deepseek_api_key = ENV['DEEPSEEK_API_KEY']
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get all models
|
15
|
-
models = RubyLLM.models.refresh
|
17
|
+
models = RubyLLM.models.refresh!
|
16
18
|
|
17
19
|
# Write to models.json
|
18
20
|
models_file = File.expand_path('../../lib/ruby_llm/models.json', __dir__)
|
19
21
|
File.write(models_file, JSON.pretty_generate(models.map(&:to_h)))
|
20
22
|
|
21
23
|
puts "Updated models.json with #{models.size} models:"
|
22
|
-
|
23
|
-
|
24
|
+
RubyLLM::Provider.providers.each do |provider_sym, provider_module|
|
25
|
+
provider_name = provider_module.to_s.split('::').last
|
26
|
+
puts "#{provider_name} models: #{models.count { |m| m.provider == provider_sym.to_s }}"
|
27
|
+
end
|
24
28
|
end
|
25
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_llm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.pre26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: event_stream_parser
|
@@ -353,12 +353,16 @@ files:
|
|
353
353
|
- lib/ruby_llm/error.rb
|
354
354
|
- lib/ruby_llm/message.rb
|
355
355
|
- lib/ruby_llm/model_capabilities/anthropic.rb
|
356
|
+
- lib/ruby_llm/model_capabilities/deepseek.rb
|
357
|
+
- lib/ruby_llm/model_capabilities/gemini.rb
|
356
358
|
- lib/ruby_llm/model_capabilities/openai.rb
|
357
359
|
- lib/ruby_llm/model_info.rb
|
358
360
|
- lib/ruby_llm/models.json
|
359
361
|
- lib/ruby_llm/models.rb
|
360
362
|
- lib/ruby_llm/provider.rb
|
361
363
|
- lib/ruby_llm/providers/anthropic.rb
|
364
|
+
- lib/ruby_llm/providers/deepseek.rb
|
365
|
+
- lib/ruby_llm/providers/gemini.rb
|
362
366
|
- lib/ruby_llm/providers/openai.rb
|
363
367
|
- lib/ruby_llm/railtie.rb
|
364
368
|
- lib/ruby_llm/stream_accumulator.rb
|