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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f1ca42c438f99a40f6ada6ab87e23377403d9d6c8db6049d54960308b6dd42f
4
- data.tar.gz: 0467734c40a0a64505b8f4de2eea4b929e2b0c615fedb3fe88d75f8cf20040de
3
+ metadata.gz: b157007e50a6d43f11591847306e9e950904ad71dde849dded2f4364f376fa0f
4
+ data.tar.gz: 9f2024f254134590b971a98b6fe1cae161bfd25378f747cd6c192237add0d80c
5
5
  SHA512:
6
- metadata.gz: ed886fb15081ce27309c0e583223e62adf171907f0f047344763e9eae5ede4dbb96657bb1b69dde9e68bc1ed56acedb93717273067236e40104dddcc09886f33
7
- data.tar.gz: 7f2aa9c50cfd1a525273256ff014712944c976229f6b90fe338decaf2525bcb82f19dec187d14795ce0891a7fceadb5c048905c8afa8066b0ddbe37d54c48edd
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) - available from 1.1.0
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! - available from 1.1.0
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'
@@ -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: 0.05,
112
- interval_randomness: 0.5,
113
- backoff_factor: 2,
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: tc.arguments.is_a?(String) ? JSON.parse(tc.arguments) : tc.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(...)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '1.1.0rc1'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -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.0rc1
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-02 00:00:00.000000000 Z
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: