ruby_llm_community 0.0.5 → 1.0.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -91
  3. data/lib/generators/ruby_llm/install/templates/create_models_migration.rb.tt +34 -0
  4. data/lib/generators/ruby_llm/install/templates/initializer.rb.tt +5 -0
  5. data/lib/generators/ruby_llm/install/templates/model_model.rb.tt +6 -0
  6. data/lib/generators/ruby_llm/install_generator.rb +27 -2
  7. data/lib/ruby_llm/active_record/acts_as.rb +168 -24
  8. data/lib/ruby_llm/aliases.json +62 -5
  9. data/lib/ruby_llm/aliases.rb +7 -25
  10. data/lib/ruby_llm/chat.rb +10 -17
  11. data/lib/ruby_llm/configuration.rb +5 -12
  12. data/lib/ruby_llm/connection.rb +4 -4
  13. data/lib/ruby_llm/connection_multipart.rb +19 -0
  14. data/lib/ruby_llm/content.rb +5 -2
  15. data/lib/ruby_llm/embedding.rb +1 -2
  16. data/lib/ruby_llm/error.rb +0 -8
  17. data/lib/ruby_llm/image.rb +23 -8
  18. data/lib/ruby_llm/image_attachment.rb +21 -0
  19. data/lib/ruby_llm/message.rb +6 -6
  20. data/lib/ruby_llm/model/info.rb +12 -10
  21. data/lib/ruby_llm/model/pricing.rb +0 -3
  22. data/lib/ruby_llm/model/pricing_category.rb +0 -2
  23. data/lib/ruby_llm/model/pricing_tier.rb +0 -1
  24. data/lib/ruby_llm/models.json +2485 -676
  25. data/lib/ruby_llm/models.rb +65 -34
  26. data/lib/ruby_llm/provider.rb +8 -8
  27. data/lib/ruby_llm/providers/anthropic/capabilities.rb +1 -46
  28. data/lib/ruby_llm/providers/anthropic/chat.rb +2 -2
  29. data/lib/ruby_llm/providers/anthropic/media.rb +0 -1
  30. data/lib/ruby_llm/providers/anthropic/tools.rb +1 -2
  31. data/lib/ruby_llm/providers/anthropic.rb +1 -2
  32. data/lib/ruby_llm/providers/bedrock/chat.rb +2 -4
  33. data/lib/ruby_llm/providers/bedrock/media.rb +0 -1
  34. data/lib/ruby_llm/providers/bedrock/models.rb +0 -2
  35. data/lib/ruby_llm/providers/bedrock/streaming/base.rb +0 -12
  36. data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +0 -7
  37. data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +0 -12
  38. data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +0 -12
  39. data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +0 -13
  40. data/lib/ruby_llm/providers/bedrock/streaming.rb +0 -18
  41. data/lib/ruby_llm/providers/bedrock.rb +1 -2
  42. data/lib/ruby_llm/providers/deepseek/capabilities.rb +1 -2
  43. data/lib/ruby_llm/providers/deepseek/chat.rb +0 -1
  44. data/lib/ruby_llm/providers/gemini/capabilities.rb +28 -100
  45. data/lib/ruby_llm/providers/gemini/chat.rb +57 -29
  46. data/lib/ruby_llm/providers/gemini/embeddings.rb +0 -2
  47. data/lib/ruby_llm/providers/gemini/images.rb +1 -2
  48. data/lib/ruby_llm/providers/gemini/media.rb +0 -1
  49. data/lib/ruby_llm/providers/gemini/models.rb +1 -2
  50. data/lib/ruby_llm/providers/gemini/streaming.rb +15 -1
  51. data/lib/ruby_llm/providers/gemini/tools.rb +0 -5
  52. data/lib/ruby_llm/providers/gpustack/chat.rb +11 -1
  53. data/lib/ruby_llm/providers/gpustack/media.rb +45 -0
  54. data/lib/ruby_llm/providers/gpustack/models.rb +44 -9
  55. data/lib/ruby_llm/providers/gpustack.rb +1 -0
  56. data/lib/ruby_llm/providers/mistral/capabilities.rb +2 -10
  57. data/lib/ruby_llm/providers/mistral/chat.rb +0 -2
  58. data/lib/ruby_llm/providers/mistral/embeddings.rb +0 -3
  59. data/lib/ruby_llm/providers/mistral/models.rb +0 -1
  60. data/lib/ruby_llm/providers/ollama/chat.rb +0 -1
  61. data/lib/ruby_llm/providers/ollama/media.rb +1 -6
  62. data/lib/ruby_llm/providers/ollama/models.rb +36 -0
  63. data/lib/ruby_llm/providers/ollama.rb +1 -0
  64. data/lib/ruby_llm/providers/openai/capabilities.rb +3 -16
  65. data/lib/ruby_llm/providers/openai/chat.rb +1 -3
  66. data/lib/ruby_llm/providers/openai/embeddings.rb +0 -3
  67. data/lib/ruby_llm/providers/openai/images.rb +73 -3
  68. data/lib/ruby_llm/providers/openai/media.rb +0 -1
  69. data/lib/ruby_llm/providers/openai/response.rb +120 -29
  70. data/lib/ruby_llm/providers/openai/response_media.rb +2 -2
  71. data/lib/ruby_llm/providers/openai/streaming.rb +107 -47
  72. data/lib/ruby_llm/providers/openai/tools.rb +1 -1
  73. data/lib/ruby_llm/providers/openai.rb +1 -3
  74. data/lib/ruby_llm/providers/openai_base.rb +2 -2
  75. data/lib/ruby_llm/providers/openrouter/models.rb +1 -16
  76. data/lib/ruby_llm/providers/perplexity/capabilities.rb +0 -1
  77. data/lib/ruby_llm/providers/perplexity/chat.rb +0 -1
  78. data/lib/ruby_llm/providers/perplexity.rb +1 -5
  79. data/lib/ruby_llm/providers/vertexai/chat.rb +14 -0
  80. data/lib/ruby_llm/providers/vertexai/embeddings.rb +32 -0
  81. data/lib/ruby_llm/providers/vertexai/models.rb +130 -0
  82. data/lib/ruby_llm/providers/vertexai/streaming.rb +14 -0
  83. data/lib/ruby_llm/providers/vertexai.rb +55 -0
  84. data/lib/ruby_llm/railtie.rb +0 -1
  85. data/lib/ruby_llm/stream_accumulator.rb +72 -10
  86. data/lib/ruby_llm/streaming.rb +16 -25
  87. data/lib/ruby_llm/tool.rb +2 -19
  88. data/lib/ruby_llm/tool_call.rb +0 -9
  89. data/lib/ruby_llm/version.rb +1 -1
  90. data/lib/ruby_llm_community.rb +5 -3
  91. data/lib/tasks/models.rake +525 -0
  92. data/lib/tasks/release.rake +37 -2
  93. data/lib/tasks/vcr.rake +0 -7
  94. metadata +13 -4
  95. data/lib/tasks/aliases.rake +0 -235
  96. data/lib/tasks/models_docs.rake +0 -224
  97. data/lib/tasks/models_update.rake +0 -108
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9007798f0f3d2c512b138292c6040aede0a135688b931e202c0c8baca10d6623
4
- data.tar.gz: 8fb9a3af7a4e48d437f65dcca8a9a2d50f7f1c04c385a2b4aa38456e7efc7993
3
+ metadata.gz: 0d28b384f53784c1954147d9f217caff1325893f1853e6be63c60158d9c37b79
4
+ data.tar.gz: 3c6e66e260c1300b3b20ae730ec3755fcca19be8afc8dee754e26cc82cbee7f4
5
5
  SHA512:
6
- metadata.gz: b5b5801c832fb0e0ccb2a38368b1160f22d1f31f17192e15f11cfcedde91b95a7a1ad6ccab273c29910354199643a67b66e1da38888393ca2017921c031a060b
7
- data.tar.gz: f37724b8396ba64f5e50b7a64173af90d0d8e02b6029d0f07c732d3323bf2038f0adb4f8f7db13430fe42dcf25d7065b2d47568f4609a382fd74035f0d25237f
6
+ metadata.gz: 568f6c9a3facf5e5f721ec6e3d44862eb0988529cf72625a88220fe80f00ba89f5602f0a178d0ead3cfc3c4accca3a4b56321a3a24f84883df16bd1c72432458
7
+ data.tar.gz: e6336936468acfc005284a1e6f7cbffe58e55e85c760082af71569d9555371ed124b26fe0cc70d274124f4b80530881c012d10079145f0c90383f2d6e2c51ff7
data/README.md CHANGED
@@ -1,99 +1,114 @@
1
+ <div align="center">
2
+
1
3
  <picture>
2
4
  <source media="(prefers-color-scheme: dark)" srcset="/docs/assets/images/logotype_dark.svg">
3
5
  <img src="/docs/assets/images/logotype.svg" alt="RubyLLM" height="120" width="250">
4
6
  </picture>
5
7
 
6
- **One *beautiful* Ruby API for GPT, Claude, Gemini, and more.** Easily build chatbots, AI agents, RAG applications, and content generators. Features chat (text, images, audio, PDFs), image generation, embeddings, tools (function calling), structured output, Rails integration, and streaming. Works with OpenAI, Anthropic, Google Gemini, AWS Bedrock, DeepSeek, Mistral, Ollama (local models), OpenRouter, Perplexity, GPUStack, and any OpenAI-compatible API.
8
+ <strong>One *beautiful* Ruby API for GPT, Claude, Gemini, and more.</strong>
9
+
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) — *Claude Code for your documents*
11
+
12
+ [![Gem Version](https://badge.fury.io/rb/ruby_llm.svg?a=7)](https://badge.fury.io/rb/ruby_llm)
13
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
14
+ [![Gem Downloads](https://img.shields.io/gem/dt/ruby_llm)](https://rubygems.org/gems/ruby_llm)
15
+ [![codecov](https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg?a=2)](https://codecov.io/gh/crmne/ruby_llm)
7
16
 
8
- <div class="badge-container">
9
- <a href="https://badge.fury.io/rb/ruby_llm"><img src="https://badge.fury.io/rb/ruby_llm.svg?a=5" alt="Gem Version" /></a>
10
- <a href="https://github.com/testdouble/standard"><img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="Ruby Style Guide" /></a>
11
- <a href="https://rubygems.org/gems/ruby_llm"><img alt="Gem Downloads" src="https://img.shields.io/gem/dt/ruby_llm"></a>
12
- <a href="https://codecov.io/gh/crmne/ruby_llm"><img src="https://codecov.io/gh/crmne/ruby_llm/branch/main/graph/badge.svg" alt="codecov" /></a>
17
+ <a href="https://trendshift.io/repositories/13640" target="_blank"><img src="https://trendshift.io/api/badge/repositories/13640" alt="crmne%2Fruby_llm | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
13
18
  </div>
14
19
 
15
- 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) — *Claude Code for your documents*
20
+ ---
21
+
22
+ Build chatbots, AI agents, RAG applications. Works with OpenAI, Anthropic, Google, AWS, local models, and any OpenAI-compatible API.
16
23
 
17
- ## The problem with AI libraries
24
+ ## Why RubyLLM?
18
25
 
19
- Every AI provider comes with its own client library, its own response format, its own conventions for streaming, and its own way of handling errors. Want to use multiple providers? Prepare to juggle incompatible APIs and bloated dependencies.
26
+ Every AI provider ships their own bloated client. Different APIs. Different response formats. Different conventions. It's exhausting.
20
27
 
21
- RubyLLM fixes all that. One beautiful API for everything. One consistent format. Minimal dependencies — just Faraday, Zeitwerk, and [Marcel](https://github.com/rails/marcel). Because working with AI should be a joy, not a chore.
28
+ 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](https://github.com/lostisland/faraday), [Zeitwerk](https://github.com/fxn/zeitwerk), and [Marcel](https://github.com/rails/marcel). That's it.
22
29
 
23
- ## What makes it great
30
+ ## Show me the code
24
31
 
25
32
  ```ruby
26
33
  # Just ask questions
27
34
  chat = RubyLLM.chat
28
35
  chat.ask "What's the best way to learn Ruby?"
36
+ ```
29
37
 
30
- # Analyze images, audio, documents, and text files
38
+ ```ruby
39
+ # Analyze any file type
31
40
  chat.ask "What's in this image?", with: "ruby_conf.jpg"
32
41
  chat.ask "Describe this meeting", with: "meeting.wav"
33
42
  chat.ask "Summarize this document", with: "contract.pdf"
34
43
  chat.ask "Explain this code", with: "app.rb"
44
+ ```
35
45
 
36
- # Multiple files at once - types automatically detected
46
+ ```ruby
47
+ # Multiple files at once
37
48
  chat.ask "Analyze these files", with: ["diagram.png", "report.pdf", "notes.txt"]
49
+ ```
38
50
 
39
- # Stream responses in real-time
40
- chat.ask "Tell me a story about a Ruby programmer" do |chunk|
51
+ ```ruby
52
+ # Stream responses
53
+ chat.ask "Tell me a story about Ruby" do |chunk|
41
54
  print chunk.content
42
55
  end
56
+ ```
43
57
 
58
+ ```ruby
44
59
  # Generate images
45
60
  RubyLLM.paint "a sunset over mountains in watercolor style"
61
+ ```
46
62
 
47
- # Create vector embeddings
63
+ ```ruby
64
+ # Create embeddings
48
65
  RubyLLM.embed "Ruby is elegant and expressive"
66
+ ```
49
67
 
68
+ ```ruby
50
69
  # Let AI use your code
51
70
  class Weather < RubyLLM::Tool
52
- description "Gets current weather for a location"
53
- param :latitude, desc: "Latitude (e.g., 52.5200)"
54
- param :longitude, desc: "Longitude (e.g., 13.4050)"
71
+ description "Get current weather"
72
+ param :latitude
73
+ param :longitude
55
74
 
56
75
  def execute(latitude:, longitude:)
57
76
  url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}&current=temperature_2m,wind_speed_10m"
58
-
59
- response = Faraday.get(url)
60
- data = JSON.parse(response.body)
61
- rescue => e
62
- { error: e.message }
77
+ JSON.parse(Faraday.get(url).body)
63
78
  end
64
79
  end
65
80
 
66
- chat.with_tool(Weather).ask "What's the weather in Berlin? (52.5200, 13.4050)"
81
+ chat.with_tool(Weather).ask "What's the weather in Berlin?"
82
+ ```
67
83
 
68
- # Get structured output with JSON schemas
84
+ ```ruby
85
+ # Get structured output
69
86
  class ProductSchema < RubyLLM::Schema
70
- string :name, description: "Product name"
71
- number :price, description: "Price in USD"
72
- array :features, description: "Key features" do
73
- string description: "Feature description"
87
+ string :name
88
+ number :price
89
+ array :features do
90
+ string
74
91
  end
75
92
  end
76
93
 
77
- response = chat.with_schema(ProductSchema)
78
- .ask "Analyze this product description", with: "product.txt"
79
- # response.content => { "name" => "...", "price" => 99.99, "features" => [...] }
94
+ response = chat.with_schema(ProductSchema).ask "Analyze this product", with: "product.txt"
80
95
  ```
81
96
 
82
- ## Core Capabilities
83
-
84
- * 💬 **Unified Chat:** Converse with models from OpenAI, Anthropic, Gemini, Bedrock, OpenRouter, DeepSeek, Perplexity, Mistral, Ollama, or any OpenAI-compatible API using `RubyLLM.chat`.
85
- * 👁️ **Vision:** Analyze images within chats.
86
- * 🔊 **Audio:** Transcribe and understand audio content.
87
- * 📄 **Document Analysis:** Extract information from PDFs, text files, CSV, JSON, XML, Markdown, and code files.
88
- * 🖼️ **Image Generation:** Create images with `RubyLLM.paint`.
89
- * 📊 **Embeddings:** Generate text embeddings for vector search with `RubyLLM.embed`.
90
- * 🔧 **Tools (Function Calling):** Let AI models call your Ruby code using `RubyLLM::Tool`.
91
- * 📋 **Structured Output:** Guarantee responses conform to JSON schemas with `RubyLLM::Schema`.
92
- * 🚂 **Rails Integration:** Easily persist chats, messages, and tool calls using `acts_as_chat` and `acts_as_message`.
93
- * 🌊 **Streaming:** Process responses in real-time with idiomatic Ruby blocks.
94
- * **Async Support:** Built-in fiber-based concurrency for high-performance operations.
95
- * 🎯 **Smart Configuration:** Global and scoped configs with automatic retries and proxy support.
96
- * 📚 **Model Registry:** Access 500+ models with capability detection and pricing info.
97
+ ## Features
98
+
99
+ * **Chat:** Conversational AI with `RubyLLM.chat`
100
+ * **Vision:** Analyze images and screenshots
101
+ * **Audio:** Transcribe and understand speech
102
+ * **Documents:** Extract from PDFs, CSVs, JSON, any file type
103
+ * **Image generation:** Create images with `RubyLLM.paint`
104
+ * **Embeddings:** Vector search with `RubyLLM.embed`
105
+ * **Tools:** Let AI call your Ruby methods
106
+ * **Structured output:** JSON schemas that just work
107
+ * **Streaming:** Real-time responses with blocks
108
+ * **Rails:** ActiveRecord integration with `acts_as_chat`
109
+ * **Async:** Fiber-based concurrency
110
+ * **Model registry:** 500+ models with capability detection and pricing
111
+ * **Providers:** OpenAI, Anthropic, Gemini, VertexAI, Bedrock, DeepSeek, Mistral, Ollama, OpenRouter, Perplexity, GPUStack, and any OpenAI-compatible API
97
112
 
98
113
  ## Installation
99
114
 
@@ -103,69 +118,36 @@ gem 'ruby_llm_community'
103
118
  ```
104
119
  Then `bundle install`.
105
120
 
106
- Configure your API keys (using environment variables is recommended):
121
+ Configure your API keys:
107
122
  ```ruby
108
- # config/initializers/ruby_llm.rb or similar
123
+ # config/initializers/ruby_llm.rb
109
124
  RubyLLM.configure do |config|
110
- config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
111
- # Add keys ONLY for providers you intend to use
112
- # config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
113
- # ... see Configuration guide for all options ...
125
+ config.openai_api_key = ENV['OPENAI_API_KEY']
114
126
  end
115
127
  ```
116
- See the [Installation Guide](https://rubyllm.com/installation) for full details.
117
128
 
118
- ## Rails Integration
119
-
120
- Add persistence to your chat models effortlessly:
129
+ ## Rails
121
130
 
122
131
  ```bash
123
- # Generate models and migrations
124
132
  rails generate ruby_llm:install
125
133
  ```
126
134
 
127
135
  ```ruby
128
- # Or add to existing models
129
136
  class Chat < ApplicationRecord
130
- acts_as_chat # Automatically saves messages & tool calls
131
- end
132
-
133
- class Message < ApplicationRecord
134
- acts_as_message
137
+ acts_as_chat
135
138
  end
136
139
 
137
- class ToolCall < ApplicationRecord
138
- acts_as_tool_call
139
- end
140
-
141
- # Now chats persist automatically
142
- chat = Chat.create!(model_id: "gpt-4.1-nano")
143
- chat.ask("What's in this file?", with: "report.pdf")
140
+ chat = Chat.create! model_id: "claude-sonnet-4"
141
+ chat.ask "What's in this file?", with: "report.pdf"
144
142
  ```
145
143
 
146
- See the [Rails Integration Guide](https://rubyllm.com/guides/rails) for details.
147
-
148
- ## Learn More
149
-
150
- Dive deeper with the official documentation:
144
+ ## Documentation
151
145
 
152
- - [Installation](https://rubyllm.com/installation)
153
- - [Configuration](https://rubyllm.com/configuration)
154
- - **Guides:**
155
- - [Getting Started](https://rubyllm.com/guides/getting-started)
156
- - [Chatting with AI Models](https://rubyllm.com/guides/chat)
157
- - [Using Tools](https://rubyllm.com/guides/tools)
158
- - [Streaming Responses](https://rubyllm.com/guides/streaming)
159
- - [Rails Integration](https://rubyllm.com/guides/rails)
160
- - [Image Generation](https://rubyllm.com/guides/image-generation)
161
- - [Embeddings](https://rubyllm.com/guides/embeddings)
162
- - [Working with Models](https://rubyllm.com/guides/models)
163
- - [Error Handling](https://rubyllm.com/guides/error-handling)
164
- - [Available Models](https://rubyllm.com/guides/available-models)
146
+ [rubyllm.com](https://rubyllm.com)
165
147
 
166
148
  ## Contributing
167
149
 
168
- We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on setup, testing, and contribution guidelines.
150
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
169
151
 
170
152
  ## License
171
153
 
@@ -0,0 +1,34 @@
1
+ class Create<%= options[:model_model_name].pluralize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :<%= options[:model_model_name].tableize %> do |t|
4
+ t.string :model_id, null: false
5
+ t.string :name, null: false
6
+ t.string :provider, null: false
7
+ t.string :family
8
+ t.datetime :model_created_at
9
+ t.integer :context_window
10
+ t.integer :max_output_tokens
11
+ t.date :knowledge_cutoff
12
+ <% if postgresql? %>
13
+ t.jsonb :modalities, default: {}
14
+ t.jsonb :capabilities, default: []
15
+ t.jsonb :pricing, default: {}
16
+ t.jsonb :metadata, default: {}
17
+ <% else %>
18
+ t.json :modalities, default: {}
19
+ t.json :capabilities, default: []
20
+ t.json :pricing, default: {}
21
+ t.json :metadata, default: {}
22
+ <% end %>
23
+ t.timestamps
24
+
25
+ t.index [:provider, :model_id], unique: true
26
+ t.index :provider
27
+ t.index :family
28
+ <% if postgresql? %>
29
+ t.index :capabilities, using: :gin
30
+ t.index :modalities, using: :gin
31
+ <% end %>
32
+ end
33
+ end
34
+ end
@@ -3,4 +3,9 @@ RubyLLM.configure do |config|
3
3
  config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
4
4
 
5
5
  # config.default_model = "gpt-4.1-nano"
6
+ <% unless options[:skip_model] %>
7
+
8
+ # Model registry persistence
9
+ config.model_registry_class = "<%= options[:model_model_name] %>"
10
+ <% end %>
6
11
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Model registry persistence
4
+ class <%= options[:model_model_name] %> < ApplicationRecord
5
+ <%= acts_as_model_declaration %>
6
+ end
@@ -18,8 +18,12 @@ module RubyLLM
18
18
  desc: 'Name of the Message model class'
19
19
  class_option :tool_call_model_name, type: :string, default: 'ToolCall',
20
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'
21
25
 
22
- desc 'Creates model files for Chat, Message, and ToolCall, and creates migrations for RubyLLM Rails integration'
26
+ desc 'Creates models and migrations for RubyLLM Rails integration'
23
27
 
24
28
  def self.next_migration_number(dirname)
25
29
  ::ActiveRecord::Generators::Base.next_migration_number(dirname)
@@ -75,6 +79,10 @@ module RubyLLM
75
79
  end
76
80
  end
77
81
 
82
+ def acts_as_model_declaration
83
+ 'acts_as_model'
84
+ end
85
+
78
86
  def create_migration_files
79
87
  # Create migrations with timestamps to ensure proper order
80
88
  # First create chats table
@@ -86,16 +94,27 @@ module RubyLLM
86
94
  migration_template 'create_messages_migration.rb.tt',
87
95
  "db/migrate/create_#{options[:message_model_name].tableize}.rb"
88
96
 
89
- # Finally create tool_calls table (references messages)
97
+ # Then create tool_calls table (references messages)
90
98
  sleep 1 # Ensure different timestamp
91
99
  migration_template 'create_tool_calls_migration.rb.tt',
92
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"
93
108
  end
94
109
 
95
110
  def create_model_files
96
111
  template 'chat_model.rb.tt', "app/models/#{options[:chat_model_name].underscore}.rb"
97
112
  template 'message_model.rb.tt', "app/models/#{options[:message_model_name].underscore}.rb"
98
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"
99
118
  end
100
119
 
101
120
  def create_initializer
@@ -110,6 +129,12 @@ module RubyLLM
110
129
  say ' 2. Set your API keys in config/initializers/ruby_llm.rb'
111
130
  say " 3. Start chatting: #{options[:chat_model_name]}.create!(model_id: 'gpt-4.1-nano').ask('Hello!')"
112
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
+
113
138
  say "\n 📚 Full docs: https://rubyllm.com", :cyan
114
139
 
115
140
  say "\n ❤️ Love RubyLLM?", :magenta