Skip to content

feat(frontend): tag-style agent playground session bar + chat UI polish - #4983

Merged
ardaerzin merged 3 commits into
big-agentsfrom
fe-feat/agent-playground-session-bar
Jun 30, 2026
Merged

feat(frontend): tag-style agent playground session bar + chat UI polish#4983
ardaerzin merged 3 commits into
big-agentsfrom
fe-feat/agent-playground-session-bar

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

What

UI pass on the agent playground (config panel, session tabs, and the chat composer).

Session bar → tags. The editable-card session tabs are replaced with a tag/chip bar (SessionTagBar), rendered through Tabs renderTabBar so the panes — and each session's live useChat stream / HITL approval state — keep antd's mount semantics. Each chip has a run-status dot, a truncated label (double-click to rename), and a hover close. The bar is a fixed 48px row with a bottom border so its bottom edge lines up with the config panel header on the left.

One source of truth for session status. big-agents had a per-session streaming boolean and this branch added a richer run-state; they're unified into sessionStatusAtomFamily (idle | running | awaiting | error). The Session Inspector's "is streaming" signal now derives from it instead of a competing flag.

Fixes

  • Trace/actions toolbar overlap — the per-message hover toolbar was centered on the bubble's bottom edge and sat on the last line of content. It now lives in a reserved lane below the bubble (no overlap, no hover-driven layout shift).
  • Config header bleed-through — the agent config header is sticky; its tint was a translucent fill, so scrolled content showed through it. The tint is now composited over an opaque surface (theme-aware, light + dark).
  • Composer double border — the rich composer's toolbar carried its own border-t on top of the container border, reading as a doubled bottom edge. Removed the redundant divider.
  • Composer width regression — after dropping the panel's padding (so the session bar could align with the config header), the composer spanned full width and touched the panel edges. Re-inset it to match the message gutter.
  • Session-tab buttons — the close / add controls were raw <button>s, which keep native browser chrome under this repo's disabled Tailwind preflight (a stray gray box). Switched to antd Button.

Why

These are all polish/regression fixes on the agent playground surface — alignment, dark-mode correctness, and removing visual artifacts (overlapping toolbar, bled-through header, doubled borders, native button chrome).

Notes

  • Frontend-only; no API or schema changes.
  • Verified with pnpm turbo lint (pre-commit) + tsc on web/oss (no new errors; the agent-touched files are clean). Not yet verified live in the running app — the local dev stack was on a different branch during this work.

- Replace the editable-card session tabs with a tag/chip bar (status dots,
  truncation, double-click rename, hover close) rendered via Tabs
  renderTabBar, so panes and their live useChat streams keep antd mount
  semantics; the bar's bottom edge now aligns with the config panel header.
- Unify per-session run state behind a single source of truth
  (sessionStatusAtomFamily); derive the inspector's streaming flag from it
  instead of a competing boolean.
- Move the per-message trace/actions toolbar into a reserved lane so it no
  longer overlays the last line of content.
- Composite the agent config header tint over an opaque surface so scrolled
  content can't bleed through the sticky header.
- Drop the rich composer's duplicate toolbar divider and re-inset it so it
  no longer touches the panel edges; use antd Button for the session-tag
  controls (raw <button> kept native chrome under disabled Tailwind preflight).
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jun 30, 2026
@vercel

vercel Bot commented Jun 30, 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 Jun 30, 2026 7:22pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 30, 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: f7b426ec-3e71-4dbc-87fb-3538449e6b02

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 replaces per-session boolean streaming state with a SessionRunStatus state machine (idle/running/awaiting/error), introduces a new SessionTagBar chip-based session selector replacing the editable-card tab bar, updates AgentChatPanel wiring accordingly, and applies minor styling adjustments to AgentMessage toolbar positioning, RichChatInput, and PlaygroundVariantConfigHeader.

Changes

Session Run Status and Tag Bar

Layer / File(s) Summary
SessionRunStatus state model
web/oss/src/components/AgentChatSlice/state/sessions.ts
Removes boolean sessionStreamingAtom/setSessionStreamingAtom; adds SessionRunStatus type, sessionStatusAtomFamily, and setSessionStatusAtom (clearing entry on idle); derives isSessionStreamingAtomFamily from status === "running".
SessionTagBar chip UI and SessionTabLabel updates
web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx, web/oss/src/components/AgentChatSlice/components/SessionTabLabel.tsx
New SessionTagBar and SessionStatusDot render a scrollable chip row with per-session status dots, labels, close buttons, and a new-session button; SessionTabLabel adds an optional className prop and adjusted input styling.
AgentChatPanel status publishing and tab wiring
web/oss/src/components/AgentChatSlice/AgentChatPanel.tsx
Publishes computed session run status (error/awaiting/running/idle) via effects, resets on unmount, removes the old streaming effect, and replaces the editable-card tab bar with renderTabBar delegating to SessionTagBar.
Composer and toolbar styling tweaks
web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx, web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx, web/oss/src/components/Playground/Components/PlaygroundVariantConfig/assets/PlaygroundVariantConfigHeader.tsx
AgentMessage toolbar moves into a reserved pb-7 bottom lane anchored at bottom-0; RichChatInput drops a top border divider and gains mx-3 mb-3 margin in AgentChatPanel; PlaygroundVariantConfigHeader uses an opaque base plus translucent gradient background.

Sequence Diagram(s)

sequenceDiagram
  participant AgentConversation
  participant setSessionStatusAtom
  participant sessionStatusAtomFamily
  participant SessionTagBar
  AgentConversation->>setSessionStatusAtom: publish error/awaiting/running/idle
  setSessionStatusAtom->>sessionStatusAtomFamily: update per-session status record
  sessionStatusAtomFamily->>SessionTagBar: status value drives status dot
  AgentConversation->>setSessionStatusAtom: reset to idle on unmount
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • Agenta-AI/agenta#4927: Both PRs modify AgentChatPanel's composer integration with RichChatInput, including streaming/HITL/onStop wiring overlapping the same UI composition layer.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main UI changes to the agent playground session bar and chat polish.
Description check ✅ Passed The description is directly related to the session bar, run-state, and chat composer updates in the changeset.
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-session-bar

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.

@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: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e440e34c-c6ba-4ec8-acb7-2433498cc9cb

📥 Commits

Reviewing files that changed from the base of the PR and between 19e0f2d and d272cc9.

📒 Files selected for processing (7)
  • web/oss/src/components/AgentChatSlice/AgentChatPanel.tsx
  • web/oss/src/components/AgentChatSlice/components/AgentMessage.tsx
  • web/oss/src/components/AgentChatSlice/components/SessionTabLabel.tsx
  • web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx
  • web/oss/src/components/AgentChatSlice/state/sessions.ts
  • web/oss/src/components/Playground/Components/PlaygroundVariantConfig/assets/PlaygroundVariantConfigHeader.tsx
  • web/packages/agenta-ui/src/RichChatInput/RichChatInput.tsx

Comment on lines +70 to +75
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
onSelect()
}
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't let rename keystrokes bubble into tab selection.

When SessionTabLabel swaps in its Input, pressing Space/Enter still bubbles here. That makes space impossible to type into a session name and re-triggers tab selection while renaming.

Suggested fix
             onKeyDown={(e) => {
+                const target = e.target as HTMLElement | null
+                if (target?.closest("input, textarea, [contenteditable='true']")) return
                 if (e.key === "Enter" || e.key === " ") {
                     e.preventDefault()
                     onSelect()
                 }
             }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
onSelect()
}
}}
onKeyDown={(e) => {
const target = e.target as HTMLElement | null
if (target?.closest("input, textarea, [contenteditable='true']")) return
if (e.key === "Enter" || e.key === " ") {
e.preventDefault()
onSelect()
}
}}

Comment thread web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx
Comment on lines +318 to +325
/** Set a session's run state (pass "idle" to clear, e.g. on unmount). */
export const setSessionStatusAtom = atom(
null,
(get, set, {id, status}: {id: string; status: SessionRunStatus}) => {
const cur = get(sessionStatusByIdAtom)
if (cur[id] === status) return
set(sessionStatusByIdAtom, {...cur, [id]: status})
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Actually clear "idle" entries from the backing map.

This setter is documented as the clear path, but it still writes {[id]: "idle"} into sessionStatusByIdAtom. Since sessionStatusAtomFamily already defaults missing keys to "idle", closed sessions will accumulate in-memory for no functional gain.

Suggested fix
 export const setSessionStatusAtom = atom(
     null,
     (get, set, {id, status}: {id: string; status: SessionRunStatus}) => {
         const cur = get(sessionStatusByIdAtom)
         if (cur[id] === status) return
-        set(sessionStatusByIdAtom, {...cur, [id]: status})
+        if (status === "idle") {
+            const {[id]: _removed, ...rest} = cur
+            set(sessionStatusByIdAtom, rest)
+            return
+        }
+        set(sessionStatusByIdAtom, {...cur, [id]: status})
     },
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** Set a session's run state (pass "idle" to clear, e.g. on unmount). */
export const setSessionStatusAtom = atom(
null,
(get, set, {id, status}: {id: string; status: SessionRunStatus}) => {
const cur = get(sessionStatusByIdAtom)
if (cur[id] === status) return
set(sessionStatusByIdAtom, {...cur, [id]: status})
},
/** Set a session's run state (pass "idle" to clear, e.g. on unmount). */
export const setSessionStatusAtom = atom(
null,
(get, set, {id, status}: {id: string; status: SessionRunStatus}) => {
const cur = get(sessionStatusByIdAtom)
if (cur[id] === status) return
if (status === "idle") {
const {[id]: _removed, ...rest} = cur
set(sessionStatusByIdAtom, rest)
return
}
set(sessionStatusByIdAtom, {...cur, [id]: status})
},
)

Comment on lines +169 to +173
// Give it a subtly tinted surface (vs the plain content): an opaque container base
// (background-color) with the translucent fill layered on top (background-image), so
// this sticky header stays opaque and scrolled content can't bleed through it.
isAgent && !embedded
? "bg-[var(--ant-color-fill-tertiary)]"
? "bg-[var(--ag-c-FFFFFF)] bg-[image:linear-gradient(var(--ant-color-fill-tertiary),var(--ant-color-fill-tertiary))]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a theme surface token for the sticky header base.

bg-[var(--ag-c-FFFFFF)] hardcodes a light background on the non-embedded sticky path, so dark mode will render a white header strip instead of an opaque themed surface. Keep the gradient overlay, but swap the base layer to a semantic background token.

Proposed fix
-                    ? "bg-[var(--ag-c-FFFFFF)] bg-[image:linear-gradient(var(--ant-color-fill-tertiary),var(--ant-color-fill-tertiary))]"
+                    ? "bg-[var(--ant-color-bg-container)] bg-[image:linear-gradient(var(--ant-color-fill-tertiary),var(--ant-color-fill-tertiary))]"
                     : "bg-[var(--ag-c-FFFFFF)]"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Give it a subtly tinted surface (vs the plain content): an opaque container base
// (background-color) with the translucent fill layered on top (background-image), so
// this sticky header stays opaque and scrolled content can't bleed through it.
isAgent && !embedded
? "bg-[var(--ant-color-fill-tertiary)]"
? "bg-[var(--ag-c-FFFFFF)] bg-[image:linear-gradient(var(--ant-color-fill-tertiary),var(--ant-color-fill-tertiary))]"
// Give it a subtly tinted surface (vs the plain content): an opaque container base
// (background-color) with the translucent fill layered on top (background-image), so
// this sticky header stays opaque and scrolled content can't bleed through it.
isAgent && !embedded
? "bg-[var(--ant-color-bg-container)] bg-[image:linear-gradient(var(--ant-color-fill-tertiary),var(--ant-color-fill-tertiary))]"
: "bg-[var(--ag-c-FFFFFF)]"

…tatus map)

- Rename input now stops its own keydown so Space is typable and Enter
  doesn't also switch tabs (kept at the editing surface, not the tab handler).
- Reveal the session close button on keyboard focus (group-focus-within),
  not just hover.
- setSessionStatusAtom stores idle as absence: passing "idle" deletes the
  entry so closed sessions don't accumulate in the status map.
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 30, 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Frontend size:L This PR changes 100-499 lines, ignoring generated files. UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant