OmniAgent
OmniAgent is a Rails engine gem for building application-native AI agents with tools. It provides a small DSL to define agents, model/provider settings, prompt templates, tool schemas, and generation lifecycle callbacks.
What It Includes
OmniAgent::Agentruntime with provider abstraction and tool-calling loopOmniAgent::ToolDSL with JSON-schema-style input definitions- Prompt composition from ERB files in
app/agents/<agent_name>/ - Agent callbacks (
before_generation,after_generation) - Agent and tool tags to support filtering strategies
- OpenAI provider integration out of the box
- Rake tasks and Rails generators for scaffolding
Installation
Add these lines to your application's Gemfile:
gem "omni_agent"
Add the provider you're using to the Gemfile as well:
gem "openai"
Then run:
bundle install
Quick Start
- Install base directories:
bundle exec rails generate omni_agent:install
- Generate an agent scaffold:
bundle exec rails generate omni_agent:agent ResearchAgent --model gpt-4.1-mini --with-tools WeatherLookup Summarize
- Add your API key in
.env:
OPENAI_ACCESS_TOKEN=your_api_key_here
- Implement your agent prompt and optional tools under:
app/agents/
research_agent.rb
research_agent/
prompt.md.erb
tools/
Agent Example
class ResearchAgent < OmniAgent::Agent
use_model "gpt-4o-mini"
before_generation :set_current_user
def set_current_user
@user = "Test User"
end
end
Tool Example
module ResearchAgent::Tools
class GetWeather < OmniAgent::Tool
description "Get current weather for a city"
:weather
category: :utility
input do
string :city, description: "City name"
end
def execute(city:)
"Sunny in #{city}"
end
end
end
Evals
OmniAgent::Eval lets you test agent quality: deterministic assertions (tool calls, output matching) and pluggable LLM-as-judge scoring.
class ResearchAgentEval < OmniAgent::Eval
agent ResearchAgent
eval_case "answers weather question" do
input "What's the weather in Paris?"
expect_tool_call :get_weather, with: { city: "Paris" }
expect_output to_include: "Paris"
end
eval_case "is polite" do
input "Tell me a joke"
judge "Is the response friendly and on-topic?", threshold: 0.7
end
eval_case "summarizes via the :summarize run alias" do
run_alias :summarize
input "Some long article text...", with: { tone: "casual" }
expect_output to_include: "summary"
end
end
input text, with: {}:with:is forwarded as the agent'scontext:, bound to matching instance variables during the run (e.g.with: { tone: "casual" }sets@tone).run_alias: Targets a method defined viarun_aliases(or any zero-arg run entrypoint) instead of plain#run— useful when that alias renders a different prompt file (<method_name>.md.erb).
Judge provider resolution order: explicit provider: kwarg on judge → OmniAgent.configuration.eval_judge_provider/eval_judge_model → the agent's own provider (zero-config default).
Caching
Eval runs are cached by default, keyed on (agent class, run_alias, input, context). Re-running the same case (e.g. iterating on assertions) replays the cached output instead of calling the provider again, saving tokens. Configure or disable it:
OmniAgent.configure do |config|
config.eval_cache_enabled = true # default
config.eval_cache_path = "tmp/omni_agent_eval_cache.json" # default
end
Bypass the cache for a run (clears it before running, no manual file deletion needed):
bundle exec omni_agent eval evals/research_agent_eval.rb --fresh
Sample output:
[PASS] mentions lorem
[FAIL] mentions something the mock never says
- output "Lorem ipsum dolor sit amet, consectetur adipiscing elit." does not include "this never appears"
1/2 cases passed
Each case prints [PASS]/[FAIL] plus its name; failing cases list every unmet assertion's message. Exits non-zero if any case failed.
For many input/expected-output pairs, load a YAML/JSON dataset instead of writing a case per row:
golden_set "evals/golden/research_agent.yml" do |row|
expect_output to_include: row[:expected_output]
end
Scaffold an eval and run it:
bundle exec rails generate omni_agent:eval ResearchAgent
# run from your Rails app root, like running rspec
bundle exec omni_agent eval
bundle exec omni_agent eval evals/research_agent_eval.rb
bundle exec omni_agent eval evals/research_agent_eval.rb --fresh
There's also an equivalent rake omni_agent:eval task (rake "omni_agent:eval[pattern,fresh]") if you'd rather not use the binstub.
Calls real LLM providers (cost, non-determinism) — deliberately not part of bundle exec rspec or CI.
Configuration
Global defaults can be configured through OmniAgent.configure:
OmniAgent.configure do |config|
config.default_provider = :openai
config.default_model = "gpt-4o-mini"
end
Running Tests
bundle exec rspec
Contributing
Issues and pull requests are welcome.
License
The gem is available as open source under the terms of the MIT License.