ruby_llm 1.1.0rc1 → 1.1.0
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 +2 -2
- data/lib/ruby_llm/chat.rb +3 -1
- data/lib/ruby_llm/configuration.rb +13 -1
- data/lib/ruby_llm/provider.rb +7 -6
- data/lib/ruby_llm/providers/bedrock.rb +16 -0
- data/lib/ruby_llm/stream_accumulator.rb +10 -2
- data/lib/ruby_llm/tool.rb +0 -3
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/tasks/models_docs.rake +156 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b157007e50a6d43f11591847306e9e950904ad71dde849dded2f4364f376fa0f
|
4
|
+
data.tar.gz: 9f2024f254134590b971a98b6fe1cae161bfd25378f747cd6c192237add0d80c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d804afb295a9b9d174f44ac110ce60e9d6b3ab6a4e96d003532bbdf5c95bc6db34b7affcec44d6025eff98d71a38a356417dee3912776b44feb735b803c49ed6
|
7
|
+
data.tar.gz: ef562bad49590fc86fb78311f861688175a55b9ab2b6d68c23d74cbaeabc1ecf9703b420bed5f8bc689fb1542cbe2fe484b1aa52e8df53d8b6fedb6737b19f18
|
data/README.md
CHANGED
@@ -135,7 +135,7 @@ chat.ask "Tell me a story about a Ruby programmer" do |chunk|
|
|
135
135
|
print chunk.content
|
136
136
|
end
|
137
137
|
|
138
|
-
# Set personality or behavior with instructions (aka system prompts)
|
138
|
+
# Set personality or behavior with instructions (aka system prompts)
|
139
139
|
chat.with_instructions "You are a friendly Ruby expert who loves to help beginners"
|
140
140
|
|
141
141
|
# Understand content in multiple forms
|
@@ -171,7 +171,7 @@ end
|
|
171
171
|
# In a background job
|
172
172
|
chat = Chat.create! model_id: "gpt-4o-mini"
|
173
173
|
|
174
|
-
# Set personality or behavior with instructions (aka system prompts) - they're persisted too!
|
174
|
+
# Set personality or behavior with instructions (aka system prompts) - they're persisted too!
|
175
175
|
chat.with_instructions "You are a friendly Ruby expert who loves to help beginners"
|
176
176
|
|
177
177
|
chat.ask("What's your favorite Ruby gem?") do |chunk|
|
data/lib/ruby_llm/chat.rb
CHANGED
@@ -32,7 +32,9 @@ module RubyLLM
|
|
32
32
|
|
33
33
|
alias say ask
|
34
34
|
|
35
|
-
def with_instructions(instructions)
|
35
|
+
def with_instructions(instructions, replace: false)
|
36
|
+
@messages = @messages.reject! { |msg| msg.role == :system } if replace
|
37
|
+
|
36
38
|
add_message role: :system, content: instructions
|
37
39
|
self
|
38
40
|
end
|
@@ -10,6 +10,7 @@ module RubyLLM
|
|
10
10
|
# config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
|
11
11
|
# end
|
12
12
|
class Configuration
|
13
|
+
# Provider-specific configuration
|
13
14
|
attr_accessor :openai_api_key,
|
14
15
|
:anthropic_api_key,
|
15
16
|
:gemini_api_key,
|
@@ -18,15 +19,26 @@ module RubyLLM
|
|
18
19
|
:bedrock_secret_key,
|
19
20
|
:bedrock_region,
|
20
21
|
:bedrock_session_token,
|
22
|
+
# Default models
|
21
23
|
:default_model,
|
22
24
|
:default_embedding_model,
|
23
25
|
:default_image_model,
|
26
|
+
# Connection configuration
|
24
27
|
:request_timeout,
|
25
|
-
:max_retries
|
28
|
+
:max_retries,
|
29
|
+
:retry_interval,
|
30
|
+
:retry_backoff_factor,
|
31
|
+
:retry_interval_randomness
|
26
32
|
|
27
33
|
def initialize
|
34
|
+
# Connection configuration
|
28
35
|
@request_timeout = 120
|
29
36
|
@max_retries = 3
|
37
|
+
@retry_interval = 0.1
|
38
|
+
@retry_backoff_factor = 2
|
39
|
+
@retry_interval_randomness = 0.5
|
40
|
+
|
41
|
+
# Default models
|
30
42
|
@default_model = 'gpt-4o-mini'
|
31
43
|
@default_embedding_model = 'text-embedding-3-small'
|
32
44
|
@default_image_model = 'dall-e-3'
|
data/lib/ruby_llm/provider.rb
CHANGED
@@ -7,7 +7,7 @@ module RubyLLM
|
|
7
7
|
module Provider
|
8
8
|
# Common functionality for all LLM providers. Implements the core provider
|
9
9
|
# interface so specific providers only need to implement a few key methods.
|
10
|
-
module Methods
|
10
|
+
module Methods # rubocop:disable Metrics/ModuleLength
|
11
11
|
extend Streaming
|
12
12
|
|
13
13
|
def complete(messages, tools:, temperature:, model:, &block) # rubocop:disable Metrics/MethodLength
|
@@ -108,9 +108,9 @@ module RubyLLM
|
|
108
108
|
|
109
109
|
f.request :retry, {
|
110
110
|
max: RubyLLM.config.max_retries,
|
111
|
-
interval:
|
112
|
-
interval_randomness:
|
113
|
-
backoff_factor:
|
111
|
+
interval: RubyLLM.config.retry_interval,
|
112
|
+
interval_randomness: RubyLLM.config.retry_interval_randomness,
|
113
|
+
backoff_factor: RubyLLM.config.retry_backoff_factor,
|
114
114
|
exceptions: [
|
115
115
|
Errno::ETIMEDOUT,
|
116
116
|
Timeout::Error,
|
@@ -119,9 +119,10 @@ module RubyLLM
|
|
119
119
|
Faraday::RetriableResponse,
|
120
120
|
RubyLLM::RateLimitError,
|
121
121
|
RubyLLM::ServerError,
|
122
|
-
RubyLLM::ServiceUnavailableError
|
122
|
+
RubyLLM::ServiceUnavailableError,
|
123
|
+
RubyLLM::OverloadedError
|
123
124
|
],
|
124
|
-
retry_statuses: [429, 500, 502, 503, 504]
|
125
|
+
retry_statuses: [429, 500, 502, 503, 504, 529]
|
125
126
|
}
|
126
127
|
|
127
128
|
f.request :json
|
@@ -33,6 +33,22 @@ module RubyLLM
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
def parse_error(response) # rubocop:disable Metrics/MethodLength
|
37
|
+
return if response.body.empty?
|
38
|
+
|
39
|
+
body = try_parse_json(response.body)
|
40
|
+
case body
|
41
|
+
when Hash
|
42
|
+
body['message']
|
43
|
+
when Array
|
44
|
+
body.map do |part|
|
45
|
+
part['message']
|
46
|
+
end.join('. ')
|
47
|
+
else
|
48
|
+
body
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
36
52
|
def sign_request(url, method: :post, payload: nil)
|
37
53
|
signer = create_signer
|
38
54
|
request = build_request(url, method:, payload:)
|
@@ -42,12 +42,20 @@ module RubyLLM
|
|
42
42
|
|
43
43
|
private
|
44
44
|
|
45
|
-
def tool_calls_from_stream
|
45
|
+
def tool_calls_from_stream # rubocop:disable Metrics/MethodLength
|
46
46
|
tool_calls.transform_values do |tc|
|
47
|
+
arguments = if tc.arguments.is_a?(String) && !tc.arguments.empty?
|
48
|
+
JSON.parse(tc.arguments)
|
49
|
+
elsif tc.arguments.is_a?(String)
|
50
|
+
{} # Return empty hash for empty string arguments
|
51
|
+
else
|
52
|
+
tc.arguments
|
53
|
+
end
|
54
|
+
|
47
55
|
ToolCall.new(
|
48
56
|
id: tc.id,
|
49
57
|
name: tc.name,
|
50
|
-
arguments:
|
58
|
+
arguments: arguments
|
51
59
|
)
|
52
60
|
end
|
53
61
|
end
|
data/lib/ruby_llm/tool.rb
CHANGED
@@ -72,9 +72,6 @@ module RubyLLM
|
|
72
72
|
result = execute(**args.transform_keys(&:to_sym))
|
73
73
|
RubyLLM.logger.debug "Tool #{name} returned: #{result.inspect}"
|
74
74
|
result
|
75
|
-
rescue StandardError => e
|
76
|
-
RubyLLM.logger.error "Tool #{name} failed with error: #{e.message}"
|
77
|
-
{ error: e.message }
|
78
75
|
end
|
79
76
|
|
80
77
|
def execute(...)
|
data/lib/ruby_llm/version.rb
CHANGED
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ruby_llm'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
MODEL_KEYS_TO_DISPLAY = %i[
|
7
|
+
id
|
8
|
+
type
|
9
|
+
display_name
|
10
|
+
provider
|
11
|
+
context_window
|
12
|
+
max_tokens
|
13
|
+
family
|
14
|
+
input_price_per_million
|
15
|
+
output_price_per_million
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def to_markdown_table(models) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
19
|
+
to_display_hash = ->(model) { model.to_h.slice(*MODEL_KEYS_TO_DISPLAY) }
|
20
|
+
model_hashes = Array(models).map { |model| to_display_hash.call(model) }
|
21
|
+
|
22
|
+
# Create abbreviated headers
|
23
|
+
headers = {
|
24
|
+
id: 'ID',
|
25
|
+
type: 'Type',
|
26
|
+
display_name: 'Name',
|
27
|
+
provider: 'Provider',
|
28
|
+
context_window: 'Context',
|
29
|
+
max_tokens: 'MaxTok',
|
30
|
+
family: 'Family',
|
31
|
+
input_price_per_million: 'In$/M',
|
32
|
+
output_price_per_million: 'Out$/M'
|
33
|
+
}
|
34
|
+
|
35
|
+
# Create header row with alignment markers
|
36
|
+
# Right-align numbers, left-align text
|
37
|
+
alignments = {
|
38
|
+
id: ':--',
|
39
|
+
type: ':--',
|
40
|
+
display_name: ':--',
|
41
|
+
provider: ':--',
|
42
|
+
context_window: '--:',
|
43
|
+
max_tokens: '--:',
|
44
|
+
family: ':--',
|
45
|
+
input_price_per_million: '--:',
|
46
|
+
output_price_per_million: '--:'
|
47
|
+
}
|
48
|
+
|
49
|
+
# Build the table
|
50
|
+
lines = []
|
51
|
+
|
52
|
+
# Header row
|
53
|
+
lines << "| #{MODEL_KEYS_TO_DISPLAY.map { |key| headers[key] }.join(' | ')} |"
|
54
|
+
|
55
|
+
# Alignment row
|
56
|
+
lines << "| #{MODEL_KEYS_TO_DISPLAY.map { |key| alignments[key] }.join(' | ')} |"
|
57
|
+
|
58
|
+
# Data rows
|
59
|
+
model_hashes.each do |model_hash|
|
60
|
+
values = MODEL_KEYS_TO_DISPLAY.map do |key|
|
61
|
+
if model_hash[key].is_a?(Float)
|
62
|
+
format('%.2f', model_hash[key])
|
63
|
+
else
|
64
|
+
model_hash[key]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
lines << "| #{values.join(' | ')} |"
|
69
|
+
end
|
70
|
+
|
71
|
+
lines.join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
namespace :models do # rubocop:disable Metrics/BlockLength
|
75
|
+
desc 'Generate available models documentation'
|
76
|
+
task :docs do # rubocop:disable Metrics/BlockLength
|
77
|
+
FileUtils.mkdir_p('docs/guides') # ensure output directory exists
|
78
|
+
|
79
|
+
output = <<~MARKDOWN
|
80
|
+
---
|
81
|
+
layout: default
|
82
|
+
title: Available Models
|
83
|
+
parent: Guides
|
84
|
+
nav_order: 10
|
85
|
+
permalink: /guides/available-models
|
86
|
+
---
|
87
|
+
|
88
|
+
# Available Models
|
89
|
+
|
90
|
+
This guide lists all models available in RubyLLM, automatically generated from the current model registry.
|
91
|
+
|
92
|
+
_Last updated: #{Time.now.utc.strftime('%Y-%m-%d')}_
|
93
|
+
|
94
|
+
## Contributing
|
95
|
+
|
96
|
+
The model list is automatically generated from the model registry. To add or update models:
|
97
|
+
|
98
|
+
1. Edit the appropriate `capabilities.rb` file in `lib/ruby_llm/providers/<provider>/`
|
99
|
+
2. Run `rake models:update` to refresh the model registry
|
100
|
+
3. Submit a pull request with the updated `models.json`
|
101
|
+
|
102
|
+
See [Contributing Guide](/CONTRIBUTING.md) for more details.
|
103
|
+
|
104
|
+
## Additional Model Information
|
105
|
+
|
106
|
+
The tables below show basic model information including context windows, token limits, and pricing. Models also have additional capabilities not shown in the tables:
|
107
|
+
|
108
|
+
- **Vision Support**: Whether the model can process images
|
109
|
+
- **Function Calling**: Whether the model supports function calling
|
110
|
+
- **JSON Mode**: Whether the model can be constrained to output valid JSON
|
111
|
+
- **Structured Output**: Whether the model supports structured output formats
|
112
|
+
|
113
|
+
For complete model information, you can check the `models.json` file in the RubyLLM source code.
|
114
|
+
|
115
|
+
For more information about working with models, see the [Working with Models](/guides/models) guide.
|
116
|
+
|
117
|
+
## Models by Type
|
118
|
+
|
119
|
+
### Chat Models (#{RubyLLM.models.chat_models.count})
|
120
|
+
|
121
|
+
#{to_markdown_table(RubyLLM.models.chat_models)}
|
122
|
+
|
123
|
+
### Image Models (#{RubyLLM.models.image_models.count})
|
124
|
+
|
125
|
+
#{to_markdown_table(RubyLLM.models.image_models)}
|
126
|
+
|
127
|
+
### Audio Models (#{RubyLLM.models.audio_models.count})
|
128
|
+
|
129
|
+
#{to_markdown_table(RubyLLM.models.audio_models)}
|
130
|
+
|
131
|
+
### Embedding Models (#{RubyLLM.models.embedding_models.count})
|
132
|
+
|
133
|
+
#{to_markdown_table(RubyLLM.models.embedding_models)}
|
134
|
+
|
135
|
+
### Moderation Models (#{RubyLLM.models.select { |m| m.type == 'moderation' }.count})
|
136
|
+
|
137
|
+
#{to_markdown_table(RubyLLM.models.select { |m| m.type == 'moderation' })}
|
138
|
+
|
139
|
+
## Models by Provider
|
140
|
+
|
141
|
+
#{RubyLLM::Provider.providers.keys.map do |provider|
|
142
|
+
models = RubyLLM.models.by_provider(provider)
|
143
|
+
next if models.none?
|
144
|
+
|
145
|
+
<<~PROVIDER
|
146
|
+
### #{provider.to_s.capitalize} Models (#{models.count})
|
147
|
+
|
148
|
+
#{to_markdown_table(models)}
|
149
|
+
PROVIDER
|
150
|
+
end.compact.join("\n")}
|
151
|
+
MARKDOWN
|
152
|
+
|
153
|
+
File.write('docs/guides/available-models.md', output)
|
154
|
+
puts 'Generated docs/guides/available-models.md'
|
155
|
+
end
|
156
|
+
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: 1.1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- lib/tasks/code_validator.rb
|
177
177
|
- lib/tasks/model_updater.rb
|
178
178
|
- lib/tasks/models.rake
|
179
|
+
- lib/tasks/models_docs.rake
|
179
180
|
- lib/tasks/vcr.rake
|
180
181
|
homepage: https://rubyllm.com
|
181
182
|
licenses:
|