| name | rubyllm-tools |
| description | Function calling for RubyLLM. Use this skill when creating tools that let AI call your Ruby code, declaring parameters with the params DSL, using tools in chat, monitoring tool calls with callbacks, handling tool security, and implementing advanced patterns like halt, provider-specific parameters, and concurrent tool execution (v1.16+).
|
| allowed-tools | ["Bash(bundle *)","Bash(bin/rails *)"] |
RubyLLM Tools
Let AI call your Ruby methods. Connect to databases, APIs, or any external system.
Creating a Tool
class Weather < RubyLLM::Tool
description "Get current weather for a location"
params do
string :latitude, description: "Latitude coordinate"
string :longitude, description: "Longitude coordinate"
end
def execute(latitude:, longitude:)
url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}¤t=temperature_2m,wind_speed_10m"
response = Faraday.get(url)
JSON.parse(response.body).to_json
end
end
Parameter Declaration
Method Signature Inference (v1.15+)
Required and optional keyword arguments are automatically inferred as tool parameters — no params block needed:
class Weather < RubyLLM::Tool
description "Get weather for a location"
def execute(latitude:, longitude:, units: "celsius")
end
end
params DSL (v1.9+)
class Scheduler < RubyLLM::Tool
description "Book a meeting"
params do
object :window, description: "Time window" do
string :start, description: "ISO8601 start"
string :finish, description: "ISO8601 end"
end
array :participants, of: :string, description: "Email addresses"
end
def execute(window:, participants:)
end
end
param Helper (Simple Tools)
class Distance < RubyLLM::Tool
description "Calculate distance between cities"
param :origin, desc: "Origin city name"
param :destination, desc: "Destination city name"
def execute(origin:, destination:)
end
end
Using Tools
chat = RubyLLM.chat.with_tool(Weather)
response = chat.ask "Weather in Berlin? (52.52, 13.40)"
chat.with_tools(Weather, Calculator, SearchDB)
chat.with_tools(Weather, choice: :auto)
chat.with_tools(Weather, choice: :required)
chat.with_tools(Weather, choice: :none)
chat.with_tools(Weather, calls: :many)
chat.with_tools(Weather, calls: :one)
Concurrent Tool Execution (v1.16+)
When the LLM requests multiple tools in one turn, run them in parallel:
chat.with_tools(Weather, StockPrice, Currency, concurrency: :threads)
chat.with_tools(Weather, StockPrice, concurrency: :fibers)
chat.with_tools(Weather, StockPrice, concurrency: false)
RubyLLM.configure { |c| c.tool_concurrency = true }
- Results stream back as tools complete but are gathered before returning to the model
- In Rails, each call runs inside the Rails executor — connection pool and
CurrentAttributes are safe
Tool Monitoring
chat = RubyLLM.chat
.with_tool(Weather)
.before_tool_call { |tc| puts "Calling: #{tc.name} args=#{tc.arguments}" }
.after_tool_result { |result| puts "Result: #{result}" }
chat.ask "Weather?"
Deprecated (v1.15, removed in v2.0): on_tool_call and on_tool_result.
Replace with before_tool_call and after_tool_result.
Rich Content from Tools
class AnalyzeTool < RubyLLM::Tool
description "Analyze and return with visualization"
param :data, desc: "Data to analyze"
def execute(data:)
chart_path = generate_chart(data)
RubyLLM::Content.new("Analysis complete", [chart_path])
end
end
Halt Tool Continuation
Skip AI commentary after tool execution:
class SaveFileTool < RubyLLM::Tool
description "Save content to file"
param :path, desc: "File path"
param :content, desc: "Content"
def execute(path:, content:)
File.write(path, content)
halt "Saved to #{path}"
end
end
Provider-Specific Parameters (v1.9+)
class TodoTool < RubyLLM::Tool
description "Add task to TODO list"
params do
string :title
end
with_params cache_control: { type: "ephemeral" }
def execute(title:)
Todo.create!(title:)
end
end
Security
⚠️ Treat tool arguments as untrusted user input
class SafeTool < RubyLLM::Tool
param :input, desc: "User input"
def execute(input:)
raise ArgumentError if input.length > 1000
raise ArgumentError if input.match?(/[<>;]/)
end
end
Error Handling
class WeatherTool < RubyLLM::Tool
def execute(city:)
return { error: "City too short" } if city.length < 3
Faraday.get("https://api.weather.com/#{city}")
rescue Faraday::ConnectionFailed
{ error: "Weather service unavailable" }
end
end
Error Strategy
- Recoverable (bad params, API down): Return
{ error: "message" }
- Unrecoverable (missing config, DB down): Raise exception
See Also