[feat] Warm brand recolor and agent playground UX rework - #5943
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe changes add persisted agent configuration-panel controls, responsive session navigation, bounded sidebar resizing, theme-aware palettes and charts, and updated layout, surface, and status styling across the application. ChangesAgent chat and session navigation
Theme and chart color system
Resizable sidebar
Playground revision and configuration layout
Agent home and entity configuration surfaces
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
Railway Preview Environment
Updated at 2026-08-12T09:18:34.200Z |
There was a problem hiding this comment.
Actionable comments posted: 11
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/oss/src/components/pages/observability/dashboard/AnalyticsDashboard.tsx (1)
110-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep an error color for
failure_count.The Requests chart previously painted the second series with
rose, which marked failures. The shared props no longer setcolors, sofailure_countnow takes the second categorical slot. Failures lose their error semantics in the chart.
CustomAreaChartPropsstill acceptscolors. Pass an explicit error color for the failure series.🎨 Proposed fix to mark the failure series
<CustomAreaChart {...defaultGraphProps} categories={ (data?.failure_rate ?? 0) > 0 ? ["success_count", "failure_count"] : ["success_count"] } + colors={ + (data?.failure_rate ?? 0) > 0 + ? [undefined as unknown as string, "var(--ag-colorError)"] + : undefined + } />
resolveColorreadscolors?.[idx] ?? series[idx % series.length], so anundefinedfirst entry keeps the theme series color forsuccess_count. If you prefer a cleaner contract, widencolorsto(string | undefined)[]inCustomAreaChart.tsx.
🟡 Minor comments (11)
web/oss/src/components/Sidebar/hooks/useSidebarResize.ts-43-43 (1)
43-43: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winRestore global styles on every drag termination path.
If
SidebarShellunmounts during a drag,user-select: noneandcursor: col-resizeremain ondocument.body. Store the previous inline values and restore them from shared cleanup used by pointer end, pointer cancellation, and effect cleanup.web/oss/src/components/Playground/Components/AgentCommitNotice.tsx-59-59 (1)
59-59: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUse the generated agent theme tokens.
Replace the raw colors with
var(--ag-type-agent-bg)andvar(--ag-type-agent-text). These tokens preserve the intended agent colors in both themes.Sources: Coding guidelines, Learnings
web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx-669-669 (1)
669-669: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winMove the agent icon colors into the semantic palette.
Both sites use raw hex and rgba values. Define one
{light, dark}semantic role inweb/oss/src/styles/theme/palette.ts, runpnpm generate:tailwind-tokensfromweb, and consume the generated semantic token in both states.
web/oss/src/components/Playground/Components/PlaygroundHeader/index.tsx#L669-L669: replace the raw icon background and text colors.web/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsx#L36-L36: consume the same semantic role as the loaded header.Verify equivalent light and dark appearance after the replacement. As per coding guidelines, “do not use raw hex colors.” Based on learnings, validate light and dark parity when replacing a color token.
Sources: Coding guidelines, Learnings
web/scripts/generate-tailwind-tokens.ts-491-499 (1)
491-499: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse hyphenated custom token keys. Ant Design 6 preserves the dot in
"zinc.1"and emits--ant-zinc.1, not--ant-zinc-1. ThecssVar: {key: "agenta"}option controls scoping only. Use keys such as"zinc-1"to emit the expected variable names.web/oss/src/styles/theme/palette.ts-632-659 (1)
632-659: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winKeep evaluator type colors distinct.
auto_semantic_similarityandauto_custom_code_runmap to different preset names but the sameTAG_SLOT.ambervalue. The evaluator table renders both throughWorkflowTypeTagin its Type column, so adjacent evaluator rows can have identical badges. Assign separate slots for evaluator types that coexist in this table.web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveFrequencyChart.tsx-122-133 (1)
122-133: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse
indexfor the default gradient ID.When
disableGradientis false andbarColoris absent, Line 133 always selects slot zero. All unhighlighted bars then use the first series color. Passindexto preserve the configured categorical cycle.Proposed fix
- return `url(#${resolveBarGradientId(0)})` + return `url(#${resolveBarGradientId(index)})`web/packages/agenta-playground-ui/src/components/shared/NodeResultCard/index.tsx-186-200 (1)
186-200: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse a theme token for the running-card accent.
Line 192 hard-codes
#D1D151in the injected stylesheet. When the effect is enabled, the accent ignores the active light and dark palette. Replace it with an existing semantic variable. If no suitable variable exists, add a{light, dark}role inweb/oss/src/styles/theme/palette.ts, runpnpm generate:tailwind-tokensfromweb, and consume the generated variable here.Proposed fix
- background: `#D1D151`; + background: var(--ag-colorPrimary);As per coding guidelines: “Consume theme colors through Ant Design semantic tokens, Tailwind color utilities, or supported
var(--ag-color*)variables; do not use raw hex colors or--ag-c-*literals.”Source: Coding guidelines
web/oss/src/components/pages/agent-home/assets/templates.ts-52-56 (1)
52-56: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReplace
#D97757
#D97757has only 3.12:1 contrast with white. The initials use normal text sizes, so they require at least 4.5:1 contrast. Replace all five occurrences and check the result in both themes.Sources: Coding guidelines, Learnings
web/oss/src/styles/code-editor-styles.css-36-37 (1)
36-37: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winWire the new error variables into the visible validation style.
The
.editor-code-highlight.validation-errorrule in Lines 289-331 still usesrgba(220, 38, 38, ...),#dc2626,#b91c1c, and related literals. Changing--editor-error-bgand--editor-error-bordertherefore does not recolor that validation state. Replace the background, border, text, hover, and focus declarations with the variables, and define those variables from semantic error tokens.The supplied PR objective includes editor-error recoloring, but the visible validation selector still uses the previous palette.
As per coding guidelines: theme colors must use semantic tokens or supported
var(--ag-color*)variables instead of raw color literals.Also applies to: 597-598
Source: Coding guidelines
web/packages/agenta-ui/src/CellRenderers/EvaluatorMetricBar.tsx-15-15 (1)
15-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winIncrease contrast for the light orange avatar-like metric color.
#FFFFFFon#D97757is approximately 3.1:1. This is below the usual 4.5:1 target for normal-size text. Use a darker semantic ink color for the light orange pair, then verify both themes.web/oss/tests/playwright/acceptance/human-annotation/index.ts-52-58 (1)
52-58: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAssert the pending status marker itself.
not.toBeVisible()passes when the locator matches no elements in Playwright 1.60.0. Assert[data-status-dot="pending"]is visible. The pending state uses the amber status dot, not the neutral dot.
🧹 Nitpick comments (6)
web/oss/src/components/Playground/Components/AgentRevisionSelector/index.tsx (2)
121-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse a Tailwind class for the warning dot.
Line 123 sets a static color with inline CSS. Move this value into the element
classNamewith a semantic-variable Tailwind utility.As per coding guidelines, “Prefer Tailwind utility classes over CSS-in-JS or separate CSS files.”
Source: Coding guidelines
26-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReduce the new comments to one short line each.
The JSX and callback names already describe these behaviors. Keep only a short comment where it adds necessary context.
web/oss/src/components/Playground/Components/AgentRevisionSelector/index.tsx#L26-L27: collapse or remove the component documentation addition.web/oss/src/components/Playground/Components/AgentRevisionSelector/index.tsx#L63-L64: replace the two-line revert-history comment with one short line.web/oss/src/components/Playground/Components/AgentRevisionSelector/index.tsx#L112-L113: replace the two-line Draft-control comment with one short line.As per coding guidelines, “Keep in-code comments to at most one short line.”
Source: Coding guidelines
web/oss/src/components/Sidebar/hooks/useSidebarResize.ts (1)
27-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueShorten the hook documentation.
This block repeats implementation details. Replace it with one short comment or remove it. As per coding guidelines, “Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements.”
Source: Coding guidelines
web/oss/src/components/AgentChatSlice/state/panelLayout.ts (1)
7-10: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueShorten these comments.
These comments describe direct code behavior. They do not document a surprising constraint, bug, race, or ordering requirement.
web/oss/src/components/AgentChatSlice/state/panelLayout.ts#L7-L10: replace the block with one short persistence comment.web/oss/src/components/AgentChatSlice/components/ShowConfigPanelButton.tsx#L1-L4: replace the block with one short restore-action comment.As per coding guidelines, “Keep in-code comments to at most one short line; use longer comments only for genuinely surprising constraints such as bugs, races, or ordering requirements.”
Source: Coding guidelines
web/oss/src/components/AgentChatSlice/components/SessionTagBar.tsx (1)
386-397: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winDeduplicate and schedule layout state updates.
Every scroll event creates a new
fadeobject. React then rerenders the bar even when both fade flags are unchanged. Each rerender also creates newmenuprops for everySessionTag.Return the previous fade state when its flags match. Schedule scroll and
ResizeObservermeasurements through onerequestAnimationFrame.As per coding guidelines, “Minimize React re-renders” and “debounce or throttle search, filter, scroll, and resize handlers.”
Also applies to: 424-427
Source: Coding guidelines
web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsx (1)
765-771: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUpdate the stale two-panel comments.
The changed
modelHarnessDrawerBodyandadvancedDrawerBodynow use single-column scroll containers. The surrounding comments still describe version history on the right and a two-panel layout. Update those comments, including themodelHarnessDrawerWidthcomment, so they match the removed UI.Proposed comment update
- // Model & harness drawer body. With inspect capabilities: harness cards + model picker on the - // left ..., version history on the right — same two-panel shape as the Advanced drawer. + // Model & harness drawer body. Capability-aware and fallback controls use a single-column + // scrollable layout. - // Advanced drawer body: two panels like Model & harness (settings left, version history right). + // Advanced drawer body: a single-column, vertically scrollable control stack. - // The capability-aware (two-panel) drawer is wider than the plain one. + // The capability-aware drawer reserves more width than the plain one.Also applies to: 966-970
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 328a3af9-f606-462b-a83a-d963894744a7
⛔ Files ignored due to path filters (2)
web/mobile/src/styles/theme.generated.cssis excluded by!**/*.generated.*web/oss/src/styles/theme/antd-overrides.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (71)
web/oss/src/components/AgentChatSlice/AgentChatPanel.tsxweb/oss/src/components/AgentChatSlice/assets/conversationLayout.tsweb/oss/src/components/AgentChatSlice/assets/sessionMotion.tsweb/oss/src/components/AgentChatSlice/components/AgentTranscript.tsxweb/oss/src/components/AgentChatSlice/components/Inspector/EventRow.tsxweb/oss/src/components/AgentChatSlice/components/Inspector/timeline.tsweb/oss/src/components/AgentChatSlice/components/SessionTabLabel.tsxweb/oss/src/components/AgentChatSlice/components/SessionTagBar.tsxweb/oss/src/components/AgentChatSlice/components/ShowConfigPanelButton.tsxweb/oss/src/components/AgentChatSlice/state/panelLayout.tsweb/oss/src/components/Drives/DriveFileRow.tsxweb/oss/src/components/Drives/OriginTag.tsxweb/oss/src/components/Drives/driveIcons.tsxweb/oss/src/components/EntityIdentity/fields.tsxweb/oss/src/components/EvalRunDetails/atoms/compare.tsweb/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/BarChart.tsxweb/oss/src/components/EvalRunDetails/components/EvaluatorMetricsChart/HistogramChart.tsxweb/oss/src/components/EvalRunDetails/components/EvaluatorMetricsSpiderChart/EvaluatorMetricsSpiderChart.tsxweb/oss/src/components/EvalRunDetails/components/FocusDrawerSidePanel.tsxweb/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewPlaceholders.tsxweb/oss/src/components/EvalRunDetails/components/views/OverviewView/constants.tsweb/oss/src/components/EvalRunDetails/utils/buildPreviewColumns.tsxweb/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveFrequencyChart.tsxweb/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsxweb/oss/src/components/Layout/ThemeContextProvider.tsxweb/oss/src/components/Playground/Components/AgentCommitNotice.tsxweb/oss/src/components/Playground/Components/AgentRevisionSelector/index.tsxweb/oss/src/components/Playground/Components/MainLayout/index.tsxweb/oss/src/components/Playground/Components/PlaygroundHeader/index.tsxweb/oss/src/components/Playground/Components/PlaygroundVariantConfig/assets/PlaygroundVariantConfigHeader.tsxweb/oss/src/components/Playground/Components/PlaygroundVariantConfig/index.tsxweb/oss/src/components/PlaygroundRouter/PlaygroundLoadingShell.tsxweb/oss/src/components/ProtectedRoute/ProtectedRoute.tsxweb/oss/src/components/Sidebar/components/SidebarSkeletonLoader.tsxweb/oss/src/components/Sidebar/components/WorkflowIdentity.tsxweb/oss/src/components/Sidebar/engine/SidebarMenu.tsxweb/oss/src/components/Sidebar/engine/SidebarShell.tsxweb/oss/src/components/Sidebar/hooks/useSidebarConfig/index.tsxweb/oss/src/components/Sidebar/hooks/useSidebarResize.tsweb/oss/src/components/pages/agent-home/StripHome.tsxweb/oss/src/components/pages/agent-home/assets/templates.tsweb/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsxweb/oss/src/components/pages/observability/dashboard/AnalyticsDashboard.tsxweb/oss/src/components/pages/observability/dashboard/CustomAreaChart.tsxweb/oss/src/components/pages/overview/agent/AgentOverview.tsxweb/oss/src/components/pages/settings/Tools/components/AgentaToolsPlaceholder.tsxweb/oss/src/lib/atoms/sidebar.tsweb/oss/src/lib/helpers/chartPalette.tsweb/oss/src/lib/helpers/colors.tsweb/oss/src/lib/hooks/useChartSeries.tsweb/oss/src/styles/animations.cssweb/oss/src/styles/code-editor-styles.cssweb/oss/src/styles/globals.cssweb/oss/src/styles/theme-variables.cssweb/oss/src/styles/theme/palette.tsweb/oss/tests/playwright/acceptance/human-annotation/index.tsweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/AgentOperationsSections.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/InstructionsDrawer.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/TriggerManagementSection.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/ItemRow.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/agentTemplate/useModelHarness.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/sectionGroups.tsxweb/packages/agenta-entity-ui/src/DrillInView/SchemaControls/triggerManagement/TriggerRow.tsxweb/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection.tsxweb/packages/agenta-entity-ui/src/DrillInView/components/PlaygroundConfigSection/useFieldSlots.tsxweb/packages/agenta-playground-ui/src/components/shared/NodeResultCard/index.tsxweb/packages/agenta-ui/src/CellRenderers/EvaluatorMetricBar.tsxweb/packages/agenta-ui/src/components/presentational/avatar/utils.tsweb/packages/agenta-ui/src/components/presentational/layout/PanelSection.tsxweb/packages/agenta-ui/src/components/presentational/section/ConfigAccordionSection.tsxweb/scripts/generate-tailwind-tokens.ts
💤 Files with no reviewable changes (1)
- web/oss/src/components/pages/settings/Tools/components/AgentaToolsPlaceholder.tsx
| export const EVENT_META: Record<TimelineEventType, {dot: EventTone; chip: string}> = { | ||
| message: {dot: {light: "#616161", dark: "#BCBCBC"}, chip: "message"}, | ||
| thought: {dot: {light: "#616161", dark: "#BCBCBC"}, chip: "thought"}, | ||
| tool_call: {dot: {light: "#113955", dark: "#8CCFFF"}, chip: "tool_call"}, | ||
| tool_result: {dot: {light: "#5E5E08", dark: "#54B5FA"}, chip: "tool_result"}, | ||
| interaction_request: {dot: {light: "#8A6400", dark: "#EBC96A"}, chip: "interaction"}, | ||
| done: {dot: {light: "#2E7D3A", dark: "#8FBF7A"}, chip: "done"}, | ||
| error: {dot: {light: "#B33F38", dark: "#FF8E8C"}, chip: "error"}, | ||
| other: {dot: {light: "#616161", dark: "#BCBCBC"}, chip: "event"}, | ||
| } | ||
|
|
||
| /** Resolve a tone for the active theme. Stays a plain hex — callers append an alpha suffix. */ | ||
| export const eventTone = (tone: EventTone, isDark: boolean): string => | ||
| isDark ? tone.dark : tone.light |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Use generated semantic theme tokens for event tones.
EVENT_META hard-codes light and dark hex values, and eventTone preserves a plain-hex contract so EventRow.tsx can append 0d to the accent color. This bypasses the palette source of truth. Define event-tone roles in web/oss/src/styles/theme/palette.ts, regenerate the theme outputs, and apply alpha with a CSS-safe color expression instead of hex-suffix concatenation.
As per coding guidelines, web/**/*.{ts,tsx,css} must consume theme colors through semantic tokens, Tailwind color utilities, or supported var(--ag-color*) variables, and web/oss/src/styles/theme/palette.ts is the source of truth for theme colors.
Source: Coding guidelines
There was a problem hiding this comment.
The convention is real and correctly cited — web/CLAUDE.md and the root AGENTS.md both make palette.ts the single source of truth and forbid raw hex in components. I am not actioning it in this pass, and I want to be explicit that this is a scope judgement rather than a disagreement, so it does not read as dismissed. Flagged for @mmabrouk.
Measured rather than estimated: this PR adds 435 lines containing hex literals across web/**/*.{ts,tsx}. This is not a stray literal or two that a reviewer folds in — migrating it means authoring roughly that many {light, dark} semantic roles, regenerating the token pipeline, and re-verifying 72 files in both appearances. That is a larger change than the recolour it would be attached to, and doing it as an unrequested review fix immediately before founder review is how a reviewable PR becomes an unreviewable one.
The other reason to hold: a mechanical hex-to-token migration is exactly the kind of change that silently shifts colours, and its only real acceptance test is looking at both themes. That verification belongs with whoever owns the recolour's visual intent.
My recommendation to the author is to treat this as a tracked follow-up covering all of the sites in this thread, and in the meantime to prioritise the two cases that are not merely conventional: the light-only chart palettes (a genuine dark-mode defect, see the chartPalette.ts thread) and any literal that duplicates a token that already exists — buildPreviewColumns.tsx was one of those and is fixed in 1a98a5d.
| // Agent accent (recolor spec): deep info ink in light, the approved #8CCFFF in dark. `light-dark()` | ||
| // resolves off the root's color-scheme, which ThemeContextProvider keeps in sync with the theme. | ||
| export const AGENT_ACCENT = "light-dark(#113955, #8CCFFF)" | ||
| /** Tag well behind the accent — the dark pair is founder-approved verbatim. */ | ||
| export const AGENT_ACCENT_BG = "light-dark(#E5F1F9, rgba(140,207,255,0.14))" | ||
| /** Same accent at 55% — the recent-file left rule. */ | ||
| export const AGENT_ACCENT_SOFT = "light-dark(rgba(17,57,85,0.55), rgba(140,207,255,0.55))" |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Centralize the new theme pairs in the palette and token pipeline.
These changes add raw #..., rgba(...), and light-dark(...) values across component, package, and CSS code. This bypasses the semantic palette and causes future theme updates to drift.
web/oss/src/components/Drives/OriginTag.tsx#L11-L17: Move the Agent light/dark roles toweb/oss/src/styles/theme/palette.ts.web/oss/src/components/Drives/OriginTag.tsx#L30-L30: Consume the generated Agent class orvar(--ag-color*)variable instead of inline color values.web/oss/src/components/Drives/driveIcons.tsx#L21-L31: Generate a semantic neutral-glyph token.web/oss/src/components/EntityIdentity/fields.tsx#L39-L40: Use generated Agent badge and dot tokens.web/oss/src/components/EvalRunDetails/components/FocusDrawerSidePanel.tsx#L98-L98: Use the generated Agent icon token.web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx#L14-L17: Use generated loader, Agent, and success tokens.web/oss/src/styles/animations.css#L36-L40: Use generated semantic CSS variables in the keyframes.web/oss/src/styles/code-editor-styles.css#L36-L37: Define the light editor error variables from semantic error roles.web/oss/src/styles/code-editor-styles.css#L597-L598: Define the dark editor error variables from semantic error roles.web/packages/agenta-ui/src/CellRenderers/EvaluatorMetricBar.tsx#L17-L35: Expose categorical and boolean colors through supported CSS variables.web/packages/agenta-ui/src/components/presentational/avatar/utils.ts#L6-L17: Expose avatar pairs through supported CSS variables.web/packages/agenta-ui/src/components/presentational/section/ConfigAccordionSection.tsx#L74-L74: Use the generated Agent indicator token.
As per coding guidelines: theme-aware colors must originate from semantic {light, dark} roles in web/oss/src/styles/theme/palette.ts, and frontend code must not use raw hex colors or --ag-c-* literals.
📍 Affects 10 files
web/oss/src/components/Drives/OriginTag.tsx#L11-L17(this comment)web/oss/src/components/Drives/OriginTag.tsx#L30-L30web/oss/src/components/Drives/driveIcons.tsx#L21-L31web/oss/src/components/EntityIdentity/fields.tsx#L39-L40web/oss/src/components/EvalRunDetails/components/FocusDrawerSidePanel.tsx#L98-L98web/oss/src/components/pages/app-management/modals/CustomAppCreationLoader.tsx#L14-L17web/oss/src/styles/animations.css#L36-L40web/oss/src/styles/code-editor-styles.css#L36-L37web/oss/src/styles/code-editor-styles.css#L597-L598web/packages/agenta-ui/src/CellRenderers/EvaluatorMetricBar.tsx#L17-L35web/packages/agenta-ui/src/components/presentational/avatar/utils.ts#L6-L17web/packages/agenta-ui/src/components/presentational/section/ConfigAccordionSection.tsx#L74-L74
Source: Coding guidelines
There was a problem hiding this comment.
The convention is real and correctly cited — web/CLAUDE.md and the root AGENTS.md both make palette.ts the single source of truth and forbid raw hex in components. I am not actioning it in this pass, and I want to be explicit that this is a scope judgement rather than a disagreement, so it does not read as dismissed. Flagged for @mmabrouk.
Measured rather than estimated: this PR adds 435 lines containing hex literals across web/**/*.{ts,tsx}. This is not a stray literal or two that a reviewer folds in — migrating it means authoring roughly that many {light, dark} semantic roles, regenerating the token pipeline, and re-verifying 72 files in both appearances. That is a larger change than the recolour it would be attached to, and doing it as an unrequested review fix immediately before founder review is how a reviewable PR becomes an unreviewable one.
The other reason to hold: a mechanical hex-to-token migration is exactly the kind of change that silently shifts colours, and its only real acceptance test is looking at both themes. That verification belongs with whoever owns the recolour's visual intent.
My recommendation to the author is to treat this as a tracked follow-up covering all of the sites in this thread, and in the meantime to prioritise the two cases that are not merely conventional: the light-only chart palettes (a genuine dark-mode defect, see the chartPalette.ts thread) and any literal that duplicates a token that already exists — buildPreviewColumns.tsx was one of those and is fixed in 1a98a5d.
| /** | ||
| * Tile accent (inline style), cycling the categorical solids in fixed order. Monograms render | ||
| * WHITE initials on it, so only the white-safe deep steps are used — and the same set covers | ||
| * both themes, since the initials are hardcoded white at every render site. | ||
| */ |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Move template accent colors into the theme palette.
These changes add raw hex literals as a second theme-color source. This violates the web/**/*.{ts,tsx} color rule and allows template accents to diverge from web/oss/src/styles/theme/palette.ts.
Store named accent roles or palette keys in web/oss/src/styles/theme/palette.ts. Resolve them through supported theme variables. Run pnpm generate:tailwind-tokens after changing the palette.
Also applies to: 190-190, 242-242, 287-287, 332-332, 375-375, 411-411, 449-449, 496-496, 535-535, 588-588, 640-640, 677-677, 715-715, 752-752, 790-790, 843-843, 896-896, 949-949, 999-999, 1055-1055, 1092-1092, 1144-1144, 1196-1196, 1232-1232, 1285-1285, 1322-1322, 1373-1373, 1425-1425
Source: Coding guidelines
There was a problem hiding this comment.
The convention is real and correctly cited — web/CLAUDE.md and the root AGENTS.md both make palette.ts the single source of truth and forbid raw hex in components. I am not actioning it in this pass, and I want to be explicit that this is a scope judgement rather than a disagreement, so it does not read as dismissed. Flagged for @mmabrouk.
Measured rather than estimated: this PR adds 435 lines containing hex literals across web/**/*.{ts,tsx}. This is not a stray literal or two that a reviewer folds in — migrating it means authoring roughly that many {light, dark} semantic roles, regenerating the token pipeline, and re-verifying 72 files in both appearances. That is a larger change than the recolour it would be attached to, and doing it as an unrequested review fix immediately before founder review is how a reviewable PR becomes an unreviewable one.
The other reason to hold: a mechanical hex-to-token migration is exactly the kind of change that silently shifts colours, and its only real acceptance test is looking at both themes. That verification belongs with whoever owns the recolour's visual intent.
My recommendation to the author is to treat this as a tracked follow-up covering all of the sites in this thread, and in the meantime to prioritise the two cases that are not merely conventional: the light-only chart palettes (a genuine dark-mode defect, see the chartPalette.ts thread) and any literal that duplicates a token that already exists — buildPreviewColumns.tsx was one of those and is fixed in 1a98a5d.
| {!embedded && | ||
| (showAgentHeader ? ( | ||
| <Tooltip title="Hide configuration"> | ||
| <Button | ||
| type="text" | ||
| size="small" | ||
| aria-label="Hide configuration" | ||
| icon={<CaretDoubleLeft size={14} />} | ||
| onClick={handleCollapseConfigPanel} | ||
| /> | ||
| </Tooltip> | ||
| ) : ( | ||
| <PlaygroundVariantHeaderMenu variantId={variantId} /> | ||
| ))} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Keep the remaining agent header actions available.
showAgentHeader replaces the entire PlaygroundVariantHeaderMenu. The menu still exposes Copy raw config and Delete for agents. This change removes both actions from the agent configuration header.
Render the collapse control in addition to an agent menu, or provide equivalent actions elsewhere.
There was a problem hiding this comment.
Valid and significant — this is the most consequential finding on this PR. Not fixed here, because the resolution is a product decision rather than a mechanical one, and I have flagged it for @mmabrouk.
The finding is confirmed against the menu source. PlaygroundVariantHeaderMenu builds its items at Menus/PlaygroundVariantHeaderMenu/index.tsx L71-L110, and only close is gated on agent mode (...(!isAgent ? [close] : []), L99-L110). In agent mode the menu therefore still renders Copy raw config, Revert Changes, and Delete. Replacing the whole menu with the collapse control drops all three.
Worth flagging explicitly: this PR's own comment at PlaygroundVariantConfigHeader.tsx L120-L121 states that "the kebab's only other item, Revert Changes, moved to the Draft tag in the page header". That is the rationale the change rests on, and it is factually wrong — there are three other items, not one. Revert Changes may well be covered by the Draft tag as described, but Copy raw config and Delete have no replacement, so agent users lose the ability to delete a variant or copy its raw config from this header.
I have not restored the menu, because "should the agent header carry a kebab at all" is a deliberate simplification the author and founder are making, and quietly reinstating it would undo an intentional design choice. The decision needed is whether to render the collapse control alongside an agent-scoped menu, or to surface Copy raw config and Delete elsewhere for agents.
| // Recolor spec: the olive accent chip in dark, the Agent tag pair in light. | ||
| className: | ||
| "bg-[#E5F1F9] text-[#113955] dark:bg-[rgba(209,209,81,0.15)] dark:text-[#D1D151]", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Move these colors into a semantic palette role.
Do not keep raw hex or RGBA values in this component. Define a {light, dark} semantic role in web/oss/src/styles/theme/palette.ts, regenerate the theme tokens, and consume the generated semantic color. Validate the replacement in both appearances.
As per coding guidelines, “Theme-aware colors must originate from semantic {light, dark} roles in palette.ts” and “do not use raw hex colors.” Based on learnings, validate that the replacement preserves parity in both light and dark appearances.
Sources: Coding guidelines, Learnings
There was a problem hiding this comment.
The convention is real and correctly cited — web/CLAUDE.md and the root AGENTS.md both make palette.ts the single source of truth and forbid raw hex in components. I am not actioning it in this pass, and I want to be explicit that this is a scope judgement rather than a disagreement, so it does not read as dismissed. Flagged for @mmabrouk.
Measured rather than estimated: this PR adds 435 lines containing hex literals across web/**/*.{ts,tsx}. This is not a stray literal or two that a reviewer folds in — migrating it means authoring roughly that many {light, dark} semantic roles, regenerating the token pipeline, and re-verifying 72 files in both appearances. That is a larger change than the recolour it would be attached to, and doing it as an unrequested review fix immediately before founder review is how a reviewable PR becomes an unreviewable one.
The other reason to hold: a mechanical hex-to-token migration is exactly the kind of change that silently shifts colours, and its only real acceptance test is looking at both themes. That verification belongs with whoever owns the recolour's visual intent.
My recommendation to the author is to treat this as a tracked follow-up covering all of the sites in this thread, and in the meantime to prioritise the two cases that are not merely conventional: the light-only chart palettes (a genuine dark-mode defect, see the chartPalette.ts thread) and any literal that duplicates a token that already exists — buildPreviewColumns.tsx was one of those and is fixed in 1a98a5d.
| {!collapsed && ( | ||
| <div | ||
| // Invisible 9px grab strip straddling the hairline; the ::after is the | ||
| // hairline itself, tinted only while hovering or dragging. | ||
| className="absolute inset-y-0 -right-1 z-10 w-[9px] cursor-col-resize touch-none after:absolute after:inset-y-0 after:left-1/2 after:w-px after:-translate-x-1/2 after:bg-transparent after:transition-colors hover:after:bg-colorBorder group-data-[resizing=true]/rail:after:bg-colorPrimary" | ||
| role="separator" | ||
| aria-orientation="vertical" | ||
| aria-label="Resize sidebar" | ||
| {...handleProps} | ||
| /> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make the resize handle keyboard operable.
The handle supports pointer input only. It has no tabIndex, keyboard handler, or range value attributes. Keyboard and assistive-technology users cannot change the persisted sidebar width. Add focus handling, Arrow key and Home/End behavior, and aria-valuemin, aria-valuemax, and aria-valuenow values through the same clamped atom update path.
There was a problem hiding this comment.
Valid finding, deliberately not fixed in this pass. SidebarShell.tsx has uncommitted work in progress from a parallel change to the sidebar resize behaviour, and editing it now would collide with that. Making a pointer-only control keyboard operable belongs with that work rather than alongside it — it needs tabIndex, Arrow/Home/End handling, and aria-valuemin/aria-valuemax/aria-valuenow driven through the same clamped atom path, which is precisely the surface being rewritten. Flagged for @mmabrouk to route to the resize change.
| export const CHART_SERIES_LIGHT = ["#D97757", "#54B5FA", "#D9D92C", "#113955", "#9D9D9D"] | ||
| export const CHART_SERIES_DARK = ["#D1D151", "#8CCFFF", "#FF8E8C", "#8FBF7A", "#787878"] |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 '\b(SPIDER_SERIES_COLORS|DEFAULT_SPIDER_SERIES_COLOR)\b' web/oss/src
rg -n -C 4 'CHART_SERIES_(LIGHT|DARK)|MEAN_LINE_COLOR' web/oss/srcRepository: Agenta-AI/agenta
Length of output: 25359
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- palette files ---'
fd -i 'palette.ts' web
printf '%s\n' '--- palette references and theme hooks ---'
rg -n -C 3 'CHART_SERIES|chartSeries|useChartSeries|useIsDarkTheme|palette' web/oss/src web/packages/agenta-sdk/src 2>/dev/null | head -n 400
printf '%s\n' '--- relevant source sections ---'
sed -n '1,180p' web/oss/src/lib/helpers/chartPalette.ts
sed -n '1,100p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/constants.ts
sed -n '1,150p' web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsxRepository: Agenta-AI/agenta
Length of output: 40618
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- palette structure and chart-related roles ---'
rg -n -C 5 'chart|series|categor|mean|ink|text|border|surface|`#D97757`|`#54B5FA`|`#D9D92C`|`#113955`|`#9D9D9D`|`#D1D151`|`#8CCFFF`|`#FF8E8C`|`#8FBF7A`|`#787878`|`#BCBCBC`|248, 250, 255' web/oss/src/styles/theme/palette.ts web/oss/src/styles/theme/legacy-shim.ts 2>/dev/null
printf '%s\n' '--- all consumers of the light-only spider palette ---'
rg -n -C 8 'SPIDER_SERIES_COLORS|DEFAULT_SPIDER_SERIES_COLOR' web/oss/src
printf '%s\n' '--- comparison palette consumers and theme context ---'
sed -n '1,130p' web/oss/src/components/EvalRunDetails/atoms/compare.ts
sed -n '1,240p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewMetricComparison.tsx
sed -n '1,250p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewSpiderChart.tsx
sed -n '1,130p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx
sed -n '1,90p' web/oss/src/lib/hooks/useChartSeries.tsRepository: Agenta-AI/agenta
Length of output: 50372
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- palette sections around categorical and exported roles ---'
sed -n '400,440p' web/oss/src/styles/theme/palette.ts
sed -n '600,660p' web/oss/src/styles/theme/palette.ts
sed -n '833,870p' web/oss/src/styles/theme/palette.ts
printf '%s\n' '--- relevant consumer implementations ---'
sed -n '1,120p' web/oss/src/components/EvalRunDetails/atoms/compare.ts
sed -n '1,115p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewMetricComparison.tsx
sed -n '1,80p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewSpiderChart.tsx
sed -n '165,205p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/OverviewSpiderChart.tsx
sed -n '1,85p' web/oss/src/components/EvalRunDetails/components/views/OverviewView/components/BaseRunMetricsSection.tsx
sed -n '1,90p' web/oss/src/lib/hooks/useChartSeries.ts
printf '%s\n' '--- direct color literals in the three reported files ---'
rg -n '#[0-9A-Fa-f]{3,8}|rgba?\(' \
web/oss/src/lib/helpers/chartPalette.ts \
web/oss/src/components/EvalRunDetails/components/views/OverviewView/constants.ts \
web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsxRepository: Agenta-AI/agenta
Length of output: 24765
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
palette = Path("web/oss/src/lib/helpers/chartPalette.ts").read_text()
constants = Path(
"web/oss/src/components/EvalRunDetails/components/views/OverviewView/constants.ts"
).read_text()
compare = Path("web/oss/src/components/EvalRunDetails/atoms/compare.ts").read_text()
metric = Path(
"web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx"
).read_text()
light = re.search(r"CHART_SERIES_LIGHT\s*=\s*\[([^\]]+)\]", palette).group(1)
dark = re.search(r"CHART_SERIES_DARK\s*=\s*\[([^\]]+)\]", palette).group(1)
light_values = re.findall(r'"(#[0-9A-Fa-f]+)"', light)
dark_values = re.findall(r'"(#[0-9A-Fa-f]+)"', dark)
assert light_values and dark_values and light_values != dark_values
assert "SPIDER_SERIES_COLORS = CHART_SERIES_LIGHT" in constants
assert "CHART_SERIES_LIGHT.map" in compare
assert 'isDark ? "`#BCBCBC`" : "`#113955`"' in metric
print("light series:", light_values)
print("dark series:", dark_values)
print("SPIDER_SERIES_COLORS is statically light:", True)
print("RUN_COMPARISON_PALETTE is statically light:", True)
print("mean line selects by theme but uses raw literals:", True)
PY
printf '%s\n' '--- solid comparison color consumers ---'
rg -n -C 5 '\b(getComparisonSolidColor|COMPARISON_SOLID_COLORS|RUN_COMPARISON_PALETTE)\b' web/oss/srcRepository: Agenta-AI/agenta
Length of output: 12285
Move chart colors into palette.ts and resolve them per theme.
The light-only SPIDER_SERIES_COLORS and RUN_COMPARISON_PALETTE values render light colors in dark mode. ResponsiveMetricChart also hard-codes the mean-line colors. Add semantic {light, dark} chart roles to palette.ts, regenerate outputs, and use mode-aware accessors in the overview charts, comparison colors, and ResponsiveMetricChart.
📍 Affects 3 files
web/oss/src/lib/helpers/chartPalette.ts#L9-L10(this comment)web/oss/src/components/EvalRunDetails/components/views/OverviewView/constants.ts#L17-L21web/oss/src/components/Evaluations/MetricDetailsPopover/assets/ResponsiveMetricChart.tsx#L100-L103
Source: Coding guidelines
There was a problem hiding this comment.
Two separate findings are bundled here. The functional half is valid and confirmed; the palette-migration half I am leaving to the author. Not fixed in this pass — flagged for @mmabrouk.
The dark-mode bug is real. Both consumers pin themselves to the light set:
EvalRunDetails/components/views/OverviewView/constants.tsL20:export const SPIDER_SERIES_COLORS = CHART_SERIES_LIGHTEvalRunDetails/atoms/compare.tsL22:export const RUN_COMPARISON_PALETTE = CHART_SERIES_LIGHT.map(...), which feedsCOMPARISON_COLORSandCOMPARISON_SOLID_COLORS
So the spider chart and the run-comparison colours render the light series in dark mode. That is a genuine defect, and a pointed one in a PR whose subject is the recolour — chartSeries(isDark) exists in chartPalette.ts precisely to make this choice, and these two callers bypass it.
The reason it is not a one-line fix: both are module-level const exports, so they cannot read theme state. Making them theme-aware means pushing resolution to the call sites (OverviewSpiderChart, OverviewMetricComparison, BaseRunMetricsSection, and the COMPARISON_* consumers) through the existing useChartSeries hook. That is a multi-file change to chart rendering whose only real acceptance test is looking at the charts in both themes, which the author is far better placed to do than I am. Landing it unverified in a PR that is about to be reviewed visually would be the wrong trade.
On moving the chart palette into palette.ts: the convention is real, but the mechanism does not fit as cleanly here as for other tokens. Charts render as SVG presentation attributes (fill=/stroke=), which need a resolved colour string rather than a CSS variable or a light-dark() value — chartPalette.ts documents exactly this in its header comment, and it is a sound reason for the palette to exist as plain values. The defensible middle ground is to keep the resolved-string accessor but source its two arrays from palette.ts roles so a recolour updates one file. Worth doing, but it is a refactor rather than a review fix.
…sion baseline, use the success token
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/oss/src/components/TemplateStrip/components/StripCard.tsx (1)
43-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShorten the inline rationale comment.
The four-line comment exceeds the repository limit for in-code comments. Replace it with one short line or remove it.
As per coding guidelines, keep in-code comments to at most one short line; longer comments are reserved for genuinely surprising constraints.
Proposed fix
- : // The warm tinted surface the Home and overview rails carry, so a template card - // reads as an object on the page rather than a white cutout. Light only: dark - // restores this strip's own card token (rgba(255,255,255,.04)), since the tint's - // dark step is a different surface and dark cards aren't part of this change. + : // Use the paper surface in light mode and the strip-card token in dark mode.Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: ff27e301-cde7-4cd4-ae14-a5dff77bcdc6
📒 Files selected for processing (1)
web/oss/src/components/TemplateStrip/components/StripCard.tsx
…arm paper surface
…erence tags on brand
…oy + kebab D-04 was filed as a deliberate lane change awaiting a product call. The release history says otherwise, so the verdict is reversed here. PR #5943 "Warm brand recolor and agent playground UX rework" (3f263b8, in both 112.0 and 112.1) states: "The kebab menu is gone (Revert lives on the Draft tag; Copy raw config and Delete are dropped, per Mahmoud); a « / » control collapses the config panel" — and, under what to QA, "the classic (prompt) playground keeps its kebab menu, Deploy button, and old behaviors throughout". So both were removed from the AGENT header by design and kept on the classic one. The package extraction reinstated them there, and in doing so left the bar with no collapse affordance and no accessible name: prod renders Commit + a 24px control labelled "Hide configuration", local rendered Deploy + Commit + an unnamed ant-dropdown-trigger. AgentConfigHeader's deploy + menu slots collapse into one trailing slot — it had a single consumer — and the agent branch passes 112.1's control back, wired to configPanelCollapsedAtom, which had survived the extraction; only the hide control was dropped while ShowConfigPanelButton kept restoring the panel. Not yet verified in the browser: the local dev server is down.
I claimed this control had "no 112.x ancestor" because prod does not render it.
Wrong on both counts, and the source settles it: 112.0 and 112.1 both carry the
switch in PlaygroundHeader, behind a flag they deliberately keep off.
// Build/Chat switch parked (not removed): Build is the only reachable mode
// until this flips back.
const SHOW_MODE_SWITCH = false
The package extraction rendered PlaygroundModeSwitch unconditionally, which
un-parked a control product had switched off — and put a second "hide the config
pane" affordance beside the << collapse control that PR #5943 designed as the
only one (chatPanelMaximizedAtom hides config and shows the session rail;
configPanelCollapsedAtom collapses the pane). Two controls, two atoms, one job.
Restores the flag and the comment verbatim from 112.1. Measured after: the agent
header is 41px, matching prod, and no [aria-label="Playground mode"] renders.
The size="sm" from the previous commit stays: it is moot while parked, but it is
the right size for a 24px control row if the switch ever flips back on.
Context
The product's colors did not match the brand: light mode ran on a cool navy system while the brand (as seen on the signup page) is warm with a yellow accent, and a dozen surfaces carried loud hardcoded colors (neon file icons, rainbow gradients, 13-hue tags). Separately, Mahmoud redesigned the agent playground's chrome through a day of live design review. This PR lands both, implemented against a designer handoff package and dozens of annotated live-QA screenshots.
Changes
Recolor, light mode. The theme source of truth (
palette.ts) moves to the warm ramp: ground #F6F5F3, white cards, ink #242424 primaries, olive links, warm semantic wells. The config panel reads warm body (#FBFAF8) with #F6F5F3 section headers and white expanded content; the chat canvas is white with #FBFAF8 user bubbles; the composer focus is an ink border instead of yellow. Two silent traps are defused: antd seed transformation (values are pinned at the rendered layer) and a frozen 789-value per-component dump that previously blocked all light-mode changes from painting.Recolor, dark mode. Exactly 37 values changed, all approved: links, the soft status set, workflow-type chips, the draft tag, and the tag family. Backgrounds, buttons, panels, and selection are byte-identical to what shipped, verified by diff after every round.
One categorical color system. The 13 antd tag hues, avatar gradients, chart palettes (six files), template tiles, timeline dots, and file icons all collapse onto six brand slots with fixed assignment order, contrast-checked. The rainbow node halo becomes a single soft pulse.
Playground UX. The kebab menu is gone (Revert lives on the Draft tag; Copy raw config and Delete are dropped, per Mahmoud); a « / » control collapses the config panel with the width persisted; the resize gutter is flush (panels touch, thin grip line, wide hit area); the session bar loses its bordered cards for hairline dividers with an ink-fill selected state, an inline + that docks right only on overflow, mask-faded labels (no ellipsis, no reflow on hover), and inline hover actions; the message stats bar renders above the chat's bottom fade (the fade was a CSS mask that isolated its subtree; it is now a sibling overlay); new sessions always scroll fully into view; the session-history icon is removed; Observability is hidden outside Classic mode (both sidebar entries, matching the existing gating pattern); the back arrow on the blank-agent page is pinned top-left; the "version history (soon)" placeholder rails are removed from the drawers; the sidebar defaults to 255px and is drag-resizable (200-340, persisted).
Tests / notes
What to QA