@tangle-network/ui 9.1.0 → 9.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 9.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d50f746: Give run/timeline tool rows a proper elevation ladder. Rows read as the same value as the canvas: `InlineToolItem` used `bg-card/40` (near-transparent) and RunGroup's OpenUI/running blocks used `bg-[var(--bg-root)]` (literally the page background). Both now use `--md3-surface-container` — one clear step above the `--bg-root` canvas — with hover/open stepping to `--md3-surface-container-high`. Rows now separate from the background instead of blending into it.
8
+ - d50f746: One user-message bubble. There were two: the exported `UserMessage` (a loud filled purple bubble with an uppercase "You" label + shadow, used by the run/message list) and a separate cleaner inline bubble inside `AgentTimeline`. Unify on the clean one — `UserMessage` is now a quiet right-aligned bordered bubble on the muted surface (no fill, no uppercase label), and `AgentTimeline` renders through it instead of its own copy. `UserMessage` accepts either session-model `parts` or a direct `content`/`timestamp`, so both call sites share it.
9
+
10
+ ## 9.1.1
11
+
12
+ ### Patch Changes
13
+
14
+ - a8d770e: Give run/timeline tool rows a proper elevation ladder. Rows read as the same value as the canvas: `InlineToolItem` used `bg-card/40` (near-transparent) and RunGroup's OpenUI/running blocks used `bg-[var(--bg-root)]` (literally the page background). Both now use `--md3-surface-container` — one clear step above the `--bg-root` canvas — with hover/open stepping to `--md3-surface-container-high`. Rows now separate from the background instead of blending into it.
15
+
3
16
  ## 9.1.0
4
17
 
5
18
  ### Minor Changes
package/dist/chat.d.ts CHANGED
@@ -75,15 +75,20 @@ interface MessageListProps {
75
75
  declare const MessageList: React.MemoExoticComponent<({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, renderRunActions, renderUserMessageActions, renderToolActions, }: MessageListProps) => react_jsx_runtime.JSX.Element>;
76
76
 
77
77
  interface UserMessageProps {
78
- message: SessionMessage;
79
- parts: SessionPart[];
78
+ /** Session-model input: text is derived from these parts. */
79
+ message?: SessionMessage;
80
+ parts?: SessionPart[];
81
+ /** Direct-content input (e.g. AgentTimeline): explicit text + timestamp. */
82
+ content?: string;
83
+ timestamp?: Date;
80
84
  actions?: ReactNode;
81
85
  }
82
86
  /**
83
- * Simple user message bubble.
84
- * Renders text parts from the user's message.
87
+ * The single user message bubble — a quiet, right-aligned bordered bubble on the
88
+ * muted surface (no loud fill, no uppercase label). Used by both the run/message
89
+ * list (session-model `parts`) and AgentTimeline (direct `content`/`timestamp`).
85
90
  */
86
- declare const UserMessage: React.MemoExoticComponent<({ message, parts, actions }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
91
+ declare const UserMessage: React.MemoExoticComponent<({ message: _message, parts, content, timestamp, actions }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
87
92
 
88
93
  type MessageRole = "user" | "assistant" | "system";
89
94
  interface ChatMessageProps {
package/dist/chat.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  MessageList,
6
6
  ThinkingIndicator,
7
7
  UserMessage
8
- } from "./chunk-4RDW4GFG.js";
8
+ } from "./chunk-BQVQGDDV.js";
9
9
  import "./chunk-AZWDI2JG.js";
10
- import "./chunk-CVXAXVYZ.js";
11
- import "./chunk-J6RQHBHR.js";
10
+ import "./chunk-KWRLQ3MR.js";
11
+ import "./chunk-WVW4KHEH.js";
12
12
  import "./chunk-ULDNFLIM.js";
13
13
  import "./chunk-AAUNOHVL.js";
14
14
  import "./chunk-52Y3FMFI.js";
@@ -6,11 +6,11 @@ import {
6
6
  import {
7
7
  InlineThinkingItem,
8
8
  RunGroup
9
- } from "./chunk-CVXAXVYZ.js";
9
+ } from "./chunk-KWRLQ3MR.js";
10
10
  import {
11
11
  ToolCallGroup,
12
12
  ToolCallStep
13
- } from "./chunk-J6RQHBHR.js";
13
+ } from "./chunk-WVW4KHEH.js";
14
14
  import {
15
15
  getToolDisplayMetadata
16
16
  } from "./chunk-ULDNFLIM.js";
@@ -38,17 +38,22 @@ import { memo as memo2 } from "react";
38
38
  // src/chat/user-message.tsx
39
39
  import { memo } from "react";
40
40
  import { jsx, jsxs } from "react/jsx-runtime";
41
- var UserMessage = memo(({ message, parts, actions }) => {
42
- const textContent = parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
43
- if (!textContent.trim()) return null;
44
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[78%] flex-col items-end gap-2", children: [
45
- /* @__PURE__ */ jsxs("div", { className: "w-full rounded-[26px] rounded-br-[12px] bg-[var(--brand-primary)] px-4 py-3 text-white shadow-[0_8px_20px_rgba(15,23,42,0.12)]", children: [
46
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-white/60", children: "You" }),
47
- /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-[15px] leading-6.5 text-white", children: textContent })
48
- ] }),
49
- actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground", children: actions }) : null
50
- ] }) });
51
- });
41
+ function formatTime(date) {
42
+ return date.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
43
+ }
44
+ var UserMessage = memo(
45
+ ({ message: _message, parts, content, timestamp, actions }) => {
46
+ const text = content ?? (parts ?? []).filter((p) => p.type === "text").map((p) => p.text).join("\n");
47
+ if (!text.trim()) return null;
48
+ return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[78%] flex-col items-end gap-2", children: [
49
+ /* @__PURE__ */ jsxs("div", { className: "w-full rounded-2xl border border-border bg-muted/50 px-4 py-3", children: [
50
+ timestamp ? /* @__PURE__ */ jsx("div", { className: "mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(timestamp) }) : null,
51
+ /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: text })
52
+ ] }),
53
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground", children: actions }) : null
54
+ ] }) });
55
+ }
56
+ );
52
57
  UserMessage.displayName = "UserMessage";
53
58
 
54
59
  // src/chat/message-list.tsx
@@ -162,7 +167,7 @@ var TONE_STYLES = {
162
167
  icon: AlertTriangle
163
168
  }
164
169
  };
165
- function formatTime(date) {
170
+ function formatTime2(date) {
166
171
  return date.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
167
172
  }
168
173
  function AgentTimelineRow({ isLast, accentClassName, children }) {
@@ -174,15 +179,9 @@ function AgentTimelineRow({ isLast, accentClassName, children }) {
174
179
  /* @__PURE__ */ jsx4("div", { className: "min-w-0 pb-3", children })
175
180
  ] });
176
181
  }
177
- function UserMessage2({ item }) {
178
- return /* @__PURE__ */ jsx4("div", { className: "mb-3 flex justify-end", children: /* @__PURE__ */ jsx4("div", { className: "max-w-[72%]", children: /* @__PURE__ */ jsxs3("div", { className: "rounded-2xl border border-border bg-muted/50 px-4 py-3", children: [
179
- item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(item.timestamp) }),
180
- /* @__PURE__ */ jsx4("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: item.content })
181
- ] }) }) });
182
- }
183
182
  function AssistantMessage({ item }) {
184
183
  return /* @__PURE__ */ jsxs3("div", { className: "-mt-0.5", children: [
185
- item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-2 text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(item.timestamp) }),
184
+ item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-2 text-[var(--font-size-xs)] text-muted-foreground", children: formatTime2(item.timestamp) }),
186
185
  item.content && /* @__PURE__ */ jsx4(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]", children: item.content }),
187
186
  item.isStreaming && /* @__PURE__ */ jsx4("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-primary align-text-bottom" }),
188
187
  item.toolCalls && /* @__PURE__ */ jsx4("div", { className: "mt-3", children: item.toolCalls }),
@@ -243,7 +242,7 @@ function AgentTimeline({
243
242
  const timelineItems = renderedItems.filter((item) => !(item.kind === "message" && item.role === "user"));
244
243
  return /* @__PURE__ */ jsx4("div", { className: cn("mx-auto w-full max-w-5xl px-4 py-4", className), children: renderedItems.map((item, index) => {
245
244
  if (item.kind === "message" && item.role === "user") {
246
- return /* @__PURE__ */ jsx4(UserMessage2, { item }, item.id);
245
+ return /* @__PURE__ */ jsx4(UserMessage, { content: item.content, timestamp: item.timestamp }, item.id);
247
246
  }
248
247
  const timelineIndex = timelineItems.indexOf(item);
249
248
  const isLast = timelineIndex === timelineItems.length - 1;
@@ -643,7 +642,7 @@ function ChatMessage({
643
642
  children: [
644
643
  !hideRoleLabel && /* @__PURE__ */ jsxs5("div", { className: cn("flex items-center gap-2 px-1", isUser && "flex-row-reverse"), children: [
645
644
  /* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground text-xs", children: isUser ? userLabel : assistantLabel }),
646
- timestamp && /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: formatTime2(timestamp) })
645
+ timestamp && /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: formatTime3(timestamp) })
647
646
  ] }),
648
647
  /* @__PURE__ */ jsxs5(
649
648
  "div",
@@ -666,7 +665,7 @@ function ChatMessage({
666
665
  }
667
666
  );
668
667
  }
669
- function formatTime2(date) {
668
+ function formatTime3(date) {
670
669
  return date.toLocaleTimeString(void 0, {
671
670
  hour: "numeric",
672
671
  minute: "2-digit"
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-OEX7NZE3.js";
12
12
  import {
13
13
  parseToolEvent
14
- } from "./chunk-N5DJ4TUO.js";
14
+ } from "./chunk-V6BF4AZ7.js";
15
15
 
16
16
  // src/hooks/use-dropdown-menu.ts
17
17
  import { useEffect, useRef, useState } from "react";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  InlineToolItem,
3
3
  LiveDuration
4
- } from "./chunk-J6RQHBHR.js";
4
+ } from "./chunk-WVW4KHEH.js";
5
5
  import {
6
6
  formatDuration,
7
7
  truncateText
@@ -347,7 +347,7 @@ var RunGroup = memo2(
347
347
  return /* @__PURE__ */ jsxs2(
348
348
  "div",
349
349
  {
350
- className: "overflow-hidden rounded-[22px] border border-[var(--border-subtle)] bg-[var(--bg-root)]",
350
+ className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]",
351
351
  children: [
352
352
  summary ? /* @__PURE__ */ jsx2("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground", children: summary }) : null,
353
353
  /* @__PURE__ */ jsx2("div", { className: "p-4", children: /* @__PURE__ */ jsx2(OpenUIArtifactRenderer, { schema }) })
@@ -360,7 +360,7 @@ var RunGroup = memo2(
360
360
  return /* @__PURE__ */ jsxs2(
361
361
  "div",
362
362
  {
363
- className: "flex items-center gap-2 rounded-[18px] border border-[var(--border-subtle)] bg-[var(--bg-root)] px-4 py-3 text-sm text-muted-foreground",
363
+ className: "flex items-center gap-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)] px-4 py-3 text-sm text-muted-foreground",
364
364
  children: [
365
365
  /* @__PURE__ */ jsx2(Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
366
366
  "Building view\u2026"
@@ -423,12 +423,12 @@ var RunGroup = memo2(
423
423
  const schema = extractOpenUISchema(toolPart.state.output);
424
424
  const summary = getOpenUISummary(toolPart.state.output);
425
425
  if (toolPart.state.status === "completed" && schema) {
426
- node = /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)]", children: [
426
+ node = /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]", children: [
427
427
  summary ? /* @__PURE__ */ jsx2("div", { className: "border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground", children: summary }) : null,
428
428
  /* @__PURE__ */ jsx2("div", { className: "p-4", children: /* @__PURE__ */ jsx2(OpenUIArtifactRenderer, { schema }) })
429
429
  ] });
430
430
  } else if (toolPart.state.status === "running") {
431
- node = /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-4 py-3 text-sm text-muted-foreground", children: [
431
+ node = /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)] px-4 py-3 text-sm text-muted-foreground", children: [
432
432
  /* @__PURE__ */ jsx2(Loader2, { className: "h-4 w-4 animate-spin text-primary" }),
433
433
  "Building view\u2026"
434
434
  ] });
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ToolCallGroup,
3
3
  ToolCallStep
4
- } from "./chunk-J6RQHBHR.js";
4
+ } from "./chunk-WVW4KHEH.js";
5
5
  import {
6
6
  Markdown
7
7
  } from "./chunk-FJBTCTZM.js";
@@ -227,8 +227,8 @@ var InlineToolItem = memo2(
227
227
  {
228
228
  className: cn(
229
229
  "w-full border text-left transition-colors",
230
- "border-[var(--border-subtle)] bg-card/40 hover:border-border hover:bg-accent/25",
231
- open && "border-border bg-accent/20",
230
+ "border-[var(--border-subtle)] bg-[var(--md3-surface-container)] hover:border-border hover:bg-[var(--md3-surface-container-high)]",
231
+ open && "border-border bg-[var(--md3-surface-container-high)]",
232
232
  shapeClass,
233
233
  className
234
234
  ),
package/dist/hooks.js CHANGED
@@ -11,15 +11,15 @@ import {
11
11
  useSSEStream,
12
12
  useSdkSession,
13
13
  useToolCallStream
14
- } from "./chunk-A5HKP3NA.js";
14
+ } from "./chunk-IVQYFG5D.js";
15
15
  import "./chunk-OEX7NZE3.js";
16
16
  import {
17
17
  useAutoScroll,
18
18
  useRunCollapseState,
19
19
  useRunGroups
20
20
  } from "./chunk-AZWDI2JG.js";
21
- import "./chunk-N5DJ4TUO.js";
22
- import "./chunk-J6RQHBHR.js";
21
+ import "./chunk-V6BF4AZ7.js";
22
+ import "./chunk-WVW4KHEH.js";
23
23
  import "./chunk-ULDNFLIM.js";
24
24
  import "./chunk-AAUNOHVL.js";
25
25
  import "./chunk-ZRVH3WCA.js";
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  useSSEStream,
18
18
  useSdkSession,
19
19
  useToolCallStream
20
- } from "./chunk-A5HKP3NA.js";
20
+ } from "./chunk-IVQYFG5D.js";
21
21
  import {
22
22
  addMessage,
23
23
  addParts,
@@ -137,7 +137,7 @@ import {
137
137
  MessageList,
138
138
  ThinkingIndicator,
139
139
  UserMessage
140
- } from "./chunk-4RDW4GFG.js";
140
+ } from "./chunk-BQVQGDDV.js";
141
141
  import {
142
142
  useAutoScroll,
143
143
  useRunCollapseState,
@@ -147,16 +147,16 @@ import "./chunk-47XH56SV.js";
147
147
  import {
148
148
  ToolCallFeed,
149
149
  parseToolEvent
150
- } from "./chunk-N5DJ4TUO.js";
150
+ } from "./chunk-V6BF4AZ7.js";
151
151
  import {
152
152
  InlineThinkingItem,
153
153
  RunGroup
154
- } from "./chunk-CVXAXVYZ.js";
154
+ } from "./chunk-KWRLQ3MR.js";
155
155
  import {
156
156
  ExpandedToolDetail,
157
157
  InlineToolItem,
158
158
  LiveDuration
159
- } from "./chunk-J6RQHBHR.js";
159
+ } from "./chunk-WVW4KHEH.js";
160
160
  import {
161
161
  TOOL_CATEGORY_ICONS,
162
162
  formatBytes,
package/dist/run.js CHANGED
@@ -2,16 +2,16 @@ import "./chunk-47XH56SV.js";
2
2
  import {
3
3
  ToolCallFeed,
4
4
  parseToolEvent
5
- } from "./chunk-N5DJ4TUO.js";
5
+ } from "./chunk-V6BF4AZ7.js";
6
6
  import {
7
7
  InlineThinkingItem,
8
8
  RunGroup
9
- } from "./chunk-CVXAXVYZ.js";
9
+ } from "./chunk-KWRLQ3MR.js";
10
10
  import {
11
11
  ExpandedToolDetail,
12
12
  InlineToolItem,
13
13
  LiveDuration
14
- } from "./chunk-J6RQHBHR.js";
14
+ } from "./chunk-WVW4KHEH.js";
15
15
  import "./chunk-ULDNFLIM.js";
16
16
  import "./chunk-AAUNOHVL.js";
17
17
  import "./chunk-52Y3FMFI.js";
package/dist/sdk-hooks.js CHANGED
@@ -5,15 +5,15 @@ import {
5
5
  useSSEStream,
6
6
  useSdkSession,
7
7
  useToolCallStream
8
- } from "./chunk-A5HKP3NA.js";
8
+ } from "./chunk-IVQYFG5D.js";
9
9
  import "./chunk-OEX7NZE3.js";
10
10
  import {
11
11
  useAutoScroll,
12
12
  useRunCollapseState,
13
13
  useRunGroups
14
14
  } from "./chunk-AZWDI2JG.js";
15
- import "./chunk-N5DJ4TUO.js";
16
- import "./chunk-J6RQHBHR.js";
15
+ import "./chunk-V6BF4AZ7.js";
16
+ import "./chunk-WVW4KHEH.js";
17
17
  import "./chunk-ULDNFLIM.js";
18
18
  import "./chunk-AAUNOHVL.js";
19
19
  import "./chunk-ZRVH3WCA.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/ui",
3
- "version": "9.1.0",
3
+ "version": "9.1.2",
4
4
  "description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -8,6 +8,7 @@ import {
8
8
  } from "lucide-react";
9
9
  import { cn } from "../lib/utils";
10
10
  import { type MessageRole } from "./chat-message";
11
+ import { UserMessage } from "./user-message";
11
12
  import { Markdown } from "../markdown/markdown";
12
13
  import { ThinkingIndicator } from "./thinking-indicator";
13
14
  import { type ToolCallData } from "../run/tool-call-feed";
@@ -146,25 +147,6 @@ function AgentTimelineRow({ isLast, accentClassName, children }: AgentTimelineRo
146
147
  );
147
148
  }
148
149
 
149
- function UserMessage({ item }: { item: AgentTimelineMessageItem }) {
150
- return (
151
- <div className="mb-3 flex justify-end">
152
- <div className="max-w-[72%]">
153
- <div className="rounded-2xl border border-border bg-muted/50 px-4 py-3">
154
- {item.timestamp && (
155
- <div className="mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground">
156
- {formatTime(item.timestamp)}
157
- </div>
158
- )}
159
- <div className="whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground">
160
- {item.content}
161
- </div>
162
- </div>
163
- </div>
164
- </div>
165
- );
166
- }
167
-
168
150
  function AssistantMessage({ item }: { item: AgentTimelineMessageItem }) {
169
151
  return (
170
152
  <div className="-mt-0.5">
@@ -285,7 +267,7 @@ export function AgentTimeline({
285
267
  {renderedItems.map((item, index) => {
286
268
  // User messages: right-aligned bubble, no connector
287
269
  if (item.kind === "message" && item.role === "user") {
288
- return <UserMessage key={item.id} item={item} />;
270
+ return <UserMessage key={item.id} content={item.content} timestamp={item.timestamp} />;
289
271
  }
290
272
 
291
273
  const timelineIndex = timelineItems.indexOf(item);
@@ -3,41 +3,56 @@ import type { SessionMessage } from "../types/message";
3
3
  import type { SessionPart } from "../types/parts";
4
4
 
5
5
  export interface UserMessageProps {
6
- message: SessionMessage;
7
- parts: SessionPart[];
6
+ /** Session-model input: text is derived from these parts. */
7
+ message?: SessionMessage;
8
+ parts?: SessionPart[];
9
+ /** Direct-content input (e.g. AgentTimeline): explicit text + timestamp. */
10
+ content?: string;
11
+ timestamp?: Date;
8
12
  actions?: ReactNode;
9
13
  }
10
14
 
15
+ function formatTime(date: Date): string {
16
+ return date.toLocaleTimeString(undefined, { hour: "numeric", minute: "2-digit" });
17
+ }
18
+
11
19
  /**
12
- * Simple user message bubble.
13
- * Renders text parts from the user's message.
20
+ * The single user message bubble — a quiet, right-aligned bordered bubble on the
21
+ * muted surface (no loud fill, no uppercase label). Used by both the run/message
22
+ * list (session-model `parts`) and AgentTimeline (direct `content`/`timestamp`).
14
23
  */
15
- export const UserMessage = memo(({ message, parts, actions }: UserMessageProps) => {
16
- const textContent = parts
17
- .filter((p) => p.type === "text")
18
- .map((p) => (p as { text: string }).text)
19
- .join("\n");
24
+ export const UserMessage = memo(
25
+ ({ message: _message, parts, content, timestamp, actions }: UserMessageProps) => {
26
+ const text =
27
+ content ??
28
+ (parts ?? [])
29
+ .filter((p) => p.type === "text")
30
+ .map((p) => (p as { text: string }).text)
31
+ .join("\n");
20
32
 
21
- if (!textContent.trim()) return null;
33
+ if (!text.trim()) return null;
22
34
 
23
- return (
24
- <div className="flex justify-end">
25
- <div className="flex max-w-[78%] flex-col items-end gap-2">
26
- <div className="w-full rounded-[26px] rounded-br-[12px] bg-[var(--brand-primary)] px-4 py-3 text-white shadow-[0_8px_20px_rgba(15,23,42,0.12)]">
27
- <div className="mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-white/60">
28
- You
29
- </div>
30
- <div className="whitespace-pre-wrap text-[15px] leading-6.5 text-white">
31
- {textContent}
35
+ return (
36
+ <div className="flex justify-end">
37
+ <div className="flex max-w-[78%] flex-col items-end gap-2">
38
+ <div className="w-full rounded-2xl border border-border bg-muted/50 px-4 py-3">
39
+ {timestamp ? (
40
+ <div className="mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground">
41
+ {formatTime(timestamp)}
42
+ </div>
43
+ ) : null}
44
+ <div className="whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground">
45
+ {text}
46
+ </div>
32
47
  </div>
48
+ {actions ? (
49
+ <div className="flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground">
50
+ {actions}
51
+ </div>
52
+ ) : null}
33
53
  </div>
34
- {actions ? (
35
- <div className="flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground">
36
- {actions}
37
- </div>
38
- ) : null}
39
54
  </div>
40
- </div>
41
- );
42
- });
55
+ );
56
+ },
57
+ );
43
58
  UserMessage.displayName = "UserMessage";
@@ -109,8 +109,8 @@ export const InlineToolItem = memo(
109
109
  <button
110
110
  className={cn(
111
111
  "w-full border text-left transition-colors",
112
- "border-[var(--border-subtle)] bg-card/40 hover:border-border hover:bg-accent/25",
113
- open && "border-border bg-accent/20",
112
+ "border-[var(--border-subtle)] bg-[var(--md3-surface-container)] hover:border-border hover:bg-[var(--md3-surface-container-high)]",
113
+ open && "border-border bg-[var(--md3-surface-container-high)]",
114
114
  shapeClass,
115
115
  className,
116
116
  )}
@@ -366,7 +366,7 @@ export const RunGroup = memo(
366
366
  return (
367
367
  <div
368
368
  key={key}
369
- className="overflow-hidden rounded-[22px] border border-[var(--border-subtle)] bg-[var(--bg-root)]"
369
+ className="overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]"
370
370
  >
371
371
  {summary ? (
372
372
  <div className="border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground">
@@ -384,7 +384,7 @@ export const RunGroup = memo(
384
384
  return (
385
385
  <div
386
386
  key={key}
387
- className="flex items-center gap-2 rounded-[18px] border border-[var(--border-subtle)] bg-[var(--bg-root)] px-4 py-3 text-sm text-muted-foreground"
387
+ className="flex items-center gap-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)] px-4 py-3 text-sm text-muted-foreground"
388
388
  >
389
389
  <Loader2 className="h-4 w-4 animate-spin text-primary" />
390
390
  Building view…
@@ -493,7 +493,7 @@ export const RunGroup = memo(
493
493
 
494
494
  if (toolPart.state.status === "completed" && schema) {
495
495
  node = (
496
- <div className="overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)]">
496
+ <div className="overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]">
497
497
  {summary ? (
498
498
  <div className="border-b border-[var(--border-subtle)] px-4 py-3 text-sm leading-6 text-foreground">
499
499
  {summary}
@@ -506,7 +506,7 @@ export const RunGroup = memo(
506
506
  );
507
507
  } else if (toolPart.state.status === "running") {
508
508
  node = (
509
- <div className="flex items-center gap-3 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-4 py-3 text-sm text-muted-foreground">
509
+ <div className="flex items-center gap-3 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)] px-4 py-3 text-sm text-muted-foreground">
510
510
  <Loader2 className="h-4 w-4 animate-spin text-primary" />
511
511
  Building view…
512
512
  </div>