@tangle-network/ui 8.1.0 → 9.1.0

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,25 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 9.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - deb065a: AgentTimeline now accepts `renderToolActions` (and carries the source `ToolPart` on its tool items) so consumers can render actions beside a tool call — e.g. "open in artifacts". Previously these hooks reached only the run-grouped `MessageList`, not the timeline presentation. ChatContainer exposes this through a new `renderTimelineToolActions?(part)` prop; the existing `renderToolActions(part, options)` contract for the `runs` presentation is unchanged.
8
+
9
+ The timeline tool-call summary now shows a human-readable detail (file path / command via `getToolDisplayMetadata`) instead of the raw input JSON, and drops the redundant `title: description` label. The source `ToolPart` is threaded into `ToolCallStep`, so the expanded detail renders the full input + output via `ExpandedToolDetail` (previously the timeline's expanded view showed only the output).
10
+
11
+ ## 9.0.0
12
+
13
+ ### Major Changes
14
+
15
+ - 87252cf: Flip the transcript convergence: RunGroup adopts AgentTimeline's look, not the reverse. 8.1 made AgentTimeline fold tool activity into RunGroup's single filled box (`AssistantRunShell`); that boxed all steps into one card and lost the timeline's separated, distinct rows. Reverted.
16
+
17
+ - **`RunGroup`** now renders as separated steps on a timeline spine (connector line + accent dots, one row per tool/reasoning/text part) with a quiet collapsible header (chevron · label · summary · status) — no wrapping `bg-card` box, and consecutive tools are no longer joined into one block. It reads like `AgentTimeline`, plus collapse.
18
+ - **`AgentTimeline`** is restored to its prior flat, separated rendering (no tool-run folding). The `collapsibleToolRuns` / `defaultToolRunsOpen` props added in 8.1 are removed.
19
+ - **`AssistantRunShell`** (added in 8.1) is removed — the boxed shell is gone.
20
+
21
+ BREAKING: `AssistantRunShell` / `AssistantRunShellProps` are no longer exported, and `AgentTimeline` drops the `collapsibleToolRuns` / `defaultToolRunsOpen` props.
22
+
3
23
  ## 8.1.0
4
24
 
5
25
  ### Minor Changes
package/dist/chat.d.ts CHANGED
@@ -32,18 +32,22 @@ interface ChatContainerProps {
32
32
  renderRunActions?: (run: Run) => ReactNode;
33
33
  /** Optional actions rendered below each user message bubble. */
34
34
  renderUserMessageActions?: (message: SessionMessage, parts: SessionPart[]) => ReactNode;
35
- /** Optional actions rendered beside individual tool items. */
35
+ /** Optional actions rendered beside individual tool items in the run-grouped
36
+ * (`runs`) presentation. */
36
37
  renderToolActions?: (part: ToolPart, options: {
37
38
  run: Run;
38
39
  messageId: string;
39
40
  partIndex: number;
40
41
  }) => ReactNode;
42
+ /** Optional actions rendered beside individual tool items in the `timeline`
43
+ * presentation, which has no run/message grouping (hence part-only). */
44
+ renderTimelineToolActions?: (part: ToolPart) => ReactNode;
41
45
  }
42
46
  /**
43
47
  * Chat transcript container: message list + auto-scroll.
44
48
  * Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
45
49
  */
46
- declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
50
+ declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, renderTimelineToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
47
51
 
48
52
  interface MessageListProps {
49
53
  groups: GroupedMessage[];
@@ -121,12 +125,17 @@ interface AgentTimelineToolItem {
121
125
  id: string;
122
126
  kind: "tool";
123
127
  call: ToolCallData;
128
+ /** Source tool part, so a consumer's `renderToolActions` gets the real
129
+ * input/output (the flat `call` is display-only). */
130
+ part?: ToolPart;
124
131
  }
125
132
  interface AgentTimelineToolGroupItem {
126
133
  id: string;
127
134
  kind: "tool_group";
128
135
  title?: string;
129
136
  calls: ToolCallData[];
137
+ /** Source tool parts, parallel to `calls`. */
138
+ parts?: ToolPart[];
130
139
  }
131
140
  interface AgentTimelineStatusItem {
132
141
  id: string;
@@ -157,21 +166,15 @@ interface AgentTimelineProps {
157
166
  isThinking?: boolean;
158
167
  emptyState?: ReactNode;
159
168
  className?: string;
160
- /**
161
- * Fold consecutive tool / tool-group items into one collapsible run shell
162
- * (the same `AssistantRunShell` `RunGroup` uses), so a burst of tool activity
163
- * reads as a single toggleable step instead of a long ladder of rows.
164
- * Default true; pass false for the flat one-row-per-tool timeline.
165
- */
166
- collapsibleToolRuns?: boolean;
167
- /** Start collapsed tool runs open (true) or collapsed (false). Default open. */
168
- defaultToolRunsOpen?: boolean;
169
+ /** Optional actions rendered beside each tool item (e.g. "open in artifacts").
170
+ * Receives the source tool part carried on the item. */
171
+ renderToolActions?: (part: ToolPart) => ReactNode;
169
172
  }
170
173
  /**
171
174
  * AgentTimeline — unified mixed-content timeline for agent-backed sandbox
172
175
  * sessions. Renders messages, tool steps, status cards, and artifact handoffs in
173
176
  * a single execution narrative.
174
177
  */
175
- declare function AgentTimeline({ items, isThinking, emptyState, className, collapsibleToolRuns, defaultToolRunsOpen, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
178
+ declare function AgentTimeline({ items, isThinking, emptyState, className, renderToolActions, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
176
179
 
177
180
  export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
package/dist/chat.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  MessageList,
6
6
  ThinkingIndicator,
7
7
  UserMessage
8
- } from "./chunk-QUAU6ZNC.js";
8
+ } from "./chunk-4RDW4GFG.js";
9
9
  import "./chunk-AZWDI2JG.js";
10
- import "./chunk-C3BIVG72.js";
11
- import "./chunk-RKQDBRTC.js";
10
+ import "./chunk-CVXAXVYZ.js";
11
+ import "./chunk-J6RQHBHR.js";
12
12
  import "./chunk-ULDNFLIM.js";
13
13
  import "./chunk-AAUNOHVL.js";
14
14
  import "./chunk-52Y3FMFI.js";
@@ -4,14 +4,13 @@ import {
4
4
  useRunGroups
5
5
  } from "./chunk-AZWDI2JG.js";
6
6
  import {
7
- AssistantRunShell,
8
7
  InlineThinkingItem,
9
8
  RunGroup
10
- } from "./chunk-C3BIVG72.js";
9
+ } from "./chunk-CVXAXVYZ.js";
11
10
  import {
12
11
  ToolCallGroup,
13
12
  ToolCallStep
14
- } from "./chunk-RKQDBRTC.js";
13
+ } from "./chunk-J6RQHBHR.js";
15
14
  import {
16
15
  getToolDisplayMetadata
17
16
  } from "./chunk-ULDNFLIM.js";
@@ -99,7 +98,6 @@ var MessageList = memo2(
99
98
  MessageList.displayName = "MessageList";
100
99
 
101
100
  // src/chat/agent-timeline.tsx
102
- import { useState as useState2 } from "react";
103
101
  import {
104
102
  AlertTriangle,
105
103
  CheckCircle2,
@@ -132,48 +130,6 @@ function ThinkingIndicator({ className }) {
132
130
 
133
131
  // src/chat/agent-timeline.tsx
134
132
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
135
- function foldToolRuns(items) {
136
- const nodes = [];
137
- let run = [];
138
- const flush = () => {
139
- if (run.length === 0) return;
140
- if (run.length === 1) {
141
- nodes.push(run[0]);
142
- } else {
143
- nodes.push({ id: `tool-run-${run[0].id}`, kind: "tool_run", items: run });
144
- }
145
- run = [];
146
- };
147
- for (const item of items) {
148
- if (item.kind === "tool" || item.kind === "tool_group") {
149
- run.push(item);
150
- } else {
151
- flush();
152
- nodes.push(item);
153
- }
154
- }
155
- flush();
156
- return nodes;
157
- }
158
- function countTools(group) {
159
- return group.items.reduce(
160
- (n, item) => n + (item.kind === "tool_group" ? item.calls.length : 1),
161
- 0
162
- );
163
- }
164
- function ToolCallRow({ call }) {
165
- return /* @__PURE__ */ jsx4(
166
- ToolCallStep,
167
- {
168
- type: call.type,
169
- label: call.label,
170
- status: call.status,
171
- detail: call.detail,
172
- output: call.output,
173
- duration: call.duration
174
- }
175
- );
176
- }
177
133
  var TONE_STYLES = {
178
134
  default: {
179
135
  dot: "bg-[var(--border-hover)]",
@@ -278,75 +234,79 @@ function AgentTimeline({
278
234
  isThinking,
279
235
  emptyState,
280
236
  className,
281
- collapsibleToolRuns = true,
282
- defaultToolRunsOpen = true
237
+ renderToolActions
283
238
  }) {
284
- const [collapsedRuns, setCollapsedRuns] = useState2({});
285
- const toggleRun = (id) => setCollapsedRuns((prev) => ({
286
- ...prev,
287
- [id]: prev[id] === void 0 ? defaultToolRunsOpen : !prev[id]
288
- }));
289
239
  if (items.length === 0 && !isThinking) {
290
240
  return emptyState ? /* @__PURE__ */ jsx4("div", { className: cn("flex h-full items-center justify-center p-4", className), children: emptyState }) : null;
291
241
  }
292
242
  const renderedItems = isThinking ? [...items, { id: "__thinking__", kind: "custom", content: /* @__PURE__ */ jsx4(ThinkingIndicator, {}) }] : items;
293
- const nodes = collapsibleToolRuns ? foldToolRuns(renderedItems) : renderedItems;
294
- const timelineNodes = nodes.filter(
295
- (node) => !(node.kind === "message" && node.role === "user")
296
- );
297
- return /* @__PURE__ */ jsx4("div", { className: cn("mx-auto w-full max-w-5xl px-4 py-4", className), children: nodes.map((node) => {
298
- if (node.kind === "message" && node.role === "user") {
299
- return /* @__PURE__ */ jsx4(UserMessage2, { item: node }, node.id);
243
+ const timelineItems = renderedItems.filter((item) => !(item.kind === "message" && item.role === "user"));
244
+ return /* @__PURE__ */ jsx4("div", { className: cn("mx-auto w-full max-w-5xl px-4 py-4", className), children: renderedItems.map((item, index) => {
245
+ if (item.kind === "message" && item.role === "user") {
246
+ return /* @__PURE__ */ jsx4(UserMessage2, { item }, item.id);
247
+ }
248
+ const timelineIndex = timelineItems.indexOf(item);
249
+ const isLast = timelineIndex === timelineItems.length - 1;
250
+ if (item.kind === "message") {
251
+ return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--brand-glow)]", children: /* @__PURE__ */ jsx4(AssistantMessage, { item }) }, item.id);
300
252
  }
301
- const isLast = timelineNodes.indexOf(node) === timelineNodes.length - 1;
302
- if (node.kind === "tool_run") {
303
- const collapsed = collapsedRuns[node.id] ?? !defaultToolRunsOpen;
304
- const total = countTools(node);
253
+ if (item.kind === "tool") {
305
254
  return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(
306
- AssistantRunShell,
255
+ ToolCallStep,
307
256
  {
308
- label: "Tools",
309
- summary: `${total} ${total === 1 ? "tool" : "tools"}`,
310
- collapsed,
311
- onToggle: () => toggleRun(node.id),
312
- children: /* @__PURE__ */ jsx4("div", { className: "space-y-px", children: node.items.map(
313
- (item) => item.kind === "tool_group" ? /* @__PURE__ */ jsx4(ToolCallGroup, { title: item.title, children: item.calls.map((call) => /* @__PURE__ */ jsx4(ToolCallRow, { call }, call.id)) }, item.id) : /* @__PURE__ */ jsx4(ToolCallRow, { call: item.call }, item.id)
314
- ) })
257
+ type: item.call.type,
258
+ label: item.call.label,
259
+ status: item.call.status,
260
+ detail: item.call.detail,
261
+ output: item.call.output,
262
+ duration: item.call.duration,
263
+ part: item.part,
264
+ actions: item.part ? renderToolActions?.(item.part) : void 0
315
265
  }
316
- ) }, node.id);
266
+ ) }, item.id);
317
267
  }
318
- if (node.kind === "message") {
319
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--brand-glow)]", children: /* @__PURE__ */ jsx4(AssistantMessage, { item: node }) }, node.id);
320
- }
321
- if (node.kind === "tool") {
322
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(ToolCallRow, { call: node.call }) }, node.id);
323
- }
324
- if (node.kind === "tool_group") {
325
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(ToolCallGroup, { title: node.title, children: node.calls.map((call) => /* @__PURE__ */ jsx4(ToolCallRow, { call }, call.id)) }) }, node.id);
268
+ if (item.kind === "tool_group") {
269
+ return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(ToolCallGroup, { title: item.title, children: item.calls.map((call, callIndex) => {
270
+ const part = item.parts?.[callIndex];
271
+ return /* @__PURE__ */ jsx4(
272
+ ToolCallStep,
273
+ {
274
+ type: call.type,
275
+ label: call.label,
276
+ status: call.status,
277
+ detail: call.detail,
278
+ output: call.output,
279
+ duration: call.duration,
280
+ part,
281
+ actions: part ? renderToolActions?.(part) : void 0
282
+ },
283
+ call.id
284
+ );
285
+ }) }) }, item.id);
326
286
  }
327
- if (node.kind === "status") {
287
+ if (item.kind === "status") {
328
288
  return /* @__PURE__ */ jsx4(
329
289
  AgentTimelineRow,
330
290
  {
331
291
  isLast,
332
- accentClassName: TONE_STYLES[node.tone ?? "default"].dot,
333
- children: /* @__PURE__ */ jsx4(StatusCard, { item: node })
292
+ accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
293
+ children: /* @__PURE__ */ jsx4(StatusCard, { item })
334
294
  },
335
- node.id
295
+ item.id
336
296
  );
337
297
  }
338
- if (node.kind === "artifact") {
298
+ if (item.kind === "artifact") {
339
299
  return /* @__PURE__ */ jsx4(
340
300
  AgentTimelineRow,
341
301
  {
342
302
  isLast,
343
- accentClassName: TONE_STYLES[node.tone ?? "default"].dot,
344
- children: /* @__PURE__ */ jsx4(ArtifactCard, { item: node })
303
+ accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
304
+ children: /* @__PURE__ */ jsx4(ArtifactCard, { item })
345
305
  },
346
- node.id
306
+ item.id
347
307
  );
348
308
  }
349
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: node.content }, node.id);
309
+ return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", children: item.content }, item.id);
350
310
  }) });
351
311
  }
352
312
 
@@ -455,9 +415,11 @@ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enab
455
415
  return {
456
416
  id: part.id,
457
417
  type: mapToolPartToTimelineType(part),
458
- label: meta.description ? `${meta.title}: ${meta.description}` : meta.title,
418
+ label: meta.title,
459
419
  status: part.state.status === "completed" ? "success" : part.state.status === "error" ? "error" : "running",
460
- detail: formatUnknown(part.state.input),
420
+ // A human-readable summary (file path / command), not the raw input JSON —
421
+ // the full input still renders in the expanded ExpandedToolDetail.
422
+ detail: meta.commandSnippet ?? meta.targetPath ?? meta.description,
461
423
  output: formatUnknown(part.state.output),
462
424
  duration: start && end ? end - start : void 0
463
425
  };
@@ -483,13 +445,15 @@ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enab
483
445
  items.push({
484
446
  id: `${message.id}-tool-${toolBuffer[0].id}`,
485
447
  kind: "tool",
486
- call: toToolCall(toolBuffer[0])
448
+ call: toToolCall(toolBuffer[0]),
449
+ part: toolBuffer[0]
487
450
  });
488
451
  } else {
489
452
  items.push({
490
453
  id: `${message.id}-tool-group-${index}`,
491
454
  kind: "tool_group",
492
455
  title: "Tool activity",
456
+ parts: [...toolBuffer],
493
457
  calls: toolBuffer.map((part) => toToolCall(part))
494
458
  });
495
459
  }
@@ -588,7 +552,8 @@ var ChatContainer = memo3(
588
552
  enableOpenUI = true,
589
553
  renderRunActions,
590
554
  renderUserMessageActions,
591
- renderToolActions
555
+ renderToolActions,
556
+ renderTimelineToolActions
592
557
  }) => {
593
558
  const scrollRef = useRef(null);
594
559
  const groups = useRunGroups({ messages, partMap, isStreaming });
@@ -609,7 +574,14 @@ var ChatContainer = memo3(
609
574
  {
610
575
  ref: scrollRef,
611
576
  className: "flex-1 overflow-y-auto [scrollbar-gutter:stable]",
612
- children: messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx5("div", { className: "max-w-md text-center", children: /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium text-muted-foreground", children: "Start a conversation." }) }) }) : presentation === "timeline" ? /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(AgentTimeline, { items: timeline.items, isThinking: timeline.showThinking }) }) : /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(
577
+ children: messages.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx5("div", { className: "max-w-md text-center", children: /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium text-muted-foreground", children: "Start a conversation." }) }) }) : presentation === "timeline" ? /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(
578
+ AgentTimeline,
579
+ {
580
+ items: timeline.items,
581
+ isThinking: timeline.showThinking,
582
+ renderToolActions: renderTimelineToolActions
583
+ }
584
+ ) }) : /* @__PURE__ */ jsx5("div", { className: "mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end", children: /* @__PURE__ */ jsx5(
613
585
  MessageList,
614
586
  {
615
587
  groups,
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-OEX7NZE3.js";
12
12
  import {
13
13
  parseToolEvent
14
- } from "./chunk-IWQZXL6A.js";
14
+ } from "./chunk-N5DJ4TUO.js";
15
15
 
16
16
  // src/hooks/use-dropdown-menu.ts
17
17
  import { useEffect, useRef, useState } from "react";