feat(app): align subagent UI with v2 (#34931)

Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
This commit is contained in:
Aarav Sareen 2026-07-03 13:23:31 +05:30 committed by GitHub
commit 4c6e2a92ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 208 additions and 7 deletions

View file

@ -230,6 +230,7 @@
line-height: var(--line-height-large);
letter-spacing: var(--letter-spacing-normal);
text-transform: capitalize;
color: var(--task-agent-legacy-color, var(--text-strong));
}
[data-slot="basic-tool-tool-subtitle"] {
@ -247,6 +248,57 @@
}
}
body[data-new-layout] {
[data-component="task-tool-card"] {
padding: 8px 12px 8px 10px;
border-radius: 8px;
border: 0;
border-color: transparent;
background: var(--task-agent-background, light-dark(#fafafa, rgba(250, 250, 250, 0.15)));
box-shadow: inset 0 0 0 0.5px var(--task-agent-border, var(--v2-border-border-base));
[data-component="task-tool-spinner"],
[data-component="task-tool-title"] {
color: var(--task-agent-color, var(--text-strong));
}
[data-component="task-tool-title"] {
height: 20px;
font-family: var(--v2-font-family-sans, "Inter", sans-serif);
font-style: normal;
font-weight: 530;
font-size: 13px;
line-height: 20px;
letter-spacing: -0.04px;
flex: none;
flex-grow: 0;
}
[data-slot="basic-tool-tool-subtitle"] {
font-family: var(--v2-font-family-sans, "Inter", sans-serif);
font-style: normal;
font-weight: 440;
font-size: 13px;
line-height: 20px;
letter-spacing: -0.04px;
color: light-dark(var(--v2-text-text-base), #fafafa);
font-variation-settings: "slnt" 0;
flex: none;
flex-grow: 0;
}
[data-component="session-progress-indicator-v2"] {
color: var(--task-agent-color, light-dark(var(--v2-text-text-base), #ffffff));
}
&:hover,
&:focus-visible {
border-color: transparent;
background: var(--task-agent-background, light-dark(#fafafa, rgba(250, 250, 250, 0.15)));
}
}
}
body:not([data-new-layout]) {
[data-component="tool-trigger"] {
[data-slot="basic-tool-tool-spinner"] {

View file

@ -62,6 +62,7 @@ import { animate } from "motion"
import { useLocation } from "@solidjs/router"
import { attached, inline, kind } from "./message-file"
import { readPartText } from "./message-part-text"
import { SessionProgressIndicatorV2 } from "../v2/components/session-progress-indicator-v2"
async function writeClipboard(text: string): Promise<boolean> {
const body = typeof document === "undefined" ? undefined : document.body
@ -370,6 +371,44 @@ const agentTones: Record<string, string> = {
plan: "var(--icon-agent-plan-base)",
}
const v2AgentTones: Record<string, { color: string; border: string; background: string }> = {
build: {
color: "var(--v2-agent-build-solid)",
border: "var(--v2-agent-build-border)",
background: "var(--v2-agent-build-background)",
},
explore: {
color: "var(--v2-agent-explore-solid)",
border: "var(--v2-agent-explore-border)",
background: "var(--v2-agent-explore-background)",
},
plan: {
color: "var(--v2-agent-plan-solid)",
border: "var(--v2-agent-plan-border)",
background: "var(--v2-agent-plan-background)",
},
}
const agentThemeColors: Record<string, string> = {
primary: "var(--text-interactive-base)",
secondary: "var(--text-base)",
accent: "var(--icon-info-base)",
success: "var(--icon-success-base)",
warning: "var(--icon-warning-base)",
error: "var(--icon-critical-base)",
info: "var(--icon-info-base)",
}
const v2AgentThemeColors: Record<string, string> = {
primary: "var(--v2-text-text-accent)",
secondary: "var(--v2-text-text-muted)",
accent: "var(--v2-icon-icon-accent)",
success: "var(--v2-state-fg-success)",
warning: "var(--v2-state-fg-warning)",
error: "var(--v2-state-fg-danger)",
info: "var(--v2-state-fg-info)",
}
const agentPalette = [
"var(--icon-agent-ask-base)",
"var(--icon-agent-build-base)",
@ -394,16 +433,31 @@ function tone(name: string) {
function taskAgent(
raw: unknown,
list?: readonly { name: string; color?: string }[],
): { name?: string; color?: string } {
): { name?: string; color?: string; v2Color?: string; border?: string; background?: string } {
if (typeof raw !== "string" || !raw) return {}
const key = raw.toLowerCase()
const item = list?.find((entry) => entry.name === raw || entry.name.toLowerCase() === key)
const v2Tone = item?.color ? undefined : v2AgentTones[key]
const color = agentColor(item?.color, agentThemeColors) ?? agentTones[key] ?? tone(key)
const v2Color = agentColor(item?.color, v2AgentThemeColors) ?? v2Tone?.color ?? color
return {
name: item?.name ?? `${raw[0]!.toUpperCase()}${raw.slice(1)}`,
color: item?.color ?? agentTones[key] ?? tone(key),
color,
v2Color,
border: v2Tone?.border ?? `color-mix(in srgb, ${v2Color} 48%, transparent)`,
background: v2Tone?.background ?? `color-mix(in srgb, ${v2Color} 12%, transparent)`,
}
}
function agentColor(value: string | undefined, themeColors: Record<string, string>) {
if (!value) return
return themeColors[value] ?? value
}
function newLayout() {
return typeof document !== "undefined" && document.body.hasAttribute("data-new-layout")
}
function webSearchProviderLabel(provider: unknown) {
if (provider === "parallel") return "Parallel Web Search"
if (provider === "exa") return "Exa Web Search"
@ -1882,6 +1936,9 @@ ToolRegistry.register({
const agent = createMemo(() => taskAgent(props.input.subagent_type, data.store.agent))
const title = createMemo(() => agent().name ?? i18n.t("ui.tool.agent.default"))
const tone = createMemo(() => agent().color)
const v2Tone = createMemo(() => agent().v2Color)
const border = createMemo(() => agent().border)
const background = createMemo(() => agent().background)
const subtitle = createMemo(() => {
const value =
typeof props.input.description === "string" && props.input.description
@ -1921,17 +1978,25 @@ ToolRegistry.register({
}
const trigger = () => (
<div data-component="task-tool-card">
<div
data-component="task-tool-card"
style={{
"--task-agent-color": v2Tone(),
"--task-agent-legacy-color": tone(),
"--task-agent-border": border(),
"--task-agent-background": background(),
}}
>
<div data-slot="basic-tool-tool-info-structured">
<div data-slot="basic-tool-tool-info-main">
<Show when={running()}>
<span data-component="task-tool-spinner" style={{ color: tone() ?? "var(--icon-interactive-base)" }}>
<Spinner />
<Show when={newLayout()} fallback={<Spinner />}>
<SessionProgressIndicatorV2 style={{ color: v2Tone() ?? "light-dark(var(--v2-text-text-base), #ffffff)" }} />
</Show>
</span>
</Show>
<span data-component="task-tool-title" style={{ color: tone() ?? "var(--text-strong)" }}>
{title()}
</span>
<span data-component="task-tool-title">{title()}</span>
<Show when={subtitle()}>
<span data-slot="basic-tool-tool-subtitle">{subtitle()}</span>
</Show>

View file

@ -281,6 +281,15 @@
--icon-agent-docs-base: #fcb239;
--icon-agent-ask-base: #2090f5;
--icon-agent-build-base: #034cff;
--v2-agent-plan-solid: var(--v2-pink-900);
--v2-agent-plan-border: rgba(200, 61, 139, 0.5);
--v2-agent-plan-background: rgba(253, 236, 243, 0.33);
--v2-agent-build-solid: var(--v2-blue-900);
--v2-agent-build-border: rgba(59, 92, 246, 0.5);
--v2-agent-build-background: rgba(236, 241, 254, 0.33);
--v2-agent-explore-solid: var(--v2-yellow-900);
--v2-agent-explore-border: rgba(142, 114, 49, 0.5);
--v2-agent-explore-background: rgba(254, 250, 236, 0.33);
--icon-on-success-base: rgba(18, 201, 5, 0.9);
--icon-on-success-hover: rgba(45, 186, 38, 0.9);
--icon-on-success-selected: rgba(7, 137, 1, 0.9);
@ -541,6 +550,15 @@
--icon-agent-docs-base: #fbb73c;
--icon-agent-ask-base: #2090f5;
--icon-agent-build-base: #9dbefe;
--v2-agent-plan-solid: var(--v2-pink-400);
--v2-agent-plan-border: rgba(250, 188, 216, 0.5);
--v2-agent-plan-background: rgba(247, 213, 228, 0.1);
--v2-agent-build-solid: var(--v2-blue-400);
--v2-agent-build-border: rgba(215, 226, 252, 0.5);
--v2-agent-build-background: rgba(215, 226, 252, 0.1);
--v2-agent-explore-solid: var(--v2-yellow-400);
--v2-agent-explore-border: rgba(247, 229, 181, 0.5);
--v2-agent-explore-background: rgba(252, 239, 208, 0.1);
--icon-on-success-base: rgba(18, 201, 5, 0.9);
--icon-on-success-hover: rgba(53, 192, 45, 0.9);
--icon-on-success-selected: rgba(77, 225, 68, 0.9);

View file

@ -3,6 +3,30 @@ import { V2_AVATAR_DARK, V2_AVATAR_LIGHT } from "./avatar"
const ref = (name: string): V2ColorValue => `var(--${name})`
const lightAgentTokens: Record<string, V2ColorValue> = {
"v2-agent-plan-solid": ref("v2-pink-900"),
"v2-agent-plan-border": "rgba(200, 61, 139, 0.5)",
"v2-agent-plan-background": "rgba(253, 236, 243, 0.33)",
"v2-agent-build-solid": ref("v2-blue-900"),
"v2-agent-build-border": "rgba(59, 92, 246, 0.5)",
"v2-agent-build-background": "rgba(236, 241, 254, 0.33)",
"v2-agent-explore-solid": ref("v2-yellow-900"),
"v2-agent-explore-border": "rgba(142, 114, 49, 0.5)",
"v2-agent-explore-background": "rgba(254, 250, 236, 0.33)",
}
const darkAgentTokens: Record<string, V2ColorValue> = {
"v2-agent-plan-solid": ref("v2-pink-400"),
"v2-agent-plan-border": "rgba(250, 188, 216, 0.5)",
"v2-agent-plan-background": "rgba(247, 213, 228, 0.1)",
"v2-agent-build-solid": ref("v2-blue-400"),
"v2-agent-build-border": "rgba(215, 226, 252, 0.5)",
"v2-agent-build-background": "rgba(215, 226, 252, 0.1)",
"v2-agent-explore-solid": ref("v2-yellow-400"),
"v2-agent-explore-border": "rgba(247, 229, 181, 0.5)",
"v2-agent-explore-background": "rgba(252, 239, 208, 0.1)",
}
const light: Record<string, V2ColorValue> = {
"v2-background-bg-base": ref("v2-grey-100"),
"v2-background-bg-deep": ref("v2-grey-200"),
@ -46,6 +70,7 @@ const light: Record<string, V2ColorValue> = {
"v2-state-bg-info": ref("v2-blue-100"),
"v2-state-fg-info": ref("v2-blue-800"),
"v2-state-border-info": ref("v2-blue-300"),
...lightAgentTokens,
...V2_AVATAR_LIGHT,
"v2-elevation-raised":
"0px 2px 4px 0px var(--v2-alpha-dark-4), 0px 1px 2px -1px var(--v2-alpha-dark-8), 0px 0px 0px 0.5px var(--v2-alpha-dark-12), 0px 0px 0px 0px var(--v2-alpha-dark-0)",
@ -110,6 +135,7 @@ const dark: Record<string, V2ColorValue> = {
"v2-state-bg-info": ref("v2-blue-1200"),
"v2-state-fg-info": ref("v2-blue-500"),
"v2-state-border-info": ref("v2-blue-900"),
...darkAgentTokens,
...V2_AVATAR_DARK,
"v2-elevation-raised":
"0px 2px 4px 0px var(--v2-alpha-dark-30), 0px 1px 2px 0px var(--v2-alpha-dark-30), 0px 0px 0px 0.5px var(--v2-alpha-light-16), 0px -0.5px 0px 0px var(--v2-alpha-light-6)",

View file

@ -77,6 +77,16 @@
--v2-state-fg-info: var(--v2-blue-800);
--v2-state-border-info: var(--v2-blue-300);
--v2-agent-plan-solid: var(--v2-pink-900);
--v2-agent-plan-border: rgba(200, 61, 139, 0.5);
--v2-agent-plan-background: rgba(253, 236, 243, 0.33);
--v2-agent-build-solid: var(--v2-blue-900);
--v2-agent-build-border: rgba(59, 92, 246, 0.5);
--v2-agent-build-background: rgba(236, 241, 254, 0.33);
--v2-agent-explore-solid: var(--v2-yellow-900);
--v2-agent-explore-border: rgba(142, 114, 49, 0.5);
--v2-agent-explore-background: rgba(254, 250, 236, 0.33);
/* ── Project avatar (fixed; theme-independent) ── */
--v2-avatar-fg: #ffffffff;
--v2-avatar-bg-orange: #ee7330ff;
@ -193,6 +203,16 @@
--v2-state-fg-info: var(--v2-blue-500);
--v2-state-border-info: var(--v2-blue-900);
--v2-agent-plan-solid: var(--v2-pink-400);
--v2-agent-plan-border: rgba(250, 188, 216, 0.5);
--v2-agent-plan-background: rgba(247, 213, 228, 0.1);
--v2-agent-build-solid: var(--v2-blue-400);
--v2-agent-build-border: rgba(215, 226, 252, 0.5);
--v2-agent-build-background: rgba(215, 226, 252, 0.1);
--v2-agent-explore-solid: var(--v2-yellow-400);
--v2-agent-explore-border: rgba(247, 229, 181, 0.5);
--v2-agent-explore-background: rgba(252, 239, 208, 0.1);
--v2-elevation-raised:
0px 2px 4px 0px var(--v2-alpha-dark-30),
0px 1px 2px 0px var(--v2-alpha-dark-30),
@ -296,6 +316,16 @@
--v2-state-fg-info: var(--v2-blue-800);
--v2-state-border-info: var(--v2-blue-300);
--v2-agent-plan-solid: var(--v2-pink-900);
--v2-agent-plan-border: rgba(200, 61, 139, 0.5);
--v2-agent-plan-background: rgba(253, 236, 243, 0.33);
--v2-agent-build-solid: var(--v2-blue-900);
--v2-agent-build-border: rgba(59, 92, 246, 0.5);
--v2-agent-build-background: rgba(236, 241, 254, 0.33);
--v2-agent-explore-solid: var(--v2-yellow-900);
--v2-agent-explore-border: rgba(142, 114, 49, 0.5);
--v2-agent-explore-background: rgba(254, 250, 236, 0.33);
--v2-elevation-raised:
0px 2px 4px 0px var(--v2-alpha-dark-4), 0px 1px 2px -1px var(--v2-alpha-dark-8),
0px 0px 0px 0.5px var(--v2-alpha-dark-12), 0px 0px 0px 0px var(--v2-alpha-dark-0);
@ -406,6 +436,16 @@
--v2-state-fg-info: var(--v2-blue-500);
--v2-state-border-info: var(--v2-blue-900);
--v2-agent-plan-solid: var(--v2-pink-400);
--v2-agent-plan-border: rgba(250, 188, 216, 0.5);
--v2-agent-plan-background: rgba(247, 213, 228, 0.1);
--v2-agent-build-solid: var(--v2-blue-400);
--v2-agent-build-border: rgba(215, 226, 252, 0.5);
--v2-agent-build-background: rgba(215, 226, 252, 0.1);
--v2-agent-explore-solid: var(--v2-yellow-400);
--v2-agent-explore-border: rgba(247, 229, 181, 0.5);
--v2-agent-explore-background: rgba(252, 239, 208, 0.1);
--v2-avatar-fg: #ffffffff;
--v2-avatar-bg-orange: #723d22ff;
--v2-avatar-border-orange: #ff8648ff;