Selaa lähdekoodia

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

Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Aarav Sareen 2 kuukautta sitten
vanhempi
commit
4c6e2a92ce

+ 52 - 0
packages/session-ui/src/components/basic-tool.css

@@ -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"] {

+ 72 - 7
packages/session-ui/src/components/message-part.tsx

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

+ 18 - 0
packages/ui/src/styles/theme.css

@@ -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);

+ 26 - 0
packages/ui/src/theme/v2/mapping.ts

@@ -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)",

+ 40 - 0
packages/ui/src/v2/styles/theme.css

@@ -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;