feat(#1756): Add dynamic agent color styling system#1757
feat(#1756): Add dynamic agent color styling system#1757aheritier wants to merge 3 commits intodocker:mainfrom
Conversation
|
Very cool idea, I just wonder how well this plays with our theme system? |
8e5f912 to
cebba6a
Compare
There was a problem hiding this comment.
Pull request overview
Adds a dynamic, deterministic agent color system to the TUI so agent badges and sidebar accents are derived from a fixed palette based on the agent’s order (as reported by the runtime team info).
Changes:
- Introduces badge and accent color palettes plus helper APIs to render agent-specific styles.
- Tracks agent ordering via a shared registry updated from
TeamInfoEvent/SetAvailableAgents. - Updates multiple TUI components to render agent badges/names using the new dynamic style functions.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/tui/styles/agent_colors.go | Implements palettes, agent→index registry, and dynamic badge/accent style helpers. |
| pkg/tui/styles/agent_colors_test.go | Adds tests for agent ordering/indexing and determinism of generated styles. |
| pkg/tui/service/sessionstate.go | Updates agent-order registry when available agents are set from runtime events. |
| pkg/tui/components/tool/transfertask/transfertask.go | Switches to dynamic agent badge styling for sender/target agent. |
| pkg/tui/components/tool/handoff/handoff.go | Switches to dynamic agent badge styling for sender/target agent. |
| pkg/tui/components/sidebar/sidebar.go | Switches current-agent prefix and name rendering to dynamic accent styling per agent. |
| pkg/tui/components/message/message.go | Switches message sender prefix to dynamic agent badge styling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // AgentBadgeColorsFor returns the badge foreground/background colors for a given agent name. | ||
| func AgentBadgeColorsFor(agentName string) AgentBadgeColors { | ||
| idx := agentIndex(agentName) | ||
| bgHex := agentColorPalette[idx] | ||
|
|
||
| theme := CurrentTheme() | ||
| fgHex := bestForegroundHex( | ||
| bgHex, | ||
| theme.Colors.TextBright, | ||
| theme.Colors.Background, | ||
| "#000000", | ||
| "#ffffff", | ||
| ) | ||
|
|
||
| return AgentBadgeColors{ | ||
| Fg: lipgloss.Color(fgHex), | ||
| Bg: lipgloss.Color(bgHex), | ||
| } |
There was a problem hiding this comment.
AgentBadgeColorsFor recomputes contrast (hex parsing + luminance math) on every call. Since badge rendering can happen frequently (e.g., per message render), consider memoizing the resolved foreground per (theme ref, palette index/bgHex) or precomputing on theme changes to avoid repeated parsing and math in hot render paths.
There was a problem hiding this comment.
precomputed all badge/accent styles in rebuildAgentColorCache(), called from
SetAgentOrder and InvalidateAgentColorCache (hooked into ApplyTheme). The hot render path now reads from cached slices.
cebba6a to
69d26b4
Compare
not yet configurable, it's what I wanted to discuss with you. |
69d26b4 to
da34a5c
Compare
|
Not sure at all cc @rumpl @krissetto @dgageot : Option 1: Add agent_colors section to ThemeColorsAdd agent_badge_colors and agent_accent_colors as string arrays to ThemeColors. Theme authors can override the full palettes. The merge logic would be: if the override provides In theme YAMLPros: Full control per theme, follows existing pattern, theme authors can curate exactly. Cons: Verbose (16×2 = 32 hex values to override), most theme authors won't bother, the Option 2: Derive agent colors from a single agent_base_hues listTheme provides a list of hue values (0–360) or a few seed colors. The system generates the full palette by adjusting saturation/lightness based on the theme's background Pros: Compact, auto-adapts to dark/light backgrounds, fewer values to maintain. Cons: More complex implementation, less precise control, HSL→hex conversion needed. Option 3: Theme provides a color_scale and system generates from itUse the theme's existing status/accent colors as seeds — brand, success, error, warning, info, accent, highlight, badge_accent, badge_info, badge_success — and derive the rest
Pros: Zero config for theme authors — it "just works" with any theme. No new YAML fields. Cons: Less control, the generated fills may not be aesthetically ideal, hard to predict Option 4: Hybrid — auto-derive with optional overrideCombine Option 3 (auto-derive from existing theme colors) as the default, with Option 1 (explicit array) as an optional override. If the theme YAML provides agent_badge_colors, Pros: Works out of the box for all existing themes, theme authors who care can override. Cons: Two code paths to maintain, but the override path is trivial. |
|
copilot feedbacks were addressed |
|
My preference would be Option 2, WDYT @krissetto ? |
|
@rumpl I also prefer Option 2. Explicit theme values could be nice to have if someone wants to define them, but generating the hues is better IMHO since there could be n agents in a team. Also @aheritier there is some code in tabbar/tab.go that does dynamic color selection for some bits of the UI that would've been too tedious to theme manually, we could adjust and consolidate the approach into something reusable across multiple places in the TUI as well so we end up with a consistent look and feel |
Implement a flexible agent color palette with deterministic color assignment based on agent order. Introduces new functions to generate badge and accent styles for agents dynamically. Changes include: - Create agent color palettes for badges and accents - Add agent order tracking mechanism - Implement color selection based on agent index - Update components to use new dynamic styling functions
…til.go Extract color math functions from tabbar/tab.go and theme.go into a shared colorutil.go module. Adds HSL conversion, CIELAB perceptual distance, and hue-based palette generation functions. This eliminates duplicate luminance/contrast implementations and provides the foundation for theme-integrated agent color generation. Assisted-By: cagent
…ation Replace hardcoded agent color palettes with dynamic generation from HSL hue values. Each theme can define agent_hues (16 hue values 0-360) in its YAML; colors auto-adapt saturation and lightness based on the theme background (dark vs light). Validation across all 10 built-in themes: - WCAG AA badge contrast (≥4.5:1 fg/bg) — all pass - WCAG AA accent contrast (≥3.0:1 vs background) — all pass - CIE76 pairwise distinctness (ΔE≥10) — all pass - Color audit report available via go test -v Assisted-By: cagent
da34a5c to
bd0fa58
Compare
|
@rumpl @krissetto @dgageot please review with caution, it's bigger than I expected |
Closes #1756
Summary
Assigns each agent in a multi-agent team a unique, deterministic color so users can visually distinguish agents across the entire TUI — message badges, sidebar entries, tab bar indicators, and handoff/transfer-task displays.
Colors are generated dynamically from hue values (0–360) defined per theme, with saturation and lightness auto-adapted based on the theme's background (dark → brighter, light → darker). This follows Option 2 from the design discussion, as agreed with @rumpl and @krissetto.
What changed
New: Color utility library (
pkg/tui/styles/colorutil.go)Shared color math extracted from
tabbar/tab.goandtheme.go, plus new functionality:ContrastRatio,EnsureContrast,MutedContrastFg)GenerateBadgePalette,GenerateAccentPalette)New: Agent color registry (
pkg/tui/styles/agent_colors.go)Thread-safe, cached mapping from agent name → palette index:
SetAgentOrder(names)— called when team info updatesAgentBadgeStyleFor(name)/AgentAccentStyleFor(name)— return precomputed lipgloss stylesInvalidateAgentColorCache()— called on theme change to regenerate stylesTheme integration
agent_huesfield inThemeColors(list of hue values 0–360)TUI component updates
AgentBadgeStyleFor(sender))AgentAccentStyleFor(agent.Name))MutedContrastFg,EnsureContrast) consolidated into sharedcolorutil.goValidation
All 10 built-in themes pass automated checks:
go test -v ./pkg/tui/styles/...Screenshots
Dark themes
Light themes
Files changed
pkg/tui/styles/colorutil.gopkg/tui/styles/colorutil_test.gopkg/tui/styles/agent_colors.gopkg/tui/styles/agent_colors_test.gopkg/tui/styles/theme.goAgentHuesfield, remove duplicated color helpers, hook cache invalidationpkg/tui/styles/theme_test.gomergeColorstest for newAgentHuesslice fieldpkg/tui/styles/themes/default.yamlagent_hueswith 16 default valuespkg/tui/service/sessionstate.goSetAgentOrderwhen available agents changepkg/tui/components/message/message.goAgentBadgeStyleFor(sender)pkg/tui/components/sidebar/sidebar.goAgentAccentStyleFor(agent.Name)pkg/tui/components/tabbar/tab.gocolorutil.go)pkg/tui/components/tabbar/tabbar.goMutedContrastFg/EnsureContrastpkg/tui/components/tool/handoff/handoff.gopkg/tui/components/tool/transfertask/transfertask.go