omni_agent 0.1.7 → 0.1.8
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 +7 -0
- data/README.md +32 -0
- data/lib/omni_agent/agent.rb +77 -4
- data/lib/omni_agent/configuration.rb +2 -1
- data/lib/omni_agent/errors.rb +2 -0
- data/lib/omni_agent/tool.rb +6 -0
- data/lib/omni_agent/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea0324a20bc12e064b994b4fcdf7af700cd0280ba7b0609dc75724717e9fc881
|
|
4
|
+
data.tar.gz: dfda03e711340e59dfbb1cd803bc785a51bbe39d972992c6a26fb5b2d4d8761a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72739c339838d0f38c172455226ff79244ab7e739920ec9e7b89f16182d220a1526886bff1f85b7b943bc6426676d5cc4dbd727f903c612df401587fc627f3f0
|
|
7
|
+
data.tar.gz: b90d265c701efaf90d5d5f5e5f9aac3b337095e998d413bf5e872e05d794a9793a44e0bd669425d30ee13eabd50ded2f0fdc2c19cadbc1ff976ec02d0e8d888f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.8](https://github.com/ACR1209/omni_agent/compare/omni_agent/v0.1.7...omni_agent/v0.1.8) (2026-07-07)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* implement multi-agent delegation with context forwarding and depth control ([e9b5497](https://github.com/ACR1209/omni_agent/commit/e9b5497b0af89172701bf4c5d93b8d5dccc77a26))
|
|
11
|
+
|
|
5
12
|
## [0.1.7](https://github.com/ACR1209/omni_agent/compare/omni_agent-v0.1.6...omni_agent/v0.1.7) (2026-06-22)
|
|
6
13
|
|
|
7
14
|
|
data/README.md
CHANGED
|
@@ -97,6 +97,38 @@ module ResearchAgent::Tools
|
|
|
97
97
|
end
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
## Multi-Agent Delegation
|
|
101
|
+
|
|
102
|
+
`delegate_to` turns an agent into a supervisor: it wraps another agent class as a tool, so the supervisor's LLM can decide when to hand off to it. The delegated agent is a normal, independently defined agent (e.g. `app/agents/research_agent.rb`) — no manual tool file needed.
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
class SupervisorAgent < OmniAgent::Agent
|
|
106
|
+
use_model "gpt-4o"
|
|
107
|
+
|
|
108
|
+
delegate_to ResearchAgent, as: :research, description: "Look up factual info"
|
|
109
|
+
delegate_to MathAgent, as: :calculate, description: "Do arithmetic"
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Each delegated agent runs in isolation (its own fresh instance, no shared context) and returns its final answer as the tool result. Delegation depth is capped by `OmniAgent.configuration.max_delegation_depth` (default `5`) to guard against runaway recursive delegation; exceeding it raises `OmniAgent::MaxDelegationDepthError`.
|
|
114
|
+
|
|
115
|
+
Pass `run_alias:` to call a `run_aliases` method (or any zero-arg run entrypoint) on the delegated agent instead of its default `#run` — useful when the sub-agent should render a different prompt file for delegated calls:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
class SupervisorAgent < OmniAgent::Agent
|
|
119
|
+
delegate_to SupportAgent, as: :triage_ticket, run_alias: :triage
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Pass `forward:` to share part (or all) of the supervisor's context with the delegated agent — an array of context keys, or `true` to forward everything. Omitted keys, and the default (`forward: []`), keep the delegated agent fully isolated:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
class SupervisorAgent < OmniAgent::Agent
|
|
127
|
+
delegate_to ResearchAgent, as: :research, forward: [ :user, :locale ]
|
|
128
|
+
delegate_to MathAgent, as: :calculate, forward: true
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
100
132
|
## Evals
|
|
101
133
|
|
|
102
134
|
`OmniAgent::Eval` lets you test agent quality: deterministic assertions (tool calls, output matching) and pluggable LLM-as-judge scoring.
|
data/lib/omni_agent/agent.rb
CHANGED
|
@@ -84,6 +84,21 @@ module OmniAgent
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
def delegate_to(agent_class, as:, description: nil, run_alias: nil, forward: [])
|
|
88
|
+
unless agent_class.is_a?(Class) && agent_class <= OmniAgent::Agent
|
|
89
|
+
raise ArgumentError, "delegate_to requires an OmniAgent::Agent subclass"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
tool_class = build_delegated_tool_class(agent_class, description: description, run_alias: run_alias, forward: forward)
|
|
93
|
+
delegated_tools_module.const_set(delegated_tool_const_name(as), tool_class)
|
|
94
|
+
|
|
95
|
+
@delegated_tool_classes = configured_delegated_tool_classes + [ tool_class ]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def configured_delegated_tool_classes
|
|
99
|
+
@delegated_tool_classes || []
|
|
100
|
+
end
|
|
101
|
+
|
|
87
102
|
def with(context = nil, provider_override: nil, model_override: nil, options_override: {}, **context_keywords)
|
|
88
103
|
merged_context = {}
|
|
89
104
|
merged_context.merge!(context) if context.is_a?(Hash)
|
|
@@ -112,6 +127,58 @@ module OmniAgent
|
|
|
112
127
|
|
|
113
128
|
private
|
|
114
129
|
|
|
130
|
+
def delegated_tools_module
|
|
131
|
+
@delegated_tools_module ||= const_set(:DelegatedTools, Module.new)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def delegated_tool_const_name(as)
|
|
135
|
+
as.to_s.split(/[_\s]+/).reject(&:empty?).map { |part| part[0].upcase + part[1..] }.join
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def build_delegated_tool_class(agent_class, description:, run_alias:, forward:)
|
|
139
|
+
tool_description = description || "Delegate to #{agent_class.name}."
|
|
140
|
+
|
|
141
|
+
Class.new(OmniAgent::Tool) do
|
|
142
|
+
description tool_description
|
|
143
|
+
|
|
144
|
+
input do
|
|
145
|
+
string :input, description: "Input/question to send to the delegated agent."
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
define_method(:execute) do |input:|
|
|
149
|
+
forwarded_context = OmniAgent::Agent.__send__(:filter_forwarded_context, context, forward)
|
|
150
|
+
OmniAgent::Agent.__send__(:run_delegated_agent, agent_class, input, run_alias, forwarded_context)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def filter_forwarded_context(context, forward)
|
|
156
|
+
return {} unless context.is_a?(Hash)
|
|
157
|
+
return context.dup if forward == true
|
|
158
|
+
return {} if forward.nil? || forward == false
|
|
159
|
+
|
|
160
|
+
keys = Array(forward).map(&:to_sym)
|
|
161
|
+
context.select { |key, _| keys.include?(key.to_sym) }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def run_delegated_agent(agent_class, input, run_alias, forwarded_context)
|
|
165
|
+
depth = (Thread.current[:omni_agent_delegation_depth] ||= 0)
|
|
166
|
+
max_depth = OmniAgent.configuration.max_delegation_depth
|
|
167
|
+
|
|
168
|
+
if depth >= max_depth
|
|
169
|
+
raise OmniAgent::MaxDelegationDepthError,
|
|
170
|
+
"Exceeded max_delegation_depth (#{max_depth}) while delegating to #{agent_class.name}."
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
Thread.current[:omni_agent_delegation_depth] = depth + 1
|
|
174
|
+
begin
|
|
175
|
+
entrypoint = run_alias || :run
|
|
176
|
+
agent_class.new.public_send(entrypoint, input, context: forwarded_context).answer
|
|
177
|
+
ensure
|
|
178
|
+
Thread.current[:omni_agent_delegation_depth] = depth
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
115
182
|
def normalize_callbacks(callback_type, callbacks)
|
|
116
183
|
raise ArgumentError, "#{callback_type} requires at least one method name" if callbacks.empty?
|
|
117
184
|
|
|
@@ -196,6 +263,7 @@ module OmniAgent
|
|
|
196
263
|
|
|
197
264
|
if tool_class
|
|
198
265
|
tool_instance = tool_class.new
|
|
266
|
+
tool_instance.context = context if tool_instance.respond_to?(:context=)
|
|
199
267
|
|
|
200
268
|
begin
|
|
201
269
|
result = tool_instance.invoke(tool_args)
|
|
@@ -238,12 +306,17 @@ module OmniAgent
|
|
|
238
306
|
|
|
239
307
|
def available_tools
|
|
240
308
|
tool_namespace = "#{self.class.name}::Tools".safe_constantize
|
|
241
|
-
return [] unless tool_namespace
|
|
242
309
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
310
|
+
namespace_tools = if tool_namespace
|
|
311
|
+
tool_namespace.constants.filter_map do |const_name|
|
|
312
|
+
const = tool_namespace.const_get(const_name)
|
|
313
|
+
const if const.is_a?(Class) && const < OmniAgent::Tool
|
|
314
|
+
end
|
|
315
|
+
else
|
|
316
|
+
[]
|
|
246
317
|
end
|
|
318
|
+
|
|
319
|
+
namespace_tools + self.class.configured_delegated_tool_classes
|
|
247
320
|
end
|
|
248
321
|
|
|
249
322
|
private
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module OmniAgent
|
|
2
2
|
class Configuration
|
|
3
3
|
attr_accessor :default_provider, :default_model, :max_retries, :retry_base_delay, :max_tool_iterations,
|
|
4
|
-
:eval_judge_provider, :eval_judge_model, :eval_cache_enabled, :eval_cache_path
|
|
4
|
+
:max_delegation_depth, :eval_judge_provider, :eval_judge_model, :eval_cache_enabled, :eval_cache_path
|
|
5
5
|
|
|
6
6
|
def initialize
|
|
7
7
|
@default_provider = :openai
|
|
@@ -9,6 +9,7 @@ module OmniAgent
|
|
|
9
9
|
@max_retries = 3
|
|
10
10
|
@retry_base_delay = 0.5
|
|
11
11
|
@max_tool_iterations = 10
|
|
12
|
+
@max_delegation_depth = 5
|
|
12
13
|
@eval_judge_provider = nil
|
|
13
14
|
@eval_judge_model = nil
|
|
14
15
|
@eval_cache_enabled = true
|
data/lib/omni_agent/errors.rb
CHANGED
|
@@ -4,6 +4,7 @@ module OmniAgent
|
|
|
4
4
|
class MissingDependencyError < Error; end
|
|
5
5
|
class UnknownProviderError < Error; end
|
|
6
6
|
class MaxToolIterationsError < Error; end
|
|
7
|
+
class MaxDelegationDepthError < Error; end
|
|
7
8
|
class EvalAssertionError < Error; end
|
|
8
9
|
end
|
|
9
10
|
|
|
@@ -11,5 +12,6 @@ module OmniAgent
|
|
|
11
12
|
MissingDependencyError = Errors::MissingDependencyError
|
|
12
13
|
UnknownProviderError = Errors::UnknownProviderError
|
|
13
14
|
MaxToolIterationsError = Errors::MaxToolIterationsError
|
|
15
|
+
MaxDelegationDepthError = Errors::MaxDelegationDepthError
|
|
14
16
|
EvalAssertionError = Errors::EvalAssertionError
|
|
15
17
|
end
|
data/lib/omni_agent/tool.rb
CHANGED
data/lib/omni_agent/version.rb
CHANGED