omni_agent 0.1.10 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +100 -2
- data/Rakefile +4 -0
- data/app/jobs/omni_agent/embed_job.rb +10 -0
- data/app/jobs/omni_agent/ingest_job.rb +12 -0
- data/docs/agent/callbacks.md +60 -0
- data/docs/agent/delegation.md +56 -0
- data/docs/agent/provider.md +93 -0
- data/docs/agent/run-entrypoints.md +81 -0
- data/docs/agent/streaming.md +62 -0
- data/docs/agent/structured-output.md +80 -0
- data/docs/configuration.md +68 -0
- data/docs/evals/caching.md +21 -0
- data/docs/evals/generating-and-running.md +87 -0
- data/docs/evals/golden-sets.md +32 -0
- data/docs/evals/judge-provider.md +20 -0
- data/docs/generators.md +143 -0
- data/docs/index.md +98 -0
- data/docs/intro.md +93 -0
- data/docs/mcp/authentication.md +226 -0
- data/docs/mcp/defining-servers.md +196 -0
- data/docs/mcp/transports.md +166 -0
- data/docs/rag.md +372 -0
- data/docs/stock-agents/ocr.md +52 -0
- data/docs/stock-agents/overview.md +91 -0
- data/docs/supported-providers.md +47 -0
- data/docs/tools.md +171 -0
- data/exe/omni_agent +48 -10
- data/lib/generators/omni_agent/chunks/chunks_generator.rb +130 -0
- data/lib/generators/omni_agent/embeddings/embeddings_generator.rb +72 -0
- data/lib/generators/omni_agent/install/install_generator.rb +78 -1
- data/lib/generators/omni_agent/mcp_server/mcp_server_generator.rb +4 -0
- data/lib/generators/omni_agent/stock_agent/stock_agent_generator.rb +73 -0
- data/lib/generators/omni_agent/vector_store.rb +113 -0
- data/lib/omni_agent/agent.rb +168 -39
- data/lib/omni_agent/chunkable.rb +181 -0
- data/lib/omni_agent/chunkers/hierarchical.rb +20 -0
- data/lib/omni_agent/chunkers/markdown.rb +41 -0
- data/lib/omni_agent/chunkers/recursive.rb +53 -0
- data/lib/omni_agent/chunkers.rb +31 -0
- data/lib/omni_agent/configuration.rb +14 -1
- data/lib/omni_agent/docs.rb +32 -0
- data/lib/omni_agent/embeddable.rb +131 -0
- data/lib/omni_agent/engine.rb +11 -0
- data/lib/omni_agent/errors.rb +15 -0
- data/lib/omni_agent/loaders/html.rb +21 -0
- data/lib/omni_agent/loaders/markdown.rb +18 -0
- data/lib/omni_agent/loaders/pdf.rb +25 -0
- data/lib/omni_agent/loaders/text.rb +15 -0
- data/lib/omni_agent/loaders.rb +68 -0
- data/lib/omni_agent/mcp/authenticator.rb +5 -2
- data/lib/omni_agent/mcp/oauth/access_token.rb +60 -0
- data/lib/omni_agent/mcp/oauth/http_client.rb +52 -0
- data/lib/omni_agent/mcp/oauth/introspection_verifier.rb +43 -0
- data/lib/omni_agent/mcp/oauth/jwt_verifier.rb +122 -0
- data/lib/omni_agent/mcp/oauth/resource_server.rb +166 -0
- data/lib/omni_agent/mcp/oauth.rb +18 -0
- data/lib/omni_agent/mcp/rack_app.rb +31 -7
- data/lib/omni_agent/mcp/server.rb +22 -5
- data/lib/omni_agent/providers/base.rb +14 -0
- data/lib/omni_agent/providers/mock.rb +89 -4
- data/lib/omni_agent/providers/ollama.rb +4 -0
- data/lib/omni_agent/providers/openai.rb +33 -2
- data/lib/omni_agent/providers/response.rb +6 -1
- data/lib/omni_agent/providers.rb +7 -0
- data/lib/omni_agent/schema.rb +200 -0
- data/lib/omni_agent/semantic_search.rb +45 -0
- data/lib/omni_agent/stock_agent.rb +59 -0
- data/lib/omni_agent/stock_agents/ocr/prompt.md.erb +6 -0
- data/lib/omni_agent/stock_agents/ocr.rb +70 -0
- data/lib/omni_agent/stock_agents.rb +26 -0
- data/lib/omni_agent/tool.rb +7 -107
- data/lib/omni_agent/version.rb +1 -1
- data/lib/omni_agent.rb +15 -1
- data/lib/tasks/omni_agent_chunks_tasks.rake +16 -0
- data/lib/tasks/omni_agent_embeddings_tasks.rake +15 -0
- metadata +55 -8
- data/app/assets/stylesheets/omni_agent/application.css +0 -15
- data/app/controllers/omni_agent/application_controller.rb +0 -4
- data/app/helpers/omni_agent/application_helper.rb +0 -4
- data/app/jobs/omni_agent/application_job.rb +0 -4
- data/app/mailers/omni_agent/application_mailer.rb +0 -6
- data/app/models/omni_agent/application_record.rb +0 -5
- data/app/views/layouts/omni_agent/application.html.erb +0 -17
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/agent/structured-output.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/agent/structured-output -->
|
|
3
|
+
|
|
4
|
+
# Structured Output
|
|
5
|
+
|
|
6
|
+
Declare an `output` block to make an agent return a validated object instead of free text. It uses the same DSL as a tool's [`input`](../tools.md#input-schema-dsl):
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
class InvoiceAgent < OmniAgent::Agent
|
|
10
|
+
use_model "gpt-4o-mini"
|
|
11
|
+
|
|
12
|
+
output do
|
|
13
|
+
string :invoice_number, description: "Invoice identifier as printed"
|
|
14
|
+
number :total, min: 0
|
|
15
|
+
enum :currency, values: %w[USD EUR]
|
|
16
|
+
array :line_items do
|
|
17
|
+
string :description
|
|
18
|
+
number :amount
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
response = InvoiceAgent.new.run(invoice_text)
|
|
24
|
+
response.structured_output
|
|
25
|
+
# => { invoice_number: "A-1042", total: 120.5, currency: "USD", line_items: [ { description: "Paper", amount: 120.5 } ] }
|
|
26
|
+
response.answer # the raw JSON string returned by the model
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
1. The schema is sent to the provider with every request. OpenAI and Ollama receive it as a `json_schema` `response_format`. Providers that don't support structured output natively get the schema in the system prompt instead (see [Custom Providers](#custom-providers)).
|
|
32
|
+
2. When the model gives its final answer, the JSON is parsed (a surrounding ` ```json ` fence is tolerated) and validated with the same rules as tool input: required fields, `enum` values, `min`/`max`, `min_length`/`max_length`, `pattern`, `min_items`/`max_items` and custom `validate:` procs. On top of that, every top-level value must match its declared type (`string`, `integer`, `number`, `boolean`, `array` or `hash`), so `total: "120.5"` is rejected for a `number`. Keys not declared in the schema are dropped, and `null` for an optional field is treated as absent.
|
|
33
|
+
3. The result is exposed as `response.structured_output`, a hash with symbol keys. It is set before `after_generation` callbacks run, so callbacks can read it from `payload[:response]`.
|
|
34
|
+
|
|
35
|
+
Type and constraint checks apply to top-level fields; nested objects are described to the model but not validated field by field.
|
|
36
|
+
|
|
37
|
+
## Handling Errors
|
|
38
|
+
|
|
39
|
+
If the model returns invalid JSON, the object fails validation, or a polymorphic `resolve: true` field can't be resolved, `run` raises `OmniAgent::StructuredOutputError`. The error keeps the raw model output so you can log it, retry or repair it without paying for the generation again:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
begin
|
|
43
|
+
InvoiceAgent.new.run(invoice_text)
|
|
44
|
+
rescue OmniAgent::StructuredOutputError => e
|
|
45
|
+
Rails.logger.warn("Invalid invoice output: #{e.message}\n#{e.content}")
|
|
46
|
+
e.response # the full OmniAgent::Providers::Response
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Strict Mode
|
|
51
|
+
|
|
52
|
+
OpenAI's strict structured outputs are enabled automatically when the schema allows it: every field is required, every `hash` has a block, and no `min_length`/`max_length` is used. Otherwise the schema is sent with `strict: false`, so the model only treats it as guidance; in that case the schema is also added to the system prompt, and OmniAgent's validation enforces it.
|
|
53
|
+
|
|
54
|
+
## Custom Providers
|
|
55
|
+
|
|
56
|
+
A provider receives the schema as the `output_schema:` keyword of `#chat` (an `OmniAgent::Schema`; call `#json_schema` on it) only when it declares support:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
class MyProvider < OmniAgent::Providers::Base
|
|
60
|
+
def supports_structured_output?
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def chat(messages:, tools: [], stream: nil, output_schema: nil, **options)
|
|
65
|
+
# send output_schema.json_schema in the provider's own format
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Providers that don't (the default in `OmniAgent::Providers::Base`) never receive `output_schema:`; the agent appends the JSON schema to the system prompt and asks for a JSON-only answer instead.
|
|
71
|
+
|
|
72
|
+
## Inheritance
|
|
73
|
+
|
|
74
|
+
`output` is inherited by subclasses, and a subclass can declare its own `output` block to replace it. This is how [stock agents](../stock-agents/overview.md) let each project decide which fields to extract.
|
|
75
|
+
|
|
76
|
+
## Mock Provider
|
|
77
|
+
|
|
78
|
+
With `provider :mock`, an agent that declares `output` gets placeholder JSON built from the schema (the first `enum` value, `min` for numbers, lorem ipsum for strings), so you can wire up code that reads `structured_output` before calling a real model.
|
|
79
|
+
|
|
80
|
+
The placeholders can't satisfy everything. If a field has a `pattern:` the lorem text doesn't match, a custom `validate:` proc that rejects the placeholder, or is a polymorphic field with `resolve: true`, the mock raises an `OmniAgent::Error` naming the field. In those tests, stub the provider's `#chat` response instead.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/configuration.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/configuration -->
|
|
3
|
+
|
|
4
|
+
# Configuration
|
|
5
|
+
|
|
6
|
+
Omni Agent ships with sensible defaults but lets you configure global behavior through an initializer.
|
|
7
|
+
|
|
8
|
+
## Global Defaults
|
|
9
|
+
|
|
10
|
+
`rails generate omni_agent:install` writes `config/initializers/omni_agent.rb` with every setting commented out at its default, so you only uncomment what you change. You can also create the file yourself:
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
OmniAgent.configure do |config|
|
|
14
|
+
config.default_provider = :openai
|
|
15
|
+
config.default_model = "gpt-4o-mini"
|
|
16
|
+
config.max_retries = 3
|
|
17
|
+
config.retry_base_delay = 0.5
|
|
18
|
+
config.max_tool_iterations = 10
|
|
19
|
+
config.max_delegation_depth = 5
|
|
20
|
+
config.mcp_allowed_origins = []
|
|
21
|
+
config.mcp_max_request_bytes = 1_048_576
|
|
22
|
+
config.embedding_provider = nil
|
|
23
|
+
config.embedding_model = nil
|
|
24
|
+
config.embedding_job_options = {}
|
|
25
|
+
config.document_loaders = {}
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
* **`default_provider`**: The provider used by agents that don't declare their own via `provider` or `use_model`. Defaults to `:openai`.
|
|
30
|
+
* **`default_model`**: The model used when an agent doesn't override it. Defaults to `"gpt-4o-mini"`.
|
|
31
|
+
* **`max_retries`**: Max retry attempts for retryable provider errors (rate limits, timeouts, 5xx). Defaults to `3`.
|
|
32
|
+
* **`retry_base_delay`**: Base delay in seconds for retry backoff. Delay doubles per attempt (exponential backoff). Defaults to `0.5`.
|
|
33
|
+
* **`max_tool_iterations`**: Max number of tool-call round trips the agent loop will perform before giving up on a final response. Defaults to `10`.
|
|
34
|
+
* **`max_delegation_depth`**: Max nesting depth for [agent delegation](agent/delegation.md) chains before raising `OmniAgent::MaxDelegationDepthError`. Defaults to `5`.
|
|
35
|
+
* **`mcp_allowed_origins`**: Browser origins (Strings or Regexps) allowed to call any [MCP server](mcp/authentication.md#origin-checks) over HTTP. Requests that send any other `Origin` get `403`. Defaults to `[]`.
|
|
36
|
+
* **`mcp_max_request_bytes`**: Largest MCP HTTP request body accepted. Larger requests get `413`. Defaults to `1_048_576` (1 MiB).
|
|
37
|
+
* **`embedding_provider`**: The provider [`OmniAgent.embed`](rag.md#embeddings) uses. Defaults to `nil`, which falls back to `default_provider`.
|
|
38
|
+
* **`embedding_model`**: The embedding model `OmniAgent.embed` uses. Defaults to `nil`, which uses the provider's default (`text-embedding-3-small` for OpenAI, `nomic-embed-text` for Ollama).
|
|
39
|
+
* **`embedding_job_options`**: ActiveJob `set` options (`queue`, `priority`, `wait`, `wait_until`) for the jobs [`has_embedding later:`](rag.md#background-embedding) and [`has_chunks`](rag.md#documents) enqueue. Models can override them with `later: { ... }`. Unknown keys raise an `ArgumentError`. Defaults to `{}`.
|
|
40
|
+
* **`document_loaders`**: Extra [loaders](rag.md#loaders) for `has_chunks`, by name (`{ docx: DocxLoader }`). Loaders with a `handles?` method are tried before the built-in ones when detecting a file's format. Defaults to `{}`.
|
|
41
|
+
|
|
42
|
+
## Retry Behavior
|
|
43
|
+
|
|
44
|
+
Providers can mark specific errors as retryable (e.g. the OpenAI provider retries `RateLimitError`, `InternalServerError`, and `APIConnectionError`). When a retryable error occurs, the provider retries up to `max_retries` times with exponential backoff (`retry_base_delay * 2^(attempt - 1)`). Non-retryable errors raise immediately.
|
|
45
|
+
|
|
46
|
+
## Tool Iteration Limit
|
|
47
|
+
|
|
48
|
+
The agent loop keeps calling tools until the model returns a final response. If the model keeps requesting tools past `max_tool_iterations`, the agent raises `OmniAgent::MaxToolIterationsError`. Raise `max_tool_iterations` in your initializer if your agent legitimately needs more tool round trips.
|
|
49
|
+
|
|
50
|
+
## Per-Agent Overrides
|
|
51
|
+
|
|
52
|
+
Any agent can override these defaults individually. See [Change an Agent's Provider or Model](agent/provider.md) for the `provider` and `use_model` DSL.
|
|
53
|
+
|
|
54
|
+
## Registered Providers
|
|
55
|
+
|
|
56
|
+
Providers are resolved from a registry at runtime:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
OmniAgent::Providers.registry
|
|
60
|
+
# => {
|
|
61
|
+
# openai: OmniAgent::Providers::OpenAI,
|
|
62
|
+
# ollama: OmniAgent::Providers::Ollama,
|
|
63
|
+
# mock: OmniAgent::Providers::Mock,
|
|
64
|
+
# mock_judge: OmniAgent::Providers::MockJudge
|
|
65
|
+
# }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
See [Supported Providers](supported-providers.md) for provider-specific setup. The `:mock` provider is useful for tests — it returns a canned response without making network calls.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/evals/caching.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/evals/caching -->
|
|
3
|
+
|
|
4
|
+
# Caching
|
|
5
|
+
|
|
6
|
+
Eval runs are cached by default, keyed on `(agent class, run_alias, input, context)`, and stored as JSON at `OmniAgent.configuration.eval_cache_path` (default `tmp/omni_agent_eval_cache.json`). Re-running the same case — e.g. while iterating on assertions — replays the cached output instead of calling the provider again, so you don't spend tokens testing the same case twice.
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
OmniAgent.configure do |config|
|
|
10
|
+
config.eval_cache_enabled = true # default
|
|
11
|
+
config.eval_cache_path = "tmp/omni_agent_eval_cache.json" # default
|
|
12
|
+
end
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
To force a fresh call without deleting the file yourself, clear the cache before running with `--fresh`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bundle exec omni_agent eval evals/research_agent_eval.rb --fresh
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The equivalent rake task takes a `fresh` arg instead: `rake "omni_agent:eval[evals/research_agent_eval.rb,fresh]"`.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/evals/generating-and-running.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/evals/generating-and-running -->
|
|
3
|
+
|
|
4
|
+
# Generating and Running Evals
|
|
5
|
+
|
|
6
|
+
`OmniAgent::Eval` lets you test agent *quality*, not just correctness — deterministic assertions (tool calls, output matching) plus pluggable LLM-as-judge scoring.
|
|
7
|
+
|
|
8
|
+
## Defining an Eval
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
class ResearchAgentEval < OmniAgent::Eval
|
|
12
|
+
agent ResearchAgent
|
|
13
|
+
|
|
14
|
+
eval_case "answers weather question" do
|
|
15
|
+
input "What's the weather in Paris?"
|
|
16
|
+
expect_tool_call :get_weather, with: { city: "Paris" }
|
|
17
|
+
expect_output to_include: "Paris"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
eval_case "is polite" do
|
|
21
|
+
input "Tell me a joke"
|
|
22
|
+
judge "Is the response friendly and on-topic?", threshold: 0.7
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
eval_case "summarizes via the :summarize run alias" do
|
|
26
|
+
run_alias :summarize
|
|
27
|
+
input "Some long article text...", with: { tone: "casual" }
|
|
28
|
+
expect_output to_include: "summary"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
* **`agent`**: The `OmniAgent::Agent` subclass under test.
|
|
34
|
+
* **`eval_case`**: Declares one scenario. `input text, with: {}` sets the message sent to the agent; `with:` is forwarded as `context:` and bound to matching instance variables during the run (e.g. `with: { tone: "casual" }` sets `@tone`).
|
|
35
|
+
* **`run_alias`**: Targets a method defined via `run_aliases` (or any zero-arg run entrypoint) instead of plain `#run`. Use this when that alias renders a different prompt file (`app/agents/<agent>/<method_name>.md.erb`) and you want to eval that specific prompt.
|
|
36
|
+
* **`expect_tool_call`**: Asserts a tool was called, optionally with specific arguments (`with:`).
|
|
37
|
+
* **`expect_output`**: Asserts on the agent's final text output via `to_include:`, `to_match:`, or a custom block.
|
|
38
|
+
* **`judge`**: Sends the output to an LLM judge with a grading criterion — see [Judge Provider](judge-provider.md) for how it picks a provider/model.
|
|
39
|
+
|
|
40
|
+
For testing many input/expected-output pairs without writing a `eval_case` per row, see [Golden Sets](golden-sets.md).
|
|
41
|
+
|
|
42
|
+
## Generating
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
rails generate omni_agent:eval ResearchAgent
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Creates `evals/research_agent_eval.rb` with a starter `eval_case`.
|
|
49
|
+
|
|
50
|
+
## Running
|
|
51
|
+
|
|
52
|
+
Run evals with the `omni_agent` CLI — works like running `rspec`:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# run every *_eval.rb under evals/
|
|
56
|
+
bundle exec omni_agent eval
|
|
57
|
+
|
|
58
|
+
# run just one eval file
|
|
59
|
+
bundle exec omni_agent eval evals/research_agent_eval.rb
|
|
60
|
+
|
|
61
|
+
# bypass the cache for this run (see Caching)
|
|
62
|
+
bundle exec omni_agent eval evals/research_agent_eval.rb --fresh
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Run it from your Rails app root — it requires `config/environment.rb` to boot, same as `bin/rails`.
|
|
66
|
+
|
|
67
|
+
It prints a pass/fail report per case (with failure messages) and exits non-zero if any case failed:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
[PASS] mentions lorem
|
|
71
|
+
[FAIL] mentions something the mock never says
|
|
72
|
+
- output "Lorem ipsum dolor sit amet, consectetur adipiscing elit." does not include "this never appears"
|
|
73
|
+
|
|
74
|
+
1/2 cases passed
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Running evals calls real LLM providers — it costs money and is non-deterministic, so it is **not** wired into `bundle exec rspec` or CI. Run it manually when you want a quality check.
|
|
78
|
+
|
|
79
|
+
### Rake task alternative
|
|
80
|
+
|
|
81
|
+
A `rake omni_agent:eval` task does the same thing, if you'd rather not use the binstub:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bundle exec rake omni_agent:eval
|
|
85
|
+
bundle exec rake "omni_agent:eval[evals/research_agent_eval.rb]"
|
|
86
|
+
bundle exec rake "omni_agent:eval[evals/research_agent_eval.rb,fresh]"
|
|
87
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/evals/golden-sets.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/evals/golden-sets -->
|
|
3
|
+
|
|
4
|
+
# Golden Sets
|
|
5
|
+
|
|
6
|
+
For many input/expected-output pairs, load a dataset file instead of writing a `eval_case` per row:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
class ResearchAgentEval < OmniAgent::Eval
|
|
10
|
+
agent ResearchAgent
|
|
11
|
+
|
|
12
|
+
golden_set "evals/golden/research_agent.yml" do |row|
|
|
13
|
+
expect_output to_include: row[:expected_output]
|
|
14
|
+
expect_tool_call row[:tool_call][:name], with: row[:tool_call][:args]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`evals/golden/research_agent.yml`:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
- name: "paris weather"
|
|
23
|
+
input: "What's the weather in Paris?"
|
|
24
|
+
expected_output: "Paris"
|
|
25
|
+
tool_call: { name: get_weather, args: { city: Paris } }
|
|
26
|
+
- name: "tokyo weather"
|
|
27
|
+
input: "What's the weather in Tokyo?"
|
|
28
|
+
expected_output: "Tokyo"
|
|
29
|
+
tool_call: { name: get_weather, args: { city: Tokyo } }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each row becomes its own `eval_case` (named from `name`, or `"row <index>"` if omitted). All keys are recursively symbolized, so nested fields like `row[:tool_call][:name]` work as shown above. Rows generated from `golden_set` run through the exact same path as inline `eval_case` blocks — there's no separate reporting for them, and they're subject to the same [caching](caching.md).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/evals/judge-provider.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/evals/judge-provider -->
|
|
3
|
+
|
|
4
|
+
# Judge Provider
|
|
5
|
+
|
|
6
|
+
`judge` resolves which provider grades the output, in this order:
|
|
7
|
+
|
|
8
|
+
1. An explicit `provider:` (and optional `model:`) kwarg passed to `judge`.
|
|
9
|
+
2. `OmniAgent.configuration.eval_judge_provider` / `eval_judge_model`, set once globally:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
OmniAgent.configure do |config|
|
|
13
|
+
config.eval_judge_provider = :openai
|
|
14
|
+
config.eval_judge_model = "gpt-4o-mini"
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
3. Falls back to the **same provider/model the agent under test already uses** — no judge setup required to get started.
|
|
19
|
+
|
|
20
|
+
The judge sends a fixed grading prompt asking for `{"score": 0-1, "reason": "..."}` and compares `score` against `threshold` from the `judge` call (see [Generating and Running Evals](generating-and-running.md)).
|
data/docs/generators.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/generators.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/generators -->
|
|
3
|
+
|
|
4
|
+
# Generators
|
|
5
|
+
|
|
6
|
+
Omni Agent ships seven Rails generators to scaffold your project.
|
|
7
|
+
|
|
8
|
+
## Install Generator
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
rails generate omni_agent:install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Creates the `app/agents` root directory and `config/initializers/omni_agent.rb`, which lists every [configuration](configuration.md) setting commented out at its default. An existing initializer is left untouched. Run this once per application, right after installing the gem.
|
|
15
|
+
|
|
16
|
+
It also adds an OmniAgent section to `AGENTS.md` (created if missing) and to `CLAUDE.md` (only if it already exists). The section tells coding agents such as Claude Code, Cursor or Codex to read the documentation bundled with the gem:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bundle exec omni_agent docs # index: conventions, typical flows and every page
|
|
20
|
+
bundle exec omni_agent docs mcp/authentication # one page
|
|
21
|
+
bundle exec omni_agent docs --path # directory holding the Markdown files
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Running the generator again doesn't duplicate the section. Pass `--skip-agents-md` to leave both files alone.
|
|
25
|
+
|
|
26
|
+
## Agent Generator
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
rails generate omni_agent:agent ResearchAgent --model gpt-4o-mini --with-tools WeatherLookup Summarize
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Generates:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
app/agents/
|
|
36
|
+
├── research_agent.rb
|
|
37
|
+
└── research_agent/
|
|
38
|
+
├── prompt.md.erb
|
|
39
|
+
└── tools/
|
|
40
|
+
├── weather_lookup.rb
|
|
41
|
+
└── summarize.rb
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Options
|
|
45
|
+
|
|
46
|
+
* **`--model`**: Sets the model used in the generated `use_model` call. If omitted, the agent uses `OmniAgent.configuration.default_model`.
|
|
47
|
+
* **`--with-tools`**: Space-separated list of tool names to scaffold under `tools/`. Each is generated as a subclass of `OmniAgent::Tool` with an example `input` schema and `execute` method. If you pass `--with-tools` with no names, an `ExampleTool` is generated.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
rails generate omni_agent:agent SupportAgent --with-tools
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Stock Agent Generator
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rails generate omni_agent:stock_agent InvoiceOcr --from=ocr --fields=invoice_number:string total:number
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Generates `app/agents/invoice_ocr.rb`, a subclass of the chosen [stock agent](stock-agents/overview.md) with an `output` block, and an optional `app/agents/invoice_ocr/prompt.md.erb` for extra instructions.
|
|
60
|
+
|
|
61
|
+
### Options
|
|
62
|
+
|
|
63
|
+
* **`--from`** (required): Stock agent to build on, by its `stock_name` (see `OmniAgent::StockAgents.all`).
|
|
64
|
+
* **`--fields`**: Space-separated `name:type` output fields (`string`, `integer`, `number` or `boolean`). If omitted, an `example_field` is generated. Use the full [structured output DSL](agent/structured-output.md) in the generated file for enums, nested objects or optional fields.
|
|
65
|
+
|
|
66
|
+
## Eval Generator
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
rails generate omni_agent:eval ResearchAgent
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Generates `evals/research_agent_eval.rb` with a starter `eval_case` for `ResearchAgent`. See [Generating and Running Evals](evals/generating-and-running.md), [Golden Sets](evals/golden-sets.md), [Judge Provider](evals/judge-provider.md), and [Caching](evals/caching.md).
|
|
73
|
+
|
|
74
|
+
## MCP Server Generator
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
rails generate omni_agent:mcp_server Support --with-tools LookupOrder RefundOrder --agents SupportAgent
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Generates:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
app/mcp_servers/
|
|
84
|
+
├── support_server.rb
|
|
85
|
+
└── support_server/
|
|
86
|
+
└── tools/
|
|
87
|
+
├── lookup_order.rb
|
|
88
|
+
└── refund_order.rb
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The server is protected by bearer tokens from `SUPPORT_MCP_TOKENS`. The generator also adds this route:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
mcp_server :support
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If `config/routes.rb` already mounts every server with a bare `mcp_servers`, the generator skips the route because the new server is mounted automatically.
|
|
98
|
+
|
|
99
|
+
It then prints the commands to connect Claude Code over HTTP and stdio.
|
|
100
|
+
|
|
101
|
+
### Options
|
|
102
|
+
|
|
103
|
+
* **`--with-tools`**: Space-separated list of server tools to scaffold under `app/mcp_servers/<name>_server/tools/`. They are added to the server automatically. If you pass `--with-tools` with no names, an `ExampleTool` is generated.
|
|
104
|
+
* **`--tools`**: Existing tool classes (for example, agent tools) to expose with `tools`.
|
|
105
|
+
* **`--agents`**: Agents whose tools are all exposed with `tools_from`.
|
|
106
|
+
* **`--path`**: Mount path, written as `mcp_server :support, path: "..."`. Defaults to `/mcp/<name>`.
|
|
107
|
+
|
|
108
|
+
The `Server` suffix is added if you leave it out (`Support` → `SupportServer`). See [Defining MCP Servers](mcp/defining-servers.md).
|
|
109
|
+
|
|
110
|
+
## Embeddings Generator
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
rails generate omni_agent:embeddings Document title content
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Adds an embedding column to the `Document` model and declares `has_embedding :title, :content` on it, so the model can be searched by agents with [`searches`](rag.md#searches). The migration matches your database: a pgvector `vector` column with a cosine index on Postgres, a `binary` column plus the sqlite-vec initializer on SQLite, a `vector` column on MariaDB. The vector size is detected by embedding one string with your configured model.
|
|
117
|
+
|
|
118
|
+
It then prints the commands to install the gems, migrate and backfill existing records.
|
|
119
|
+
|
|
120
|
+
### Options
|
|
121
|
+
|
|
122
|
+
* **`--backend`**: `pgvector`, `sqlite`, `mariadb` or `ruby`. Defaults to the one matching your database adapter. Plain MySQL is refused unless you pass `--backend=ruby`, which is [for small tables only](rag.md#ruby-fallback-small-tables-only).
|
|
123
|
+
* **`--dimensions`**: Vector size. Pass it when the embedding model can't be reached (offline, no API key).
|
|
124
|
+
* **`--column`**: Vector column name. Defaults to `embedding`.
|
|
125
|
+
* **`--later`**: Embed in a [background job](rag.md#background-embedding) after commit instead of during `save`.
|
|
126
|
+
|
|
127
|
+
## Chunks Generator
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
rails generate omni_agent:chunks Document file
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Creates a `DocumentChunk` model and its table (with a vector column that matches your database, like the [embeddings generator](#embeddings-generator)) and declares `has_chunks :file` on `Document`, so its [documents are split and searched in chunks](rag.md#documents). If `file` is neither declared on the model nor a column, it's taken as an upload and `has_one_attached :file` is added too.
|
|
134
|
+
|
|
135
|
+
It then prints the commands to install the gems, migrate and ingest existing records.
|
|
136
|
+
|
|
137
|
+
### Options
|
|
138
|
+
|
|
139
|
+
* **`--as`**: A [loader](rag.md#loaders) to enforce (`pdf`, `html`, `markdown`, `text`). Defaults to detecting each file's format.
|
|
140
|
+
* **`--chunker`**: `recursive`, `markdown` or `hierarchical`. Defaults to `recursive`.
|
|
141
|
+
* **`--size`** / **`--overlap`**: Chunk size and overlap, in characters.
|
|
142
|
+
* **`--inline`**: Ingest right after commit instead of in a background job.
|
|
143
|
+
* **`--backend`** / **`--dimensions`**: Same as the [embeddings generator](#options-3).
|
data/docs/index.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# OmniAgent Documentation
|
|
2
|
+
|
|
3
|
+
Offline copy of https://omniagent.activetaskers.com/docs/intro, bundled with the `omni_agent` gem so coding
|
|
4
|
+
agents (Claude Code, Cursor, Codex...) can learn how the gem works from inside
|
|
5
|
+
a project that depends on it. Every page is plain Markdown; links between
|
|
6
|
+
pages are relative.
|
|
7
|
+
|
|
8
|
+
Locate these files from a host app with:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bundle exec omni_agent docs # print this index
|
|
12
|
+
bundle exec omni_agent docs tools # print one page (path without .md)
|
|
13
|
+
bundle exec omni_agent docs --path # print the directory holding these files
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Conventions at a Glance
|
|
17
|
+
|
|
18
|
+
OmniAgent is convention over configuration: classes are discovered from
|
|
19
|
+
where they live, so put files where the generators put them.
|
|
20
|
+
|
|
21
|
+
| What | Where | Class |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| Global settings | `config/initializers/omni_agent.rb` (written by `omni_agent:install`) | `OmniAgent.configure` |
|
|
24
|
+
| Agent | `app/agents/<name>.rb` | `<Name> < OmniAgent::Agent` |
|
|
25
|
+
| Agent system prompt | `app/agents/<name>/prompt.md.erb` | |
|
|
26
|
+
| Entrypoint prompt | `app/agents/<name>/<entrypoint>.md.erb` | |
|
|
27
|
+
| Agent tool | `app/agents/<name>/tools/<tool>.rb` | `<Name>::Tools::<Tool> < OmniAgent::Tool` |
|
|
28
|
+
| MCP server | `app/mcp_servers/<name>_server.rb` | `<Name>Server < OmniAgent::MCP::Server` |
|
|
29
|
+
| MCP server tool | `app/mcp_servers/<name>_server/tools/<tool>.rb` | `<Name>Server::Tools::<Tool>` |
|
|
30
|
+
| Eval | `evals/<name>_eval.rb` | `< OmniAgent::Eval` |
|
|
31
|
+
|
|
32
|
+
Prefer the generators (`rails generate omni_agent:agent`, `omni_agent:mcp_server`,
|
|
33
|
+
`omni_agent:stock_agent`, `omni_agent:eval`, `omni_agent:embeddings`,
|
|
34
|
+
`omni_agent:chunks`) over writing these files by hand.
|
|
35
|
+
See [Generators](generators.md).
|
|
36
|
+
|
|
37
|
+
## Typical Flows
|
|
38
|
+
|
|
39
|
+
* **Build an agent:** [Introduction](intro.md) → [Tools](tools.md) →
|
|
40
|
+
[Run Entrypoints](agent/run-entrypoints.md) → [Structured Output](agent/structured-output.md).
|
|
41
|
+
* **Pick a provider or model:** [Supported Providers](supported-providers.md),
|
|
42
|
+
[Configuration](configuration.md), [Change an Agent's Provider or Model](agent/provider.md).
|
|
43
|
+
* **Compose agents:** [Multi-Agent Delegation](agent/delegation.md),
|
|
44
|
+
[Stock Agents](stock-agents/overview.md).
|
|
45
|
+
* **Observe a run:** [Generation Callbacks](agent/callbacks.md),
|
|
46
|
+
[Streaming Responses](agent/streaming.md).
|
|
47
|
+
* **Answer from your own data (RAG):** [Retrieval-Augmented Generation](rag.md)
|
|
48
|
+
(`has_embedding`, `has_chunks` and the `searches` agent macro).
|
|
49
|
+
* **Test quality:** [Generating and Running Evals](evals/generating-and-running.md) →
|
|
50
|
+
[Golden Sets](evals/golden-sets.md) → [Judge Provider](evals/judge-provider.md).
|
|
51
|
+
* **Expose tools to MCP clients:** [Defining MCP Servers](mcp/defining-servers.md) →
|
|
52
|
+
[Authentication](mcp/authentication.md) → [Transports and Clients](mcp/transports.md).
|
|
53
|
+
|
|
54
|
+
## All Pages
|
|
55
|
+
|
|
56
|
+
### Core
|
|
57
|
+
|
|
58
|
+
* [Introduction](intro.md): **Omni Agent** is a gem focused on generating agentic code the Rails way.
|
|
59
|
+
* [Supported providers](supported-providers.md): This is a list of our currently supported providers.
|
|
60
|
+
* [Configuration](configuration.md): Omni Agent ships with sensible defaults but lets you configure global behavior through an initializer.
|
|
61
|
+
* [Tools](tools.md): Tools are how agents take action beyond generating text. Every tool is a small class that declares an input schema and implements `#execute`.
|
|
62
|
+
* [Generators](generators.md): Omni Agent ships seven Rails generators to scaffold your project.
|
|
63
|
+
* [Retrieval-Augmented Generation (RAG)](rag.md): RAG lets an agent answer from your own data: it searches your records for the passages relevant to a question and gives them to the model. Omni Agent keeps the vectors in your own database (or Meilisearch) and turns any searchable model into an agent tool. Records are searched whole with `has_embedding`, and files or long text in chunks with `has_chunks`.
|
|
64
|
+
|
|
65
|
+
### Agents
|
|
66
|
+
|
|
67
|
+
Learn about agent specific features and functionalities.
|
|
68
|
+
|
|
69
|
+
* [Generation Callbacks](agent/callbacks.md): Agents support `before_generation` and `after_generation` callbacks, letting you hook into the lifecycle of a single `run` without overriding it yourself.
|
|
70
|
+
* [Run Entrypoints](agent/run-entrypoints.md): `OmniAgent::Agent` always exposes the low-level `run` method, but you'll usually call an agent through one of its higher-level entrypoints.
|
|
71
|
+
* [Change an Agent's Provider or Model](agent/provider.md): By default, agents use the configured `default_provider` and `default_model`. You can override these settings on a per-agent basis using one of the following DSL directives.
|
|
72
|
+
* [Multi-Agent Delegation](agent/delegation.md): `delegate_to` wraps another agent as a tool your agent's LLM can call, turning your agent into a **supervisor** that routes work to sub-agents. The delegated agent is defined and used like any other agent — a normal class under `app/agents/`, not a manual tool file.
|
|
73
|
+
* [Streaming Responses](agent/streaming.md): Any run entrypoint — `run`, an implicit entrypoint, or a `run_aliases` method — can stream its response by prefixing the call with `.stream` and passing a block. Without `.stream` (or without a block), behavior is completely unchanged.
|
|
74
|
+
* [Structured Output](agent/structured-output.md): Declare an `output` block to make an agent return a validated object instead of free text. It uses the same DSL as a tool's `input`.
|
|
75
|
+
|
|
76
|
+
### Stock Agents
|
|
77
|
+
|
|
78
|
+
Ready-made agents shipped with the gem that your project subclasses and customizes.
|
|
79
|
+
|
|
80
|
+
* [Overview](stock-agents/overview.md): Stock agents are ready-made agents shipped with the gem under `OmniAgent::StockAgents`. They bring their own prompt, model settings and tools; your project subclasses one and declares the structured output it needs.
|
|
81
|
+
* [OCR](stock-agents/ocr.md): `OmniAgent::StockAgents::OCR` reads photos, scans and PDFs with a vision model (`gpt-4o` by default). Its default output is `{ text: "..." }`, the full text in reading order; declare your own `output` to extract fields instead.
|
|
82
|
+
|
|
83
|
+
### Evals
|
|
84
|
+
|
|
85
|
+
Test agent quality with deterministic assertions and LLM-as-judge scoring.
|
|
86
|
+
|
|
87
|
+
* [Generating and Running Evals](evals/generating-and-running.md): `OmniAgent::Eval` lets you test agent *quality*, not just correctness — deterministic assertions (tool calls, output matching) plus pluggable LLM-as-judge scoring.
|
|
88
|
+
* [Golden Sets](evals/golden-sets.md): For many input/expected-output pairs, load a dataset file instead of writing a `eval_case` per row.
|
|
89
|
+
* [Judge Provider](evals/judge-provider.md): `judge` resolves which provider grades the output, in this order.
|
|
90
|
+
* [Caching](evals/caching.md): Eval runs are cached by default, keyed on `(agent class, run_alias, input, context)`, and stored as JSON at `OmniAgent.configuration.eval_cache_path` (default `tmp/omni_agent_eval_cache.json`). Re-running the same case — e.g. while iterating on assertions — replays the cached output instead of calling the provider again, so you don't spend tokens testing the same case twice.
|
|
91
|
+
|
|
92
|
+
### MCP Servers
|
|
93
|
+
|
|
94
|
+
Expose your tools and agents to Claude Code, Claude Desktop, Cursor and other MCP clients.
|
|
95
|
+
|
|
96
|
+
* [Defining MCP Servers](mcp/defining-servers.md): The Model Context Protocol (MCP) lets AI clients such as Claude Code, Claude Desktop and Cursor call tools that live in your app. `OmniAgent::MCP::Server` turns the `OmniAgent::Tool` classes you already wrote for your agents — and the agents themselves — into an MCP server, with no extra gem.
|
|
97
|
+
* [Authentication](mcp/authentication.md): An MCP server mounted over HTTP lets anyone who can reach the URL run your tools. For that reason, **every server must declare `authenticate`**. A server without it raises `OmniAgent::MCPError` on the first HTTP request. To make a server public on purpose, write `authenticate :none`.
|
|
98
|
+
* [Transports and Clients](mcp/transports.md): OmniAgent supports both MCP transports.
|
data/docs/intro.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!-- Generated from omniagent-docs/docs/intro.mdx by `bundle exec rake docs:sync`. Do not edit by hand. -->
|
|
2
|
+
<!-- Online version: https://omniagent.activetaskers.com/docs/intro -->
|
|
3
|
+
|
|
4
|
+
# Introduction
|
|
5
|
+
|
|
6
|
+
**Omni Agent** is a gem focused on generating agentic code the Rails way.
|
|
7
|
+
|
|
8
|
+
It is designed to be highly opinionated, fully embracing the "convention over configuration" philosophy.
|
|
9
|
+
|
|
10
|
+
Let's get your first AI agent up and running **in less than 5 minutes**.
|
|
11
|
+
|
|
12
|
+
## Getting Started
|
|
13
|
+
|
|
14
|
+
### 1. Install the Gem
|
|
15
|
+
First, add Omni Agent to your Rails application. You can add it directly to your `Gemfile`:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'omni_agent'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or, run the following command in your terminal:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bundle add omni_agent
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Install an AI Provider
|
|
28
|
+
|
|
29
|
+
Omni Agent is provider-agnostic, meaning you need to install the specific gem for the AI provider you plan to use. You can find a full list of supported providers [here](supported-providers.md).
|
|
30
|
+
|
|
31
|
+
For example, to use OpenAI:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bundle add openai
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 3. Run the Install Generator
|
|
38
|
+
|
|
39
|
+
Prepare your project by running the Omni Agent installation generator:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
rails generate omni_agent:install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This will set up the necessary foundation for your agents, starting by creating the core `app/agents` directory.
|
|
46
|
+
|
|
47
|
+
> **Note:** As of version `0.1.4`, this command is lightweight. It lays the groundwork for more advanced configurations and planned features in future releases.
|
|
48
|
+
|
|
49
|
+
## Create Your First Agent
|
|
50
|
+
|
|
51
|
+
With the setup complete, you can use the built-in generator to scaffold your first agent.
|
|
52
|
+
|
|
53
|
+
Run the following command to create a `DemoAgent`, specify the model, and attach a couple of tools:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rails generate omni_agent:agent DemoAgent --model gpt-4o-mini --with-tools DemoTool SecondDemoTool
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This will generate the following directory structure inside `app/agents/`:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
app/agents/
|
|
63
|
+
├── demo_agent.rb
|
|
64
|
+
└── demo_agent/
|
|
65
|
+
├── prompt.md.erb
|
|
66
|
+
└── tools/
|
|
67
|
+
├── demo_tool.rb
|
|
68
|
+
└── second_demo_tool.rb
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**What are these files?**
|
|
73
|
+
|
|
74
|
+
* **`demo_agent.rb`**: The main configuration file dictating how your agent behaves.
|
|
75
|
+
* **`prompt.md.erb`**: The core system prompt injected into your agent. It uses ERB, allowing for dynamic Ruby interpolation.
|
|
76
|
+
* **`tools/`**: The directory housing the custom tools (`DemoTool`, `SecondDemoTool`) at your agent's disposal.
|
|
77
|
+
|
|
78
|
+
## Calling the Agent
|
|
79
|
+
|
|
80
|
+
After running the generator, your agent is ready to go out of the box. You can quickly test it in your Rails console (`rails c`) or anywhere in your app:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
DemoAgent.new.run("Hello!")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Congratulations - you are successfully using Omni Agent!
|
|
87
|
+
|
|
88
|
+
## What Else Can It Do?
|
|
89
|
+
|
|
90
|
+
* **[Tools](tools.md)** with typed, validated input schemas.
|
|
91
|
+
* **[Multi-agent delegation](agent/delegation.md)**, **[streaming](agent/streaming.md)** and **[callbacks](agent/callbacks.md)**.
|
|
92
|
+
* **[Evals](index.md#evals)** with golden sets and LLM-as-judge scoring.
|
|
93
|
+
* **[MCP servers](index.md#mcp-servers)**: expose your tools and agents to Claude Code, Claude Desktop, Cursor and other MCP clients.
|