diff --git a/packages/ui/src/components/message-block-list.tsx b/packages/ui/src/components/message-block-list.tsx index 02f81a5c..8e0c8159 100644 --- a/packages/ui/src/components/message-block-list.tsx +++ b/packages/ui/src/components/message-block-list.tsx @@ -3,6 +3,10 @@ import VirtualItem from "./virtual-item" import MessageBlock from "./message-block" import type { InstanceMessageStore } from "../stores/message-v2/instance-store" +export function getMessageAnchorId(messageId: string) { + return `message-anchor-${messageId}` +} + const VIRTUAL_ITEM_MARGIN_PX = 800 const ESTIMATED_MESSAGE_HEIGHT = 320 const INITIAL_FORCE_MIN_ITEMS = 12 @@ -73,14 +77,16 @@ export default function MessageBlockList(props: MessageBlockListProps) { } return ( !props.loading} - forceVisible={forceVisible} - onMeasured={handleMeasured} - > + id={getMessageAnchorId(messageId())} + cacheKey={messageId()} + scrollContainer={props.scrollContainer} + threshold={VIRTUAL_ITEM_MARGIN_PX} + placeholderClass="message-stream-placeholder" + virtualizationEnabled={() => !props.loading} + forceVisible={forceVisible} + onMeasured={handleMeasured} + > + { showCommandPalette(props.instanceId) } - + + const handleTimelineSegmentClick = (segment: TimelineSegment) => { + if (typeof document === "undefined") return + const anchor = document.getElementById(getMessageAnchorId(segment.messageId)) + anchor?.scrollIntoView({ block: "start", behavior: "smooth" }) + } + const messageIndexMap = createMemo(() => { + const map = new Map() const ids = messageIds() ids.forEach((id, index) => map.set(id, index)) return map }) - + const lastAssistantIndex = createMemo(() => { const ids = messageIds() const resolvedStore = store() @@ -95,9 +103,25 @@ export default function MessageSection(props: MessageSectionProps) { } return -1 }) - + + const timelineSegments = createMemo(() => { + const ids = messageIds() + const resolvedStore = store() + const segments: TimelineSegment[] = [] + ids.forEach((messageId) => { + const record = resolvedStore.getMessage(messageId) + if (!record) return + const built = buildTimelineSegments(props.instanceId, record) + segments.push(...built) + }) + return segments + }) + + const hasTimelineSegments = () => timelineSegments().length > 0 + const changeToken = createMemo(() => String(sessionRevision())) + const scrollCache = useScrollCache({ instanceId: () => props.instanceId, sessionId: () => props.sessionId, @@ -362,76 +386,87 @@ export default function MessageSection(props: MessageSectionProps) { forceCompactStatusLayout={props.forceCompactStatusLayout} /> -
-