ruby_llm_community 0.0.6 → 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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -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/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 +43 -0
  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 +10 -4
  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 +3 -0
  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 +112 -332
  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 +130 -11
  37. data/lib/ruby_llm/aliases.rb +7 -25
  38. data/lib/ruby_llm/attachment.rb +22 -0
  39. data/lib/ruby_llm/chat.rb +10 -17
  40. data/lib/ruby_llm/configuration.rb +11 -12
  41. data/lib/ruby_llm/connection.rb +4 -4
  42. data/lib/ruby_llm/connection_multipart.rb +19 -0
  43. data/lib/ruby_llm/content.rb +5 -2
  44. data/lib/ruby_llm/embedding.rb +1 -2
  45. data/lib/ruby_llm/error.rb +0 -8
  46. data/lib/ruby_llm/image.rb +23 -8
  47. data/lib/ruby_llm/image_attachment.rb +30 -0
  48. data/lib/ruby_llm/message.rb +7 -7
  49. data/lib/ruby_llm/model/info.rb +12 -10
  50. data/lib/ruby_llm/model/pricing.rb +0 -3
  51. data/lib/ruby_llm/model/pricing_category.rb +0 -2
  52. data/lib/ruby_llm/model/pricing_tier.rb +0 -1
  53. data/lib/ruby_llm/models.json +4705 -2144
  54. data/lib/ruby_llm/models.rb +56 -35
  55. data/lib/ruby_llm/provider.rb +14 -12
  56. data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -46
  57. data/lib/ruby_llm/providers/anthropic/chat.rb +2 -2
  58. data/lib/ruby_llm/providers/anthropic/media.rb +1 -2
  59. data/lib/ruby_llm/providers/anthropic/tools.rb +1 -2
  60. data/lib/ruby_llm/providers/anthropic.rb +1 -2
  61. data/lib/ruby_llm/providers/bedrock/chat.rb +2 -4
  62. data/lib/ruby_llm/providers/bedrock/media.rb +0 -1
  63. data/lib/ruby_llm/providers/bedrock/models.rb +19 -3
  64. data/lib/ruby_llm/providers/bedrock/streaming/base.rb +0 -12
  65. data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +0 -7
  66. data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +0 -12
  67. data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +0 -12
  68. data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +0 -13
  69. data/lib/ruby_llm/providers/bedrock/streaming.rb +0 -18
  70. data/lib/ruby_llm/providers/bedrock.rb +1 -2
  71. data/lib/ruby_llm/providers/deepseek/capabilities.rb +1 -2
  72. data/lib/ruby_llm/providers/deepseek/chat.rb +0 -1
  73. data/lib/ruby_llm/providers/gemini/capabilities.rb +28 -100
  74. data/lib/ruby_llm/providers/gemini/chat.rb +57 -29
  75. data/lib/ruby_llm/providers/gemini/embeddings.rb +0 -2
  76. data/lib/ruby_llm/providers/gemini/images.rb +1 -2
  77. data/lib/ruby_llm/providers/gemini/media.rb +1 -2
  78. data/lib/ruby_llm/providers/gemini/models.rb +1 -2
  79. data/lib/ruby_llm/providers/gemini/streaming.rb +15 -1
  80. data/lib/ruby_llm/providers/gemini/tools.rb +0 -5
  81. data/lib/ruby_llm/providers/gpustack/chat.rb +11 -1
  82. data/lib/ruby_llm/providers/gpustack/media.rb +45 -0
  83. data/lib/ruby_llm/providers/gpustack/models.rb +44 -9
  84. data/lib/ruby_llm/providers/gpustack.rb +1 -0
  85. data/lib/ruby_llm/providers/mistral/capabilities.rb +2 -10
  86. data/lib/ruby_llm/providers/mistral/chat.rb +0 -2
  87. data/lib/ruby_llm/providers/mistral/embeddings.rb +0 -3
  88. data/lib/ruby_llm/providers/mistral/models.rb +0 -1
  89. data/lib/ruby_llm/providers/ollama/chat.rb +0 -1
  90. data/lib/ruby_llm/providers/ollama/media.rb +2 -7
  91. data/lib/ruby_llm/providers/ollama/models.rb +36 -0
  92. data/lib/ruby_llm/providers/ollama.rb +1 -0
  93. data/lib/ruby_llm/providers/openai/capabilities.rb +3 -16
  94. data/lib/ruby_llm/providers/openai/chat.rb +1 -3
  95. data/lib/ruby_llm/providers/openai/embeddings.rb +0 -3
  96. data/lib/ruby_llm/providers/openai/images.rb +73 -3
  97. data/lib/ruby_llm/providers/openai/media.rb +4 -5
  98. data/lib/ruby_llm/providers/openai/response.rb +121 -29
  99. data/lib/ruby_llm/providers/openai/response_media.rb +3 -3
  100. data/lib/ruby_llm/providers/openai/streaming.rb +110 -47
  101. data/lib/ruby_llm/providers/openai/tools.rb +12 -7
  102. data/lib/ruby_llm/providers/openai.rb +1 -3
  103. data/lib/ruby_llm/providers/openai_base.rb +2 -2
  104. data/lib/ruby_llm/providers/openrouter/models.rb +1 -16
  105. data/lib/ruby_llm/providers/perplexity/capabilities.rb +0 -1
  106. data/lib/ruby_llm/providers/perplexity/chat.rb +0 -1
  107. data/lib/ruby_llm/providers/perplexity.rb +1 -5
  108. data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
  109. data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
  110. data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
  111. data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
  112. data/lib/ruby_llm/providers/vertexai.rb +55 -0
  113. data/lib/ruby_llm/providers/xai/capabilities.rb +166 -0
  114. data/lib/ruby_llm/providers/xai/chat.rb +15 -0
  115. data/lib/ruby_llm/providers/xai/models.rb +48 -0
  116. data/lib/ruby_llm/providers/xai.rb +46 -0
  117. data/lib/ruby_llm/railtie.rb +20 -4
  118. data/lib/ruby_llm/stream_accumulator.rb +68 -10
  119. data/lib/ruby_llm/streaming.rb +16 -25
  120. data/lib/ruby_llm/tool.rb +2 -19
  121. data/lib/ruby_llm/tool_call.rb +0 -9
  122. data/lib/ruby_llm/utils.rb +5 -9
  123. data/lib/ruby_llm/version.rb +1 -1
  124. data/lib/ruby_llm_community.rb +8 -5
  125. data/lib/tasks/models.rake +549 -0
  126. data/lib/tasks/release.rake +37 -2
  127. data/lib/tasks/ruby_llm.rake +15 -0
  128. data/lib/tasks/vcr.rake +2 -9
  129. metadata +44 -6
  130. data/lib/generators/ruby_llm/install/templates/INSTALL_INFO.md.tt +0 -108
  131. data/lib/generators/ruby_llm/install_generator.rb +0 -121
  132. data/lib/tasks/aliases.rake +0 -235
  133. data/lib/tasks/models_docs.rake +0 -224
  134. data/lib/tasks/models_update.rake +0 -108
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: 0.0.6
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Shippy
@@ -136,16 +136,39 @@ 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
159
+ - lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt
143
160
  - lib/generators/ruby_llm/install/templates/create_tool_calls_migration.rb.tt
144
161
  - lib/generators/ruby_llm/install/templates/initializer.rb.tt
145
162
  - lib/generators/ruby_llm/install/templates/message_model.rb.tt
163
+ - lib/generators/ruby_llm/install/templates/model_model.rb.tt
146
164
  - lib/generators/ruby_llm/install/templates/tool_call_model.rb.tt
147
- - 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
148
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
149
172
  - lib/ruby_llm/aliases.json
150
173
  - lib/ruby_llm/aliases.rb
151
174
  - lib/ruby_llm/attachment.rb
@@ -153,11 +176,13 @@ files:
153
176
  - lib/ruby_llm/chunk.rb
154
177
  - lib/ruby_llm/configuration.rb
155
178
  - lib/ruby_llm/connection.rb
179
+ - lib/ruby_llm/connection_multipart.rb
156
180
  - lib/ruby_llm/content.rb
157
181
  - lib/ruby_llm/context.rb
158
182
  - lib/ruby_llm/embedding.rb
159
183
  - lib/ruby_llm/error.rb
160
184
  - lib/ruby_llm/image.rb
185
+ - lib/ruby_llm/image_attachment.rb
161
186
  - lib/ruby_llm/message.rb
162
187
  - lib/ruby_llm/mime_type.rb
163
188
  - lib/ruby_llm/model.rb
@@ -204,6 +229,7 @@ files:
204
229
  - lib/ruby_llm/providers/gemini/tools.rb
205
230
  - lib/ruby_llm/providers/gpustack.rb
206
231
  - lib/ruby_llm/providers/gpustack/chat.rb
232
+ - lib/ruby_llm/providers/gpustack/media.rb
207
233
  - lib/ruby_llm/providers/gpustack/models.rb
208
234
  - lib/ruby_llm/providers/mistral.rb
209
235
  - lib/ruby_llm/providers/mistral/capabilities.rb
@@ -213,6 +239,7 @@ files:
213
239
  - lib/ruby_llm/providers/ollama.rb
214
240
  - lib/ruby_llm/providers/ollama/chat.rb
215
241
  - lib/ruby_llm/providers/ollama/media.rb
242
+ - lib/ruby_llm/providers/ollama/models.rb
216
243
  - lib/ruby_llm/providers/openai.rb
217
244
  - lib/ruby_llm/providers/openai/capabilities.rb
218
245
  - lib/ruby_llm/providers/openai/chat.rb
@@ -231,6 +258,15 @@ files:
231
258
  - lib/ruby_llm/providers/perplexity/capabilities.rb
232
259
  - lib/ruby_llm/providers/perplexity/chat.rb
233
260
  - lib/ruby_llm/providers/perplexity/models.rb
261
+ - lib/ruby_llm/providers/vertexai.rb
262
+ - lib/ruby_llm/providers/vertexai/chat.rb
263
+ - lib/ruby_llm/providers/vertexai/embeddings.rb
264
+ - lib/ruby_llm/providers/vertexai/models.rb
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
234
270
  - lib/ruby_llm/railtie.rb
235
271
  - lib/ruby_llm/stream_accumulator.rb
236
272
  - lib/ruby_llm/streaming.rb
@@ -240,10 +276,9 @@ files:
240
276
  - lib/ruby_llm/version.rb
241
277
  - lib/ruby_llm_community.rb
242
278
  - lib/shims/ruby_llm.rb
243
- - lib/tasks/aliases.rake
244
- - lib/tasks/models_docs.rake
245
- - lib/tasks/models_update.rake
279
+ - lib/tasks/models.rake
246
280
  - lib/tasks/release.rake
281
+ - lib/tasks/ruby_llm.rake
247
282
  - lib/tasks/vcr.rake
248
283
  homepage: https://rubyllm.com
249
284
  licenses:
@@ -255,6 +290,9 @@ metadata:
255
290
  documentation_uri: https://rubyllm.com
256
291
  bug_tracker_uri: https://github.com/tpaulshippy/ruby_llm_community/issues
257
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/
258
296
  rdoc_options: []
259
297
  require_paths:
260
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,121 +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
-
22
- desc 'Creates model files for Chat, Message, and ToolCall, and creates migrations for RubyLLM Rails integration'
23
-
24
- def self.next_migration_number(dirname)
25
- ::ActiveRecord::Generators::Base.next_migration_number(dirname)
26
- end
27
-
28
- def migration_version
29
- "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
30
- end
31
-
32
- def postgresql?
33
- ::ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
34
- rescue StandardError
35
- false
36
- end
37
-
38
- def acts_as_chat_declaration
39
- acts_as_chat_params = []
40
- if options[:message_model_name] != 'Message'
41
- acts_as_chat_params << "message_class: \"#{options[:message_model_name]}\""
42
- end
43
- if options[:tool_call_model_name] != 'ToolCall'
44
- acts_as_chat_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
45
- end
46
- if acts_as_chat_params.any?
47
- "acts_as_chat #{acts_as_chat_params.join(', ')}"
48
- else
49
- 'acts_as_chat'
50
- end
51
- end
52
-
53
- def acts_as_message_declaration
54
- acts_as_message_params = []
55
- acts_as_message_params << "chat_class: \"#{options[:chat_model_name]}\"" if options[:chat_model_name] != 'Chat'
56
- if options[:tool_call_model_name] != 'ToolCall'
57
- acts_as_message_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
58
- end
59
- if acts_as_message_params.any?
60
- "acts_as_message #{acts_as_message_params.join(', ')}"
61
- else
62
- 'acts_as_message'
63
- end
64
- end
65
-
66
- def acts_as_tool_call_declaration
67
- acts_as_tool_call_params = []
68
- if options[:message_model_name] != 'Message'
69
- acts_as_tool_call_params << "message_class: \"#{options[:message_model_name]}\""
70
- end
71
- if acts_as_tool_call_params.any?
72
- "acts_as_tool_call #{acts_as_tool_call_params.join(', ')}"
73
- else
74
- 'acts_as_tool_call'
75
- end
76
- end
77
-
78
- def create_migration_files
79
- # Create migrations with timestamps to ensure proper order
80
- # First create chats table
81
- migration_template 'create_chats_migration.rb.tt',
82
- "db/migrate/create_#{options[:chat_model_name].tableize}.rb"
83
-
84
- # Then create messages table (must come before tool_calls due to foreign key)
85
- sleep 1 # Ensure different timestamp
86
- migration_template 'create_messages_migration.rb.tt',
87
- "db/migrate/create_#{options[:message_model_name].tableize}.rb"
88
-
89
- # Finally create tool_calls table (references messages)
90
- sleep 1 # Ensure different timestamp
91
- migration_template 'create_tool_calls_migration.rb.tt',
92
- "db/migrate/create_#{options[:tool_call_model_name].tableize}.rb"
93
- end
94
-
95
- def create_model_files
96
- template 'chat_model.rb.tt', "app/models/#{options[:chat_model_name].underscore}.rb"
97
- template 'message_model.rb.tt', "app/models/#{options[:message_model_name].underscore}.rb"
98
- template 'tool_call_model.rb.tt', "app/models/#{options[:tool_call_model_name].underscore}.rb"
99
- end
100
-
101
- def create_initializer
102
- template 'initializer.rb.tt', 'config/initializers/ruby_llm.rb'
103
- end
104
-
105
- def show_install_info
106
- say "\n ✅ RubyLLM installed!", :green
107
-
108
- say "\n Next steps:", :yellow
109
- say ' 1. Run: rails db:migrate'
110
- say ' 2. Set your API keys in config/initializers/ruby_llm.rb'
111
- say " 3. Start chatting: #{options[:chat_model_name]}.create!(model_id: 'gpt-4.1-nano').ask('Hello!')"
112
-
113
- say "\n 📚 Full docs: https://rubyllm.com", :cyan
114
-
115
- say "\n ❤️ Love RubyLLM?", :magenta
116
- say ' • ⭐ Star on GitHub: https://github.com/crmne/ruby_llm'
117
- say ' • 💖 Sponsor: https://github.com/sponsors/crmne'
118
- say "\n"
119
- end
120
- end
121
- end
@@ -1,235 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- namespace :aliases do # rubocop:disable Metrics/BlockLength
6
- desc 'Generate aliases.json from models in the registry'
7
- task :generate do # rubocop:disable Metrics/BlockLength
8
- require 'ruby_llm'
9
-
10
- # Group models by provider
11
- models = Hash.new { |h, k| h[k] = [] }
12
-
13
- RubyLLM.models.all.each do |model|
14
- models[model.provider] << model.id
15
- end
16
-
17
- aliases = {}
18
-
19
- # OpenAI models
20
- models['openai'].each do |model|
21
- openrouter_model = "openai/#{model}"
22
- next unless models['openrouter'].include?(openrouter_model)
23
-
24
- alias_key = model.gsub('-latest', '')
25
- aliases[alias_key] = {
26
- 'openai' => model,
27
- 'openrouter' => openrouter_model
28
- }
29
- end
30
-
31
- # Anthropic models - group by base name and find latest
32
- anthropic_latest = group_anthropic_models_by_base_name(models['anthropic'])
33
-
34
- anthropic_latest.each do |base_name, latest_model|
35
- # Check OpenRouter naming patterns for the BASE NAME (not the full dated model)
36
- openrouter_variants = [
37
- "anthropic/#{base_name}", # anthropic/claude-3-5-sonnet
38
- "anthropic/#{base_name.gsub(/-(\d)/, '.\1')}", # anthropic/claude-3.5-sonnet
39
- "anthropic/#{base_name.gsub(/claude-(\d+)-(\d+)/, 'claude-\1.\2')}", # claude-3-5 -> claude-3.5
40
- "anthropic/#{base_name.gsub(/(\d+)-(\d+)/, '\1.\2')}" # any X-Y -> X.Y pattern
41
- ]
42
-
43
- openrouter_model = openrouter_variants.find { |v| models['openrouter'].include?(v) }
44
-
45
- # Find corresponding Bedrock model
46
- bedrock_model = find_best_bedrock_model(latest_model, models['bedrock'])
47
-
48
- # Create alias if we have any match (OpenRouter OR Bedrock) OR if it's Anthropic-only
49
- next unless openrouter_model || bedrock_model || models['anthropic'].include?(latest_model)
50
-
51
- aliases[base_name] = {
52
- 'anthropic' => latest_model
53
- }
54
-
55
- aliases[base_name]['openrouter'] = openrouter_model if openrouter_model
56
- aliases[base_name]['bedrock'] = bedrock_model if bedrock_model
57
- end
58
-
59
- # Also check if Bedrock has models that Anthropic doesn't
60
- models['bedrock'].each do |bedrock_model|
61
- next unless bedrock_model.start_with?('anthropic.')
62
-
63
- # Extract the Claude model name
64
- next unless bedrock_model =~ /anthropic\.(claude-[\d\.]+-[a-z]+)/
65
-
66
- base_name = Regexp.last_match(1)
67
- # Normalize to Anthropic naming convention
68
- anthropic_name = base_name.tr('.', '-')
69
-
70
- # Skip if we already have an alias for this
71
- next if aliases[anthropic_name]
72
-
73
- # Check if this model exists in OpenRouter
74
- openrouter_variants = [
75
- "anthropic/#{anthropic_name}",
76
- "anthropic/#{base_name}" # Keep the dots
77
- ]
78
-
79
- openrouter_model = openrouter_variants.find { |v| models['openrouter'].include?(v) }
80
-
81
- aliases[anthropic_name] = {
82
- 'bedrock' => bedrock_model
83
- }
84
-
85
- aliases[anthropic_name]['anthropic'] = anthropic_name if models['anthropic'].include?(anthropic_name)
86
- aliases[anthropic_name]['openrouter'] = openrouter_model if openrouter_model
87
- end
88
-
89
- # Gemini models
90
- models['gemini'].each do |model|
91
- # OpenRouter uses "google/" prefix and sometimes different naming
92
- openrouter_variants = [
93
- "google/#{model}",
94
- "google/#{model.gsub('gemini-', 'gemini-').tr('.', '-')}",
95
- "google/#{model.gsub('gemini-', 'gemini-')}"
96
- ]
97
-
98
- openrouter_model = openrouter_variants.find { |v| models['openrouter'].include?(v) }
99
- next unless openrouter_model
100
-
101
- alias_key = model.gsub('-latest', '')
102
- aliases[alias_key] = {
103
- 'gemini' => model,
104
- 'openrouter' => openrouter_model
105
- }
106
- end
107
-
108
- # DeepSeek models
109
- models['deepseek'].each do |model|
110
- openrouter_model = "deepseek/#{model}"
111
- next unless models['openrouter'].include?(openrouter_model)
112
-
113
- alias_key = model.gsub('-latest', '')
114
- aliases[alias_key] = {
115
- 'deepseek' => model,
116
- 'openrouter' => openrouter_model
117
- }
118
- end
119
-
120
- # Write the result
121
- sorted_aliases = aliases.sort.to_h
122
- File.write('lib/ruby_llm/aliases.json', JSON.pretty_generate(sorted_aliases))
123
-
124
- puts "Generated #{sorted_aliases.size} aliases"
125
- end
126
-
127
- def group_anthropic_models_by_base_name(anthropic_models) # rubocop:disable Rake/MethodDefinitionInTask
128
- grouped = Hash.new { |h, k| h[k] = [] }
129
-
130
- anthropic_models.each do |model|
131
- base_name = extract_base_name(model)
132
- grouped[base_name] << model
133
- end
134
-
135
- # Find the latest model for each base name
136
- latest_models = {}
137
- grouped.each do |base_name, model_list|
138
- if model_list.size == 1
139
- latest_models[base_name] = model_list.first
140
- else
141
- # Sort by date and take the latest
142
- latest_model = model_list.max_by { |model| extract_date_from_model(model) }
143
- latest_models[base_name] = latest_model
144
- end
145
- end
146
-
147
- latest_models
148
- end
149
-
150
- def extract_base_name(model) # rubocop:disable Rake/MethodDefinitionInTask
151
- # Remove date suffix (YYYYMMDD) from model name
152
- if model =~ /^(.+)-(\d{8})$/
153
- Regexp.last_match(1)
154
- else
155
- # Models without date suffix (like claude-2.0, claude-2.1)
156
- model
157
- end
158
- end
159
-
160
- def extract_date_from_model(model) # rubocop:disable Rake/MethodDefinitionInTask
161
- # Extract date for comparison, return '00000000' for models without dates
162
- if model =~ /-(\d{8})$/
163
- Regexp.last_match(1)
164
- else
165
- '00000000' # Ensures models without dates sort before dated ones
166
- end
167
- end
168
-
169
- def find_best_bedrock_model(anthropic_model, bedrock_models) # rubocop:disable Metrics/PerceivedComplexity,Rake/MethodDefinitionInTask
170
- # Special mapping for Claude 2.x models
171
- base_pattern = case anthropic_model
172
- when 'claude-2.0', 'claude-2'
173
- 'claude-v2'
174
- when 'claude-2.1'
175
- 'claude-v2:1'
176
- when 'claude-instant-v1', 'claude-instant'
177
- 'claude-instant'
178
- else
179
- # For Claude 3+ models, extract base name
180
- extract_base_name(anthropic_model)
181
- end
182
-
183
- # Find all matching Bedrock models by stripping provider prefix and comparing base name
184
- matching_models = bedrock_models.select do |bedrock_model|
185
- # Strip any provider prefix (anthropic. or us.anthropic.)
186
- model_without_prefix = bedrock_model.sub(/^(?:us\.)?anthropic\./, '')
187
- model_without_prefix.start_with?(base_pattern)
188
- end
189
-
190
- return nil if matching_models.empty?
191
-
192
- # Get model info to check context window
193
- begin
194
- model_info = RubyLLM.models.find(anthropic_model)
195
- target_context = model_info.context_window
196
- rescue StandardError
197
- target_context = nil
198
- end
199
-
200
- # If we have context window info, try to match it
201
- if target_context
202
- # Convert to k format (200000 -> 200k)
203
- target_k = target_context / 1000
204
-
205
- # Find models with this specific context window
206
- with_context = matching_models.select do |m|
207
- m.include?(":#{target_k}k") || m.include?(":0:#{target_k}k")
208
- end
209
-
210
- return with_context.first if with_context.any?
211
- end
212
-
213
- # Otherwise, pick the one with the highest context window or latest version
214
- matching_models.min_by do |model|
215
- # Extract context window if specified
216
- context_priority = if model =~ /:(?:\d+:)?(\d+)k/
217
- -Regexp.last_match(1).to_i # Negative for descending sort
218
- else
219
- 0 # No context specified
220
- end
221
-
222
- # Extract version if present
223
- version_priority = if model =~ /-v(\d+):/
224
- -Regexp.last_match(1).to_i # Negative for descending sort (latest version first)
225
- else
226
- 0
227
- end
228
-
229
- # Prefer models with explicit context windows
230
- has_context_priority = model.include?('k') ? -1 : 0
231
-
232
- [has_context_priority, context_priority, version_priority]
233
- end
234
- end
235
- end