activeagent 1.1.0 → 1.3.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 +185 -0
- data/README.md +58 -14
- data/lib/active_agent/base.rb +11 -2
- data/lib/active_agent/concerns/delegation.rb +385 -0
- data/lib/active_agent/delegation/backend.rb +109 -0
- data/lib/active_agent/delegation/budget.rb +138 -0
- data/lib/active_agent/delegation/contract.rb +117 -0
- data/lib/active_agent/delegation/definition.rb +95 -0
- data/lib/active_agent/delegation/ledger.rb +56 -0
- data/lib/active_agent/delegation/pricing.rb +106 -0
- data/lib/active_agent/delegation/runner.rb +283 -0
- data/lib/active_agent/delegation/schema.rb +220 -0
- data/lib/active_agent/providers/_base_provider.rb +97 -1
- data/lib/active_agent/providers/open_ai/chat_provider.rb +21 -2
- data/lib/active_agent/telemetry/configuration.rb +13 -9
- data/lib/active_agent/telemetry/instrumentation.rb +38 -1
- data/lib/active_agent/telemetry/tool_origin.rb +90 -0
- data/lib/active_agent/telemetry.rb +1 -0
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +1 -5
- metadata +31 -32
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/api/traces_controller.rb +0 -138
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/application_controller.rb +0 -64
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/dashboard_controller.rb +0 -129
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/traces_controller.rb +0 -123
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/agent_execution_job.rb +0 -56
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/application_job.rb +0 -14
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_cleanup_job.rb +0 -49
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_provision_job.rb +0 -65
- data/lib/active_agent/dashboard/app/jobs/active_agent/process_telemetry_traces_job.rb +0 -86
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent.rb +0 -256
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_run.rb +0 -113
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_template.rb +0 -208
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_version.rb +0 -60
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/application_record.rb +0 -46
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_action.rb +0 -125
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_snapshot.rb +0 -83
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_run.rb +0 -52
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_session.rb +0 -169
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/session_recording.rb +0 -193
- data/lib/active_agent/dashboard/app/models/active_agent/telemetry_trace.rb +0 -214
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/_trace_detail.html.erb +0 -117
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/index.html.erb +0 -135
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/metrics.html.erb +0 -145
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/show.html.erb +0 -36
- data/lib/active_agent/dashboard/app/views/layouts/active_agent/dashboard/application.html.erb +0 -94
- data/lib/active_agent/dashboard/config/routes.rb +0 -19
- data/lib/active_agent/dashboard/engine.rb +0 -43
- data/lib/active_agent/dashboard.rb +0 -161
- data/lib/generators/active_agent/dashboard/install_generator.rb +0 -92
- data/lib/generators/active_agent/dashboard/templates/active_agent_dashboard.rb.erb +0 -67
- data/lib/generators/active_agent/dashboard/templates/create_active_agent_telemetry_traces.rb.erb +0 -46
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 45044ca9e6ddabcdfb1be0f32074149a3e9fb8fcaa9e7c8a79c02f81c73eb64b
|
|
4
|
+
data.tar.gz: 7f0a2489a68e01f0dd0e9a1fb96878bb900acaab173ba0a0157ad82a8a510fe6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c4797fc3bc8e97be8624ef989abc1486fe0d357f5248353dd09bc9852de605e0b14cebb33f3fb35ba166f62e64f7ce5522f62da94ad25b5b188a771f1f8aeec
|
|
7
|
+
data.tar.gz: 72bc8b89a042c1d3fd2489de0eb452d2e95106eaf9a46ad4dc5e8f1378b3441345c0b652c123490804943064f16526a1baa67584ce4b2a4315255beb3783203e
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,152 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0] - 2026-08-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Agent-as-tool delegation.** A tool is a Ruby method the model can call; a
|
|
13
|
+
delegation is another agent it can call. The callee keeps its own
|
|
14
|
+
instructions, templates, model and budget, so a specialist agent stays
|
|
15
|
+
specialist and the generalist orchestrating it never inherits its prompt.
|
|
16
|
+
Declared with `delegation :action, description:` on the sub-agent, with a
|
|
17
|
+
JSON Schema for the inputs and an optional `returns` schema that becomes the
|
|
18
|
+
sub-agent's response format. See `docs/actions/delegation.md`.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **Streamed generations report their token usage.** A request with
|
|
23
|
+
`stream: true` recorded zero input and output tokens, and so zero cost and
|
|
24
|
+
no context-pressure estimate downstream — dashboards showed `Tokens 0` and
|
|
25
|
+
`$0.00` beside a run that had plainly called the API. Three things had to
|
|
26
|
+
hold at once for the usage to survive, and none did: the streaming path
|
|
27
|
+
returns `nil` rather than a response body to read usage from; Chat
|
|
28
|
+
Completions only emits its usage chunk when the request sets
|
|
29
|
+
`stream_options: {include_usage: true}`, which was never sent; and that
|
|
30
|
+
chunk arrives *after* `content.done`, where the response was already being
|
|
31
|
+
built. Completion now defers until the stream drains, and the usage chunk
|
|
32
|
+
is recorded on the way past. A provider hook (`api_stream_usage_parameters`,
|
|
33
|
+
empty by default) keeps providers that report unconditionally — or not at
|
|
34
|
+
all — unaffected.
|
|
35
|
+
|
|
36
|
+
Also fixed a silent conversion failure behind the same symptom:
|
|
37
|
+
`Usage.from_provider_usage` early-returns on anything that is not a Hash,
|
|
38
|
+
and the stainless gems hand back model objects, so usage was dropped even
|
|
39
|
+
when it did arrive.
|
|
40
|
+
|
|
41
|
+
### Note on the 1.2.0 tag
|
|
42
|
+
|
|
43
|
+
The `v1.2.0` tag had been moved to a commit later than the one published as
|
|
44
|
+
`activeagent 1.2.0`, so the tag and the gem disagreed. It has been repointed
|
|
45
|
+
to the commit that actually produced the release. If you fetched the tag
|
|
46
|
+
between 2026-08-14 and 2026-08-18, re-fetch with `git fetch --tags --force`.
|
|
47
|
+
|
|
48
|
+
## [1.2.2] - 2026-08-14
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **`actionagent`: every engine constant resolves under a host's
|
|
53
|
+
inflections.** 1.2.1 scoped its autoloader override to the basename `api`,
|
|
54
|
+
which covered the controllers under `app/controllers/action_agent/api` and
|
|
55
|
+
nothing else. Seven files camelize differently once a host registers an
|
|
56
|
+
acronym — `mcp_catalog.rb`, `mcp_recording_middleware.rb`,
|
|
57
|
+
`playwright_mcp_client.rb`, `api_key.rb`, and the `api_keys`, `mcp` and
|
|
58
|
+
`mcp_servers` controllers — and each raised `Zeitwerk::NameError` on first
|
|
59
|
+
reference. In a host declaring `inflect.acronym "MCP"` the **Tools view was
|
|
60
|
+
unreachable** (`uninitialized constant
|
|
61
|
+
ActionAgent::ToolDiscovery::McpCatalog`), as were the MCP endpoints and
|
|
62
|
+
anything touching an API key.
|
|
63
|
+
|
|
64
|
+
Every path under the engine now camelizes with Zeitwerk's default
|
|
65
|
+
inflector, ignoring the host's acronyms, scoped by path so the host's own
|
|
66
|
+
constants keep their spelling. The router half generalizes with it: an
|
|
67
|
+
all-caps run in a missing constant is retried in the relaxed spelling
|
|
68
|
+
(`API` → `Api`, `MCPServersController` → `McpServersController`) rather
|
|
69
|
+
than aliasing each pair by hand.
|
|
70
|
+
|
|
71
|
+
## [1.2.1] - 2026-08-14
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- **`actionagent`: the install migrations now run on MySQL.** Both templates
|
|
76
|
+
already chose the JSON column type per adapter, but kept `default: []` /
|
|
77
|
+
`default: {}` for every adapter, and MySQL rejects a default on a JSON
|
|
78
|
+
column outright — so `rails g action_agent:install && rails db:migrate`
|
|
79
|
+
aborted mid-`create_table` on any MySQL host. The default (and the paired
|
|
80
|
+
`null: false`, which without it would reject the inserts the default
|
|
81
|
+
existed to satisfy) is now PostgreSQL-only. Every JSON column is read
|
|
82
|
+
through `Array(...)` / `|| {}`, so a NULL reads as the empty value.
|
|
83
|
+
- **`actionagent`: the mount works in a host that declares
|
|
84
|
+
`inflect.acronym "API"`.** An engine's files are autoloaded under the
|
|
85
|
+
host's inflections, so such a host made Zeitwerk expect
|
|
86
|
+
`ActionAgent::API::TracesController` from a file defining
|
|
87
|
+
`ActionAgent::Api::TracesController`, and every request to the mount
|
|
88
|
+
raised `Zeitwerk::NameError`. Rails separately camelizes a route's stored
|
|
89
|
+
controller path with the host's global inflections, which no engine-level
|
|
90
|
+
setting scopes. The autoloader is now pinned to `Api` for this engine's
|
|
91
|
+
own path, and the namespace answers to `API` as well.
|
|
92
|
+
|
|
93
|
+
## [1.2.0] - 2026-08-14
|
|
94
|
+
|
|
95
|
+
### ⚠️ The dashboard has moved to its own gem
|
|
96
|
+
|
|
97
|
+
The dashboard engine that shipped inside `activeagent` is now a separate
|
|
98
|
+
gem, **`actionagent`**. Nothing is gone — the dashboard is the same
|
|
99
|
+
dashboard, and it gained a great deal in this release — but it comes from a
|
|
100
|
+
different gem now. `activeagent` is the framework alone: it no longer
|
|
101
|
+
defines `ActiveAgent::Dashboard`, and no longer pulls Active Record into
|
|
102
|
+
apps that do not use it.
|
|
103
|
+
|
|
104
|
+
**If you mount the dashboard, add the new gem in the same change that
|
|
105
|
+
upgrades `activeagent`:**
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
gem "activeagent", "~> 1.2"
|
|
109
|
+
gem "actionagent", "~> 1.2" # required if you mount the dashboard
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This is a minor version, so a `~> 1.0` or `~> 1.1` constraint **will** pick
|
|
113
|
+
it up on the next `bundle update`. If you mount the dashboard and do not add
|
|
114
|
+
`actionagent` at the same time, the app fails at boot with
|
|
115
|
+
`NameError: uninitialized constant ActiveAgent::Dashboard`, raised by your
|
|
116
|
+
own initializer or by the `mount ActiveAgent::Dashboard::Engine` line in
|
|
117
|
+
`config/routes.rb`. Adding the gem is the whole fix — your existing
|
|
118
|
+
configuration keeps working through the compatibility shims below.
|
|
119
|
+
|
|
120
|
+
If you do not mount the dashboard, there is nothing to do: the framework API
|
|
121
|
+
is unchanged, and the gem is 95% smaller.
|
|
122
|
+
|
|
123
|
+
With `actionagent` installed, the old constants keep resolving through
|
|
124
|
+
`ActionAgent::Compatibility` with a deprecation warning:
|
|
125
|
+
|
|
126
|
+
- `ActiveAgent::Dashboard` → `ActionAgent`
|
|
127
|
+
- `ActiveAgent::TelemetryTrace` → `ActionAgent::TelemetryTrace`
|
|
128
|
+
- `ActiveAgent::ProcessTelemetryTracesJob` → `ActionAgent::ProcessTelemetryTracesJob`
|
|
129
|
+
|
|
130
|
+
That last one matters beyond tidiness: Active Job serializes the class name
|
|
131
|
+
into the queue payload, so jobs enqueued before the upgrade still resolve
|
|
132
|
+
after it.
|
|
133
|
+
|
|
134
|
+
Other changes for mounted installs:
|
|
135
|
+
|
|
136
|
+
- **The server-rendered traces console moves from `/traces` to
|
|
137
|
+
`/console/traces`.** `/traces` is now the React traces view — the same
|
|
138
|
+
data, with more of it.
|
|
139
|
+
- **The mount is authenticated everywhere but development and test.** The
|
|
140
|
+
sandbox API, the session-recording capture endpoints and the template
|
|
141
|
+
endpoints previously allowed anonymous access; they no longer do. The
|
|
142
|
+
`GET /api/session_recordings/demo` endpoint is removed.
|
|
143
|
+
- **`current_user_method` / `current_account_method` are superseded by
|
|
144
|
+
`current_user_resolver` / `current_account_resolver`.** The engine's
|
|
145
|
+
controllers are their own base class, so a host app's `current_user`
|
|
146
|
+
helper is not available to them.
|
|
147
|
+
- **An unresolved owner now scopes to nothing rather than to everything.**
|
|
148
|
+
If you configure `user_class` or `account_class`, make sure the matching
|
|
149
|
+
resolver actually returns a record, or the dashboard will show no data.
|
|
150
|
+
- Existing installs upgrading from the in-gem dashboard: re-run
|
|
151
|
+
`rails generate action_agent:install`. It detects the migrations you
|
|
152
|
+
already have and emits only what is missing.
|
|
153
|
+
|
|
8
154
|
## [1.1.0] - 2026-08-12
|
|
9
155
|
|
|
10
156
|
### Dashboard — self-hosted (enterprise) mount readiness
|
|
@@ -45,6 +191,45 @@ observability surface (see `docs/framework/self-hosted-observability.md`):
|
|
|
45
191
|
it remains a no-op accessor with its historical default so existing
|
|
46
192
|
initializers keep booting, and will be removed in the next major.
|
|
47
193
|
|
|
194
|
+
### Agent-as-tool delegation
|
|
195
|
+
|
|
196
|
+
Sub-agents are now a first-class primitive. A tool is a Ruby method your
|
|
197
|
+
model can call; a delegation is another agent your model can call — with
|
|
198
|
+
its own instructions, templates, model and budget.
|
|
199
|
+
|
|
200
|
+
- **`delegation :action, description:`** declares what a sub-agent exposes:
|
|
201
|
+
a description for the calling model, a JSON Schema for its inputs (block
|
|
202
|
+
DSL, a plain hash, or any class responding to `to_json_schema`), and
|
|
203
|
+
optionally a `returns` schema. A declared `returns` becomes the
|
|
204
|
+
sub-agent's `response_format`, and its answer is parsed and checked
|
|
205
|
+
before the caller sees it.
|
|
206
|
+
- **`delegate_to AgentClass`** exposes those contracts to the calling model
|
|
207
|
+
as tools, with `only:`/`except:`/`as:` for scoping and renaming,
|
|
208
|
+
`params:` for forwarding, and `action:` for declaring a contract at the
|
|
209
|
+
call site when you don't own the sub-agent. Per-action scoping via the
|
|
210
|
+
`delegations:` prompt option.
|
|
211
|
+
- **Cost and latency budgets**: `max_calls`, `max_tokens`, `max_cost`,
|
|
212
|
+
`max_duration` and a per-call `timeout`, set per delegation and/or
|
|
213
|
+
agent-wide with `delegation_budget`. Exhausting one returns a structured
|
|
214
|
+
result the model can act on (`on_exceeded: :stop`, the default) instead
|
|
215
|
+
of raising mid-conversation; `:raise` is available. Budgets are scoped
|
|
216
|
+
to a single generation, and spend is readable afterwards via
|
|
217
|
+
`delegation_ledger`.
|
|
218
|
+
- **Swappable backends**: `backend: :ollama` or
|
|
219
|
+
`backend: { provider: :anthropic, model: "claude-haiku-4-5" }` moves a
|
|
220
|
+
delegation to different silicon without touching the sub-agent. Provider
|
|
221
|
+
swaps rebuild provider configuration rather than merging over it, and
|
|
222
|
+
template lookup still resolves to the original agent's views.
|
|
223
|
+
- **Cost registry**: `ActiveAgent::Delegation::Pricing.register` records
|
|
224
|
+
token rates in USD per 1M tokens (no built-in price list, so `max_cost`
|
|
225
|
+
never fires on stale numbers); rates can also be stated inline on a budget.
|
|
226
|
+
- **Instrumentation**: `delegate.active_agent` (agent, sub-agent, action,
|
|
227
|
+
model, duration, usage, cost, ledger) and
|
|
228
|
+
`delegation_refused.active_agent` (violated limit).
|
|
229
|
+
- **New docs** (`docs/actions/delegation.md`) with a worked support-triage
|
|
230
|
+
example, plus test coverage in `test/features/delegation_test.rb` and
|
|
231
|
+
`test/docs/actions/delegation_examples_test.rb`.
|
|
232
|
+
|
|
48
233
|
### Dashboard & Telemetry — dev console readiness
|
|
49
234
|
|
|
50
235
|
The dashboard engine — Active Agent's local dev console — now works out of
|
data/README.md
CHANGED
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
>
|
|
11
11
|
> *Makes code [TonsOfFun](https://tonsoffun.github.io)!*
|
|
12
12
|
|
|
13
|
+
[](https://rubygems.org/gems/activeagent)
|
|
14
|
+
[](https://rubygems.org/gems/actionagent)
|
|
15
|
+
[](https://rubygems.org/gems/activeagent)
|
|
16
|
+
[](https://github.com/activeagents/activeagent/actions/workflows/ci.yml)
|
|
17
|
+
[](https://github.com/activeagents/activeagent/actions/workflows/integration.yml)
|
|
18
|
+
[](https://docs.activeagents.ai)
|
|
19
|
+
[](https://www.ruby-lang.org)
|
|
20
|
+
[](https://rubyonrails.org)
|
|
21
|
+
[](LICENSE)
|
|
22
|
+
|
|
13
23
|
# Active Agent
|
|
14
24
|
Active Agent provides that missing AI layer in the Rails framework, offering a structured approach to building AI-powered applications through Agent Oriented Programming. **Now Agents are Controllers!** Designing applications using agents allows developers to create modular, reusable components that can be easily integrated into existing systems. This approach promotes code reusability, maintainability, and scalability, making it easier to build complex AI-driven applications with the Object Oriented Ruby code you already use today.
|
|
15
25
|
|
|
@@ -25,6 +35,10 @@ Use bundler to add activeagent to your Gemfile and install:
|
|
|
25
35
|
bundle add activeagent
|
|
26
36
|
```
|
|
27
37
|
|
|
38
|
+
That is the framework — agents, providers, generation and telemetry
|
|
39
|
+
reporting. The dashboard is a second gem, `actionagent`, added separately
|
|
40
|
+
when you want it; see [Dashboard & Dev Console](#dashboard--dev-console).
|
|
41
|
+
|
|
28
42
|
Add the generation provider gem you want to use:
|
|
29
43
|
|
|
30
44
|
```bash
|
|
@@ -127,14 +141,19 @@ development:
|
|
|
127
141
|
service: "RubyLLM"
|
|
128
142
|
```
|
|
129
143
|
|
|
130
|
-
## Dev Console
|
|
144
|
+
## Dashboard & Dev Console
|
|
131
145
|
|
|
132
|
-
|
|
133
|
-
token usage
|
|
134
|
-
|
|
146
|
+
The dashboard is its own gem, `actionagent`: a mountable Rails engine with
|
|
147
|
+
traces and span waterfalls, token usage and per-agent metrics, plus the agent
|
|
148
|
+
builder, runs, conversations, evaluations, scorecards and cost estimates — so
|
|
149
|
+
you can watch and drive your agents while you build. It ships separately
|
|
150
|
+
because its models are Active Record models and it runs agents through
|
|
151
|
+
[solid_agent](https://github.com/activeagents/solid_agent) — neither of which
|
|
152
|
+
`activeagent` depends on, so an app that only runs agents installs neither.
|
|
135
153
|
|
|
136
154
|
```bash
|
|
137
|
-
|
|
155
|
+
bundle add actionagent
|
|
156
|
+
rails generate action_agent:install
|
|
138
157
|
rails db:migrate
|
|
139
158
|
```
|
|
140
159
|
|
|
@@ -145,13 +164,14 @@ telemetry:
|
|
|
145
164
|
local_storage: true
|
|
146
165
|
```
|
|
147
166
|
|
|
148
|
-
|
|
167
|
+
The generator mounts the engine at `/activeagents` — open it and every
|
|
168
|
+
generation appears as a trace. See
|
|
149
169
|
[docs/framework/dashboard.md](docs/framework/dashboard.md) for
|
|
150
|
-
authentication, remote ingestion, and multi-tenant mode.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
free low-volume trial.
|
|
170
|
+
authentication, remote ingestion, and multi-tenant mode. The hosted
|
|
171
|
+
platform at [activeagents.ai](https://activeagents.ai) runs this same
|
|
172
|
+
engine multi-tenant, adding what a hosted product has to have — accounts,
|
|
173
|
+
plans, billing, quotas and managed sandboxes; every workspace starts with
|
|
174
|
+
a free low-volume trial.
|
|
155
175
|
|
|
156
176
|
## Features
|
|
157
177
|
|
|
@@ -161,6 +181,7 @@ free low-volume trial.
|
|
|
161
181
|
- **View Templates**: Use ERB templates for prompts (text, JSON, HTML)
|
|
162
182
|
- **Streaming Support**: Real-time response streaming with ActionCable
|
|
163
183
|
- **Tool/Function Calling**: Agents can use tools to interact with external services
|
|
184
|
+
- **Agent-as-Tool Delegation**: Hand work to sub-agents with declared schemas, cost/latency budgets, and swappable backends
|
|
164
185
|
- **Context Management**: Maintain conversation history across interactions
|
|
165
186
|
- **Structured Output**: Define JSON schemas for predictable responses
|
|
166
187
|
|
|
@@ -195,16 +216,39 @@ response = prompt.generate_now
|
|
|
195
216
|
# Response includes tool call results
|
|
196
217
|
```
|
|
197
218
|
|
|
219
|
+
### Delegation
|
|
220
|
+
Hand part of a job to a sub-agent, under a declared contract and a budget:
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
class SummarizerAgent < ApplicationAgent
|
|
224
|
+
generate_with :openai, model: "gpt-4o-mini"
|
|
225
|
+
|
|
226
|
+
delegation :summarize, description: "Condense a document into key points" do
|
|
227
|
+
string :text, required: true, description: "Full document text"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def summarize(text:) = prompt(message: text)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class ResearchAgent < ApplicationAgent
|
|
234
|
+
generate_with :openai, model: "gpt-4o"
|
|
235
|
+
|
|
236
|
+
delegate_to SummarizerAgent, budget: { max_calls: 3, timeout: 20 }
|
|
237
|
+
|
|
238
|
+
def research(topic:) = prompt(message: "Research #{topic}")
|
|
239
|
+
end
|
|
240
|
+
```
|
|
241
|
+
|
|
198
242
|
## Learn More
|
|
199
243
|
|
|
200
244
|
- [Documentation](https://docs.activeagents.ai)
|
|
201
245
|
- [Getting Started Guide](https://docs.activeagents.ai/getting_started)
|
|
202
|
-
- [API Reference](https://docs.activeagents.ai/
|
|
203
|
-
- [Examples](https://docs.activeagents.ai/
|
|
246
|
+
- [API Reference](https://docs.activeagents.ai/framework)
|
|
247
|
+
- [Examples](https://docs.activeagents.ai/agents)
|
|
204
248
|
|
|
205
249
|
## Contributing
|
|
206
250
|
|
|
207
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.
|
|
251
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.MD) for details.
|
|
208
252
|
|
|
209
253
|
## License
|
|
210
254
|
|
data/lib/active_agent/base.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "active_support/core_ext/module/anonymous"
|
|
|
5
5
|
require "active_support/core_ext/string/inflections"
|
|
6
6
|
|
|
7
7
|
require "active_agent/concerns/callbacks"
|
|
8
|
+
require "active_agent/concerns/delegation"
|
|
8
9
|
require "active_agent/concerns/observers"
|
|
9
10
|
require "active_agent/concerns/parameterized"
|
|
10
11
|
require "active_agent/concerns/preview"
|
|
@@ -42,6 +43,7 @@ module ActiveAgent
|
|
|
42
43
|
include AbstractController::Caching
|
|
43
44
|
|
|
44
45
|
include Callbacks
|
|
46
|
+
include Delegation
|
|
45
47
|
include Parameterized
|
|
46
48
|
include Provider
|
|
47
49
|
include Queueing
|
|
@@ -299,18 +301,25 @@ module ActiveAgent
|
|
|
299
301
|
|
|
300
302
|
# @api private
|
|
301
303
|
def prepare_prompt_parameters
|
|
302
|
-
parameters = prompt_options.deep_dup.except(:locals, *PROTECTED_OPTIONS)
|
|
304
|
+
parameters = prompt_options.deep_dup.except(:locals, :delegations, *PROTECTED_OPTIONS)
|
|
303
305
|
|
|
304
306
|
# Render out proc/lamda attributes before rendering templates
|
|
305
307
|
parameters.deep_transform_values! { _1.respond_to?(:call) ? _1.call : _1 }
|
|
306
308
|
|
|
309
|
+
# Expose declared sub-agents (agent-as-tool) alongside the action's own tools
|
|
310
|
+
parameters = apply_delegated_tools(parameters, prompt_options)
|
|
311
|
+
|
|
307
312
|
# Strip parameters the target model rejects (e.g. temperature/top_p
|
|
308
313
|
# on thinking-first models) before they reach the provider.
|
|
309
314
|
ModelCapabilities.sanitize!(parameters)
|
|
310
315
|
|
|
311
316
|
# Apply Callbacks
|
|
317
|
+
#
|
|
318
|
+
# The trace id is written back so it stays stable for the generation and
|
|
319
|
+
# readable from prompt_options — delegated sub-agents inherit it, which
|
|
320
|
+
# is what lets a delegation tree show up as one trace.
|
|
312
321
|
parameters.merge!(
|
|
313
|
-
trace_id: prompt_options[:trace_id]
|
|
322
|
+
trace_id: prompt_options[:trace_id] ||= SecureRandom.uuid,
|
|
314
323
|
exception_handler:,
|
|
315
324
|
stream_broadcaster:,
|
|
316
325
|
tools_function:,
|