ruby_llm 1.6.4 → 1.7.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb +127 -0
  4. data/lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt +39 -0
  5. data/lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt +24 -0
  6. data/lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt +14 -0
  7. data/lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +12 -0
  8. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +16 -0
  9. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt +29 -0
  10. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt +16 -0
  11. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt +11 -0
  12. data/lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt +23 -0
  13. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt +21 -0
  14. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt +10 -0
  15. data/lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +9 -0
  16. data/lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt +16 -0
  17. data/lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt +30 -0
  18. data/lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt +18 -0
  19. data/lib/generators/ruby_llm/generator_helpers.rb +129 -0
  20. data/lib/generators/ruby_llm/install/install_generator.rb +104 -0
  21. data/lib/generators/ruby_llm/install/templates/chat_model.rb.tt +2 -2
  22. data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +4 -4
  23. data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +8 -7
  24. data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +40 -0
  25. data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +6 -5
  26. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +10 -4
  27. data/lib/generators/ruby_llm/install/templates/message_model.rb.tt +4 -3
  28. data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +3 -0
  29. data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +2 -2
  30. data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +145 -0
  31. data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +121 -0
  32. data/lib/ruby_llm/active_record/acts_as.rb +111 -327
  33. data/lib/ruby_llm/active_record/acts_as_legacy.rb +398 -0
  34. data/lib/ruby_llm/active_record/chat_methods.rb +336 -0
  35. data/lib/ruby_llm/active_record/message_methods.rb +72 -0
  36. data/lib/ruby_llm/active_record/model_methods.rb +84 -0
  37. data/lib/ruby_llm/aliases.json +54 -13
  38. data/lib/ruby_llm/attachment.rb +20 -0
  39. data/lib/ruby_llm/chat.rb +5 -5
  40. data/lib/ruby_llm/configuration.rb +9 -0
  41. data/lib/ruby_llm/connection.rb +4 -4
  42. data/lib/ruby_llm/model/info.rb +12 -0
  43. data/lib/ruby_llm/models.json +3579 -2029
  44. data/lib/ruby_llm/models.rb +51 -22
  45. data/lib/ruby_llm/provider.rb +3 -3
  46. data/lib/ruby_llm/providers/anthropic/chat.rb +2 -2
  47. data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
  48. data/lib/ruby_llm/providers/bedrock/chat.rb +2 -2
  49. data/lib/ruby_llm/providers/bedrock/models.rb +19 -1
  50. data/lib/ruby_llm/providers/gemini/chat.rb +1 -1
  51. data/lib/ruby_llm/providers/gemini/media.rb +1 -1
  52. data/lib/ruby_llm/providers/gpustack/chat.rb +11 -0
  53. data/lib/ruby_llm/providers/gpustack/media.rb +45 -0
  54. data/lib/ruby_llm/providers/gpustack/models.rb +44 -8
  55. data/lib/ruby_llm/providers/gpustack.rb +1 -0
  56. data/lib/ruby_llm/providers/ollama/media.rb +2 -6
  57. data/lib/ruby_llm/providers/ollama/models.rb +36 -0
  58. data/lib/ruby_llm/providers/ollama.rb +1 -0
  59. data/lib/ruby_llm/providers/openai/chat.rb +1 -1
  60. data/lib/ruby_llm/providers/openai/media.rb +4 -4
  61. data/lib/ruby_llm/providers/openai/tools.rb +11 -6
  62. data/lib/ruby_llm/providers/openai.rb +2 -2
  63. data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
  64. data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
  65. data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
  66. data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
  67. data/lib/ruby_llm/providers/vertexai.rb +55 -0
  68. data/lib/ruby_llm/railtie.rb +20 -3
  69. data/lib/ruby_llm/streaming.rb +1 -1
  70. data/lib/ruby_llm/utils.rb +5 -9
  71. data/lib/ruby_llm/version.rb +1 -1
  72. data/lib/ruby_llm.rb +4 -3
  73. data/lib/tasks/models.rake +39 -28
  74. data/lib/tasks/ruby_llm.rake +15 -0
  75. data/lib/tasks/vcr.rake +2 -2
  76. metadata +38 -3
  77. data/lib/generators/ruby_llm/install/templates/INSTALL_INFO.md.tt +0 -108
  78. data/lib/generators/ruby_llm/install_generator.rb +0 -121
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ class VertexAI
6
+ # Models methods for the Vertex AI integration
7
+ module Models
8
+ # Gemini and other Google models that aren't returned by the API
9
+ KNOWN_GOOGLE_MODELS = %w[
10
+ gemini-2.5-flash-lite
11
+ gemini-2.5-pro
12
+ gemini-2.5-flash
13
+ gemini-2.0-flash-lite-001
14
+ gemini-2.0-flash-001
15
+ gemini-2.0-flash
16
+ gemini-2.0-flash-exp
17
+ gemini-1.5-pro-002
18
+ gemini-1.5-pro
19
+ gemini-1.5-flash-002
20
+ gemini-1.5-flash
21
+ gemini-1.5-flash-8b
22
+ gemini-pro
23
+ gemini-pro-vision
24
+ gemini-exp-1206
25
+ gemini-exp-1121
26
+ gemini-embedding-001
27
+ text-embedding-005
28
+ text-embedding-004
29
+ text-multilingual-embedding-002
30
+ ].freeze
31
+
32
+ def list_models
33
+ all_models = []
34
+ page_token = nil
35
+
36
+ all_models.concat(build_known_models)
37
+
38
+ loop do
39
+ response = @connection.get('publishers/google/models') do |req|
40
+ req.headers['x-goog-user-project'] = @config.vertexai_project_id
41
+ req.params = { pageSize: 100 }
42
+ req.params[:pageToken] = page_token if page_token
43
+ end
44
+
45
+ publisher_models = response.body['publisherModels'] || []
46
+ publisher_models.each do |model_data|
47
+ next if model_data['launchStage'] == 'DEPRECATED'
48
+
49
+ model_id = extract_model_id_from_path(model_data['name'])
50
+ all_models << build_model_from_api_data(model_data, model_id)
51
+ end
52
+
53
+ page_token = response.body['nextPageToken']
54
+ break unless page_token
55
+ end
56
+
57
+ all_models
58
+ rescue StandardError => e
59
+ RubyLLM.logger.debug "Error fetching Vertex AI models: #{e.message}"
60
+ build_known_models
61
+ end
62
+
63
+ private
64
+
65
+ def build_known_models
66
+ KNOWN_GOOGLE_MODELS.map do |model_id|
67
+ Model::Info.new(
68
+ id: model_id,
69
+ name: model_id,
70
+ provider: slug,
71
+ family: determine_model_family(model_id),
72
+ created_at: nil,
73
+ context_window: nil,
74
+ max_output_tokens: nil,
75
+ modalities: nil,
76
+ capabilities: %w[streaming function_calling],
77
+ pricing: nil,
78
+ metadata: {
79
+ source: 'known_models'
80
+ }
81
+ )
82
+ end
83
+ end
84
+
85
+ def build_model_from_api_data(model_data, model_id)
86
+ Model::Info.new(
87
+ id: model_id,
88
+ name: model_id,
89
+ provider: slug,
90
+ family: determine_model_family(model_id),
91
+ created_at: nil,
92
+ context_window: nil,
93
+ max_output_tokens: nil,
94
+ modalities: nil,
95
+ capabilities: extract_capabilities(model_data),
96
+ pricing: nil,
97
+ metadata: {
98
+ version_id: model_data['versionId'],
99
+ open_source_category: model_data['openSourceCategory'],
100
+ launch_stage: model_data['launchStage'],
101
+ supported_actions: model_data['supportedActions'],
102
+ publisher_model_template: model_data['publisherModelTemplate']
103
+ }
104
+ )
105
+ end
106
+
107
+ def extract_model_id_from_path(path)
108
+ path.split('/').last
109
+ end
110
+
111
+ def determine_model_family(model_id)
112
+ case model_id
113
+ when /^gemini-2\.\d+/ then 'gemini-2'
114
+ when /^gemini-1\.\d+/ then 'gemini-1.5'
115
+ when /^text-embedding/ then 'text-embedding'
116
+ when /bison/ then 'palm'
117
+ else 'gemini'
118
+ end
119
+ end
120
+
121
+ def extract_capabilities(model_data)
122
+ capabilities = ['streaming']
123
+ model_name = model_data['name']
124
+ capabilities << 'function_calling' if model_name.include?('gemini')
125
+ capabilities.uniq
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ class VertexAI
6
+ # Streaming methods for the Vertex AI implementation
7
+ module Streaming
8
+ def stream_url
9
+ "projects/#{@config.vertexai_project_id}/locations/#{@config.vertexai_location}/publishers/google/models/#{@model}:streamGenerateContent?alt=sse" # rubocop:disable Layout/LineLength
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Providers
5
+ # Google Vertex AI implementation
6
+ class VertexAI < Gemini
7
+ include VertexAI::Chat
8
+ include VertexAI::Streaming
9
+ include VertexAI::Embeddings
10
+ include VertexAI::Models
11
+
12
+ def initialize(config)
13
+ super
14
+ @authorizer = nil
15
+ end
16
+
17
+ def api_base
18
+ "https://#{@config.vertexai_location}-aiplatform.googleapis.com/v1beta1"
19
+ end
20
+
21
+ def headers
22
+ {
23
+ 'Authorization' => "Bearer #{access_token}"
24
+ }
25
+ end
26
+
27
+ class << self
28
+ def configuration_requirements
29
+ %i[vertexai_project_id vertexai_location]
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def access_token
36
+ return 'test-token' if defined?(VCR) && !VCR.current_cassette.recording?
37
+
38
+ initialize_authorizer unless @authorizer
39
+ @authorizer.fetch_access_token!['access_token']
40
+ end
41
+
42
+ def initialize_authorizer
43
+ require 'googleauth'
44
+ @authorizer = ::Google::Auth.get_application_default(
45
+ scope: [
46
+ 'https://www.googleapis.com/auth/cloud-platform',
47
+ 'https://www.googleapis.com/auth/generative-language.retriever'
48
+ ]
49
+ )
50
+ rescue LoadError
51
+ raise Error, 'The googleauth gem is required for Vertex AI. Please add it to your Gemfile: gem "googleauth"'
52
+ end
53
+ end
54
+ end
55
+ end
@@ -3,14 +3,31 @@
3
3
  module RubyLLM
4
4
  # Rails integration for RubyLLM
5
5
  class Railtie < Rails::Railtie
6
+ initializer 'ruby_llm.inflections' do
7
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
8
+ inflect.acronym 'LLM'
9
+ end
10
+ end
11
+
6
12
  initializer 'ruby_llm.active_record' do
7
13
  ActiveSupport.on_load :active_record do
8
- include RubyLLM::ActiveRecord::ActsAs
14
+ if RubyLLM.config.use_new_acts_as
15
+ require 'ruby_llm/active_record/acts_as'
16
+ ::ActiveRecord::Base.include RubyLLM::ActiveRecord::ActsAs
17
+ else
18
+ require 'ruby_llm/active_record/acts_as_legacy'
19
+ ::ActiveRecord::Base.include RubyLLM::ActiveRecord::ActsAsLegacy
20
+
21
+ Rails.logger.warn(
22
+ "\n!!! RubyLLM's legacy acts_as API is deprecated and will be removed in RubyLLM 2.0.0. " \
23
+ "Please consult the migration guide at https://rubyllm.com/upgrading-to-1-7/\n"
24
+ )
25
+ end
9
26
  end
10
27
  end
11
28
 
12
- generators do
13
- require 'generators/ruby_llm/install_generator'
29
+ rake_tasks do
30
+ load 'tasks/ruby_llm.rake'
14
31
  end
15
32
  end
16
33
  end
@@ -24,7 +24,7 @@ module RubyLLM
24
24
  end
25
25
 
26
26
  message = accumulator.to_message(response)
27
- RubyLLM.logger.debug "Stream completed: #{message.inspect}"
27
+ RubyLLM.logger.debug "Stream completed: #{message.content}"
28
28
  message
29
29
  end
30
30
 
@@ -5,10 +5,6 @@ module RubyLLM
5
5
  module Utils
6
6
  module_function
7
7
 
8
- def format_text_file_for_llm(text_file)
9
- "<file name='#{text_file.filename}' mime_type='#{text_file.mime_type}'>#{text_file.content}</file>"
10
- end
11
-
12
8
  def hash_get(hash, key)
13
9
  hash[key.to_sym] || hash[key.to_s]
14
10
  end
@@ -36,12 +32,12 @@ module RubyLLM
36
32
  value.is_a?(Date) ? value : Date.parse(value.to_s)
37
33
  end
38
34
 
39
- def deep_merge(params, payload)
40
- params.merge(payload) do |_key, params_value, payload_value|
41
- if params_value.is_a?(Hash) && payload_value.is_a?(Hash)
42
- deep_merge(params_value, payload_value)
35
+ def deep_merge(original, overrides)
36
+ original.merge(overrides) do |_key, original_value, overrides_value|
37
+ if original_value.is_a?(Hash) && overrides_value.is_a?(Hash)
38
+ deep_merge(original_value, overrides_value)
43
39
  else
44
- payload_value
40
+ overrides_value
45
41
  end
46
42
  end
47
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLLM
4
- VERSION = '1.6.4'
4
+ VERSION = '1.7.1'
5
5
  end
data/lib/ruby_llm.rb CHANGED
@@ -21,11 +21,11 @@ loader.inflector.inflect(
21
21
  'openrouter' => 'OpenRouter',
22
22
  'gpustack' => 'GPUStack',
23
23
  'mistral' => 'Mistral',
24
- 'pdf' => 'PDF'
24
+ 'vertexai' => 'VertexAI',
25
+ 'pdf' => 'PDF',
26
+ 'UI' => 'UI'
25
27
  )
26
28
  loader.ignore("#{__dir__}/tasks")
27
- loader.ignore("#{__dir__}/ruby_llm/railtie")
28
- loader.ignore("#{__dir__}/ruby_llm/active_record")
29
29
  loader.ignore("#{__dir__}/generators")
30
30
  loader.setup
31
31
 
@@ -88,6 +88,7 @@ RubyLLM::Provider.register :ollama, RubyLLM::Providers::Ollama
88
88
  RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
89
89
  RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter
90
90
  RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity
91
+ RubyLLM::Provider.register :vertexai, RubyLLM::Providers::VertexAI
91
92
 
92
93
  if defined?(Rails::Railtie)
93
94
  require 'ruby_llm/railtie'
@@ -46,6 +46,8 @@ def configure_from_env
46
46
  config.perplexity_api_key = ENV.fetch('PERPLEXITY_API_KEY', nil)
47
47
  config.openrouter_api_key = ENV.fetch('OPENROUTER_API_KEY', nil)
48
48
  config.mistral_api_key = ENV.fetch('MISTRAL_API_KEY', nil)
49
+ config.vertexai_location = ENV.fetch('GOOGLE_CLOUD_LOCATION', nil)
50
+ config.vertexai_project_id = ENV.fetch('GOOGLE_CLOUD_PROJECT', nil)
49
51
  configure_bedrock(config)
50
52
  config.request_timeout = 30
51
53
  end
@@ -74,7 +76,7 @@ def refresh_models
74
76
  validate_models!(models)
75
77
 
76
78
  puts "Saving models.json (#{models.all.size} models)"
77
- models.save_models
79
+ models.save_to_json
78
80
  end
79
81
 
80
82
  @models = models
@@ -152,28 +154,11 @@ def generate_models_markdown
152
154
 
153
155
  ---
154
156
 
155
- After reading this guide, you will know:
157
+ ## Model Data Sources
156
158
 
157
- * How RubyLLM's model registry works and where data comes from
158
- * How to find models by provider, capability, or purpose
159
- * What information is available for each model
160
- * How to use model aliases for simpler configuration
161
-
162
- ## How Model Data Works
163
-
164
- RubyLLM's model registry combines data from multiple sources:
165
-
166
- - **OpenAI, Anthropic, DeepSeek, Gemini**: Data from [Parsera](https://api.parsera.org/v1/llm-specs)
167
- - **OpenRouter**: Direct from OpenRouter's API
168
- - **Other providers**: Defined in `capabilities.rb` files
169
-
170
- ## Contributing Model Updates
171
-
172
- **For major providers** (OpenAI, Anthropic, DeepSeek, Gemini): File issues with [Parsera](https://github.com/parsera-labs/api-llm-specs/issues) for public model data corrections.
173
-
174
- **For other providers**: Edit `lib/ruby_llm/providers/<provider>/capabilities.rb` then run `rake models:update`.
175
-
176
- See the [Contributing Guide](https://github.com/crmne/ruby_llm/blob/main/CONTRIBUTING.md) for details.
159
+ - **OpenAI, Anthropic, DeepSeek, Gemini, VertexAI**: Enriched by [🚀 Parsera](https://parsera.org/) *([free LLM metadata API](https://api.parsera.org/v1/llm-specs) - [go say thanks!](https://github.com/parsera-labs/api-llm-specs))*
160
+ - **OpenRouter**: Direct API
161
+ - **Others**: Local capabilities files
177
162
 
178
163
  ## Last Updated
179
164
  {: .d-inline-block }
@@ -369,7 +354,7 @@ def generate_aliases # rubocop:disable Metrics/PerceivedComplexity
369
354
 
370
355
  models['bedrock'].each do |bedrock_model|
371
356
  next unless bedrock_model.start_with?('anthropic.')
372
- next unless bedrock_model =~ /anthropic\.(claude-[\d\.]+-[a-z]+)/
357
+ next unless bedrock_model =~ /anthropic\.(claude-[\d.]+-[a-z]+)/
373
358
 
374
359
  base_name = Regexp.last_match(1)
375
360
  anthropic_name = base_name.tr('.', '-')
@@ -388,6 +373,7 @@ def generate_aliases # rubocop:disable Metrics/PerceivedComplexity
388
373
  aliases[anthropic_name]['openrouter'] = openrouter_model if openrouter_model
389
374
  end
390
375
 
376
+ # Gemini models (also map to vertexai)
391
377
  models['gemini'].each do |model|
392
378
  openrouter_variants = [
393
379
  "google/#{model}",
@@ -396,13 +382,38 @@ def generate_aliases # rubocop:disable Metrics/PerceivedComplexity
396
382
  ]
397
383
 
398
384
  openrouter_model = openrouter_variants.find { |v| models['openrouter'].include?(v) }
399
- next unless openrouter_model
385
+ vertexai_model = models['vertexai'].include?(model) ? model : nil
386
+
387
+ next unless openrouter_model || vertexai_model
400
388
 
401
389
  alias_key = model.gsub('-latest', '')
402
- aliases[alias_key] = {
403
- 'gemini' => model,
404
- 'openrouter' => openrouter_model
405
- }
390
+ aliases[alias_key] = { 'gemini' => model }
391
+ aliases[alias_key]['openrouter'] = openrouter_model if openrouter_model
392
+ aliases[alias_key]['vertexai'] = vertexai_model if vertexai_model
393
+ end
394
+
395
+ # VertexAI models that aren't in Gemini (e.g. older models like text-bison)
396
+ models['vertexai'].each do |model|
397
+ # Skip if already handled above
398
+ next if models['gemini'].include?(model)
399
+
400
+ # Check if OpenRouter has this Google model
401
+ openrouter_variants = [
402
+ "google/#{model}",
403
+ "google/#{model.tr('.', '-')}"
404
+ ]
405
+
406
+ openrouter_model = openrouter_variants.find { |v| models['openrouter'].include?(v) }
407
+ gemini_model = models['gemini'].include?(model) ? model : nil
408
+
409
+ next unless openrouter_model || gemini_model
410
+
411
+ alias_key = model.gsub('-latest', '')
412
+ next if aliases[alias_key] # Skip if already created
413
+
414
+ aliases[alias_key] = { 'vertexai' => model }
415
+ aliases[alias_key]['openrouter'] = openrouter_model if openrouter_model
416
+ aliases[alias_key]['gemini'] = gemini_model if gemini_model
406
417
  end
407
418
 
408
419
  models['deepseek'].each do |model|
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :ruby_llm do
4
+ desc 'Load models from models.json into the database'
5
+ task load_models: :environment do
6
+ if RubyLLM.config.model_registry_class
7
+ RubyLLM.models.load_from_json!
8
+ model_class = RubyLLM.config.model_registry_class.constantize
9
+ model_class.save_to_database
10
+ puts "✅ Loaded #{model_class.count} models into database"
11
+ else
12
+ puts 'Model registry not configured. Run rails generate ruby_llm:install'
13
+ end
14
+ end
15
+ end
data/lib/tasks/vcr.rake CHANGED
@@ -75,11 +75,11 @@ end
75
75
 
76
76
  namespace :vcr do
77
77
  desc 'Record VCR cassettes (rake vcr:record[all] or vcr:record[openai,anthropic])'
78
- task :record, [:providers] do |_, args|
78
+ task :record, :providers do |_, args|
79
79
  require 'fileutils'
80
80
  require 'ruby_llm'
81
81
 
82
- providers = (args[:providers] || '').downcase.split(',')
82
+ providers = args.extras.unshift(args[:providers]).compact.map(&:downcase)
83
83
  cassette_dir = 'spec/fixtures/vcr_cassettes'
84
84
  FileUtils.mkdir_p(cassette_dir)
85
85
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.4
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carmine Paolino
@@ -136,17 +136,41 @@ extra_rdoc_files: []
136
136
  files:
137
137
  - LICENSE
138
138
  - README.md
139
- - lib/generators/ruby_llm/install/templates/INSTALL_INFO.md.tt
139
+ - lib/generators/ruby_llm/chat_ui/chat_ui_generator.rb
140
+ - lib/generators/ruby_llm/chat_ui/templates/controllers/chats_controller.rb.tt
141
+ - lib/generators/ruby_llm/chat_ui/templates/controllers/messages_controller.rb.tt
142
+ - lib/generators/ruby_llm/chat_ui/templates/controllers/models_controller.rb.tt
143
+ - lib/generators/ruby_llm/chat_ui/templates/jobs/chat_response_job.rb.tt
144
+ - lib/generators/ruby_llm/chat_ui/templates/views/chats/_chat.html.erb.tt
145
+ - lib/generators/ruby_llm/chat_ui/templates/views/chats/_form.html.erb.tt
146
+ - lib/generators/ruby_llm/chat_ui/templates/views/chats/index.html.erb.tt
147
+ - lib/generators/ruby_llm/chat_ui/templates/views/chats/new.html.erb.tt
148
+ - lib/generators/ruby_llm/chat_ui/templates/views/chats/show.html.erb.tt
149
+ - lib/generators/ruby_llm/chat_ui/templates/views/messages/_form.html.erb.tt
150
+ - lib/generators/ruby_llm/chat_ui/templates/views/messages/_message.html.erb.tt
151
+ - lib/generators/ruby_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt
152
+ - lib/generators/ruby_llm/chat_ui/templates/views/models/_model.html.erb.tt
153
+ - lib/generators/ruby_llm/chat_ui/templates/views/models/index.html.erb.tt
154
+ - lib/generators/ruby_llm/chat_ui/templates/views/models/show.html.erb.tt
155
+ - lib/generators/ruby_llm/generator_helpers.rb
156
+ - lib/generators/ruby_llm/install/install_generator.rb
140
157
  - lib/generators/ruby_llm/install/templates/chat_model.rb.tt
141
158
  - lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt
142
159
  - lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt
160
+ - lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt
143
161
  - lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt
144
162
  - lib/generators/ruby_llm/install/templates/initializer.rb.tt
145
163
  - lib/generators/ruby_llm/install/templates/message_model.rb.tt
164
+ - lib/generators/ruby_llm/install/templates/model_model.rb.tt
146
165
  - lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt
147
- - lib/generators/ruby_llm/install_generator.rb
166
+ - lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt
167
+ - lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb
148
168
  - lib/ruby_llm.rb
149
169
  - lib/ruby_llm/active_record/acts_as.rb
170
+ - lib/ruby_llm/active_record/acts_as_legacy.rb
171
+ - lib/ruby_llm/active_record/chat_methods.rb
172
+ - lib/ruby_llm/active_record/message_methods.rb
173
+ - lib/ruby_llm/active_record/model_methods.rb
150
174
  - lib/ruby_llm/aliases.json
151
175
  - lib/ruby_llm/aliases.rb
152
176
  - lib/ruby_llm/attachment.rb
@@ -205,6 +229,7 @@ files:
205
229
  - lib/ruby_llm/providers/gemini/tools.rb
206
230
  - lib/ruby_llm/providers/gpustack.rb
207
231
  - lib/ruby_llm/providers/gpustack/chat.rb
232
+ - lib/ruby_llm/providers/gpustack/media.rb
208
233
  - lib/ruby_llm/providers/gpustack/models.rb
209
234
  - lib/ruby_llm/providers/mistral.rb
210
235
  - lib/ruby_llm/providers/mistral/capabilities.rb
@@ -214,6 +239,7 @@ files:
214
239
  - lib/ruby_llm/providers/ollama.rb
215
240
  - lib/ruby_llm/providers/ollama/chat.rb
216
241
  - lib/ruby_llm/providers/ollama/media.rb
242
+ - lib/ruby_llm/providers/ollama/models.rb
217
243
  - lib/ruby_llm/providers/openai.rb
218
244
  - lib/ruby_llm/providers/openai/capabilities.rb
219
245
  - lib/ruby_llm/providers/openai/chat.rb
@@ -229,6 +255,11 @@ files:
229
255
  - lib/ruby_llm/providers/perplexity/capabilities.rb
230
256
  - lib/ruby_llm/providers/perplexity/chat.rb
231
257
  - lib/ruby_llm/providers/perplexity/models.rb
258
+ - lib/ruby_llm/providers/vertexai.rb
259
+ - lib/ruby_llm/providers/vertexai/chat.rb
260
+ - lib/ruby_llm/providers/vertexai/embeddings.rb
261
+ - lib/ruby_llm/providers/vertexai/models.rb
262
+ - lib/ruby_llm/providers/vertexai/streaming.rb
232
263
  - lib/ruby_llm/railtie.rb
233
264
  - lib/ruby_llm/stream_accumulator.rb
234
265
  - lib/ruby_llm/streaming.rb
@@ -238,6 +269,7 @@ files:
238
269
  - lib/ruby_llm/version.rb
239
270
  - lib/tasks/models.rake
240
271
  - lib/tasks/release.rake
272
+ - lib/tasks/ruby_llm.rake
241
273
  - lib/tasks/vcr.rake
242
274
  homepage: https://rubyllm.com
243
275
  licenses:
@@ -249,6 +281,9 @@ metadata:
249
281
  documentation_uri: https://rubyllm.com
250
282
  bug_tracker_uri: https://github.com/crmne/ruby_llm/issues
251
283
  rubygems_mfa_required: 'true'
284
+ post_install_message: |
285
+ Upgrading from RubyLLM <= 1.6.x? Check the upgrade guide for new features and migration instructions
286
+ --> https://rubyllm.com/upgrading-to-1-7/
252
287
  rdoc_options: []
253
288
  require_paths:
254
289
  - lib
@@ -1,108 +0,0 @@
1
- # RubyLLM Rails Setup Complete!
2
-
3
- Thanks for installing RubyLLM in your Rails application. Here's what was created:
4
-
5
- ## Models
6
-
7
- - `<%= options[:chat_model_name] %>` - Stores chat sessions and their associated model ID
8
- - `<%= options[:message_model_name] %>` - Stores individual messages in a chat
9
- - `<%= options[:tool_call_model_name] %>` - Stores tool calls made by language models
10
-
11
- **Note:** Do not add `validates :content, presence: true` to your Message model - RubyLLM creates empty assistant messages before API calls for streaming support.
12
-
13
- ## Configuration Options
14
-
15
- The generator supports the following options to customize model names:
16
-
17
- ```bash
18
- rails generate ruby_llm:install \
19
- --chat-model-name=Conversation \
20
- --message-model-name=ChatMessage \
21
- --tool-call-model-name=FunctionCall
22
- ```
23
-
24
- This is useful when you need to avoid namespace collisions with existing models in your application. Table names will be automatically derived from the model names following Rails conventions.
25
-
26
- ## Next Steps
27
-
28
- 1. **Run migrations:**
29
- ```bash
30
- rails db:migrate
31
- ```
32
-
33
- **Database Note:** The migrations use `jsonb` for PostgreSQL and `json` for MySQL/SQLite automatically.
34
-
35
- 2. **Set your API keys** in `config/initializers/ruby_llm.rb` or using environment variables:
36
- ```ruby
37
- # config/initializers/ruby_llm.rb
38
- RubyLLM.configure do |config|
39
- config.openai_api_key = ENV['OPENAI_API_KEY']
40
- config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
41
- config.gemini_api_key = ENV['GEMINI_API_KEY']
42
- # ... add other providers as needed
43
- end
44
- ```
45
-
46
- 3. **Start using RubyLLM in your code:**
47
- ```ruby
48
- # Basic usage
49
- chat = <%= options[:chat_model_name] %>.create!(model_id: 'gpt-4.1-nano')
50
- response = chat.ask("What is Ruby on Rails?")
51
-
52
- # With file attachments (requires ActiveStorage setup)
53
- chat.ask("What's in this file?", with: "report.pdf")
54
- chat.ask("Analyze these files", with: ["image.jpg", "data.csv", "notes.txt"])
55
- ```
56
-
57
- 4. **For streaming responses** with Hotwire/Turbo:
58
- ```ruby
59
- # app/models/<%= options[:message_model_name].underscore %>.rb
60
- class <%= options[:message_model_name] %> < ApplicationRecord
61
- acts_as_message
62
-
63
- # Helper to broadcast chunks during streaming
64
- def broadcast_append_chunk(chunk_content)
65
- broadcast_append_to [ chat, "messages" ],
66
- target: dom_id(self, "content"),
67
- html: chunk_content
68
- end
69
- end
70
-
71
- # app/jobs/chat_stream_job.rb
72
- class ChatStreamJob < ApplicationJob
73
- def perform(chat_id, user_content)
74
- chat = <%= options[:chat_model_name] %>.find(chat_id)
75
- chat.ask(user_content) do |chunk|
76
- assistant_message = chat.messages.last
77
- if chunk.content && assistant_message
78
- assistant_message.broadcast_append_chunk(chunk.content)
79
- end
80
- end
81
- end
82
- end
83
-
84
- # In your controller
85
- ChatStreamJob.perform_later(@chat.id, params[:content])
86
- ```
87
-
88
- ## Optional: ActiveStorage for Attachments
89
-
90
- If you want to use file attachments (PDFs, images, etc.), set up ActiveStorage:
91
-
92
- ```bash
93
- rails active_storage:install
94
- rails db:migrate
95
- ```
96
-
97
- Then add to your Message model:
98
- ```ruby
99
- class <%= options[:message_model_name] %> < ApplicationRecord
100
- acts_as_message
101
- has_many_attached :attachments
102
- end
103
- ```
104
-
105
- ## Learn More
106
-
107
- - See the [Rails Integration Guide](https://rubyllm.com/guides/rails) for detailed examples
108
- - Visit the [RubyLLM Documentation](https://rubyllm.com) for full API reference