Uh oh!
There was an error while loading. Please reload this page.
fix(actionagent): register observed agents when a trace is ingested - #363
Merged
Conversation
AgentRegistrar has existed since the engine shipped, is documented as the thing that gives telemetry-only agents an identity, and is never called — only referenced from comments. The result is the exact failure its own docstring describes: an agent running inside a host app never authors a dashboard record, so the Agents list reads 0 while Traces and Interactions are full of that agent's runs. Everything downstream of that identity is empty too. agent_id stays null on every trace, so per-agent traces, interactions, metrics, evaluations and versions have nothing to scope to, and the agent pages do not exist. create_from_payload is the single funnel every ingest path goes through — the API controller, ProcessTelemetryTracesJob, AgentExecutionService, and the local_storage store — so registering there covers all of them. The registrar was already written for this: identity is (owner, service_name, agent_class, action_name), it caps observed records per owner, it adopts the winner on a concurrent RecordNotUnique, and it never raises. A regression test covers that last property by stubbing the instance rather than the class method, so the real rescue runs. Worth noting the platform app carries this as a workaround in its own TelemetryTrace subclass, which is why the hosted dashboard lists agents and a self-hosted mount does not. That override can be dropped once this ships. Verified against a self-hosted mount: two agents registered themselves from live traces with correct class/action, and their agent pages, per-agent traces and interactions all populated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TonsOfFun
marked this pull request as ready for review
August 14, 2026 23:49
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
The bug
A self-hosted mount shows Agents: 0 while Traces and Interactions are full of that agent's runs.
AgentRegistrarhas shipped with the engine since the split, is well written (identity is(owner, service_name, agent_class, action_name), caps observed records per owner, adopts the winner on a concurrentRecordNotUnique, never raises) — and is never called. It appears only in comments.Its own docstring describes the exact failure:
Why it matters beyond the count
agent_idstays null on every ingested trace, so everything that scopes to an agent is empty: per-agent Traces, Interactions, Metrics, Evals, Versions, and the agent detail page itself. For a host app reporting telemetry — the whole self-hosted story — the Agents section is inert.The fix
One line in
create_from_payload, which is the single funnel every ingest path already goes through: the API controller,ProcessTelemetryTracesJob,AgentExecutionService, and thelocal_storagestore.Note on the platform app
activeagents.aicarries this as a workaround in its ownTelemetryTracesubclass, which is why the hosted dashboard lists agents and a self-hosted mount does not. That override can be dropped once this ships.Verification
Against a self-hosted mount with
local_storage: true, starting from an empty telemetry DB:CourseBuilderChatAgent(2 turns) andQuizBlueprintAgent(1) from a host appagent_class_name/action_name, statusobservedagent_idsetregenerate_quiz, calls=1), which also depends on this attributionDistinct actions on one class register separately, as designed —
DocumentEnrichmentAgent.extract_page_summaries_batchand.extract_document_sectionsare different agents.Tests
Three added to
actionagent/test/telemetry_trace_test.rb: registration on ingest with attribution, reuse across repeated ingests, and that a registration failure does not fail ingest. The last stubsAgentRegistrar.newrather than.call, so the real rescue runs instead of the stub.ActiveSupport::MessageEncryptor::InvalidMessage, no master key), which breaks existing tests on a clean tree too. Relying on CI here.Risk
Low, and bounded by the registrar's own guarantees: it never raises, so a registration failure cannot cost a host app its telemetry;
MAX_OBSERVED_PER_OWNERbounds runaway creation from a misconfigured reporter; and it returns early whenagent_idis already set, so re-ingest is idempotent.🤖 Generated with Claude Code