@tangle-network/ui 11.47.0 → 11.48.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,11 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.48.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 182708a: `@tangle-network/ui/chat` adds `partitionBySpeaker` and `SpeakerHeader` for a turn addressed to several agents. `partitionBySpeaker(parts)` splits one assistant turn's parts by responder: a stored row by position after each speaker part, a live stream by each part's `speaker` tag, and a repeated speaker part carries that responder's end state. `SpeakerHeader` is the author line with the agent's handle and its state: answering, done (silent) or failed. `MessageAuthor` now renders children after the name and role.
8
+
3
9
  ## 11.47.0
4
10
 
5
11
  ### Minor Changes
@@ -7,16 +7,17 @@ import { HTMLAttributes } from "react";
7
7
  * `viewerId`, every authored message belongs to someone else.
8
8
  */
9
9
  export declare function isViewerMessage(author: ChatAuthor | undefined, viewerId: string | undefined): boolean;
10
- export interface MessageAuthorProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
10
+ export interface MessageAuthorProps extends HTMLAttributes<HTMLDivElement> {
11
11
  author: ChatAuthor;
12
12
  }
13
13
  /**
14
14
  * The line above a message in a transcript with several participants: the
15
- * author's avatar, name and, when given, their role as a tag.
15
+ * author's avatar, name and, when given, their role as a tag. Children follow
16
+ * on the same line, such as a responder's handle and state.
16
17
  *
17
18
  * The avatar's tone comes from the author's id, so a participant keeps one
18
19
  * colour for the whole thread and in every product. Tones can repeat between
19
20
  * participants, so the name is always shown beside it. The avatar repeats the
20
21
  * visible name and is hidden from assistive technology.
21
22
  */
22
- export declare function MessageAuthor({ author, className, ...props }: MessageAuthorProps): import("react").JSX.Element;
23
+ export declare function MessageAuthor({ author, className, children, ...props }: MessageAuthorProps): import("react").JSX.Element;
@@ -15,14 +15,15 @@ function isViewerMessage(author, viewerId) {
15
15
  }
16
16
  /**
17
17
  * The line above a message in a transcript with several participants: the
18
- * author's avatar, name and, when given, their role as a tag.
18
+ * author's avatar, name and, when given, their role as a tag. Children follow
19
+ * on the same line, such as a responder's handle and state.
19
20
  *
20
21
  * The avatar's tone comes from the author's id, so a participant keeps one
21
22
  * colour for the whole thread and in every product. Tones can repeat between
22
23
  * participants, so the name is always shown beside it. The avatar repeats the
23
24
  * visible name and is hidden from assistive technology.
24
25
  */
25
- function MessageAuthor({ author, className, ...props }) {
26
+ function MessageAuthor({ author, className, children, ...props }) {
26
27
  return /* @__PURE__ */ jsxs("div", {
27
28
  "data-message-author": "",
28
29
  className: cn("flex min-w-0 max-w-full items-center gap-2", className),
@@ -45,7 +46,8 @@ function MessageAuthor({ author, className, ...props }) {
45
46
  emphasis: "outline",
46
47
  className: "max-w-[50%]",
47
48
  children: author.role
48
- }) : null
49
+ }) : null,
50
+ children
49
51
  ]
50
52
  });
51
53
  }
@@ -0,0 +1,57 @@
1
+ import { HTMLAttributes } from "react";
2
+ /** Where one responder is in its answer. */
3
+ export type SpeakerState = "answering" | "done" | "failed";
4
+ /**
5
+ * A responder of a turn addressed to several agents. In the turn's parts it is
6
+ * a `{ type: "speaker", id, name, handle?, state? }` part written before the
7
+ * responder's answer.
8
+ */
9
+ export interface Speaker {
10
+ /** The agent's stable id. It keys the avatar's tone and a live part's `speaker` tag. */
11
+ id: string;
12
+ name: string;
13
+ /** What a person types after `@` to address the agent. */
14
+ handle?: string;
15
+ /** Set once the responder ended; absent while it answers and on rows written before responders reported an end. */
16
+ state?: SpeakerState;
17
+ }
18
+ export type SpeakerPart = Speaker & {
19
+ type: "speaker";
20
+ };
21
+ /** One responder's share of a turn: its speaker part and the parts it wrote. */
22
+ export interface SpeakerSection<T> {
23
+ /** The latest speaker part for this responder; null for the parts no speaker owns. */
24
+ speaker: (T & SpeakerPart) | null;
25
+ parts: T[];
26
+ }
27
+ /**
28
+ * Splits one assistant turn's parts by the agent that wrote them.
29
+ *
30
+ * A stored row holds a speaker part before each responder's answer, so a part
31
+ * belongs to the speaker part before it. A live stream announces every
32
+ * responder first and then interleaves their output, so a part names its owner
33
+ * in `speaker` (the responder's id), which wins over position. A later speaker
34
+ * part with an id already seen replaces that responder's speaker part, which is
35
+ * how its end state arrives, and never opens a second section.
36
+ *
37
+ * Sections keep the order speakers were first announced. Parts no speaker owns
38
+ * come first, in a section whose `speaker` is null; a turn without speaker
39
+ * parts is that one section. No part is dropped, copied or reordered within its
40
+ * section.
41
+ */
42
+ export declare function partitionBySpeaker<T extends object>(parts: readonly T[]): SpeakerSection<T>[];
43
+ export interface SpeakerHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
44
+ speaker: Speaker;
45
+ /** The turn is still running, so a responder that has not reported an end is answering. */
46
+ live?: boolean;
47
+ }
48
+ /**
49
+ * The line above one responder's answer: the author line every participant
50
+ * gets, then the handle a person types to address the agent, then its state.
51
+ *
52
+ * The state comes from the speaker's own end state, else from `live`. An
53
+ * answering responder shows the status grammar's open ring with the word, a
54
+ * failed one its cross with the word, and a finished one nothing, as a settled
55
+ * run row does. `data-speaker-state` carries all three.
56
+ */
57
+ export declare function SpeakerHeader({ speaker, live, ...props }: SpeakerHeaderProps): import("react").JSX.Element;
@@ -0,0 +1,84 @@
1
+ import { StatusPill } from "../primitives/status-pill.js";
2
+ import { MessageAuthor } from "./message-author.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ // src/chat/speaker.tsx
5
+ function isSpeakerPart(part) {
6
+ const record = part;
7
+ return !!record && record.type === "speaker" && typeof record.id === "string" && typeof record.name === "string";
8
+ }
9
+ /**
10
+ * Splits one assistant turn's parts by the agent that wrote them.
11
+ *
12
+ * A stored row holds a speaker part before each responder's answer, so a part
13
+ * belongs to the speaker part before it. A live stream announces every
14
+ * responder first and then interleaves their output, so a part names its owner
15
+ * in `speaker` (the responder's id), which wins over position. A later speaker
16
+ * part with an id already seen replaces that responder's speaker part, which is
17
+ * how its end state arrives, and never opens a second section.
18
+ *
19
+ * Sections keep the order speakers were first announced. Parts no speaker owns
20
+ * come first, in a section whose `speaker` is null; a turn without speaker
21
+ * parts is that one section. No part is dropped, copied or reordered within its
22
+ * section.
23
+ */
24
+ function partitionBySpeaker(parts) {
25
+ const sections = /* @__PURE__ */ new Map();
26
+ const unowned = [];
27
+ let current;
28
+ for (const part of parts) {
29
+ if (isSpeakerPart(part)) {
30
+ current = sections.get(part.id);
31
+ if (current) current.speaker = part;
32
+ else sections.set(part.id, current = {
33
+ speaker: part,
34
+ parts: []
35
+ });
36
+ continue;
37
+ }
38
+ const tag = part.speaker;
39
+ ((typeof tag === "string" ? sections.get(tag) : current)?.parts ?? unowned).push(part);
40
+ }
41
+ const owned = [...sections.values()];
42
+ return unowned.length > 0 || owned.length === 0 ? [{
43
+ speaker: null,
44
+ parts: unowned
45
+ }, ...owned] : owned;
46
+ }
47
+ /**
48
+ * The line above one responder's answer: the author line every participant
49
+ * gets, then the handle a person types to address the agent, then its state.
50
+ *
51
+ * The state comes from the speaker's own end state, else from `live`. An
52
+ * answering responder shows the status grammar's open ring with the word, a
53
+ * failed one its cross with the word, and a finished one nothing, as a settled
54
+ * run row does. `data-speaker-state` carries all three.
55
+ */
56
+ function SpeakerHeader({ speaker, live = false, ...props }) {
57
+ const state = speaker.state ?? (live ? "answering" : "done");
58
+ return /* @__PURE__ */ jsxs(MessageAuthor, {
59
+ author: {
60
+ id: speaker.id,
61
+ name: speaker.name
62
+ },
63
+ "data-speaker-state": state,
64
+ ...props,
65
+ children: [speaker.handle ? /* @__PURE__ */ jsxs("span", {
66
+ className: "min-w-0 truncate text-muted-foreground text-sm",
67
+ title: `@${speaker.handle}`,
68
+ children: ["@", speaker.handle]
69
+ }) : null, state === "answering" ? /* @__PURE__ */ jsx(StatusPill, {
70
+ tone: "running",
71
+ bare: true,
72
+ size: "md",
73
+ className: "shrink-0 py-0",
74
+ children: "Answering"
75
+ }) : state === "failed" ? /* @__PURE__ */ jsx(StatusPill, {
76
+ tone: "danger",
77
+ bare: true,
78
+ size: "md",
79
+ className: "shrink-0 py-0",
80
+ children: "Failed"
81
+ }) : null]
82
+ });
83
+ }
84
+ export { SpeakerHeader, partitionBySpeaker };
package/dist/chat.d.ts CHANGED
@@ -4,7 +4,8 @@ import { MessageList, MessageListProps } from "./chat/message-list.js";
4
4
  import { UserMessage, UserMessageProps } from "./chat/user-message.js";
5
5
  import { ChatMessage, ChatMessageProps, MessageRole } from "./chat/chat-message.js";
6
6
  import { MessageAuthor, MessageAuthorProps, isViewerMessage } from "./chat/message-author.js";
7
+ import { Speaker, SpeakerHeader, SpeakerHeaderProps, SpeakerPart, SpeakerSection, SpeakerState, partitionBySpeaker } from "./chat/speaker.js";
7
8
  import { ThinkingIndicator, ThinkingIndicatorProps } from "./chat/thinking-indicator.js";
8
9
  import { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineColumn, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineStep, AgentTimelineStepKind, AgentTimelineStepProps, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, agentTimelineStepKind } from "./chat/agent-timeline.js";
9
10
  import { TRANSCRIPT_TEXT } from "./chat/transcript-text.js";
10
- export { AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, type ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, TRANSCRIPT_TEXT, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps, agentTimelineStepKind, isViewerMessage };
11
+ export { AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, type ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, type Speaker, SpeakerHeader, type SpeakerHeaderProps, type SpeakerPart, type SpeakerSection, type SpeakerState, TRANSCRIPT_TEXT, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps, agentTimelineStepKind, isViewerMessage, partitionBySpeaker };
package/dist/chat.js CHANGED
@@ -6,4 +6,5 @@ import { ThinkingIndicator } from "./chat/thinking-indicator.js";
6
6
  import { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineStepKind } from "./chat/agent-timeline.js";
7
7
  import { ChatContainer } from "./chat/chat-container.js";
8
8
  import { ChatMessage } from "./chat/chat-message.js";
9
- export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, ChatContainer, ChatMessage, MessageAuthor, MessageList, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, agentTimelineStepKind, isViewerMessage };
9
+ import { SpeakerHeader, partitionBySpeaker } from "./chat/speaker.js";
10
+ export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, ChatContainer, ChatMessage, MessageAuthor, MessageList, SpeakerHeader, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, agentTimelineStepKind, isViewerMessage, partitionBySpeaker };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ import { MessageList, MessageListProps } from "./chat/message-list.js";
16
16
  import { UserMessage, UserMessageProps } from "./chat/user-message.js";
17
17
  import { ChatMessage, ChatMessageProps, MessageRole } from "./chat/chat-message.js";
18
18
  import { MessageAuthor, MessageAuthorProps, isViewerMessage } from "./chat/message-author.js";
19
+ import { Speaker, SpeakerHeader, SpeakerHeaderProps, SpeakerPart, SpeakerSection, SpeakerState, partitionBySpeaker } from "./chat/speaker.js";
19
20
  import { ThinkingIndicator, ThinkingIndicatorProps } from "./chat/thinking-indicator.js";
20
21
  import { ToolCallStatus, ToolCallType } from "./run/tool-call-step.js";
21
22
  import { FeedSegment, ToolCallData, ToolCallFeed, ToolCallFeedProps, parseToolEvent } from "./run/tool-call-feed.js";
@@ -143,4 +144,4 @@ import { QuestionPreview, QuestionPreviewProps } from "./tool-previews/question-
143
144
  import { DiffPreview, DiffPreviewProps } from "./tool-previews/diff-preview.js";
144
145
  import { RedactedDocSegment, RedactedDocument, RedactedDocumentData, RedactedDocumentProps, RevealResult } from "./redaction/redacted-document.js";
145
146
  import "./redaction.js";
146
- export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
147
+ export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, type Speaker, SpeakerHeader, type SpeakerHeaderProps, type SpeakerPart, type SpeakerSection, type SpeakerState, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, partitionBySpeaker, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
package/dist/index.js CHANGED
@@ -98,6 +98,7 @@ import { ThinkingIndicator } from "./chat/thinking-indicator.js";
98
98
  import { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineStepKind } from "./chat/agent-timeline.js";
99
99
  import { ChatContainer } from "./chat/chat-container.js";
100
100
  import { ChatMessage } from "./chat/chat-message.js";
101
+ import { SpeakerHeader, partitionBySpeaker } from "./chat/speaker.js";
101
102
  import { LiveDuration } from "./run/run-item-primitives.js";
102
103
  import { ToolCallFeed, parseToolEvent } from "./run/tool-call-feed.js";
103
104
  import { TaskList, showsTaskPriority, taskProgress, taskStatus } from "./run/task-list.js";
@@ -127,4 +128,4 @@ import { addMessage, addParts, clearChat, isStreamingAtom, messagesAtom, partMap
127
128
  import { copyText } from "./utils/copy-text.js";
128
129
  import { timeAgo } from "./utils/time-ago.js";
129
130
  import { RedactedDocument } from "./redaction/redacted-document.js";
130
- export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricChart, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, Wizard, WizardStep, WriteFilePreview, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
131
+ export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricChart, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, SpeakerHeader, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, Wizard, WizardStep, WriteFilePreview, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, partitionBySpeaker, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/ui",
3
- "version": "11.47.0",
3
+ "version": "11.48.0",
4
4
  "description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/chat/index.ts CHANGED
@@ -3,6 +3,15 @@ export { MessageList, type MessageListProps } from "./message-list";
3
3
  export { UserMessage, type UserMessageProps } from "./user-message";
4
4
  export { ChatMessage, type ChatMessageProps, type MessageRole } from "./chat-message";
5
5
  export { MessageAuthor, isViewerMessage, type MessageAuthorProps } from "./message-author";
6
+ export {
7
+ SpeakerHeader,
8
+ partitionBySpeaker,
9
+ type Speaker,
10
+ type SpeakerHeaderProps,
11
+ type SpeakerPart,
12
+ type SpeakerSection,
13
+ type SpeakerState,
14
+ } from "./speaker";
6
15
  export type { ChatAuthor } from "../types/message";
7
16
  export { ThinkingIndicator, type ThinkingIndicatorProps } from "./thinking-indicator";
8
17
  export {
@@ -15,20 +15,21 @@ export function isViewerMessage(author: ChatAuthor | undefined, viewerId: string
15
15
  return author === undefined || author.id === viewerId;
16
16
  }
17
17
 
18
- export interface MessageAuthorProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
18
+ export interface MessageAuthorProps extends HTMLAttributes<HTMLDivElement> {
19
19
  author: ChatAuthor;
20
20
  }
21
21
 
22
22
  /**
23
23
  * The line above a message in a transcript with several participants: the
24
- * author's avatar, name and, when given, their role as a tag.
24
+ * author's avatar, name and, when given, their role as a tag. Children follow
25
+ * on the same line, such as a responder's handle and state.
25
26
  *
26
27
  * The avatar's tone comes from the author's id, so a participant keeps one
27
28
  * colour for the whole thread and in every product. Tones can repeat between
28
29
  * participants, so the name is always shown beside it. The avatar repeats the
29
30
  * visible name and is hidden from assistive technology.
30
31
  */
31
- export function MessageAuthor({ author, className, ...props }: MessageAuthorProps) {
32
+ export function MessageAuthor({ author, className, children, ...props }: MessageAuthorProps) {
32
33
  return (
33
34
  <div data-message-author="" className={cn("flex min-w-0 max-w-full items-center gap-2", className)} {...props}>
34
35
  <IconTile
@@ -47,6 +48,7 @@ export function MessageAuthor({ author, className, ...props }: MessageAuthorProp
47
48
  {author.role}
48
49
  </Tag>
49
50
  ) : null}
51
+ {children}
50
52
  </div>
51
53
  );
52
54
  }
@@ -0,0 +1,95 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { partitionBySpeaker, SpeakerHeader } from './speaker'
3
+ import { TRANSCRIPT_TEXT } from './transcript-text'
4
+
5
+ type Part =
6
+ | { type: 'speaker'; id: string; name: string; handle?: string; state?: 'answering' | 'done' | 'failed' }
7
+ | { type: 'text'; text: string; speaker?: string }
8
+ | { type: 'tool'; tool: string; status: string; speaker?: string }
9
+ | { type: 'notice'; text: string; speaker?: string }
10
+
11
+ /** One turn's parts drawn the way a product draws them: a header per responder, its parts under it. */
12
+ function Turn({ parts, live = false }: { parts: Part[]; live?: boolean }) {
13
+ return (
14
+ <div className="mx-auto flex w-full max-w-3xl flex-col gap-6 px-4 py-6">
15
+ <p className={`ml-auto w-fit max-w-[78%] rounded-2xl bg-foreground px-4 py-3 text-background ${TRANSCRIPT_TEXT}`}>
16
+ @writer @research-lead plan the launch announcement for the roster feature.
17
+ </p>
18
+ {partitionBySpeaker(parts).map(({ speaker, parts: own }) => (
19
+ <section key={speaker?.id ?? 'turn'} className="flex flex-col gap-2">
20
+ {speaker ? <SpeakerHeader speaker={speaker} live={live} /> : null}
21
+ {own.map((part, index) =>
22
+ part.type === 'text' ? (
23
+ <p key={index} className={TRANSCRIPT_TEXT}>{part.text}</p>
24
+ ) : part.type === 'tool' ? (
25
+ <p key={index} className="font-mono text-muted-foreground text-sm">{part.tool} · {part.status}</p>
26
+ ) : part.type === 'notice' ? (
27
+ <p key={index} className="text-[var(--surface-danger-text)] text-sm">{part.text}</p>
28
+ ) : null,
29
+ )}
30
+ </section>
31
+ ))}
32
+ </div>
33
+ )
34
+ }
35
+
36
+ const meta: Meta<typeof Turn> = {
37
+ title: 'Chat/Speakers',
38
+ component: Turn,
39
+ parameters: { layout: 'fullscreen' },
40
+ decorators: [
41
+ (Story) => (
42
+ <div className="min-h-screen bg-[var(--bg-root)]">
43
+ <Story />
44
+ </div>
45
+ ),
46
+ ],
47
+ }
48
+
49
+ export default meta
50
+ type Story = StoryObj<typeof Turn>
51
+
52
+ /**
53
+ * A live turn as the stream delivers it: both responders announced first, then
54
+ * their output interleaved, each part tagged with its responder. The Writer has
55
+ * reported its end; the Research Lead is still answering.
56
+ */
57
+ export const AnsweringAtOnce: Story = {
58
+ args: {
59
+ live: true,
60
+ parts: [
61
+ { type: 'speaker', id: 'ap_writer', name: 'Writer', handle: 'writer' },
62
+ { type: 'speaker', id: 'ap_research', name: 'Research Lead', handle: 'research-lead' },
63
+ { type: 'text', speaker: 'ap_writer', text: 'Draft headline: "Every agent in your workspace, one @ away."' },
64
+ { type: 'tool', speaker: 'ap_research', tool: 'search_repo', status: 'running' },
65
+ { type: 'text', speaker: 'ap_writer', text: 'Subhead: address any agent from any thread, and let it run on a schedule while you sleep.' },
66
+ { type: 'speaker', id: 'ap_writer', name: 'Writer', handle: 'writer', state: 'done' },
67
+ { type: 'text', speaker: 'ap_research', text: 'Checking the roster and the mention routes before naming risks.' },
68
+ ],
69
+ },
70
+ }
71
+
72
+ /** A stored row: a speaker part before each answer. The Research Lead failed and keeps its header and its notice. */
73
+ export const StoredWithFailure: Story = {
74
+ args: {
75
+ parts: [
76
+ { type: 'speaker', id: 'ap_writer', name: 'Writer', handle: 'writer', state: 'done' },
77
+ { type: 'text', text: 'Draft headline: "Every agent in your workspace, one @ away."' },
78
+ { type: 'speaker', id: 'ap_research', name: 'Research Lead', handle: 'research-lead', state: 'failed' },
79
+ { type: 'tool', tool: 'search_repo', status: 'error' },
80
+ { type: 'notice', text: 'Research Lead could not answer: the model provider refused the request (429).' },
81
+ ],
82
+ },
83
+ }
84
+
85
+ /** Worst case for a phone: a long name and handle while answering. The name and handle truncate; the state stays whole. */
86
+ export const LongNames: Story = {
87
+ args: {
88
+ live: true,
89
+ parts: [
90
+ { type: 'speaker', id: 'ap_compliance', name: 'Regional Compliance and Disclosure Reviewer', handle: 'regional-compliance-disclosure-reviewer' },
91
+ { type: 'text', text: 'Reading the disclosure rules for each launch region.' },
92
+ { type: 'speaker', id: 'ap_q', name: 'Q', state: 'failed' },
93
+ ],
94
+ },
95
+ }
@@ -0,0 +1,81 @@
1
+ import { render, screen } from "@testing-library/react"
2
+ import { describe, expect, it } from "vitest"
3
+ import { MessageAuthor } from "./message-author"
4
+ import { partitionBySpeaker, SpeakerHeader, type Speaker } from "./speaker"
5
+
6
+ type Part = { type: string; id?: string; name?: string; handle?: string; state?: Speaker["state"]; text?: string; speaker?: string }
7
+
8
+ const writer = { type: "speaker", id: "ap_writer", name: "Writer", handle: "writer" }
9
+ const research = { type: "speaker", id: "ap_research", name: "Research Lead", handle: "research-lead" }
10
+ const text = (value: string, speaker?: string): Part => ({ type: "text", text: value, ...(speaker ? { speaker } : {}) })
11
+
12
+ /** Each section as `[speaker id or null, its texts]`. */
13
+ const shape = (parts: Part[]) =>
14
+ partitionBySpeaker(parts).map((section) => [section.speaker?.id ?? null, section.parts.map((part) => part.text)])
15
+
16
+ describe("partitionBySpeaker", () => {
17
+ it("splits a stored row at its speaker parts, in stored order", () => {
18
+ expect(shape([writer, text("headline"), text("subhead"), research, text("risks")])).toEqual([
19
+ ["ap_writer", ["headline", "subhead"]],
20
+ ["ap_research", ["risks"]],
21
+ ])
22
+ })
23
+
24
+ it("groups a live stream by each part's speaker tag, not by where it arrived", () => {
25
+ const live = [writer, research, text("headline", "ap_writer"), text("searching", "ap_research"), text("subhead", "ap_writer"), text("risks", "ap_research")]
26
+ expect(shape(live)).toEqual([
27
+ ["ap_writer", ["headline", "subhead"]],
28
+ ["ap_research", ["searching", "risks"]],
29
+ ])
30
+ })
31
+
32
+ it("takes a responder's end state from a later speaker part, without a second section", () => {
33
+ const sections = partitionBySpeaker<Part>([writer, research, text("headline", "ap_writer"), { ...writer, state: "done" }, text("risks", "ap_research")])
34
+ expect(sections.map((section) => [section.speaker?.name, section.speaker?.state])).toEqual([["Writer", "done"], ["Research Lead", undefined]])
35
+ expect(sections[1]?.parts.map((part) => part.text)).toEqual(["risks"])
36
+ })
37
+
38
+ it("keeps parts no speaker owns, first, and drops none", () => {
39
+ expect(shape([text("preamble"), writer, text("headline"), text("stray", "ap_nobody")])).toEqual([
40
+ [null, ["preamble", "stray"]],
41
+ ["ap_writer", ["headline"]],
42
+ ])
43
+ expect(shape([text("one agent"), text("one answer")])).toEqual([[null, ["one agent", "one answer"]]])
44
+ expect(shape([])).toEqual([[null, []]])
45
+ })
46
+ })
47
+
48
+ describe("SpeakerHeader", () => {
49
+ it("names the responder in its own element, with its handle, answering while the turn runs", () => {
50
+ const { container } = render(<SpeakerHeader speaker={{ id: "ap_writer", name: "Writer", handle: "writer" }} live />)
51
+ expect(screen.getByText(/^Writer$/)).toBeInTheDocument()
52
+ expect(screen.getByText("@writer")).toBeInTheDocument()
53
+ expect(screen.getByText("Answering")).toBeInTheDocument()
54
+ expect(container.querySelector("[data-speaker-state]")?.getAttribute("data-speaker-state")).toBe("answering")
55
+ })
56
+
57
+ it("says nothing more once the responder has ended, even while others answer", () => {
58
+ const { container } = render(<SpeakerHeader speaker={{ id: "ap_writer", name: "Writer", state: "done" }} live />)
59
+ expect(screen.queryByText("Answering")).not.toBeInTheDocument()
60
+ expect(screen.queryByText("Failed")).not.toBeInTheDocument()
61
+ expect(container.querySelector("[data-speaker-state]")?.getAttribute("data-speaker-state")).toBe("done")
62
+ })
63
+
64
+ it("shows a failed responder as failed while the turn still runs", () => {
65
+ render(<SpeakerHeader speaker={{ id: "ap_research", name: "Research Lead", state: "failed" }} live />)
66
+ expect(screen.getByText("Failed")).toBeInTheDocument()
67
+ expect(screen.queryByText("Answering")).not.toBeInTheDocument()
68
+ })
69
+
70
+ it("treats a responder without an end state on a finished turn as done", () => {
71
+ const { container } = render(<SpeakerHeader speaker={{ id: "ap_writer", name: "Writer" }} />)
72
+ expect(container.querySelector("[data-speaker-state]")?.getAttribute("data-speaker-state")).toBe("done")
73
+ })
74
+
75
+ it("draws the author line every participant gets, so an agent keeps its tone", () => {
76
+ const avatar = (node: HTMLElement) => node.querySelector("[aria-hidden]")!.className
77
+ const header = render(<SpeakerHeader speaker={{ id: "ap_writer", name: "Writer" }} />).container
78
+ const author = render(<MessageAuthor author={{ id: "ap_writer", name: "Writer" }} />).container
79
+ expect(avatar(header)).toBe(avatar(author))
80
+ })
81
+ })
@@ -0,0 +1,110 @@
1
+ import type { HTMLAttributes } from "react";
2
+ import { StatusPill } from "../primitives/status-pill";
3
+ import { MessageAuthor } from "./message-author";
4
+
5
+ /** Where one responder is in its answer. */
6
+ export type SpeakerState = "answering" | "done" | "failed";
7
+
8
+ /**
9
+ * A responder of a turn addressed to several agents. In the turn's parts it is
10
+ * a `{ type: "speaker", id, name, handle?, state? }` part written before the
11
+ * responder's answer.
12
+ */
13
+ export interface Speaker {
14
+ /** The agent's stable id. It keys the avatar's tone and a live part's `speaker` tag. */
15
+ id: string;
16
+ name: string;
17
+ /** What a person types after `@` to address the agent. */
18
+ handle?: string;
19
+ /** Set once the responder ended; absent while it answers and on rows written before responders reported an end. */
20
+ state?: SpeakerState;
21
+ }
22
+
23
+ export type SpeakerPart = Speaker & { type: "speaker" };
24
+
25
+ /** One responder's share of a turn: its speaker part and the parts it wrote. */
26
+ export interface SpeakerSection<T> {
27
+ /** The latest speaker part for this responder; null for the parts no speaker owns. */
28
+ speaker: (T & SpeakerPart) | null;
29
+ parts: T[];
30
+ }
31
+
32
+ function isSpeakerPart<T>(part: T): part is T & SpeakerPart {
33
+ const record = part as { type?: unknown; id?: unknown; name?: unknown } | null;
34
+ return !!record && record.type === "speaker" && typeof record.id === "string" && typeof record.name === "string";
35
+ }
36
+
37
+ /**
38
+ * Splits one assistant turn's parts by the agent that wrote them.
39
+ *
40
+ * A stored row holds a speaker part before each responder's answer, so a part
41
+ * belongs to the speaker part before it. A live stream announces every
42
+ * responder first and then interleaves their output, so a part names its owner
43
+ * in `speaker` (the responder's id), which wins over position. A later speaker
44
+ * part with an id already seen replaces that responder's speaker part, which is
45
+ * how its end state arrives, and never opens a second section.
46
+ *
47
+ * Sections keep the order speakers were first announced. Parts no speaker owns
48
+ * come first, in a section whose `speaker` is null; a turn without speaker
49
+ * parts is that one section. No part is dropped, copied or reordered within its
50
+ * section.
51
+ */
52
+ export function partitionBySpeaker<T extends object>(parts: readonly T[]): SpeakerSection<T>[] {
53
+ const sections = new Map<string, SpeakerSection<T>>();
54
+ const unowned: T[] = [];
55
+ let current: SpeakerSection<T> | undefined;
56
+ for (const part of parts) {
57
+ if (isSpeakerPart(part)) {
58
+ current = sections.get(part.id);
59
+ if (current) current.speaker = part;
60
+ else sections.set(part.id, (current = { speaker: part, parts: [] }));
61
+ continue;
62
+ }
63
+ const tag = (part as { speaker?: unknown }).speaker;
64
+ const owner = typeof tag === "string" ? sections.get(tag) : current;
65
+ (owner?.parts ?? unowned).push(part);
66
+ }
67
+ const owned = [...sections.values()];
68
+ return unowned.length > 0 || owned.length === 0 ? [{ speaker: null, parts: unowned }, ...owned] : owned;
69
+ }
70
+
71
+ export interface SpeakerHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
72
+ speaker: Speaker;
73
+ /** The turn is still running, so a responder that has not reported an end is answering. */
74
+ live?: boolean;
75
+ }
76
+
77
+ /**
78
+ * The line above one responder's answer: the author line every participant
79
+ * gets, then the handle a person types to address the agent, then its state.
80
+ *
81
+ * The state comes from the speaker's own end state, else from `live`. An
82
+ * answering responder shows the status grammar's open ring with the word, a
83
+ * failed one its cross with the word, and a finished one nothing, as a settled
84
+ * run row does. `data-speaker-state` carries all three.
85
+ */
86
+ export function SpeakerHeader({ speaker, live = false, ...props }: SpeakerHeaderProps) {
87
+ const state: SpeakerState = speaker.state ?? (live ? "answering" : "done");
88
+ return (
89
+ <MessageAuthor
90
+ author={{ id: speaker.id, name: speaker.name }}
91
+ data-speaker-state={state}
92
+ {...props}
93
+ >
94
+ {speaker.handle ? (
95
+ <span className="min-w-0 truncate text-muted-foreground text-sm" title={`@${speaker.handle}`}>
96
+ @{speaker.handle}
97
+ </span>
98
+ ) : null}
99
+ {state === "answering" ? (
100
+ <StatusPill tone="running" bare size="md" className="shrink-0 py-0">
101
+ Answering
102
+ </StatusPill>
103
+ ) : state === "failed" ? (
104
+ <StatusPill tone="danger" bare size="md" className="shrink-0 py-0">
105
+ Failed
106
+ </StatusPill>
107
+ ) : null}
108
+ </MessageAuthor>
109
+ );
110
+ }