use icons for timeline short labels
This commit is contained in:
@@ -4,6 +4,8 @@ import { messageStoreBus } from "../stores/message-v2/bus"
|
|||||||
import type { ClientPart } from "../types/message"
|
import type { ClientPart } from "../types/message"
|
||||||
import type { MessageRecord } from "../stores/message-v2/types"
|
import type { MessageRecord } from "../stores/message-v2/types"
|
||||||
import { buildRecordDisplayData } from "../stores/message-v2/record-display-cache"
|
import { buildRecordDisplayData } from "../stores/message-v2/record-display-cache"
|
||||||
|
import { getToolIcon } from "./tool-call/utils"
|
||||||
|
import { User as UserIcon, Bot as BotIcon } from "lucide-solid"
|
||||||
|
|
||||||
export type TimelineSegmentType = "user" | "assistant" | "tool"
|
export type TimelineSegmentType = "user" | "assistant" | "tool"
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ export interface TimelineSegment {
|
|||||||
type: TimelineSegmentType
|
type: TimelineSegmentType
|
||||||
label: string
|
label: string
|
||||||
tooltip: string
|
tooltip: string
|
||||||
|
shortLabel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageTimelineProps {
|
interface MessageTimelineProps {
|
||||||
@@ -29,12 +32,6 @@ const SEGMENT_LABELS: Record<TimelineSegmentType, string> = {
|
|||||||
tool: "Tool",
|
tool: "Tool",
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEGMENT_SHORT_LABELS: Record<TimelineSegmentType, string> = {
|
|
||||||
user: "U",
|
|
||||||
assistant: "A",
|
|
||||||
tool: "T",
|
|
||||||
}
|
|
||||||
|
|
||||||
const TOOL_FALLBACK_LABEL = "Tool Call"
|
const TOOL_FALLBACK_LABEL = "Tool Call"
|
||||||
const MAX_TOOLTIP_LENGTH = 220
|
const MAX_TOOLTIP_LENGTH = 220
|
||||||
|
|
||||||
@@ -46,6 +43,7 @@ interface PendingSegment {
|
|||||||
reasoningTexts: string[]
|
reasoningTexts: string[]
|
||||||
toolTitles: string[]
|
toolTitles: string[]
|
||||||
toolTypeLabels: string[]
|
toolTypeLabels: string[]
|
||||||
|
toolIcons: string[]
|
||||||
hasPrimaryText: boolean
|
hasPrimaryText: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,10 +157,12 @@ export function buildTimelineSegments(instanceId: string, record: MessageRecord)
|
|||||||
pending = null
|
pending = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const label = pending.type === "tool"
|
const isToolSegment = pending.type === "tool"
|
||||||
|
const label = isToolSegment
|
||||||
? pending.toolTypeLabels[0] || TOOL_FALLBACK_LABEL.slice(0, 4)
|
? pending.toolTypeLabels[0] || TOOL_FALLBACK_LABEL.slice(0, 4)
|
||||||
: SEGMENT_LABELS[pending.type]
|
: SEGMENT_LABELS[pending.type]
|
||||||
const tooltip = pending.type === "tool"
|
const shortLabel = isToolSegment ? pending.toolIcons[0] || getToolIcon("tool") : undefined
|
||||||
|
const tooltip = isToolSegment
|
||||||
? formatToolTooltip(pending.toolTitles)
|
? formatToolTooltip(pending.toolTitles)
|
||||||
: formatTextsTooltip(
|
: formatTextsTooltip(
|
||||||
[...pending.texts, ...pending.reasoningTexts],
|
[...pending.texts, ...pending.reasoningTexts],
|
||||||
@@ -175,6 +175,7 @@ export function buildTimelineSegments(instanceId: string, record: MessageRecord)
|
|||||||
type: pending.type,
|
type: pending.type,
|
||||||
label,
|
label,
|
||||||
tooltip,
|
tooltip,
|
||||||
|
shortLabel,
|
||||||
})
|
})
|
||||||
segmentIndex += 1
|
segmentIndex += 1
|
||||||
pending = null
|
pending = null
|
||||||
@@ -183,7 +184,7 @@ export function buildTimelineSegments(instanceId: string, record: MessageRecord)
|
|||||||
const ensureSegment = (type: TimelineSegmentType): PendingSegment => {
|
const ensureSegment = (type: TimelineSegmentType): PendingSegment => {
|
||||||
if (!pending || pending.type !== type) {
|
if (!pending || pending.type !== type) {
|
||||||
flushPending()
|
flushPending()
|
||||||
pending = { type, texts: [], reasoningTexts: [], toolTitles: [], toolTypeLabels: [], hasPrimaryText: type !== "assistant" }
|
pending = { type, texts: [], reasoningTexts: [], toolTitles: [], toolTypeLabels: [], toolIcons: [], hasPrimaryText: type !== "assistant" }
|
||||||
}
|
}
|
||||||
return pending!
|
return pending!
|
||||||
}
|
}
|
||||||
@@ -199,6 +200,7 @@ export function buildTimelineSegments(instanceId: string, record: MessageRecord)
|
|||||||
const toolPart = part as ToolCallPart
|
const toolPart = part as ToolCallPart
|
||||||
target.toolTitles.push(getToolTitle(toolPart))
|
target.toolTitles.push(getToolTitle(toolPart))
|
||||||
target.toolTypeLabels.push(getToolTypeLabel(toolPart))
|
target.toolTypeLabels.push(getToolTypeLabel(toolPart))
|
||||||
|
target.toolIcons.push(getToolIcon(typeof toolPart.tool === "string" ? toolPart.tool : "tool"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +309,15 @@ const MessageTimeline: Component<MessageTimelineProps> = (props) => {
|
|||||||
{(segment) => {
|
{(segment) => {
|
||||||
onCleanup(() => buttonRefs.delete(segment.id))
|
onCleanup(() => buttonRefs.delete(segment.id))
|
||||||
const isActive = () => props.activeMessageId === segment.messageId
|
const isActive = () => props.activeMessageId === segment.messageId
|
||||||
|
const shortLabelContent = () => {
|
||||||
|
if (segment.type === "tool") {
|
||||||
|
return segment.shortLabel ?? getToolIcon("tool")
|
||||||
|
}
|
||||||
|
if (segment.type === "user") {
|
||||||
|
return <UserIcon class="message-timeline-icon" aria-hidden="true" />
|
||||||
|
}
|
||||||
|
return <BotIcon class="message-timeline-icon" aria-hidden="true" />
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
ref={(el) => registerButtonRef(segment.id, el)}
|
ref={(el) => registerButtonRef(segment.id, el)}
|
||||||
@@ -318,9 +329,7 @@ const MessageTimeline: Component<MessageTimelineProps> = (props) => {
|
|||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
>
|
>
|
||||||
<span class="message-timeline-label message-timeline-label-full">{segment.label}</span>
|
<span class="message-timeline-label message-timeline-label-full">{segment.label}</span>
|
||||||
<span class="message-timeline-label message-timeline-label-short">
|
<span class="message-timeline-label message-timeline-label-short">{shortLabelContent()}</span>
|
||||||
{segment.type === "tool" ? segment.label.charAt(0).toUpperCase() : SEGMENT_SHORT_LABELS[segment.type]}
|
|
||||||
</span>
|
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -138,6 +138,14 @@
|
|||||||
|
|
||||||
.message-timeline-label-short {
|
.message-timeline-label-short {
|
||||||
display: none;
|
display: none;
|
||||||
|
line-height: 1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-timeline-icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
@@ -145,7 +153,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.message-timeline-label-short {
|
.message-timeline-label-short {
|
||||||
display: block;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user