Skip to content

feat(frontend): agent playground Build/Chat modes#5008

Merged
ardaerzin merged 3 commits into
big-agentsfrom
fe-feat/agent-playground-build-chat-modes
Jul 1, 2026
Merged

feat(frontend): agent playground Build/Chat modes#5008
ardaerzin merged 3 commits into
big-agentsfrom
fe-feat/agent-playground-build-chat-modes

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

Context

The agent playground put the config panel and the chat side by side, with only a small splitter handle to hide one or the other. There was no clear way to focus on the conversation, no home for browsing past sessions, and mode changes snapped instead of animating. Messages also showed no run data and no timestamps.

This adds two explicit modes and fills in the missing chat metadata.

Changes

Build / Chat modes. A persistent segmented switch in the playground header (agent single view) toggles between:

  • Build: the 2-panel edit view (config + chat).
  • Chat: full-screen chat with a session-history side rail; the config pane collapses.

The switch is now the single mode control. The splitter's own collapse/expand handles are removed so there is only one way to change modes.

Session rail (Chat mode). A vertical list of the full session history (the same data the history popover uses), with search, per-session status dots, inline rename, inspect on the active row, and permanent delete. Rows animate in on add and collapse out on remove.

Animated transitions. Switching Build to Chat eases the config pane width, the rail width, and the otherwise-empty chat top-bar height together over 240ms. The transition is armed only around a toggle, so dragging the splitter and resizing the window stay 1:1 with the cursor.

Split sizing fix. The agent config pane used a px default against a percentage runs default, so it mounted wider than its max and snapped smaller on the first drag. It now mounts at its configured width and resizes back cleanly.

Chat body width. Long turns are capped to a centered reading column, so a wide (maximized) panel no longer stretches bubbles and text edge to edge.

Per-message metadata (in the hover toolbar):

  • Run metrics: tokens, cost, and latency when the turn is traced. These were only shown when a trace existed. The token/cost usage stamped on the message itself is now surfaced on the no-trace path too.
  • Timestamps: relative time ("just now", "5m ago", "2h ago") that refreshes on a shared one-minute tick, with the exact date on hover. The time comes from the trace's real start time (the turn's own trace for an assistant message, the paired turn's trace for a user message), and falls back to a client first-seen stamp only when there is no trace.

Notes

  • Backend session load is still a no-op, so message content and the client-stamp fallback come from localStorage. A turn with no trace at all cannot be back-dated (it uses the first-seen stamp); anything with trace info dates correctly.
  • The rail's animated delete is driven by the rail, so a session removed elsewhere (the history popover in Build mode) still disappears without the exit animation.
  • eslint/prettier clean on the touched files. Not yet exercised with live end-to-end runs.

What to QA

  • In an agent playground, use the header Build / Chat switch. Chat maximizes the conversation with the session rail on the left; Build restores the config panel. The change animates, it does not snap.
  • In Chat mode, add a session (rail "+") and delete one. The new row eases in; the deleted row collapses out and the list closes the gap.
  • Search the rail, rename a session (double-click the label), and open an older session by clicking its row.
  • Hover an assistant turn. The toolbar shows tokens and cost (plus latency if traced) and a relative timestamp; hover the timestamp for the exact date.
  • Open a session that is a couple of days old with trace info. The timestamps read "Xd ago", not "just now".
  • Regression: the prompt (non-agent) playground still shows the normal splitter with its collapse handles and no Build/Chat switch.

Add a two-mode agent playground driven by a persistent Build/Chat header
switch, with animated transitions between the 2-panel edit view and a
full-screen chat.

- Header Build/Chat segmented switch (agent single-view) as the single mode
  control; remove the splitter's own collapse/expand handles
- Full-screen Chat mode: config pane collapses and a session-history side rail
  slides in (search, status dots, inline rename, inspect, animated add/remove);
  the now-empty chat top bar collapses away
- Animate Build<->Chat: config flex-basis, rail width and top-bar height ease
  together, armed only around a toggle so drag/window-resize stay 1:1
- Fix agent config split sizing so it mounts at its max width and no longer
  jumps on the first drag
- Center the chat body in a max-width reading column so wide panels don't sprawl
- Surface per-message run metrics (tokens/cost, latency when traced) even on the
  no-trace path
- Show per-message timestamps (relative, self-refreshing) sourced from the
  trace's real start time, falling back to a client first-seen stamp
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jul 1, 2026
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 1, 2026 8:16pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d516d7e1-26e2-4ae1-892f-6e90c0000e79

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a full-screen maximize mode for the agent chat panel, with a new session rail, trace-derived message timestamps, and coordinated playground splitter/header behavior driven by a shared maximize atom.

Changes

Agent chat maximize mode, session rail, and message timestamps

Layer / File(s) Summary
Message created-at stamping and time helpers
web/oss/src/components/AgentChatSlice/state/sessions.ts, web/oss/src/components/AgentChatSlice/components/SessionHistoryMenu.tsx
Adds per-message created-at storage, a stamping write atom, timeAgo formatting, and nowTickAtom, and reuses the shared timeAgo helper in session history.
AgentMessage timestamp and metrics rendering
web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
Adds trace-based timestamps, turnTraceId support, timestamp toolbar rendering, and fallback execution metrics when no trace metrics are available.
Chat panel layout and rail wiring
web/oss/src/components/AgentChatSlice/AgentChatPanel.tsx, web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx, web/oss/src/components/AgentChatSlice/state/panelLayout.ts
Centers the conversation column, stamps messages on change, computes paired trace ids for user turns, and collapses the session rail and tab bar when the panel is maximized.
Session rail and playground splitter
web/oss/src/components/AgentChatSlice/components/SessionRail.tsx, web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx, web/oss/src/components/Playground/Components/MainLayout/index.tsx, web/oss/src/styles/globals.css
Renders the searchable session navigator with animated rows and row actions, and wires the chat/build toggle into splitter sizing, collapse behavior, and splitter styling.

Estimated code review effort: 3 (Moderate) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PlaygroundHeader
    participant chatPanelMaximizedAtom
    participant AgentChatPanel
    participant SessionRail
    participant MainLayout

    User->>PlaygroundHeader: Click "Chat" segmented control
    PlaygroundHeader->>chatPanelMaximizedAtom: setChatMaximized(true)
    chatPanelMaximizedAtom-->>AgentChatPanel: chatMaximized = true
    AgentChatPanel->>SessionRail: collapse width to 0, set inert
    AgentChatPanel->>AgentChatPanel: collapse SessionTagBar, hide extras
    chatPanelMaximizedAtom-->>MainLayout: chatMaximized = true
    MainLayout->>MainLayout: compute configCollapsed, animateSplit
    MainLayout->>MainLayout: apply playground-splitter-animated class
Loading

Possibly related PRs

  • Agenta-AI/agenta#4850: Both PRs modify the same chat-rendering components, including AgentChatPanel.tsx and AgentMessage.tsx, around trace-related message rendering.
  • Agenta-AI/agenta#4927: Both PRs modify AgentChatPanel.tsx around the chat composer and panel wiring.
  • Agenta-AI/agenta#4983: Both PRs touch the session bar flow and SessionTagBar behavior used by the agent chat panel.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: adding Build/Chat modes to the agent playground.
Description check ✅ Passed The description is detailed and directly matches the changes in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fe-feat/agent-playground-build-chat-modes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added enhancement New feature or request Frontend labels Jul 1, 2026
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
web/oss/src/styles/globals.css (1)

157-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Splitter transitions don't respect prefers-reduced-motion.

The flex-basis/opacity transitions added here have no reduced-motion guard, whereas SessionRailRow in this same cohort uses Tailwind's motion-safe: variant for its animations. Consider wrapping these in @media (prefers-reduced-motion: no-preference) for consistency.

♿ Proposed fix
+@media (prefers-reduced-motion: no-preference) {
 .playground-splitter-animated .ant-splitter-panel {
     transition: flex-basis 240ms cubic-bezier(0.4, 0, 0.2, 1);
 }
+}

 /* Full-screen chat: the config panel is 0-width and driven by the header Build/Chat switch, so
    fade the (now inert) split bar out rather than snapping it away. */
+@media (prefers-reduced-motion: no-preference) {
 .playground-splitter .ant-splitter-bar {
     transition: opacity 200ms ease;
 }
+}
web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx (1)

204-221: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Redundant duplicate subscription for assistant messages.

For an assistant message, traceId is truthy so both ownSummary (Line 216) and timeSummary (Line 220) resolve to traceDataSummaryAtomFamily(traceId) — the same atom read twice via two separate useAtomValue calls. Consider deriving traceError from timeSummary (or vice versa) when traceId is set, and only reading the second atom for the user-turn (turnTraceId) case.

♻️ Possible consolidation
-    const ownSummary = useAtomValue(traceDataSummaryAtomFamily(traceId ?? null))
-    const traceError = ownSummary.error
-    // Timestamp uses the run's real start: own trace for an assistant turn, the paired turn trace for
-    // a user turn (shares the same cached atom, so no extra fetch). Falls back to the client stamp.
-    const timeSummary = useAtomValue(traceDataSummaryAtomFamily((traceId || turnTraceId) ?? null))
+    // Timestamp uses the run's real start: own trace for an assistant turn, the paired turn trace for
+    // a user turn (shares the same cached atom, so no extra fetch). Falls back to the client stamp.
+    const timeSummary = useAtomValue(traceDataSummaryAtomFamily((traceId || turnTraceId) ?? null))
+    // For an assistant turn, timeSummary already reads the own trace — reuse it instead of a second subscription.
+    const ownSummary = traceId ? timeSummary : useAtomValue(traceDataSummaryAtomFamily(null))
+    const traceError = ownSummary.error

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 464f952c-24e9-4fd4-9a17-7ec04d65c867

📥 Commits

Reviewing files that changed from the base of the PR and between 91ad02f and 9b9da25.

📒 Files selected for processing (10)
  • web/oss/src/components/AgentChatSlice/AgentChatPanel.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/components/SessionHistoryMenu.tsx
  • web/oss/src/components/AgentChatSlice/components/SessionRail.tsx
  • web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx
  • web/oss/src/components/AgentChatSlice/state/panelLayout.ts
  • web/oss/src/components/AgentChatSlice/state/sessions.ts
  • web/oss/src/components/Playground/Components/MainLayout/index.tsx
  • web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx
  • web/oss/src/styles/globals.css

Comment thread web/oss/src/components/AgentChatSlice/components/SessionRail.tsx
Comment on lines +249 to +255
/** Per-message first-seen timestamp (ms), keyed by message id. `UIMessage`s carry no time and user
* turns get no server metadata, so we stamp it locally when a message first appears; persisted so a
* reloaded session keeps its times. */
export const messageCreatedAtMapAtom = atomWithStorage<Record<string, number>>(
"agenta:agent-message-created-at",
{},
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether session/message deletion paths prune messageCreatedAtMapAtom.
rg -n "messageCreatedAtMapAtom|deleteSessionAtomFamily|persistSessionMessagesAtom" web/oss/src/components/AgentChatSlice/state/sessions.ts -A5 -B5

Repository: Agenta-AI/agenta

Length of output: 2273


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the full session state file around delete/persist/stamp logic.
sed -n '1,360p' web/oss/src/components/AgentChatSlice/state/sessions.ts

# Look for any cleanup/reset of the persisted timestamp map or related storage atoms.
rg -n "agenta:agent-message-created-at|messageCreatedAtMapAtom|removeItem\\(|RESET|reset.*Atom|clear.*Atom|deleteSessionAtomFamily|persistSessionMessagesAtom" web/oss/src/components/AgentChatSlice -S

Repository: Agenta-AI/agenta

Length of output: 17622


Prune messageCreatedAtMapAtom when deleting a session web/oss/src/components/AgentChatSlice/state/sessions.ts:202-270deleteSessionAtomFamily removes the session’s messages, but the per-message timestamp map keeps those ids forever. Clearing the matching entries here keeps agenta:agent-message-created-at bounded and avoids eventual localStorage quota errors.

- SessionRail: track pending delete timers and clear them on unmount so a
  mid-animation unmount can't fire deleteSession against a stale scope
- Message timestamps: keep the first-seen fallback map in memory instead of
  localStorage (the trace start time is authoritative); removes the unbounded,
  lifecycle-unmanaged persisted store rather than pruning it per delete
- Respect prefers-reduced-motion for all Build/Chat transitions: gate the
  splitter flex-basis/bar-fade in globals.css behind a media query and add
  motion-safe to the rail-width and top-bar-height transitions
- AgentMessage: read the paired-turn trace summary only for user turns, so an
  assistant turn no longer subscribes to the same trace atom twice
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Frontend size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant