-
-
Notifications
You must be signed in to change notification settings - Fork 193
Rails Generator for RubyLLM Models #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
487d4e4
3577f31
24467aa
2d50909
6e68d36
dacb148
f469f60
844614b
131e51c
f40d1b4
5eeedf9
9d8c2d6
61d66ab
a239b34
8316ce5
cf4a560
492188f
52d761a
cc3d23f
9eba7bc
7cded01
21c4ee0
fda4df1
6270f22
f5454aa
5be36c1
1f8d3b0
a350738
1ed3c2e
f16858a
26bcf50
c352d5f
b064713
5a9b3b8
224b24e
1fe4320
882f3fc
4789f80
d2196bd
bf2244a
145d2d2
5982876
50befbe
9d92db3
4cc4054
3ecfeaf
d66c305
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# RubyLLM Development Guidelines | ||
|
||
## Commands | ||
- Run all tests: `bundle exec rspec` | ||
- Run single test: `bundle exec rspec spec/path/to/file_spec.rb` | ||
- Run specific test: `bundle exec rspec spec/path/to/file_spec.rb:LINE_NUMBER` | ||
- Code style check: `bundle exec rubocop` | ||
- Auto-fix style issues: `bundle exec rubocop -A` | ||
- Record VCR cassettes: `bundle exec rake vcr:record[provider]` (where provider is openai, anthropic, gemini, etc.) | ||
|
||
## Style Guidelines | ||
- Follow Standard Ruby style (https://github.com/testdouble/standard) | ||
- Use frozen_string_literal comment at top of files | ||
- Add YARD documentation comments for public methods | ||
- Use proper error handling with specific error classes | ||
- Follow consistent model naming conventions across providers | ||
- Keep normalized model IDs (separate model from provider) | ||
- Use consistent parameter naming across providers | ||
|
||
## Testing Practices | ||
- Tests automatically create VCR cassettes based on their descriptions | ||
- Use specific, descriptive test descriptions | ||
- Check VCR cassettes for sensitive information | ||
- Write tests for all new features and bug fixes |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
class Chat < ApplicationRecord | ||
acts_as_chat | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# frozen_string_literal: true | ||
|
||
class CreateChats < ActiveRecord::Migration<%= migration_version %> | ||
def change | ||
create_table :chats do |t| | ||
t.string :model_id | ||
t.timestamps | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# frozen_string_literal: true | ||
|
||
# This migration must be run AFTER create_chats and create_tool_calls migrations | ||
# to ensure proper foreign key references | ||
class CreateMessages < ActiveRecord::Migration<%= migration_version %> | ||
def change | ||
create_table :messages do |t| | ||
t.references :chat, null: false, foreign_key: true | ||
t.string :role | ||
t.text :content | ||
t.string :model_id | ||
t.integer :input_tokens | ||
t.integer :output_tokens | ||
t.references :tool_call, foreign_key: true | ||
t.timestamps | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# frozen_string_literal: true | ||
|
||
# Migration for creating tool_calls table with database-specific JSON handling | ||
class CreateToolCalls < ActiveRecord::Migration<%= migration_version %> | ||
def change | ||
create_table :tool_calls do |t| | ||
# No reference to message to avoid circular references | ||
# Messages will reference tool_calls, not the other way around | ||
kieranklaassen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
t.string :tool_call_id, null: false | ||
t.string :name, null: false | ||
|
||
# Use the appropriate JSON column type for the database | ||
if postgresql? | ||
t.jsonb :arguments, default: {} | ||
else | ||
t.json :arguments, default: {} | ||
end | ||
|
||
t.timestamps | ||
end | ||
|
||
add_index :tool_calls, :tool_call_id | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# frozen_string_literal: true | ||
|
||
# RubyLLM configuration | ||
RubyLLM.configure do |config| | ||
# Set your API keys here or use environment variables | ||
# config.openai_api_key = ENV["OPENAI_API_KEY"] | ||
# config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"] | ||
# config.gemini_api_key = ENV["GEMINI_API_KEY"] | ||
# config.deepseek_api_key = ENV["DEEPSEEK_API_KEY"] | ||
|
||
# Uncomment to set a default model | ||
# config.default_model = "gpt-4o-mini" | ||
|
||
# Uncomment to set default options | ||
# config.default_options = { temperature: 0.7 } | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
class Message < ApplicationRecord | ||
acts_as_message | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
class ToolCall < ApplicationRecord | ||
acts_as_tool_call | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# frozen_string_literal: true | ||
|
||
require "rails/generators" | ||
require "rails/generators/active_record" | ||
|
||
module RubyLLM | ||
# Generator for RubyLLM Rails models and migrations | ||
class InstallGenerator < Rails::Generators::Base | ||
include Rails::Generators::Migration | ||
|
||
source_root File.expand_path("install/templates", __dir__) | ||
|
||
desc "Creates model files for Chat, Message, and ToolCall, and creates migrations for RubyLLM Rails integration" | ||
|
||
def self.next_migration_number(dirname) | ||
ActiveRecord::Generators::Base.next_migration_number(dirname) | ||
end | ||
|
||
def migration_version | ||
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" | ||
end | ||
|
||
def postgresql? | ||
ActiveRecord::Base.connection.adapter_name.downcase.include?("postgresql") | ||
rescue | ||
false | ||
end | ||
|
||
def create_migration_files | ||
# Create migrations in the correct order with sequential timestamps | ||
# to ensure proper foreign key references: | ||
# 1. First create chats (no dependencies) | ||
# 2. Then create tool_calls (will be referenced by messages) | ||
# 3. Finally create messages (depends on both chats and tool_calls) | ||
|
||
# Use a fixed timestamp for testing and to ensure they're sequential | ||
@migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S") | ||
migration_template "create_chats_migration.rb", "db/migrate/create_chats.rb" | ||
|
||
# Increment timestamp for the next migration | ||
@migration_number = (@migration_number.to_i + 1).to_s | ||
migration_template "create_tool_calls_migration.rb", "db/migrate/create_tool_calls.rb" | ||
|
||
# Increment timestamp again for the final migration | ||
@migration_number = (@migration_number.to_i + 2).to_s | ||
migration_template "create_messages_migration.rb", "db/migrate/create_messages.rb" | ||
end | ||
|
||
def create_model_files | ||
template "chat_model.rb", "app/models/chat.rb" | ||
template "message_model.rb", "app/models/message.rb" | ||
template "tool_call_model.rb", "app/models/tool_call.rb" | ||
end | ||
|
||
def create_initializer | ||
template "initializer.rb", "config/initializers/ruby_llm.rb" | ||
end | ||
|
||
def show_readme | ||
readme "README.md" | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,5 +8,15 @@ class Railtie < Rails::Railtie | |
include RubyLLM::ActiveRecord::ActsAs | ||
end | ||
end | ||
|
||
# Include rake tasks if applicable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should include the ruby_llm rake tasks in a Rails application:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added an issue for the rake task not show up in a Rails application: #136 This is making it harder for me to use the latest Gemini models. |
||
rake_tasks do | ||
# Task definitions go here if needed | ||
end | ||
|
||
# Register generators | ||
generators do | ||
require 'generators/ruby_llm/install_generator' | ||
end | ||
end | ||
end |
Uh oh!
There was an error while loading. Please reload this page.