ruby_llm 1.15.0 → 1.16.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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -4
  3. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +1 -1
  4. data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +3 -3
  5. data/lib/ruby_llm/active_record/acts_as.rb +1 -26
  6. data/lib/ruby_llm/active_record/acts_as_legacy.rb +71 -4
  7. data/lib/ruby_llm/active_record/chat_methods.rb +2 -2
  8. data/lib/ruby_llm/active_record/message_methods.rb +70 -3
  9. data/lib/ruby_llm/agent.rb +1 -0
  10. data/lib/ruby_llm/aliases.json +78 -75
  11. data/lib/ruby_llm/aliases.rb +3 -0
  12. data/lib/ruby_llm/attachment.rb +34 -17
  13. data/lib/ruby_llm/chat.rb +176 -47
  14. data/lib/ruby_llm/configuration.rb +14 -1
  15. data/lib/ruby_llm/connection.rb +36 -7
  16. data/lib/ruby_llm/content.rb +15 -1
  17. data/lib/ruby_llm/deprecator.rb +24 -0
  18. data/lib/ruby_llm/embedding.rb +31 -1
  19. data/lib/ruby_llm/error.rb +11 -75
  20. data/lib/ruby_llm/error_middleware.rb +81 -0
  21. data/lib/ruby_llm/image.rb +2 -0
  22. data/lib/ruby_llm/instrumentation.rb +36 -0
  23. data/lib/ruby_llm/mime_type.rb +25 -0
  24. data/lib/ruby_llm/model/info.rb +36 -2
  25. data/lib/ruby_llm/model/pricing.rb +19 -9
  26. data/lib/ruby_llm/model/pricing_tier.rb +20 -9
  27. data/lib/ruby_llm/model_registry.rb +39 -0
  28. data/lib/ruby_llm/models.json +18225 -19144
  29. data/lib/ruby_llm/models.rb +95 -30
  30. data/lib/ruby_llm/provider.rb +11 -2
  31. data/lib/ruby_llm/providers/anthropic/chat.rb +49 -15
  32. data/lib/ruby_llm/providers/anthropic/models.rb +2 -0
  33. data/lib/ruby_llm/providers/anthropic/streaming.rb +2 -0
  34. data/lib/ruby_llm/providers/anthropic/tools.rb +28 -2
  35. data/lib/ruby_llm/providers/azure/media.rb +1 -1
  36. data/lib/ruby_llm/providers/bedrock/auth.rb +1 -0
  37. data/lib/ruby_llm/providers/bedrock/chat.rb +2 -0
  38. data/lib/ruby_llm/providers/bedrock/media.rb +21 -3
  39. data/lib/ruby_llm/providers/bedrock/models.rb +1 -1
  40. data/lib/ruby_llm/providers/bedrock/streaming.rb +6 -0
  41. data/lib/ruby_llm/providers/bedrock.rb +2 -2
  42. data/lib/ruby_llm/providers/deepseek/capabilities.rb +43 -0
  43. data/lib/ruby_llm/providers/deepseek/chat.rb +9 -0
  44. data/lib/ruby_llm/providers/gemini/chat.rb +2 -3
  45. data/lib/ruby_llm/providers/gemini/media.rb +16 -9
  46. data/lib/ruby_llm/providers/gemini/streaming.rb +2 -0
  47. data/lib/ruby_llm/providers/gemini/tools.rb +2 -0
  48. data/lib/ruby_llm/providers/gpustack/chat.rb +8 -1
  49. data/lib/ruby_llm/providers/gpustack/models.rb +2 -0
  50. data/lib/ruby_llm/providers/mistral/capabilities.rb +1 -1
  51. data/lib/ruby_llm/providers/mistral/chat.rb +1 -1
  52. data/lib/ruby_llm/providers/mistral/media.rb +55 -0
  53. data/lib/ruby_llm/providers/mistral/models.rb +2 -0
  54. data/lib/ruby_llm/providers/mistral.rb +2 -2
  55. data/lib/ruby_llm/providers/ollama/chat.rb +8 -1
  56. data/lib/ruby_llm/providers/openai/chat.rb +16 -1
  57. data/lib/ruby_llm/providers/openai/images.rb +9 -9
  58. data/lib/ruby_llm/providers/openai/media.rb +40 -16
  59. data/lib/ruby_llm/providers/openai/streaming.rb +2 -0
  60. data/lib/ruby_llm/providers/openai/tools.rb +2 -0
  61. data/lib/ruby_llm/providers/openai/transcription.rb +1 -0
  62. data/lib/ruby_llm/providers/openrouter/chat.rb +6 -2
  63. data/lib/ruby_llm/providers/perplexity/chat.rb +11 -0
  64. data/lib/ruby_llm/providers/perplexity/media.rb +62 -0
  65. data/lib/ruby_llm/providers/perplexity.rb +2 -2
  66. data/lib/ruby_llm/providers/vertexai.rb +5 -1
  67. data/lib/ruby_llm/providers/xai/chat.rb +9 -0
  68. data/lib/ruby_llm/providers/xai/models.rb +15 -27
  69. data/lib/ruby_llm/providers/xai.rb +2 -2
  70. data/lib/ruby_llm/railtie.rb +5 -1
  71. data/lib/ruby_llm/stream_accumulator.rb +45 -30
  72. data/lib/ruby_llm/streaming.rb +4 -0
  73. data/lib/ruby_llm/tool_concurrency.rb +105 -0
  74. data/lib/ruby_llm/transcription.rb +2 -1
  75. data/lib/ruby_llm/utils.rb +39 -0
  76. data/lib/ruby_llm/version.rb +1 -1
  77. data/lib/ruby_llm.rb +9 -2
  78. data/lib/tasks/models.rake +32 -4
  79. data/lib/tasks/release.rake +50 -23
  80. metadata +17 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cfdd21451b6e3daac0463dfdb7655892967e5a4da6b00846f353809a9abe18a
4
- data.tar.gz: e1505ddd57326601298bb8975c20049a195eb87babd62b08ac0e6340c9e653f6
3
+ metadata.gz: ba1ac6556eb9321cc5c4840eb10c4f2253a35991298d3a4f9cf6dd85035ba069
4
+ data.tar.gz: f87c2f1e7c1898c31ae732db0bae3a96f8b9c9082d8f9abd9a728b2b9d295426
5
5
  SHA512:
6
- metadata.gz: 7222e575d4f1e5cf620fdc37f4c255c7ededeee945d7b77fac4129c2947d6f78f7d5641b45ed39470180e5bf2dfd48b36e0a6c16579e4e4835564c48b6907920
7
- data.tar.gz: ce3fb0f0e8b3665fafe56717cf8fcb10733008821633b024013d0f6e5d0bc90ef47f25b0109aa0e80ee3df4002e2f9b6a20cd98595031aa57235588cb4677052
6
+ metadata.gz: f75855b2dc79679febdf4edb67130f5ee60d7445bd1a34d7f29c69f3cd363711b881ffe2b51eac8fa4f2a74b297e364e53263e12674333055c8daf702d528a3a
7
+ data.tar.gz: aceac99dd86c4e4db028411d1d58cd2602351f3ba0b3cb7fc2334d979459a97294f2617e10770d851b57f70aa26b49f9995dd239d1f52cff43814d1293419a75
data/README.md CHANGED
@@ -5,9 +5,10 @@
5
5
  <img src="/docs/assets/images/logotype.svg" alt="RubyLLM" height="120" width="250">
6
6
  </picture>
7
7
 
8
- <strong>One *beautiful* Ruby API for GPT, Claude, Gemini, and more.</strong>
8
+ <strong>A single, beautiful Ruby framework for all major AI providers. Easily build chatbots, AI agents, RAG applications, content generators, and every AI workflow you can think of.
9
+ </strong>
9
10
 
10
- Battle tested at [<picture><source media="(prefers-color-scheme: dark)" srcset="https://chatwithwork.com/logotype-dark.svg"><img src="https://chatwithwork.com/logotype.svg" alt="Chat with Work" height="30" align="absmiddle"></picture>](https://chatwithwork.com) *Your AI coworker*
11
+ Battle tested at [<picture><source media="(prefers-color-scheme: dark)" srcset="https://chatwithwork.com/logotype-dark.svg"><img src="https://chatwithwork.com/logotype.svg" alt="Chat with Work" height="30" align="absmiddle"></picture>](https://chatwithwork.com) - *Fully private work AI*
11
12
 
12
13
  [![Gem Version](https://badge.fury.io/rb/ruby_llm.svg)](https://badge.fury.io/rb/ruby_llm)
13
14
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
@@ -24,7 +25,7 @@ Battle tested at [<picture><source media="(prefers-color-scheme: dark)" srcset="
24
25
 
25
26
  Build chatbots, AI agents, RAG applications. Works with OpenAI, xAI, Anthropic, Google, AWS, local models, and any OpenAI-compatible API.
26
27
 
27
- ## From zero to AI chat app in under two minutes
28
+ ## Build a working Ruby AI chat in two minutes
28
29
 
29
30
  https://github.com/user-attachments/assets/65422091-9338-47da-a303-92b918bd1345
30
31
 
@@ -32,7 +33,7 @@ https://github.com/user-attachments/assets/65422091-9338-47da-a303-92b918bd1345
32
33
 
33
34
  Every AI provider ships their own bloated client. Different APIs. Different response formats. Different conventions. It's exhausting.
34
35
 
35
- RubyLLM gives you one beautiful API for all of them. Same interface whether you're using GPT, Claude, or your local Ollama. Just three dependencies: Faraday, Zeitwerk, and Marcel. That's it.
36
+ RubyLLM gives you one beautiful framework for all of them. Same interface whether you're using GPT, Claude, or your local Ollama. Just three dependencies: Faraday, Zeitwerk, and Marcel. That's it.
36
37
 
37
38
  ## Show me the code
38
39
 
@@ -2,7 +2,7 @@ RubyLLM.configure do |config|
2
2
  config.openai_api_key = ENV.fetch("OPENAI_API_KEY", Rails.application.credentials.dig(:openai_api_key))
3
3
  # config.default_model = "gpt-5-nano"
4
4
 
5
- # Use the new association-based acts_as API (recommended)
5
+ # Use the association-based acts_as API (recommended)
6
6
  config.use_new_acts_as = true
7
7
  <% if model_model_name != 'Model' -%>
8
8
 
@@ -6,7 +6,7 @@ require_relative '../generator_helpers'
6
6
 
7
7
  module RubyLLM
8
8
  module Generators
9
- # Generator to upgrade existing RubyLLM apps to v1.7 with new Rails-like API
9
+ # Generator to upgrade existing RubyLLM apps to v1.7 with association-based Rails API
10
10
  class UpgradeToV17Generator < Rails::Generators::Base
11
11
  include Rails::Generators::Migration
12
12
  include RubyLLM::Generators::GeneratorHelpers
@@ -24,7 +24,7 @@ module RubyLLM
24
24
 
25
25
  argument :model_mappings, type: :array, default: [], banner: 'chat:ChatName message:MessageName ...'
26
26
 
27
- desc 'Upgrades existing RubyLLM apps to v1.7 with new Rails-like API\n' \
27
+ desc 'Upgrades existing RubyLLM apps to v1.7 with association-based Rails API\n' \
28
28
  'Usage: bin/rails g ruby_llm:upgrade_to_v1_7 [chat:ChatName] [message:MessageName] ...'
29
29
 
30
30
  def self.next_migration_number(dirname)
@@ -78,7 +78,7 @@ module RubyLLM
78
78
  return if initializer_content.include?('config.use_new_acts_as')
79
79
 
80
80
  inject_into_file initializer_path, before: /^end/ do
81
- lines = ["\n # Enable the new Rails-like API", ' config.use_new_acts_as = true']
81
+ lines = ["\n # Enable the association-based Rails API", ' config.use_new_acts_as = true']
82
82
  lines << " config.model_registry_class = \"#{model_model_name}\"" if model_model_name != 'Model'
83
83
  lines << "\n"
84
84
  lines.join("\n")
@@ -9,34 +9,9 @@ module RubyLLM
9
9
  module ActsAs
10
10
  extend ActiveSupport::Concern
11
11
 
12
- # When ActsAs is included, ensure models are loaded from database
13
12
  def self.included(base)
14
13
  super
15
- # Monkey-patch Models to use database when ActsAs is active
16
- RubyLLM::Models.class_eval do
17
- def self.load_models
18
- database_models = read_from_database
19
- return database_models if database_models.any?
20
-
21
- RubyLLM.logger.debug { 'Model registry is empty in database, falling back to JSON registry' }
22
- read_from_json
23
- rescue StandardError => e
24
- RubyLLM.logger.debug { "Failed to load models from database: #{e.message}, falling back to JSON" }
25
- read_from_json
26
- end
27
-
28
- def self.read_from_database
29
- model_class = RubyLLM.config.model_registry_class
30
- model_class = model_class.constantize if model_class.is_a?(String)
31
- return [] unless model_class.table_exists?
32
-
33
- model_class.all.map(&:to_llm)
34
- end
35
-
36
- def load_from_database!
37
- @models = self.class.read_from_database
38
- end
39
- end
14
+ RubyLLM.config.model_registry_source ||= RubyLLM::ModelRegistry::ActiveRecordSource.new
40
15
  end
41
16
 
42
17
  class_methods do # rubocop:disable Metrics/BlockLength
@@ -222,7 +222,7 @@ module RubyLLM
222
222
  end
223
223
 
224
224
  def create_user_message(content, with: nil)
225
- RubyLLM.logger.warn(
225
+ RubyLLM.deprecator.warn(
226
226
  '`create_user_message` is deprecated and will be removed in RubyLLM 2.0. ' \
227
227
  'Use `add_message(role: :user, content: ...)` instead.'
228
228
  )
@@ -505,13 +505,80 @@ module RubyLLM
505
505
  RubyLLM::Content.new(text_content).tap do |content_obj|
506
506
  @_tempfiles = []
507
507
 
508
- attachments.each do |attachment|
509
- tempfile = download_attachment(attachment)
510
- content_obj.add_attachment(tempfile, filename: attachment.filename.to_s)
508
+ attachment_sources.each do |attachment, attachable|
509
+ add_attachment_to_content(content_obj, attachment, attachable)
511
510
  end
512
511
  end
513
512
  end
514
513
 
514
+ def attachment_sources
515
+ change = pending_attachment_change
516
+ return attachments.map { |attachment| [attachment, nil] } unless pending_attachment_change?(change)
517
+
518
+ change.attachments.zip(change.attachables)
519
+ end
520
+
521
+ def pending_attachment_change
522
+ attachment_changes['attachments'] if respond_to?(:attachment_changes)
523
+ end
524
+
525
+ def pending_attachment_change?(change)
526
+ change.respond_to?(:attachments) && change.respond_to?(:attachables)
527
+ end
528
+
529
+ def add_attachment_to_content(content_obj, attachment, attachable)
530
+ if pending_upload_attachable?(attachable)
531
+ add_pending_upload_attachment(content_obj, attachable)
532
+ else
533
+ tempfile = download_attachment(attachment)
534
+ content_obj.add_attachment(tempfile, filename: attachment.filename.to_s)
535
+ end
536
+ end
537
+
538
+ def pending_upload_attachable?(attachable)
539
+ return false if attachable.nil? || attachable.is_a?(String)
540
+ return false if instance_of_class?(attachable, 'ActiveStorage::Blob')
541
+
542
+ uploaded_file?(attachable) || active_storage_upload_hash?(attachable) ||
543
+ attachable.is_a?(File) || pathname?(attachable)
544
+ end
545
+
546
+ def uploaded_file?(attachable)
547
+ instance_of_class?(attachable, 'ActionDispatch::Http::UploadedFile') ||
548
+ instance_of_class?(attachable, 'Rack::Test::UploadedFile')
549
+ end
550
+
551
+ def active_storage_upload_hash?(attachable)
552
+ attachable.is_a?(Hash) && attachment_hash_io(attachable).present?
553
+ end
554
+
555
+ def pathname?(attachable)
556
+ defined?(Pathname) && attachable.is_a?(Pathname)
557
+ end
558
+
559
+ def add_pending_upload_attachment(content_obj, attachable)
560
+ if attachable.is_a?(Hash)
561
+ content_obj.add_attachment(attachment_hash_io(attachable), filename: attachment_hash_filename(attachable))
562
+ else
563
+ content_obj.add_attachment(attachable)
564
+ end
565
+ end
566
+
567
+ def attachment_hash_io(attachable)
568
+ attachable[:io] || attachable['io']
569
+ end
570
+
571
+ def attachment_hash_filename(attachable)
572
+ filename = attachable[:filename] || attachable['filename']
573
+ filename&.to_s
574
+ end
575
+
576
+ def instance_of_class?(object, class_name)
577
+ Object.const_get(class_name).then { |klass| object.is_a?(klass) }
578
+ rescue NameError
579
+ false
580
+ end
581
+
515
582
  def download_attachment(attachment)
516
583
  ext = File.extname(attachment.filename.to_s)
517
584
  basename = File.basename(attachment.filename.to_s, ext)
@@ -65,8 +65,8 @@ module RubyLLM
65
65
  m.context_window = model_info.context_window
66
66
  m.max_output_tokens = model_info.max_output_tokens
67
67
  m.capabilities = model_info.capabilities || []
68
- m.modalities = model_info.modalities || {}
69
- m.pricing = model_info.pricing || {}
68
+ m.modalities = model_info.modalities.to_h
69
+ m.pricing = model_info.pricing.to_h
70
70
  m.metadata = model_info.metadata || {}
71
71
  end
72
72
 
@@ -122,13 +122,80 @@ module RubyLLM
122
122
  RubyLLM::Content.new(content_value).tap do |content_obj|
123
123
  @_tempfiles = []
124
124
 
125
- attachments.each do |attachment|
126
- tempfile = download_attachment(attachment)
127
- content_obj.add_attachment(tempfile, filename: attachment.filename.to_s)
125
+ attachment_sources.each do |attachment, attachable|
126
+ add_attachment_to_content(content_obj, attachment, attachable)
128
127
  end
129
128
  end
130
129
  end
131
130
 
131
+ def attachment_sources
132
+ change = pending_attachment_change
133
+ return attachments.map { |attachment| [attachment, nil] } unless pending_attachment_change?(change)
134
+
135
+ change.attachments.zip(change.attachables)
136
+ end
137
+
138
+ def pending_attachment_change
139
+ attachment_changes['attachments'] if respond_to?(:attachment_changes)
140
+ end
141
+
142
+ def pending_attachment_change?(change)
143
+ change.respond_to?(:attachments) && change.respond_to?(:attachables)
144
+ end
145
+
146
+ def add_attachment_to_content(content_obj, attachment, attachable)
147
+ if pending_upload_attachable?(attachable)
148
+ add_pending_upload_attachment(content_obj, attachable)
149
+ else
150
+ tempfile = download_attachment(attachment)
151
+ content_obj.add_attachment(tempfile, filename: attachment.filename.to_s)
152
+ end
153
+ end
154
+
155
+ def pending_upload_attachable?(attachable)
156
+ return false if attachable.nil? || attachable.is_a?(String)
157
+ return false if instance_of_class?(attachable, 'ActiveStorage::Blob')
158
+
159
+ uploaded_file?(attachable) || active_storage_upload_hash?(attachable) ||
160
+ attachable.is_a?(File) || pathname?(attachable)
161
+ end
162
+
163
+ def uploaded_file?(attachable)
164
+ instance_of_class?(attachable, 'ActionDispatch::Http::UploadedFile') ||
165
+ instance_of_class?(attachable, 'Rack::Test::UploadedFile')
166
+ end
167
+
168
+ def active_storage_upload_hash?(attachable)
169
+ attachable.is_a?(Hash) && attachment_hash_io(attachable).present?
170
+ end
171
+
172
+ def pathname?(attachable)
173
+ defined?(Pathname) && attachable.is_a?(Pathname)
174
+ end
175
+
176
+ def add_pending_upload_attachment(content_obj, attachable)
177
+ if attachable.is_a?(Hash)
178
+ content_obj.add_attachment(attachment_hash_io(attachable), filename: attachment_hash_filename(attachable))
179
+ else
180
+ content_obj.add_attachment(attachable)
181
+ end
182
+ end
183
+
184
+ def attachment_hash_io(attachable)
185
+ attachable[:io] || attachable['io']
186
+ end
187
+
188
+ def attachment_hash_filename(attachable)
189
+ filename = attachable[:filename] || attachable['filename']
190
+ filename&.to_s
191
+ end
192
+
193
+ def instance_of_class?(object, class_name)
194
+ Object.const_get(class_name).then { |klass| object.is_a?(klass) }
195
+ rescue NameError
196
+ false
197
+ end
198
+
132
199
  def download_attachment(attachment)
133
200
  ext = File.extname(attachment.filename.to_s)
134
201
  basename = File.basename(attachment.filename.to_s, ext)
@@ -125,6 +125,7 @@ module RubyLLM
125
125
  record
126
126
  end
127
127
 
128
+ # Mutates persisted instructions on the configured chat record.
128
129
  def sync_instructions!(chat_or_id, **kwargs)
129
130
  raise ArgumentError, 'chat_model must be configured to use sync_instructions!' unless resolved_chat_model
130
131
 
@@ -8,13 +8,10 @@
8
8
  "anthropic": "claude-3-5-haiku-latest"
9
9
  },
10
10
  "claude-3-5-sonnet": {
11
- "anthropic": "claude-3-5-sonnet-20241022",
12
- "bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0"
11
+ "anthropic": "claude-3-5-sonnet-20241022"
13
12
  },
14
13
  "claude-3-7-sonnet": {
15
- "anthropic": "claude-3-7-sonnet-20250219",
16
- "openrouter": "anthropic/claude-3.7-sonnet",
17
- "bedrock": "anthropic.claude-3-7-sonnet-20250219-v1:0"
14
+ "anthropic": "claude-3-7-sonnet-20250219"
18
15
  },
19
16
  "claude-3-haiku": {
20
17
  "anthropic": "claude-3-haiku-20240307",
@@ -36,8 +33,7 @@
36
33
  },
37
34
  "claude-opus-4": {
38
35
  "anthropic": "claude-opus-4-20250514",
39
- "openrouter": "anthropic/claude-opus-4",
40
- "bedrock": "anthropic.claude-opus-4-1-20250805-v1:0"
36
+ "openrouter": "anthropic/claude-opus-4"
41
37
  },
42
38
  "claude-opus-4-0": {
43
39
  "anthropic": "claude-opus-4-0"
@@ -66,10 +62,15 @@
66
62
  "bedrock": "anthropic.claude-opus-4-7",
67
63
  "azure": "claude-opus-4-7"
68
64
  },
65
+ "claude-opus-4-8": {
66
+ "anthropic": "claude-opus-4-8",
67
+ "openrouter": "anthropic/claude-opus-4.8",
68
+ "bedrock": "anthropic.claude-opus-4-8"
69
+ },
69
70
  "claude-sonnet-4": {
70
71
  "anthropic": "claude-sonnet-4-20250514",
71
72
  "openrouter": "anthropic/claude-sonnet-4",
72
- "bedrock": "anthropic.claude-sonnet-4-20250514-v1:0"
73
+ "bedrock": "us.anthropic.claude-sonnet-4-20250514-v1:0"
73
74
  },
74
75
  "claude-sonnet-4-0": {
75
76
  "anthropic": "claude-sonnet-4-0"
@@ -98,25 +99,12 @@
98
99
  "deepseek": "deepseek-v4-pro",
99
100
  "openrouter": "deepseek/deepseek-v4-pro"
100
101
  },
101
- "gemini-1.5-flash": {
102
- "gemini": "gemini-1.5-flash",
103
- "vertexai": "gemini-1.5-flash"
104
- },
105
- "gemini-1.5-flash-8b": {
106
- "gemini": "gemini-1.5-flash-8b",
107
- "vertexai": "gemini-1.5-flash-8b"
108
- },
109
- "gemini-1.5-pro": {
110
- "gemini": "gemini-1.5-pro",
111
- "vertexai": "gemini-1.5-pro"
112
- },
113
102
  "gemini-2.0-flash": {
114
103
  "gemini": "gemini-2.0-flash",
115
104
  "vertexai": "gemini-2.0-flash"
116
105
  },
117
106
  "gemini-2.0-flash-001": {
118
107
  "gemini": "gemini-2.0-flash-001",
119
- "openrouter": "google/gemini-2.0-flash-001",
120
108
  "vertexai": "gemini-2.0-flash-001"
121
109
  },
122
110
  "gemini-2.0-flash-lite": {
@@ -125,7 +113,6 @@
125
113
  },
126
114
  "gemini-2.0-flash-lite-001": {
127
115
  "gemini": "gemini-2.0-flash-lite-001",
128
- "openrouter": "google/gemini-2.0-flash-lite-001",
129
116
  "vertexai": "gemini-2.0-flash-lite-001"
130
117
  },
131
118
  "gemini-2.5-flash": {
@@ -142,62 +129,42 @@
142
129
  "openrouter": "google/gemini-2.5-flash-lite",
143
130
  "vertexai": "gemini-2.5-flash-lite"
144
131
  },
145
- "gemini-2.5-flash-lite-preview-06-17": {
146
- "gemini": "gemini-2.5-flash-lite-preview-06-17",
147
- "vertexai": "gemini-2.5-flash-lite-preview-06-17"
148
- },
149
- "gemini-2.5-flash-lite-preview-09-2025": {
150
- "gemini": "gemini-2.5-flash-lite-preview-09-2025",
151
- "openrouter": "google/gemini-2.5-flash-lite-preview-09-2025",
152
- "vertexai": "gemini-2.5-flash-lite-preview-09-2025"
153
- },
154
- "gemini-2.5-flash-preview-04-17": {
155
- "gemini": "gemini-2.5-flash-preview-04-17",
156
- "vertexai": "gemini-2.5-flash-preview-04-17"
157
- },
158
- "gemini-2.5-flash-preview-05-20": {
159
- "gemini": "gemini-2.5-flash-preview-05-20",
160
- "vertexai": "gemini-2.5-flash-preview-05-20"
161
- },
162
- "gemini-2.5-flash-preview-09-2025": {
163
- "gemini": "gemini-2.5-flash-preview-09-2025",
164
- "openrouter": "google/gemini-2.5-flash-preview-09-2025",
165
- "vertexai": "gemini-2.5-flash-preview-09-2025"
166
- },
167
132
  "gemini-2.5-pro": {
168
133
  "gemini": "gemini-2.5-pro",
169
134
  "openrouter": "google/gemini-2.5-pro",
170
135
  "vertexai": "gemini-2.5-pro"
171
136
  },
172
- "gemini-2.5-pro-preview-05-06": {
173
- "gemini": "gemini-2.5-pro-preview-05-06",
174
- "openrouter": "google/gemini-2.5-pro-preview-05-06",
175
- "vertexai": "gemini-2.5-pro-preview-05-06"
176
- },
177
- "gemini-2.5-pro-preview-06-05": {
178
- "gemini": "gemini-2.5-pro-preview-06-05",
179
- "openrouter": "google/gemini-2.5-pro-preview-06-05",
180
- "vertexai": "gemini-2.5-pro-preview-06-05"
181
- },
182
137
  "gemini-3-flash-preview": {
183
138
  "gemini": "gemini-3-flash-preview",
184
139
  "openrouter": "google/gemini-3-flash-preview",
185
140
  "vertexai": "gemini-3-flash-preview"
186
141
  },
142
+ "gemini-3-pro-image": {
143
+ "gemini": "gemini-3-pro-image",
144
+ "vertexai": "gemini-3-pro-image"
145
+ },
187
146
  "gemini-3-pro-image-preview": {
188
147
  "gemini": "gemini-3-pro-image-preview",
189
148
  "openrouter": "google/gemini-3-pro-image-preview"
190
149
  },
191
150
  "gemini-3-pro-preview": {
192
151
  "gemini": "gemini-3-pro-preview",
193
- "openrouter": "google/gemini-3-pro-preview",
194
152
  "vertexai": "gemini-3-pro-preview"
195
153
  },
154
+ "gemini-3.1-flash-image": {
155
+ "gemini": "gemini-3.1-flash-image",
156
+ "vertexai": "gemini-3.1-flash-image"
157
+ },
196
158
  "gemini-3.1-flash-image-preview": {
197
159
  "gemini": "gemini-3.1-flash-image-preview",
198
160
  "openrouter": "google/gemini-3.1-flash-image-preview",
199
161
  "vertexai": "gemini-3.1-flash-image-preview"
200
162
  },
163
+ "gemini-3.1-flash-lite": {
164
+ "gemini": "gemini-3.1-flash-lite",
165
+ "openrouter": "google/gemini-3.1-flash-lite",
166
+ "vertexai": "gemini-3.1-flash-lite"
167
+ },
201
168
  "gemini-3.1-flash-lite-preview": {
202
169
  "gemini": "gemini-3.1-flash-lite-preview",
203
170
  "openrouter": "google/gemini-3.1-flash-lite-preview",
@@ -213,6 +180,11 @@
213
180
  "openrouter": "google/gemini-3.1-pro-preview-customtools",
214
181
  "vertexai": "gemini-3.1-pro-preview-customtools"
215
182
  },
183
+ "gemini-3.5-flash": {
184
+ "gemini": "gemini-3.5-flash",
185
+ "openrouter": "google/gemini-3.5-flash",
186
+ "vertexai": "gemini-3.5-flash"
187
+ },
216
188
  "gemini-embedding-001": {
217
189
  "gemini": "gemini-embedding-001",
218
190
  "vertexai": "gemini-embedding-001"
@@ -229,22 +201,6 @@
229
201
  "gemini": "gemini-flash-lite-latest",
230
202
  "vertexai": "gemini-flash-lite-latest"
231
203
  },
232
- "gemma-3-12b-it": {
233
- "gemini": "gemma-3-12b-it",
234
- "openrouter": "google/gemma-3-12b-it"
235
- },
236
- "gemma-3-27b-it": {
237
- "gemini": "gemma-3-27b-it",
238
- "openrouter": "google/gemma-3-27b-it"
239
- },
240
- "gemma-3-4b-it": {
241
- "gemini": "gemma-3-4b-it",
242
- "openrouter": "google/gemma-3-4b-it"
243
- },
244
- "gemma-3n-e4b-it": {
245
- "gemini": "gemma-3n-e4b-it",
246
- "openrouter": "google/gemma-3n-e4b-it"
247
- },
248
204
  "gemma-4-26b-a4b-it": {
249
205
  "gemini": "gemma-4-26b-a4b-it",
250
206
  "openrouter": "google/gemma-4-26b-a4b-it"
@@ -309,10 +265,6 @@
309
265
  "openrouter": "openai/gpt-4o-2024-11-20",
310
266
  "azure": "gpt-4o-2024-11-20"
311
267
  },
312
- "gpt-4o-audio-preview": {
313
- "openai": "gpt-4o-audio-preview",
314
- "openrouter": "openai/gpt-4o-audio-preview"
315
- },
316
268
  "gpt-4o-mini": {
317
269
  "openai": "gpt-4o-mini",
318
270
  "openrouter": "openai/gpt-4o-mini",
@@ -416,6 +368,57 @@
416
368
  "openai": "gpt-audio-mini",
417
369
  "openrouter": "openai/gpt-audio-mini"
418
370
  },
371
+ "grok-3": {
372
+ "xai": "grok-4.3"
373
+ },
374
+ "grok-3-latest": {
375
+ "xai": "grok-4.3"
376
+ },
377
+ "grok-3-mini": {
378
+ "xai": "grok-4.3"
379
+ },
380
+ "grok-3-mini-latest": {
381
+ "xai": "grok-4.3"
382
+ },
383
+ "grok-4": {
384
+ "xai": "grok-4.3"
385
+ },
386
+ "grok-4-1-fast": {
387
+ "xai": "grok-4.3"
388
+ },
389
+ "grok-4-1-fast-non-reasoning": {
390
+ "xai": "grok-4.3"
391
+ },
392
+ "grok-4-1-fast-non-reasoning-latest": {
393
+ "xai": "grok-4.3"
394
+ },
395
+ "grok-4-1-fast-reasoning": {
396
+ "xai": "grok-4.3"
397
+ },
398
+ "grok-4-1-fast-reasoning-latest": {
399
+ "xai": "grok-4.3"
400
+ },
401
+ "grok-4-fast": {
402
+ "xai": "grok-4.3"
403
+ },
404
+ "grok-4-fast-non-reasoning": {
405
+ "xai": "grok-4.3"
406
+ },
407
+ "grok-4-fast-non-reasoning-latest": {
408
+ "xai": "grok-4.3"
409
+ },
410
+ "grok-4-fast-reasoning": {
411
+ "xai": "grok-4.3"
412
+ },
413
+ "grok-4-fast-reasoning-latest": {
414
+ "xai": "grok-4.3"
415
+ },
416
+ "grok-4-latest": {
417
+ "xai": "grok-4.3"
418
+ },
419
+ "grok-latest": {
420
+ "xai": "grok-4.3"
421
+ },
419
422
  "lyria-3-clip-preview": {
420
423
  "gemini": "lyria-3-clip-preview",
421
424
  "openrouter": "google/lyria-3-clip-preview"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module RubyLLM
4
6
  # Manages model aliases for provider-specific versions
5
7
  class Aliases
@@ -30,6 +32,7 @@ module RubyLLM
30
32
  end
31
33
  end
32
34
 
35
+ # Replaces the cached alias map from aliases.json.
33
36
  def reload!
34
37
  @aliases = load_aliases
35
38
  end