import { DataWithScrollModifier, ScrollModifier, VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListMethods, VirtuosoMessageListProps, } from '@virtuoso.dev/message-list'; import { useEffect, useMemo, useRef, useState } from 'react'; import DisplayConversationEntry from '../NormalizedConversation/DisplayConversationEntry'; import { useEntries } from '@/contexts/EntriesContext'; import { AddEntryType, PatchTypeWithKey, useConversationHistory, } from '@/hooks/useConversationHistory'; import { Loader2 } from 'lucide-react'; import { TaskAttempt } from 'shared/types'; import { ApprovalFormProvider } from '@/contexts/ApprovalFormContext'; interface VirtualizedListProps { attempt: TaskAttempt; } interface MessageListContext { attempt: TaskAttempt; } const INITIAL_TOP_ITEM = { index: 'LAST' as const, align: 'end' as const }; const InitialDataScrollModifier: ScrollModifier = { type: 'item-location', location: INITIAL_TOP_ITEM, purgeItemSizes: true, }; const AutoScrollToBottom: ScrollModifier = { type: 'auto-scroll-to-bottom', autoScroll: 'smooth', }; const ItemContent: VirtuosoMessageListProps< PatchTypeWithKey, MessageListContext >['ItemContent'] = ({ data, context }) => { const attempt = context?.attempt; if (data.type === 'STDOUT') { return

{data.content}

; } if (data.type === 'STDERR') { return

{data.content}

; } if (data.type === 'NORMALIZED_ENTRY' && attempt) { return ( ); } return null; }; const computeItemKey: VirtuosoMessageListProps< PatchTypeWithKey, MessageListContext >['computeItemKey'] = ({ data }) => `l-${data.patchKey}`; const VirtualizedList = ({ attempt }: VirtualizedListProps) => { const [channelData, setChannelData] = useState | null>(null); const [loading, setLoading] = useState(true); const { setEntries, reset } = useEntries(); useEffect(() => { setLoading(true); setChannelData(null); reset(); }, [attempt.id, reset]); const onEntriesUpdated = ( newEntries: PatchTypeWithKey[], addType: AddEntryType, newLoading: boolean ) => { let scrollModifier: ScrollModifier = InitialDataScrollModifier; if (addType === 'running' && !loading) { scrollModifier = AutoScrollToBottom; } setChannelData({ data: newEntries, scrollModifier }); setEntries(newEntries); if (loading) { setLoading(newLoading); } }; useConversationHistory({ attempt, onEntriesUpdated }); const messageListRef = useRef(null); const messageListContext = useMemo(() => ({ attempt }), [attempt]); return ( ref={messageListRef} className="flex-1" data={channelData} initialLocation={INITIAL_TOP_ITEM} context={messageListContext} computeItemKey={computeItemKey} ItemContent={ItemContent} Header={() =>
} Footer={() =>
} />
{loading && (

Loading History

)}
); }; export default VirtualizedList;