feat(dashboard): give Agent a generations association - #469
Merged
Merged
Conversation
`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
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ActionAgent::Agentdeclared five associations but not the one a host most often wants: the generations recorded against the agent.Generations hang off
AgentContextpolymorphically, so reaching them meant knowing that shape and writing the join by hand: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: :contextableandhas_many :generations, through: :agent_contextsonAgent.AgentContextalready declaredhas_many :generations, so thethrough:needs no explicit source.sample_generationsuses the association, so there is one definition rather than two. Ordering is unchanged — hash-formorder(created_at: :desc)is qualified to the generations table either way.agent.generationsstays a scope, soagent.generations.countanswers 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: :destroyonagent_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
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.... bin/test— 2035 runs, 0 failures. (The 34 errors are this sandbox blocking outbound HTTP; the identical set is present before the change.)bin/lint— 552 files, no offenses.Screenshots
N/A — no visual surface.
Closes
Closes #464
Special Handling
🤖 Generated with Claude Code
https://claude.ai/code/session_01J9cRpVTtxA8QZBTmnYSC7V
Generated by Claude Code