Skip to content

feat(dashboard): give Agent a generations association - #469

Merged
TonsOfFun merged 3 commits into
release/1.6.3from
feat/agent-generations-association
Sep 18, 2026
Merged

TonsOfFun merged 3 commits into
release/1.6.3from
feat/agent-generations-association

Conversation

@TonsOfFun

Copy link
Copy Markdown
Contributor

ActionAgent::Agent declared five associations but not the one a host most often wants: the generations recorded against the agent.

Generations hang off AgentContext polymorphically, so reaching them meant knowing that shape and writing the join by hand:

AgentGeneration.joins(:agent_context)
  .where(AgentContext.table_name => { contextable: agent })

The engine already wrote exactly that, in EvaluationRunnerService#sample_generations — but as a private method on a service, so a host could not reuse it and copied the join instead. That couples host code to an implementation detail of how contexts are modelled, and a change to it breaks the host silently rather than at the engine boundary.

Changes

  • has_many :agent_contexts, as: :contextable and has_many :generations, through: :agent_contexts on Agent. AgentContext already declared has_many :generations, so the through: needs no explicit source.
  • sample_generations uses the association, so there is one definition rather than two. Ordering is unchanged — hash-form order(created_at: :desc) is qualified to the generations table either way.

agent.generations stays a scope, so agent.generations.count answers the "has this agent actually run?" question the dashboard's own views had no cheap way to ask.

One deliberate deviation from the issue

The issue suggested dependent: :destroy on agent_contexts, and the four sibling associations do use it. This does not, and a test pins that.

Destroying an agent has never taken its conversations with it. An association added so that history can be read should not quietly begin deleting it, and doing so in a patch release would be a silent data-loss change for any host that destroys agents. If the cascade is wanted it is worth its own decision and its own note in the changelog.

UAT Steps

  1. BUNDLE_GEMFILE=gemfiles/rails8.gemfile bin/test actionagent/test/agent_generations_association_test.rb actionagent/test/evaluation_runner_service_test.rb — 6 runs, 0 failures.
  2. Full suite: ... bin/test — 2035 runs, 0 failures. (The 34 errors are this sandbox blocking outbound HTTP; the identical set is present before the change.)
  3. bin/lint — 552 files, no offenses.

Screenshots

N/A — no visual surface.

Closes

Closes #464

Special Handling

  • This PR requires user testing
  • Include this PR in the changelog

🤖 Generated with Claude Code

https://claude.ai/code/session_01J9cRpVTtxA8QZBTmnYSC7V


Generated by Claude Code

`ActionAgent::Agent` declared five associations but not the one a host most
often wants. Generations hang off `AgentContext` polymorphically, so reading
them meant knowing that shape and writing the join by hand:

    AgentGeneration.joins(:agent_context)
      .where(AgentContext.table_name => { contextable: agent })

The engine already wrote exactly that, in `EvaluationRunnerService#sample_generations`
— but as a private method on a service, so a host could not reuse it and copied
the join instead, coupling itself to an implementation detail of how contexts
are modelled. A change to that shape would then break host code silently rather
than at the engine boundary.

`agent.generations` is now that one definition, and `sample_generations` uses
it. It stays a scope, so `agent.generations.count` answers the "has this agent
actually run?" question the dashboard's own views had no cheap way to ask.

Deliberately no `dependent:` on `agent_contexts`. The issue suggested
`dependent: :destroy` and the sibling associations use it, but destroying an
agent has never taken its conversations with it, and quietly starting to delete
recorded history in a patch release is not something an association added for
reading should do. A test pins the current behaviour; changing it is a separate
call.

Closes #464

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J9cRpVTtxA8QZBTmnYSC7V
@TonsOfFun
TonsOfFun merged commit 4777f0f into release/1.6.3 Sep 18, 2026
8 checks passed
TonsOfFun added a commit that referenced this pull request Sep 18, 2026
chore(release): activeagent and actionagent 1.6.3

Brings main up to the 1.6.3 release line: context-meter token attribution
(#458), host-adapter metering, provider validation and on_removed (#460),
evaluation trace correlation (#465), the judge call kind (#468, closes #462),
Agent#generations (#469, closes #464), and the host-adapter docs (#466).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants