- Add RunTimeline component with vertical event timeline, collapsible run cards, per-kind icons, status animations, and agent lane badges - Add runTimelineFormatting helpers for timestamps, durations, labels, content truncation, and consecutive thinking-event collapsing - Integrate Timeline section into ActivityPanel between Agents and Tools - Wire jump-to-message in App.tsx using DOM data-message-id attributes on ChatPane messages with smooth scroll and temporary highlight ring - Add comprehensive unit tests for all formatting helpers - Update HANDOVER.md to document completed frontend implementation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8.1 KiB
Rich run timeline handover
This change implements the backend half of the Rich run timeline roadmap item and leaves the actual timeline UI/UX for the next agent.
What is done
- Persisted structured run history on every
SessionRecord - Added a shared run/timeline domain model for durable per-run metadata and ordered timeline events
- Started a new run record whenever
sendSessionMessage(...)kicks off a turn - Grouped streamed assistant output into a single timeline message event keyed by
messageId - Persisted timeline updates during agent activity, message streaming, completion, and failure
- Added explicit handoff source metadata so the future UI can draw source/target handoff edges
- Added a live
run-updatedsession event so the renderer can receive timeline changes incrementally without waiting for a full workspace refresh - Kept duplicate-session behavior simple and safe: duplicated sessions copy transcript/tooling config but start with
runs: []
Important files
src/shared/domain/runTimeline.ts- New shared types and helpers:
SessionRunRecordRunTimelineEventRecordcreateSessionRunRecord(...)appendRunActivityEvent(...)upsertRunMessageEvent(...)completeSessionRunRecord(...)failSessionRunRecord(...)
- New shared types and helpers:
src/shared/domain/session.tsSessionRecordnow includesruns: SessionRunRecord[]
src/main/persistence/workspaceRepository.ts- Normalizes persisted
session.runs
- Normalizes persisted
src/main/EryxAppService.ts- Creates and updates run records during turn execution
- Emits live
run-updatedsession events
src/shared/domain/event.ts- Added session event kind
run-updated - Added optional
runpayload onSessionEventRecord
- Added session event kind
src/renderer/lib/sessionWorkspace.ts- Applies
run-updatedevents by replacing/inserting the full run snapshot
- Applies
src/shared/contracts/sidecar.tsAgentActivityEventnow carries optionalsourceAgentId/sourceAgentName
sidecar/src/Eryx.AgentHost/Contracts/ProtocolModels.cs- C# DTO mirror for the new handoff source fields
sidecar/src/Eryx.AgentHost/Services/CopilotWorkflowRunner.cs- Handoff activity now includes the active/source agent when available
Backend contract
Session shape
Every session now has:
runs: SessionRunRecord[]
Runs are stored newest-first.
SessionRunRecord
Key fields:
idrequestIdprojectIdprojectPathworkspaceKindpatternIdpatternNamepatternModetriggerMessageIdstartedAtcompletedAt?statusagentsevents
agents is the per-run lane metadata the UI should use for lane headers / agent grouping.
RunTimelineEventRecord
Event kinds:
run-startedthinkinghandofftool-callmessagerun-completedrun-failed
Useful payload fields:
occurredAtupdatedAt?statusagentId/agentNamesourceAgentId/sourceAgentNametargetAgentId/targetAgentNametoolNamemessageIdcontenterror
Live update event
The renderer now receives:
{
sessionId: string;
kind: 'run-updated';
occurredAt: string;
run: SessionRunRecord;
}
This is a full run snapshot, not a delta patch. The reducer already replaces/upserts the run for the selected session.
Current runtime behavior
Run start
sendSessionMessage(...) now:
- appends the user message
- creates a new
SessionRunRecord - persists the workspace
- starts the turn
The initial run contains a run-started event pointing at triggerMessageId.
Thinking / handoff / tool activity
Agent activity events now append timeline entries:
thinkinghandofftool-call
For handoffs, the backend now stores both source and target when the source agent is known.
Streamed assistant output
Message streaming is grouped into one message event per messageId.
During streaming:
- the existing message event is updated in place
statusstaysrunningcontentholds the latest snapshotupdatedAtadvances
On completion:
- the same event becomes
status: 'completed' - final content is persisted
Run completion / failure
Successful runs append run-completed.
Failed runs append run-failed and also mark any still-running message events as errored.
Notes for the UI/UX agent
You do not need new IPC or backend endpoints for the first timeline UI pass.
Use:
session.runsfor initial render / reload- live
run-updatedsession events for in-flight changes
Suggested UI plan:
- Replace or reframe the current agent-activity tiles around the run model instead of mixing unrelated tiles together.
- Show runs newest-first in the side panel.
- Inside a run, render a vertical timeline ordered by
events[]. - Use
agents[]to build per-agent lanes or grouped headers. - Render
messageevents as the coherent answer step for streamed assistant output. - Use
messageIdandtriggerMessageIdfor jump-to-message actions. - Use
agentId,sourceAgentId, andtargetAgentIdfor jump-to-agent / handoff visuals.
UX-specific suggestions
run-started: compact start card linked to the triggering user messagethinking: lightweight state card or inline badge in the agent lanehandoff: directional edge/card from source -> targettool-call: small tool chip/card with tool name and agentmessage: the main rich output card; this is the item that should expand/collapse cleanlyrun-completed/run-failed: footer-style terminal state card
Known limitations / open questions
- There is no dedicated persisted
completedactivity event. Final assistant output plusrun-completedis the canonical completion signal for now. - Tool results are not persisted yet; only tool invocation metadata is stored.
- Pattern version metadata is not persisted yet; only
patternId,patternName, andpatternModeare captured. - Duplicate sessions intentionally start with empty run history. If product wants copied traces later, that needs an explicit decision.
- Live
run-updatedevents currently send the full run snapshot each time. That keeps the reducer simple; optimize later only if payload size becomes a problem.
Frontend implementation (completed)
The UI has been implemented with the following files:
src/renderer/lib/runTimelineFormatting.ts— formatting helpers for timestamps, durations, event labels, and a thinking-event collapsing algorithmsrc/renderer/components/RunTimeline.tsx— the main timeline UI component with collapsible run cards, vertical timeline connector lines, event icons, and jump-to-message supportsrc/renderer/components/ActivityPanel.tsx— updated to include a Timeline section between Agents and Toolssrc/renderer/App.tsx— wiredonJumpToMessagecallback that scrolls to the target message with a temporary highlight ringsrc/renderer/components/ChatPane.tsx— addeddata-message-idattributes on message elements for DOM-based scroll targetingtests/renderer/runTimelineFormatting.test.ts— unit tests for all formatting helpers
UI features
- Collapsible run cards — newest first, auto-expanded for the latest run, with pattern name and live status badge
- Vertical timeline — ordered event list with connector lines and per-kind icons (Brain for thinking, ArrowRight for handoff, Wrench for tool-call, MessageSquare for message, etc.)
- Thinking collapse — consecutive thinking events from the same agent are collapsed into a single "×N" row
- Message preview — message events show a truncated content preview
- Jump to message — clicking a message or run-started event scrolls the ChatPane to the corresponding message with a brief indigo highlight ring
- Agent badges — multi-agent runs show agent lane badges at the top of the expanded timeline
- Duration footer — completed runs show total wall-clock duration
- Status animations — running events pulse, completed events show green checks, failed events show red alerts
Validation completed
bun run typecheckbun test(81 tests, 0 failures)bun run sidecar:test(55 tests, 0 failures)bun run build