ruby_llm 1.5.1 → 1.6.1
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 +8 -34
- data/lib/ruby_llm/active_record/acts_as.rb +64 -10
- data/lib/ruby_llm/aliases.json +23 -3
- data/lib/ruby_llm/chat.rb +30 -8
- data/lib/ruby_llm/configuration.rb +7 -18
- data/lib/ruby_llm/connection.rb +11 -6
- data/lib/ruby_llm/context.rb +2 -3
- data/lib/ruby_llm/embedding.rb +3 -4
- data/lib/ruby_llm/error.rb +2 -2
- data/lib/ruby_llm/image.rb +3 -4
- data/lib/ruby_llm/message.rb +4 -0
- data/lib/ruby_llm/models.json +6598 -6370
- data/lib/ruby_llm/models.rb +22 -31
- data/lib/ruby_llm/provider.rb +150 -89
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -2
- data/lib/ruby_llm/providers/anthropic/chat.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/models.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/streaming.rb +1 -1
- data/lib/ruby_llm/providers/anthropic/tools.rb +1 -1
- data/lib/ruby_llm/providers/anthropic.rb +17 -22
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +3 -63
- data/lib/ruby_llm/providers/bedrock/chat.rb +5 -4
- data/lib/ruby_llm/providers/bedrock/media.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/models.rb +5 -6
- data/lib/ruby_llm/providers/bedrock/signing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/base.rb +5 -4
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +1 -1
- data/lib/ruby_llm/providers/bedrock/streaming.rb +1 -1
- data/lib/ruby_llm/providers/bedrock.rb +26 -31
- data/lib/ruby_llm/providers/deepseek/capabilities.rb +16 -57
- data/lib/ruby_llm/providers/deepseek/chat.rb +1 -1
- data/lib/ruby_llm/providers/deepseek.rb +12 -17
- data/lib/ruby_llm/providers/gemini/capabilities.rb +1 -1
- data/lib/ruby_llm/providers/gemini/chat.rb +1 -1
- data/lib/ruby_llm/providers/gemini/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/gemini/images.rb +1 -1
- data/lib/ruby_llm/providers/gemini/media.rb +1 -1
- data/lib/ruby_llm/providers/gemini/models.rb +1 -1
- data/lib/ruby_llm/providers/gemini/streaming.rb +1 -1
- data/lib/ruby_llm/providers/gemini/tools.rb +1 -7
- data/lib/ruby_llm/providers/gemini.rb +18 -23
- data/lib/ruby_llm/providers/gpustack/chat.rb +1 -1
- data/lib/ruby_llm/providers/gpustack/models.rb +1 -1
- data/lib/ruby_llm/providers/gpustack.rb +16 -19
- data/lib/ruby_llm/providers/mistral/capabilities.rb +1 -1
- data/lib/ruby_llm/providers/mistral/chat.rb +1 -1
- data/lib/ruby_llm/providers/mistral/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/mistral/models.rb +1 -1
- data/lib/ruby_llm/providers/mistral.rb +14 -19
- data/lib/ruby_llm/providers/ollama/chat.rb +1 -1
- data/lib/ruby_llm/providers/ollama/media.rb +1 -1
- data/lib/ruby_llm/providers/ollama.rb +13 -18
- data/lib/ruby_llm/providers/openai/capabilities.rb +3 -3
- data/lib/ruby_llm/providers/openai/chat.rb +3 -6
- data/lib/ruby_llm/providers/openai/embeddings.rb +1 -1
- data/lib/ruby_llm/providers/openai/images.rb +1 -1
- data/lib/ruby_llm/providers/openai/media.rb +1 -1
- data/lib/ruby_llm/providers/openai/models.rb +1 -1
- data/lib/ruby_llm/providers/openai/streaming.rb +1 -1
- data/lib/ruby_llm/providers/openai/tools.rb +1 -1
- data/lib/ruby_llm/providers/openai.rb +24 -36
- data/lib/ruby_llm/providers/openrouter/models.rb +1 -1
- data/lib/ruby_llm/providers/openrouter.rb +9 -14
- data/lib/ruby_llm/providers/perplexity/capabilities.rb +1 -30
- data/lib/ruby_llm/providers/perplexity/chat.rb +1 -1
- data/lib/ruby_llm/providers/perplexity/models.rb +1 -1
- data/lib/ruby_llm/providers/perplexity.rb +13 -18
- data/lib/ruby_llm/stream_accumulator.rb +3 -3
- data/lib/ruby_llm/streaming.rb +16 -3
- data/lib/ruby_llm/tool.rb +19 -0
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/tasks/models_docs.rake +18 -11
- data/lib/tasks/models_update.rake +5 -4
- metadata +9 -8
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
|
-
|
5
|
+
class Gemini
|
6
6
|
# Tools methods for the Gemini API implementation
|
7
7
|
module Tools
|
8
8
|
# Format tools for Gemini API
|
@@ -18,26 +18,20 @@ module RubyLLM
|
|
18
18
|
def extract_tool_calls(data)
|
19
19
|
return nil unless data
|
20
20
|
|
21
|
-
# Get the first candidate
|
22
21
|
candidate = data.is_a?(Hash) ? data.dig('candidates', 0) : nil
|
23
22
|
return nil unless candidate
|
24
23
|
|
25
|
-
# Get the parts array from content
|
26
24
|
parts = candidate.dig('content', 'parts')
|
27
25
|
return nil unless parts.is_a?(Array)
|
28
26
|
|
29
|
-
# Find the function call part
|
30
27
|
function_call_part = parts.find { |p| p['functionCall'] }
|
31
28
|
return nil unless function_call_part
|
32
29
|
|
33
|
-
# Get the function call data
|
34
30
|
function_data = function_call_part['functionCall']
|
35
31
|
return nil unless function_data
|
36
32
|
|
37
|
-
# Create a unique ID for the tool call
|
38
33
|
id = SecureRandom.uuid
|
39
34
|
|
40
|
-
# Return the tool call in the expected format
|
41
35
|
{
|
42
36
|
id => ToolCall.new(
|
43
37
|
id: id,
|
@@ -3,38 +3,33 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
5
|
# Native Gemini API implementation
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
extend Gemini::Media
|
6
|
+
class Gemini < Provider
|
7
|
+
include Gemini::Chat
|
8
|
+
include Gemini::Embeddings
|
9
|
+
include Gemini::Images
|
10
|
+
include Gemini::Models
|
11
|
+
include Gemini::Streaming
|
12
|
+
include Gemini::Tools
|
13
|
+
include Gemini::Media
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
def api_base(_config)
|
15
|
+
def api_base
|
19
16
|
'https://generativelanguage.googleapis.com/v1beta'
|
20
17
|
end
|
21
18
|
|
22
|
-
def headers
|
19
|
+
def headers
|
23
20
|
{
|
24
|
-
'x-goog-api-key' => config.gemini_api_key
|
21
|
+
'x-goog-api-key' => @config.gemini_api_key
|
25
22
|
}
|
26
23
|
end
|
27
24
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def slug
|
33
|
-
'gemini'
|
34
|
-
end
|
25
|
+
class << self
|
26
|
+
def capabilities
|
27
|
+
Gemini::Capabilities
|
28
|
+
end
|
35
29
|
|
36
|
-
|
37
|
-
|
30
|
+
def configuration_requirements
|
31
|
+
%i[gemini_api_key]
|
32
|
+
end
|
38
33
|
end
|
39
34
|
end
|
40
35
|
end
|
@@ -3,33 +3,30 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
5
|
# GPUStack API integration based on Ollama.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
extend GPUStack::Models
|
6
|
+
class GPUStack < OpenAI
|
7
|
+
include GPUStack::Chat
|
8
|
+
include GPUStack::Models
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
def api_base(config)
|
14
|
-
config.gpustack_api_base
|
10
|
+
def api_base
|
11
|
+
@config.gpustack_api_base
|
15
12
|
end
|
16
13
|
|
17
|
-
def headers
|
14
|
+
def headers
|
15
|
+
return {} unless @config.gpustack_api_key
|
16
|
+
|
18
17
|
{
|
19
|
-
'Authorization' => "Bearer #{config.gpustack_api_key}"
|
18
|
+
'Authorization' => "Bearer #{@config.gpustack_api_key}"
|
20
19
|
}
|
21
20
|
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def local?
|
28
|
-
true
|
29
|
-
end
|
22
|
+
class << self
|
23
|
+
def local?
|
24
|
+
true
|
25
|
+
end
|
30
26
|
|
31
|
-
|
32
|
-
|
27
|
+
def configuration_requirements
|
28
|
+
%i[gpustack_api_base]
|
29
|
+
end
|
33
30
|
end
|
34
31
|
end
|
35
32
|
end
|
@@ -3,34 +3,29 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
5
|
# Mistral API integration.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
extend Mistral::Embeddings
|
6
|
+
class Mistral < OpenAI
|
7
|
+
include Mistral::Chat
|
8
|
+
include Mistral::Models
|
9
|
+
include Mistral::Embeddings
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
def api_base(_config)
|
11
|
+
def api_base
|
15
12
|
'https://api.mistral.ai/v1'
|
16
13
|
end
|
17
14
|
|
18
|
-
def headers
|
15
|
+
def headers
|
19
16
|
{
|
20
|
-
'Authorization' => "Bearer #{config.mistral_api_key}"
|
17
|
+
'Authorization' => "Bearer #{@config.mistral_api_key}"
|
21
18
|
}
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def slug
|
29
|
-
'mistral'
|
30
|
-
end
|
21
|
+
class << self
|
22
|
+
def capabilities
|
23
|
+
Mistral::Capabilities
|
24
|
+
end
|
31
25
|
|
32
|
-
|
33
|
-
|
26
|
+
def configuration_requirements
|
27
|
+
%i[mistral_api_key]
|
28
|
+
end
|
34
29
|
end
|
35
30
|
end
|
36
31
|
end
|
@@ -3,31 +3,26 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
5
|
# Ollama API integration.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
extend Ollama::Media
|
6
|
+
class Ollama < OpenAI
|
7
|
+
include Ollama::Chat
|
8
|
+
include Ollama::Media
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
def api_base(config)
|
14
|
-
config.ollama_api_base
|
10
|
+
def api_base
|
11
|
+
@config.ollama_api_base
|
15
12
|
end
|
16
13
|
|
17
|
-
def headers
|
14
|
+
def headers
|
18
15
|
{}
|
19
16
|
end
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def configuration_requirements
|
26
|
-
%i[ollama_api_base]
|
27
|
-
end
|
18
|
+
class << self
|
19
|
+
def configuration_requirements
|
20
|
+
%i[ollama_api_base]
|
21
|
+
end
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
def local?
|
24
|
+
true
|
25
|
+
end
|
31
26
|
end
|
32
27
|
end
|
33
28
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
|
-
|
5
|
+
class OpenAI
|
6
6
|
# Determines capabilities and pricing for OpenAI models
|
7
7
|
module Capabilities
|
8
8
|
module_function
|
@@ -216,7 +216,7 @@ module RubyLLM
|
|
216
216
|
end
|
217
217
|
|
218
218
|
def self.normalize_temperature(temperature, model_id)
|
219
|
-
if model_id.match?(/^o\d/)
|
219
|
+
if model_id.match?(/^(o\d|gpt-5)/)
|
220
220
|
RubyLLM.logger.debug "Model #{model_id} requires temperature=1.0, ignoring provided value"
|
221
221
|
1.0
|
222
222
|
elsif model_id.match?(/-search/)
|
@@ -264,7 +264,7 @@ module RubyLLM
|
|
264
264
|
capabilities << 'batch' if model_id.match?(/embedding|batch/)
|
265
265
|
|
266
266
|
# Advanced capabilities
|
267
|
-
capabilities << 'reasoning' if model_id.match?(/
|
267
|
+
capabilities << 'reasoning' if model_id.match?(/o\d|gpt-5|codex/)
|
268
268
|
|
269
269
|
if model_id.match?(/gpt-4-turbo|gpt-4o/)
|
270
270
|
capabilities << 'image_generation' if model_id.match?(/vision/)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
|
-
|
5
|
+
class OpenAI
|
6
6
|
# Chat methods of the OpenAI API integration
|
7
7
|
module Chat
|
8
8
|
def completion_url
|
@@ -21,10 +21,7 @@ module RubyLLM
|
|
21
21
|
# Only include temperature if it's not nil (some models don't accept it)
|
22
22
|
payload[:temperature] = temperature unless temperature.nil?
|
23
23
|
|
24
|
-
if tools.any?
|
25
|
-
payload[:tools] = tools.map { |_, tool| tool_for(tool) }
|
26
|
-
payload[:tool_choice] = 'auto'
|
27
|
-
end
|
24
|
+
payload[:tools] = tools.map { |_, tool| tool_for(tool) } if tools.any?
|
28
25
|
|
29
26
|
if schema
|
30
27
|
# Use strict mode from schema if specified, default to true
|
@@ -78,7 +75,7 @@ module RubyLLM
|
|
78
75
|
def format_role(role)
|
79
76
|
case role
|
80
77
|
when :system
|
81
|
-
'developer'
|
78
|
+
@config.openai_use_system_role ? 'system' : 'developer'
|
82
79
|
else
|
83
80
|
role.to_s
|
84
81
|
end
|
@@ -5,51 +5,39 @@ module RubyLLM
|
|
5
5
|
# OpenAI API integration. Handles chat completion, function calling,
|
6
6
|
# and OpenAI's unique streaming format. Supports GPT-4, GPT-3.5,
|
7
7
|
# and other OpenAI models.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
base.extend(Provider)
|
20
|
-
base.extend(OpenAI::Chat)
|
21
|
-
base.extend(OpenAI::Embeddings)
|
22
|
-
base.extend(OpenAI::Models)
|
23
|
-
base.extend(OpenAI::Streaming)
|
24
|
-
base.extend(OpenAI::Tools)
|
25
|
-
base.extend(OpenAI::Images)
|
26
|
-
base.extend(OpenAI::Media)
|
8
|
+
class OpenAI < Provider
|
9
|
+
include OpenAI::Chat
|
10
|
+
include OpenAI::Embeddings
|
11
|
+
include OpenAI::Models
|
12
|
+
include OpenAI::Streaming
|
13
|
+
include OpenAI::Tools
|
14
|
+
include OpenAI::Images
|
15
|
+
include OpenAI::Media
|
16
|
+
|
17
|
+
def api_base
|
18
|
+
@config.openai_api_base || 'https://api.openai.com/v1'
|
27
19
|
end
|
28
20
|
|
29
|
-
|
30
|
-
|
31
|
-
def api_base(config)
|
32
|
-
config.openai_api_base || 'https://api.openai.com/v1'
|
33
|
-
end
|
34
|
-
|
35
|
-
def headers(config)
|
21
|
+
def headers
|
36
22
|
{
|
37
|
-
'Authorization' => "Bearer #{config.openai_api_key}",
|
38
|
-
'OpenAI-Organization' => config.openai_organization_id,
|
39
|
-
'OpenAI-Project' => config.openai_project_id
|
23
|
+
'Authorization' => "Bearer #{@config.openai_api_key}",
|
24
|
+
'OpenAI-Organization' => @config.openai_organization_id,
|
25
|
+
'OpenAI-Project' => @config.openai_project_id
|
40
26
|
}.compact
|
41
27
|
end
|
42
28
|
|
43
|
-
def
|
44
|
-
OpenAI::Capabilities
|
29
|
+
def maybe_normalize_temperature(temperature, model_id)
|
30
|
+
OpenAI::Capabilities.normalize_temperature(temperature, model_id)
|
45
31
|
end
|
46
32
|
|
47
|
-
|
48
|
-
|
49
|
-
|
33
|
+
class << self
|
34
|
+
def capabilities
|
35
|
+
OpenAI::Capabilities
|
36
|
+
end
|
50
37
|
|
51
|
-
|
52
|
-
|
38
|
+
def configuration_requirements
|
39
|
+
%i[openai_api_key]
|
40
|
+
end
|
53
41
|
end
|
54
42
|
end
|
55
43
|
end
|
@@ -3,28 +3,23 @@
|
|
3
3
|
module RubyLLM
|
4
4
|
module Providers
|
5
5
|
# OpenRouter API integration.
|
6
|
-
|
7
|
-
|
8
|
-
extend OpenRouter::Models
|
6
|
+
class OpenRouter < OpenAI
|
7
|
+
include OpenRouter::Models
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
def api_base(_config)
|
9
|
+
def api_base
|
13
10
|
'https://openrouter.ai/api/v1'
|
14
11
|
end
|
15
12
|
|
16
|
-
def headers
|
13
|
+
def headers
|
17
14
|
{
|
18
|
-
'Authorization' => "Bearer #{config.openrouter_api_key}"
|
15
|
+
'Authorization' => "Bearer #{@config.openrouter_api_key}"
|
19
16
|
}
|
20
17
|
end
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def configuration_requirements
|
27
|
-
%i[openrouter_api_key]
|
19
|
+
class << self
|
20
|
+
def configuration_requirements
|
21
|
+
%i[openrouter_api_key]
|
22
|
+
end
|
28
23
|
end
|
29
24
|
end
|
30
25
|
end
|