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.

@ardaerzin
ardaerzin merged commit 559677b into big-agents Jun 30, 2026
14 of 15 checks passed
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