diff --git a/src/client/SideChatView.module.css b/src/client/SideChatView.module.css index 73d657f..fbae146 100644 --- a/src/client/SideChatView.module.css +++ b/src/client/SideChatView.module.css @@ -221,6 +221,18 @@ transform: rotate(90deg); } +/* Tool-kind leading glyph (the main conversation's 16px slot; the icon + * itself renders at 14). Failed rows pass a StateDot instead. */ +.sidechatRowIcon { + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + color: var(--dsw-alias-label-tertiary); +} + .sidechatRowLabel { flex: none; max-width: 60%; diff --git a/src/client/SideChatView.tsx b/src/client/SideChatView.tsx index ccb4019..e409c1a 100644 --- a/src/client/SideChatView.tsx +++ b/src/client/SideChatView.tsx @@ -29,10 +29,15 @@ import clsx from 'clsx' import { ConnectionIndicator, DiffBlock, + IconApiOutline14, + IconBrowseOutline16, IconChevronRightOutline14, + IconEditOutline16, IconNewChatOutline16, IconPlusOutline16, + IconSearchOutline16, IconSendOutline16, + IconSparkle16, IconStopFill16, MarkdownText, Menu, @@ -149,8 +154,13 @@ function CollapsibleRow(props: { mono?: boolean streaming?: boolean failed?: boolean + /** 16px leading glyph (tool-kind icon, the main conversation's row head). */ + icon?: React.ReactNode children?: React.ReactNode }): React.ReactNode { + const leading = props.icon === undefined ? null : ( + {props.icon} + ) const label = ( + {leading} {label} {meta} @@ -185,6 +196,7 @@ function CollapsibleRow(props: { + {leading} {label} {meta} @@ -215,6 +227,30 @@ function toolCardBody(card: SidechatToolCard, executing: boolean, labels: RowLab return } +/** The tool row's 16px leading slot, the way the main conversation draws it + * (GenericToolCard's variant table): the tool-kind glyph at 14, replaced by + * an error StateDot on failed rows. */ +function toolLeading(name: string, failed: boolean): React.ReactNode { + if (failed) return + switch (name) { + case 'bash': + case 'pwsh': + return + case 'read': + case 'web_fetch': + return + case 'edit': + case 'write': + return + case 'grep': + case 'glob': + case 'web_search': + return + default: + return + } +} + /** One row renderer (React keys ride the source event seq). */ function renderRow(row: SidechatTranscriptRow, labels: RowLabels): React.ReactNode { switch (row.kind) { @@ -275,6 +311,7 @@ function renderRow(row: SidechatTranscriptRow, labels: RowLabels): React.ReactNo key={`${row.kind}:${row.seq}`} label={row.name} meta={toolArgsSummary(row.args)} + icon={toolLeading(row.name, row.failed)} mono streaming={row.executing === true} failed={row.failed}