Skip to content

One expandable-object design for traces, spans and interactions (into #353) - #354

Merged
TonsOfFun merged 2 commits into
claude/activeagents-local-engine-ky54n7from
claude/dashboard-traces-interactions-expand-6eitzf
Aug 13, 2026
Merged

One expandable-object design for traces, spans and interactions (into #353)#354
TonsOfFun merged 2 commits into
claude/activeagents-local-engine-ky54n7from
claude/dashboard-traces-interactions-expand-6eitzf

Conversation

@TonsOfFun

Copy link
Copy Markdown
Contributor

Targets #353's branch, not main — this is dashboard work that was written against the platform's copy of the components before #353 moved them into actionagent. Merging it here keeps it with the engine; the version against the old location (#103) is superseded and should be closed.

Why it ported cleanly

The engine's copies of the three files I'd changed are byte-identical to what I started from in the platform, apart from one adaptation each — hardcoded /dashboard/… links became dashboardPath(…). So this is the same change plus those paths, plus the portable rewrite the engine needs.

What was wrong

Traces kept two render trees — a dark one built from the landing page's stylesheet (.span-row, .trace-header-row) and a light one built from Tailwind utilities — and they had drifted. Dark mode never got the Spans/Conversation toggle, the span sorting, the log-scale bars for non-chronological orders, or the tool roster in span details. Interactions showed the same runs from the conversation side with a third set of affordances again: no content preview on a collapsed row, and a mini waterfall whose spans couldn't be opened at all.

Everything now composes the same primitives, so a trace, a span, a span's contents, an interaction and a generation are the same object at different scales.

  • TelemetryObject.jsx — the shared chrome: card, chevron, input:/output: preview lines, segmented sub-view control, ▸ key: content disclosure, and one theme-aware palette.
  • SpanWaterfall.jsx — a trace's spans, with per-span expansion and the detail panel (contents lifted into a conversation, tool roster, remaining attributes as individually expandable lines).
  • TraceDetail.jsx — the whole trace panel: Spans/Conversation, span sort, context pressure, generation-vs-tools breakdown, tokens, error. It owns its own conversation fetch.
  • TraceCard.jsx — one trace as a row, rendered by both themes.
  • TraceSpanBar.jsx (was TraceSpanPills.jsx) — reduced to the collapsed pill summary; expansion is now the shared waterfall.

Interactions gain the same Conversation | Spans toggle, and each generation is an expandable object that opens the very panel Traces opens. Preview lines open in place — JSON indents, prose wraps, both cap at 320px and scroll — because the value you're already reading is the one you want in full, and making you open the whole span to get at it was a detour.

TracesView.jsx drops ~1000 lines along the way.

Engine-specific changes

  • DISTINCT ON is gone. The collapsed-row previews need the first and last message per context. The platform version used DISTINCT ON; this takes the min/max id per context instead — messages are only ever appended, so the ends of the stream are the smallest and largest ids. That's the same portable pass the latest-model lookup right beside it already uses, and it runs on SQLite.
  • Mount-relative links. Client-side hrefs go through dashboardPath; fetch('/api/…') stays absolute for the entry point's shim.
  • Build output refreshed (app/assets/builds/action_agent.{js,css}), since committing it is what lets a host app skip the JavaScript build.
  • InteractionPreview holds the truncation rule both sources share.

Testing

  • Engine suite: 48 runs, 203 assertions, 0 failures on SQLite via gemfiles/rails8.gemfile — 42 before, plus 6 new in actionagent/test/interaction_preview_test.rb covering both interaction sources, the tool-calling turn that carries no prose, per-context isolation, empty streams, and clipping.
  • bin/rubocop clean on the changed Ruby.
  • npm run build clean; verified the minified bundle carries the new code.
  • The UI itself was driven in a running app at the previous location, where these components are identical: every state in both themes — trace list, trace expanded, span details, prompt span with tool roster, sort-by-slowest, Conversation tab, interaction list and conversation, the Spans tab, a generation expanded, and in/out opened in place.

Review notes

  • frontend/package-lock.json picks up a two-line rename (active-agent-dashboardaction-agent-dashboard) that npm corrected on install — Extract the dashboard into the actionagent gem, with feature parity #353 renamed the package but not the lockfile. Unrelated to this diff; reverting it would only re-dirty on the next install.
  • The dark-mode Traces page header wraps its subtitle into a narrow column and overflows horizontally below ~1300px. Pre-existing, in markup this change doesn't touch — happy to fix separately.

Generated by Claude Code

TonsOfFun pushed a commit to activeagents/activeagents that referenced this pull request Aug 13, 2026
Lockfile only: the actionagent branch these views live on was rebased onto
activeagents/activeagent#354, so the pinned revision moves with it.
solid_agent stays at 0.1.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BoEMwqrTweQW7rSuiJLqSG
@TonsOfFun
TonsOfFun marked this pull request as ready for review August 13, 2026 18:47
@TonsOfFun
TonsOfFun force-pushed the claude/dashboard-traces-interactions-expand-6eitzf branch from f773179 to 7f10edf Compare August 13, 2026 22:30
claude added 2 commits August 13, 2026 22:38
Ported from #103, which was written against the platform's copy
of the dashboard before it moved into this gem. The engine's components were
byte-identical to that copy apart from mount-relative paths, so this is that
work plus those paths — and the portable rewrite the engine needs.

Traces kept two render trees, a dark one built from the landing page's
stylesheet and a light one built from Tailwind utilities, and they had
drifted. Dark mode never got the Spans/Conversation toggle, the span sorting,
the log-scale bars for non-chronological orders, or the tool roster in span
details. Interactions showed the same runs from the conversation side with a
third set of affordances again: no content preview on a collapsed row, and a
mini waterfall whose spans couldn't be opened.

Everything now composes the same primitives:

- TelemetryObject: the card, chevron, input/output preview lines, segmented
  sub-view control, and content disclosure every expandable telemetry object
  shares, plus one theme-aware palette.
- SpanWaterfall: a trace's spans, with per-span expansion and the detail
  panel — contents as a conversation, tool roster, attributes.
- TraceDetail: the whole trace panel — Spans/Conversation, sort, context
  pressure, generation-vs-tools, tokens, error.
- TraceCard: one trace as a row, rendered by both themes.
- TraceSpanBar (was TraceSpanPills): reduced to the collapsed pill summary,
  since expansion is now the shared waterfall.

Interactions gain the same Conversation/Spans toggle, and each generation is
an expandable object opening the very panel Traces opens. Preview lines open
in place: JSON indents, prose wraps, both cap and scroll — the value you are
reading is the one you want in full.

Collapsed rows carry input/output lines on both sides of the API. The
platform version read them with DISTINCT ON; the engine runs on SQLite too,
so this takes the min/max id per context instead — messages are only ever
appended, which is the same pass the latest-model lookup beside it already
uses.

Client-side links go through dashboardPath so they follow the mount; fetches
stay absolute for the entry point's shim. Build output is refreshed, since
that is what lets a host app skip the JavaScript build.
JSON.parse raises TypeError, not ParserError, when handed a Hash or an
Array. A reporter that posts tool.arguments or prompt.input.messages as
real JSON rather than as a JSON string therefore took down the entire
Interactions list, not just its own row — and the trace ingest endpoint
accepts unauthenticated posts in local mode, so one bad row is easy to
come by. Both readers now pass a decoded value straight through.
@TonsOfFun
TonsOfFun force-pushed the claude/dashboard-traces-interactions-expand-6eitzf branch from 7f10edf to 3e7fc5a Compare August 13, 2026 22:39
TonsOfFun pushed a commit that referenced this pull request Aug 13, 2026
…eractions-expand-6eitzf

One expandable-object design for traces, spans and interactions
@TonsOfFun
TonsOfFun merged commit 3e7fc5a into main Aug 13, 2026
6 checks passed
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