Rails Integration for Soka AI Agent Framework
Features • Installation • Quick Start • Usage • Generators • Testing • Contributing
Soka Rails is a Rails integration package for the Soka AI Agent Framework, providing seamless integration with the Rails ecosystem. It follows Rails conventions and best practices, making it easy for developers to use AI Agents in their Rails applications.
- 🚂 Native Rails Integration: Following Rails conventions and best practices
- 📁 Auto-loading Support: Automatically loads the
app/soka
directory - 🛠️ Generator Support: Quickly generate Agent and Tool templates
- ⚙️ Rails Configuration Integration: Uses Rails' configuration system
- 🧪 Rails Testing Integration: Seamless integration with RSpec
- 🔄 Rails Lifecycle Hooks: Integrates with Rails logging and error tracking
- 💾 Session Memory Support: Store conversation history in Rails sessions
- 🔐 Authentication Integration: Works with Rails authentication systems
- 🗣️ Custom Instructions: Customize agent personality and behavior
- 🎯 Dynamic Instructions: Generate instructions dynamically via methods
- 🌐 Multilingual Thinking: Support for reasoning in different languages
Add the following to your Gemfile:
gem 'soka-rails'
Then execute:
bundle install
Run the installation generator:
rails generate soka:install
This will generate:
config/initializers/soka.rb
- Main configuration fileapp/soka/agents/application_agent.rb
- Base Agent classapp/soka/tools/application_tool.rb
- Base Tool class
# config/initializers/soka.rb
Soka::Rails.configure do |config|
config.ai do |ai|
ai.provider = ENV.fetch('SOKA_PROVIDER', :gemini)
ai.model = ENV.fetch('SOKA_MODEL', 'gemini-2.5-flash-lite')
ai.api_key = ENV['SOKA_API_KEY']
end
end
rails generate soka:agent customer_support
# app/soka/agents/customer_support_agent.rb
class CustomerSupportAgent < ApplicationAgent
tool OrderLookupTool
tool UserInfoTool
end
class ConversationsController < ApplicationController
def create
agent = CustomerSupportAgent.new
result = agent.run(params[:message])
render json: {
answer: result.final_answer,
status: result.status
}
end
end
rails-app/
├── app/
│ └── soka/
│ ├── agents/ # Agent definitions
│ │ ├── application_agent.rb
│ │ └── customer_support_agent.rb
│ └── tools/ # Tool definitions
│ ├── application_tool.rb
│ └── order_lookup_tool.rb
└── config/
└── initializers/
└── soka.rb # Global configuration
class WeatherAgent < ApplicationAgent
# Configure AI settings
provider :gemini
model 'gemini-2.5-flash-lite'
max_iterations 10
# Register tools
tool WeatherApiTool
tool LocationTool
# Custom instructions
# instructions "You are a helpful weather assistant"
# Dynamic instructions via method
# instructions :generate_instructions
# Multilingual thinking
# think_in 'zh-TW' # Think in Traditional Chinese
# Rails integration hooks
before_action :log_request
on_error :notify_error_service
private
def log_request(input)
Rails.logger.info "[WeatherAgent] Processing: #{input}"
end
def notify_error_service(error, context)
Rails.error.report(error, context: context)
:continue
end
# Example of dynamic instructions method
# def generate_instructions
# <<~PROMPT
# You are a weather assistant for #{Rails.env} environment.
# Current time: #{Time.zone.now}
# User location: #{request&.location&.city || 'Unknown'}
# PROMPT
# end
end
class OrderLookupTool < ApplicationTool
desc "Look up order information"
params do
requires :order_id, String, desc: "Order ID"
optional :include_items, :boolean, desc: "Include order items", default: false
end
def call(order_id:, include_items: false)
order = Order.find_by(id: order_id)
return { error: "Order not found" } unless order
data = {
id: order.id,
status: order.status,
total: order.total,
created_at: order.created_at
}
data[:items] = order.items if include_items
data
end
end
class ConversationsController < ApplicationController
def create
# Load memory from session
memory = session[:conversation_memory] || []
agent = CustomerSupportAgent.new(memory: memory)
result = agent.run(params[:message])
# Update session memory
session[:conversation_memory] = agent.memory.to_a
render json: { answer: result.final_answer }
end
end
class CustomerSupportAgent < ApplicationAgent
# Static instructions
instructions <<~PROMPT
You are a friendly customer support agent.
Always be polite and helpful.
Use emojis when appropriate.
PROMPT
# OR Dynamic instructions via method
instructions :generate_context_aware_instructions
private
def generate_context_aware_instructions
business_hours = (9..17).include?(Time.zone.now.hour)
<<~PROMPT
You are a customer support agent for #{Rails.application.class.module_parent_name}.
Environment: #{Rails.env}
Current time: #{Time.zone.now.strftime('%Y-%m-%d %H:%M:%S %Z')}
Business hours: #{business_hours ? 'Yes' : 'No (after hours)'}
#{business_hours ? 'Provide immediate assistance.' : 'Inform about callback options.'}
PROMPT
end
end
class GlobalSupportAgent < ApplicationAgent
# Set default thinking language
think_in 'zh-TW' # Think in Traditional Chinese
# Or set dynamically at runtime
def initialize(options = {})
super
# Detect user's preferred language from session or request
self.think_in = detect_user_language
end
private
def detect_user_language
# Logic to detect language from session, user preferences, or request headers
session[:locale] || I18n.locale || 'en'
end
end
class ConversationsController < ApplicationController
include ActionController::Live
def stream
response.headers['Content-Type'] = 'text/event-stream'
agent = CustomerSupportAgent.new
agent.run(params[:message]) do |event|
response.stream.write("event: #{event.type}\n")
response.stream.write("data: #{event.content.to_json}\n\n")
end
ensure
response.stream.close
end
end
rails generate soka:install
# Basic usage
rails generate soka:agent weather
# With tools - automatically registers tools in the agent
rails generate soka:agent weather forecast temperature humidity
Creates app/soka/agents/weather_agent.rb
with a template structure.
When tools are specified, the generated agent will include them:
class WeatherAgent < ApplicationAgent
# Tool registration
tool ForecastTool
tool TemperatureTool
tool HumidityTool
# Custom instructions
# instructions "You are a weather expert. Always provide temperature in both Celsius and Fahrenheit."
# Dynamic instructions via method
# instructions :generate_instructions
# Multilingual thinking
# think_in 'en' # Supported: 'en', 'zh-TW', 'ja-JP', etc.
# Configuration
# max_iterations 10
end
# Basic usage
rails generate soka:tool weather_api
# With parameters - automatically generates parameter definitions
rails generate soka:tool weather_api location:string units:string
Creates app/soka/tools/weather_api_tool.rb
with parameter definitions.
When parameters are specified, the generated tool will include them:
class WeatherApiTool < ApplicationTool
desc 'Description of your tool'
params do
requires :location, String, desc: 'Location'
requires :units, String, desc: 'Units'
end
def call(**params)
# Implement your tool logic here
end
end
# spec/rails_helper.rb
require 'soka/rails/rspec'
RSpec.configure do |config|
config.include Soka::Rails::TestHelpers, type: :agent
config.include Soka::Rails::TestHelpers, type: :tool
end
RSpec.describe WeatherAgent, type: :agent do
let(:agent) { described_class.new }
before do
mock_ai_response(
final_answer: "Today in Tokyo it's sunny with 28°C"
)
end
it "responds to weather queries" do
result = agent.run("What's the weather in Tokyo?")
expect(result).to be_successful
expect(result.final_answer).to include("28°C")
end
end
RSpec.describe OrderLookupTool, type: :tool do
let(:tool) { described_class.new }
let(:order) { create(:order, id: "123", status: "delivered") }
it "finds existing orders" do
result = tool.call(order_id: order.id)
expect(result[:status]).to eq("delivered")
expect(result[:id]).to eq("123")
end
it "handles missing orders" do
result = tool.call(order_id: "nonexistent")
expect(result[:error]).to include("not found")
end
end
A built-in tool for accessing Rails application information:
class RailsInfoTool < ApplicationTool
desc "Get Rails application information"
params do
requires :info_type, String, desc: "Type of information",
validates: { inclusion: { in: %w[routes version environment config] } }
end
def call(info_type:)
case info_type
when 'routes'
# Returns application routes
when 'version'
# Returns Rails and Ruby versions
when 'environment'
# Returns environment information
when 'config'
# Returns safe configuration values
end
end
end
Soka::Rails.configure do |config|
config.ai do |ai|
ai.provider = ENV.fetch('SOKA_PROVIDER', :gemini)
ai.model = ENV.fetch('SOKA_MODEL', 'gemini-2.5-flash-lite')
ai.api_key = ENV['SOKA_API_KEY']
end
config.performance do |perf|
perf.max_iterations = Rails.env.production? ? 10 : 5
end
end
Based on extensive testing with the Soka framework, here are the recommended models for optimal performance:
Provider | ✅ Recommended Models | Notes | |
---|---|---|---|
Gemini | gemini-2.5-flash-lite ⭐gemini-2.5-pro |
gemini-2.5-flash |
gemini-2.5-flash-lite: Fast, cost-effective, with good performance Avoid gemini-2.5-flash: Often skips thinking process when using tools, directly jumps to tool usage |
OpenAI | gpt-5 gpt-5-mini ⭐ |
gpt-5-nano |
gpt-5-mini: Good balance of price, speed, and effectiveness Avoid gpt-5-nano: Can enter infinite tool-calling loops, fails to complete tasks |
Claude | To be tested | - | Testing in progress |
⭐ = Best choice for most use cases
- Ruby: >= 3.4
- Rails: >= 7.0
- Soka: >= 0.0.4
We welcome all forms of contributions!
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Please ensure:
- Add appropriate tests
- Update relevant documentation
- Follow Rails coding conventions
- Pass Rubocop checks
This project is licensed under the MIT License. See the LICENSE file for details.
Made with ❤️ for the Rails Community
Built on top of Soka AI Agent Framework
Created by Claude Code