ruby_llm_community 1.0.0 → 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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -1
  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/install/install_generator.rb +227 -0
  20. data/lib/generators/ruby_llm/install/templates/chat_model.rb.tt +2 -2
  21. data/lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt +4 -4
  22. data/lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt +8 -7
  23. data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +12 -3
  24. data/lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt +6 -5
  25. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +9 -8
  26. data/lib/generators/ruby_llm/install/templates/message_model.rb.tt +4 -3
  27. data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +2 -5
  28. data/lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt +2 -2
  29. data/lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt +137 -0
  30. data/lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +170 -0
  31. data/lib/ruby_llm/active_record/acts_as.rb +108 -467
  32. data/lib/ruby_llm/active_record/acts_as_legacy.rb +403 -0
  33. data/lib/ruby_llm/active_record/chat_methods.rb +336 -0
  34. data/lib/ruby_llm/active_record/message_methods.rb +72 -0
  35. data/lib/ruby_llm/active_record/model_methods.rb +84 -0
  36. data/lib/ruby_llm/aliases.json +72 -6
  37. data/lib/ruby_llm/attachment.rb +22 -0
  38. data/lib/ruby_llm/configuration.rb +6 -0
  39. data/lib/ruby_llm/image_attachment.rb +12 -3
  40. data/lib/ruby_llm/message.rb +1 -1
  41. data/lib/ruby_llm/models.json +2640 -1756
  42. data/lib/ruby_llm/models.rb +5 -15
  43. data/lib/ruby_llm/provider.rb +6 -4
  44. data/lib/ruby_llm/providers/anthropic/media.rb +1 -1
  45. data/lib/ruby_llm/providers/bedrock/models.rb +19 -1
  46. data/lib/ruby_llm/providers/gemini/media.rb +1 -1
  47. data/lib/ruby_llm/providers/gpustack/media.rb +1 -1
  48. data/lib/ruby_llm/providers/ollama/media.rb +1 -1
  49. data/lib/ruby_llm/providers/openai/media.rb +4 -4
  50. data/lib/ruby_llm/providers/openai/response.rb +7 -6
  51. data/lib/ruby_llm/providers/openai/response_media.rb +1 -1
  52. data/lib/ruby_llm/providers/openai/streaming.rb +14 -11
  53. data/lib/ruby_llm/providers/openai/tools.rb +11 -6
  54. data/lib/ruby_llm/providers/vertexai.rb +1 -1
  55. data/lib/ruby_llm/providers/xai/capabilities.rb +166 -0
  56. data/lib/ruby_llm/providers/xai/chat.rb +15 -0
  57. data/lib/ruby_llm/providers/xai/models.rb +48 -0
  58. data/lib/ruby_llm/providers/xai.rb +46 -0
  59. data/lib/ruby_llm/railtie.rb +20 -3
  60. data/lib/ruby_llm/stream_accumulator.rb +0 -4
  61. data/lib/ruby_llm/utils.rb +5 -9
  62. data/lib/ruby_llm/version.rb +1 -1
  63. data/lib/ruby_llm_community.rb +4 -3
  64. data/lib/tasks/models.rake +29 -5
  65. data/lib/tasks/ruby_llm.rake +15 -0
  66. data/lib/tasks/vcr.rake +2 -2
  67. metadata +32 -3
  68. data/lib/generators/ruby_llm/install/templates/INSTALL_INFO.md.tt +0 -108
  69. data/lib/generators/ruby_llm/install_generator.rb +0 -146
@@ -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.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
@@ -26,12 +26,12 @@ loader.inflector.inflect(
26
26
  'mistral' => 'Mistral',
27
27
  'pdf' => 'PDF',
28
28
  'version' => 'VERSION',
29
- 'vertexai' => 'VertexAI'
29
+ 'vertexai' => 'VertexAI',
30
+ 'xai' => 'XAI',
31
+ 'UI' => 'UI'
30
32
  )
31
33
  loader.ignore("#{__dir__}/shims")
32
34
  loader.ignore("#{__dir__}/tasks")
33
- loader.ignore("#{__dir__}/ruby_llm/railtie")
34
- loader.ignore("#{__dir__}/ruby_llm/active_record")
35
35
  loader.ignore("#{__dir__}/generators")
36
36
  loader.setup
37
37
 
@@ -99,6 +99,7 @@ RubyLLM::Provider.register :openai, RubyLLM::Providers::OpenAI
99
99
  RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter
100
100
  RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity
101
101
  RubyLLM::Provider.register :vertexai, RubyLLM::Providers::VertexAI
102
+ RubyLLM::Provider.register :xai, RubyLLM::Providers::XAI
102
103
 
103
104
  if defined?(Rails::Railtie)
104
105
  require 'ruby_llm/railtie'
@@ -39,16 +39,19 @@ end
39
39
 
40
40
  def configure_from_env
41
41
  RubyLLM.configure do |config|
42
- config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
42
+ # Providers
43
43
  config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
44
- config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil)
45
44
  config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY', nil)
46
- config.perplexity_api_key = ENV.fetch('PERPLEXITY_API_KEY', nil)
47
- config.openrouter_api_key = ENV.fetch('OPENROUTER_API_KEY', nil)
45
+ config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil)
48
46
  config.mistral_api_key = ENV.fetch('MISTRAL_API_KEY', nil)
47
+ config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
48
+ config.openrouter_api_key = ENV.fetch('OPENROUTER_API_KEY', nil)
49
+ config.perplexity_api_key = ENV.fetch('PERPLEXITY_API_KEY', nil)
49
50
  config.vertexai_location = ENV.fetch('GOOGLE_CLOUD_LOCATION', nil)
50
51
  config.vertexai_project_id = ENV.fetch('GOOGLE_CLOUD_PROJECT', nil)
52
+ config.xai_api_key = ENV.fetch('XAI_API_KEY', nil)
51
53
  configure_bedrock(config)
54
+ # Requests
52
55
  config.request_timeout = 30
53
56
  end
54
57
  end
@@ -76,7 +79,7 @@ def refresh_models
76
79
  validate_models!(models)
77
80
 
78
81
  puts "Saving models.json (#{models.all.size} models)"
79
- models.save_models
82
+ models.save_to_json
80
83
  end
81
84
 
82
85
  @models = models
@@ -427,6 +430,27 @@ def generate_aliases # rubocop:disable Metrics/PerceivedComplexity
427
430
  }
428
431
  end
429
432
 
433
+ models['xai'].each do |model|
434
+ # xAI aliases
435
+ m = RubyLLM.models.find(model)
436
+ next unless m.metadata&.dig(:aliases)
437
+
438
+ m.metadata[:aliases].each do |alias_name|
439
+ aliases[alias_name] = { 'xai' => m.id }
440
+ end
441
+
442
+ # OpenRouter aliases.
443
+ # NOTE: OpenRouter uses "x-ai" as the provider slug
444
+ openrouter_model = "x-ai/#{model}"
445
+ next unless models['openrouter'].include?(openrouter_model)
446
+
447
+ alias_key = model.gsub('-latest', '').gsub(/-\d{4}/, '-4')
448
+ aliases[alias_key] = {
449
+ 'xai' => alias_key,
450
+ 'openrouter' => openrouter_model
451
+ }
452
+ end
453
+
430
454
  sorted_aliases = aliases.sort.to_h
431
455
  File.write(RubyLLM::Aliases.aliases_file, JSON.pretty_generate(sorted_aliases))
432
456
 
@@ -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_community
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Shippy
@@ -136,7 +136,23 @@ 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/install/install_generator.rb
140
156
  - lib/generators/ruby_llm/install/templates/chat_model.rb.tt
141
157
  - lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt
142
158
  - lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt
@@ -146,8 +162,13 @@ files:
146
162
  - lib/generators/ruby_llm/install/templates/message_model.rb.tt
147
163
  - lib/generators/ruby_llm/install/templates/model_model.rb.tt
148
164
  - lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt
149
- - lib/generators/ruby_llm/install_generator.rb
165
+ - lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt
166
+ - lib/generators/ruby_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb
150
167
  - lib/ruby_llm/active_record/acts_as.rb
168
+ - lib/ruby_llm/active_record/acts_as_legacy.rb
169
+ - lib/ruby_llm/active_record/chat_methods.rb
170
+ - lib/ruby_llm/active_record/message_methods.rb
171
+ - lib/ruby_llm/active_record/model_methods.rb
151
172
  - lib/ruby_llm/aliases.json
152
173
  - lib/ruby_llm/aliases.rb
153
174
  - lib/ruby_llm/attachment.rb
@@ -242,6 +263,10 @@ files:
242
263
  - lib/ruby_llm/providers/vertexai/embeddings.rb
243
264
  - lib/ruby_llm/providers/vertexai/models.rb
244
265
  - lib/ruby_llm/providers/vertexai/streaming.rb
266
+ - lib/ruby_llm/providers/xai.rb
267
+ - lib/ruby_llm/providers/xai/capabilities.rb
268
+ - lib/ruby_llm/providers/xai/chat.rb
269
+ - lib/ruby_llm/providers/xai/models.rb
245
270
  - lib/ruby_llm/railtie.rb
246
271
  - lib/ruby_llm/stream_accumulator.rb
247
272
  - lib/ruby_llm/streaming.rb
@@ -253,6 +278,7 @@ files:
253
278
  - lib/shims/ruby_llm.rb
254
279
  - lib/tasks/models.rake
255
280
  - lib/tasks/release.rake
281
+ - lib/tasks/ruby_llm.rake
256
282
  - lib/tasks/vcr.rake
257
283
  homepage: https://rubyllm.com
258
284
  licenses:
@@ -264,6 +290,9 @@ metadata:
264
290
  documentation_uri: https://rubyllm.com
265
291
  bug_tracker_uri: https://github.com/tpaulshippy/ruby_llm_community/issues
266
292
  rubygems_mfa_required: 'true'
293
+ post_install_message: |
294
+ Upgrading from RubyLLM <= 1.6.x? Check the upgrade guide for new features and migration instructions
295
+ --> https://rubyllm.com/upgrading-to-1-7/
267
296
  rdoc_options: []
268
297
  require_paths:
269
298
  - 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
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators'
4
- require 'rails/generators/active_record'
5
-
6
- module RubyLLM
7
- # Generator for RubyLLM Rails models and migrations
8
- class InstallGenerator < Rails::Generators::Base
9
- include Rails::Generators::Migration
10
-
11
- namespace 'ruby_llm:install'
12
-
13
- source_root File.expand_path('install/templates', __dir__)
14
-
15
- class_option :chat_model_name, type: :string, default: 'Chat',
16
- desc: 'Name of the Chat model class'
17
- class_option :message_model_name, type: :string, default: 'Message',
18
- desc: 'Name of the Message model class'
19
- class_option :tool_call_model_name, type: :string, default: 'ToolCall',
20
- desc: 'Name of the ToolCall model class'
21
- class_option :model_model_name, type: :string, default: 'Model',
22
- desc: 'Name of the Model model class (for model registry)'
23
- class_option :skip_model, type: :boolean, default: false,
24
- desc: 'Skip creating Model model for model registry persistence'
25
-
26
- desc 'Creates models and migrations for RubyLLM Rails integration'
27
-
28
- def self.next_migration_number(dirname)
29
- ::ActiveRecord::Generators::Base.next_migration_number(dirname)
30
- end
31
-
32
- def migration_version
33
- "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
34
- end
35
-
36
- def postgresql?
37
- ::ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
38
- rescue StandardError
39
- false
40
- end
41
-
42
- def acts_as_chat_declaration
43
- acts_as_chat_params = []
44
- if options[:message_model_name] != 'Message'
45
- acts_as_chat_params << "message_class: \"#{options[:message_model_name]}\""
46
- end
47
- if options[:tool_call_model_name] != 'ToolCall'
48
- acts_as_chat_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
49
- end
50
- if acts_as_chat_params.any?
51
- "acts_as_chat #{acts_as_chat_params.join(', ')}"
52
- else
53
- 'acts_as_chat'
54
- end
55
- end
56
-
57
- def acts_as_message_declaration
58
- acts_as_message_params = []
59
- acts_as_message_params << "chat_class: \"#{options[:chat_model_name]}\"" if options[:chat_model_name] != 'Chat'
60
- if options[:tool_call_model_name] != 'ToolCall'
61
- acts_as_message_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
62
- end
63
- if acts_as_message_params.any?
64
- "acts_as_message #{acts_as_message_params.join(', ')}"
65
- else
66
- 'acts_as_message'
67
- end
68
- end
69
-
70
- def acts_as_tool_call_declaration
71
- acts_as_tool_call_params = []
72
- if options[:message_model_name] != 'Message'
73
- acts_as_tool_call_params << "message_class: \"#{options[:message_model_name]}\""
74
- end
75
- if acts_as_tool_call_params.any?
76
- "acts_as_tool_call #{acts_as_tool_call_params.join(', ')}"
77
- else
78
- 'acts_as_tool_call'
79
- end
80
- end
81
-
82
- def acts_as_model_declaration
83
- 'acts_as_model'
84
- end
85
-
86
- def create_migration_files
87
- # Create migrations with timestamps to ensure proper order
88
- # First create chats table
89
- migration_template 'create_chats_migration.rb.tt',
90
- "db/migrate/create_#{options[:chat_model_name].tableize}.rb"
91
-
92
- # Then create messages table (must come before tool_calls due to foreign key)
93
- sleep 1 # Ensure different timestamp
94
- migration_template 'create_messages_migration.rb.tt',
95
- "db/migrate/create_#{options[:message_model_name].tableize}.rb"
96
-
97
- # Then create tool_calls table (references messages)
98
- sleep 1 # Ensure different timestamp
99
- migration_template 'create_tool_calls_migration.rb.tt',
100
- "db/migrate/create_#{options[:tool_call_model_name].tableize}.rb"
101
-
102
- # Finally create models table (for model registry)
103
- return if options[:skip_model]
104
-
105
- sleep 1 # Ensure different timestamp
106
- migration_template 'create_models_migration.rb.tt',
107
- "db/migrate/create_#{options[:model_model_name].tableize}.rb"
108
- end
109
-
110
- def create_model_files
111
- template 'chat_model.rb.tt', "app/models/#{options[:chat_model_name].underscore}.rb"
112
- template 'message_model.rb.tt', "app/models/#{options[:message_model_name].underscore}.rb"
113
- template 'tool_call_model.rb.tt', "app/models/#{options[:tool_call_model_name].underscore}.rb"
114
-
115
- return if options[:skip_model]
116
-
117
- template 'model_model.rb.tt', "app/models/#{options[:model_model_name].underscore}.rb"
118
- end
119
-
120
- def create_initializer
121
- template 'initializer.rb.tt', 'config/initializers/ruby_llm.rb'
122
- end
123
-
124
- def show_install_info
125
- say "\n ✅ RubyLLM installed!", :green
126
-
127
- say "\n Next steps:", :yellow
128
- say ' 1. Run: rails db:migrate'
129
- say ' 2. Set your API keys in config/initializers/ruby_llm.rb'
130
- say " 3. Start chatting: #{options[:chat_model_name]}.create!(model_id: 'gpt-4.1-nano').ask('Hello!')"
131
-
132
- unless options[:skip_model]
133
- say " 4. Sync models: #{options[:model_model_name]}.sync!"
134
- say "\n 🚀 Model registry is database-backed!", :cyan
135
- say ' Models will automatically load from the database'
136
- end
137
-
138
- say "\n 📚 Full docs: https://rubyllm.com", :cyan
139
-
140
- say "\n ❤️ Love RubyLLM?", :magenta
141
- say ' • ⭐ Star on GitHub: https://github.com/crmne/ruby_llm'
142
- say ' • 💖 Sponsor: https://github.com/sponsors/crmne'
143
- say "\n"
144
- end
145
- end
146
- end