@@ -9,6 +9,7 @@ import { extractTextCached } from "./message-extract.ts";
99import { normalizeMessage , stripMessageDisplayMetadataText } from "./message-normalizer.ts" ;
1010import { normalizeRoleForGrouping } from "./role-normalizer.ts" ;
1111import { messageMatchesSearchQuery } from "./search-match.ts" ;
12+ import { trimAccumulatedStreamPrefix } from "./stream-text.ts" ;
1213import { extractToolCardsCached , extractToolPreview } from "./tool-cards.ts" ;
1314import { buildUserChatMessageContentBlocks } from "./user-message-content.ts" ;
1415
@@ -300,13 +301,6 @@ function sanitizeStreamText(text: string): string {
300301 return stripped . trim ( ) . length > 0 ? stripped : "" ;
301302}
302303
303- function trimAccumulatedStreamPrefix ( text : string , previousText : string | null ) : string {
304- if ( ! previousText || ! text . startsWith ( previousText ) ) {
305- return text ;
306- }
307- return text . slice ( previousText . length ) . trimStart ( ) ;
308- }
309-
310304function shouldRenderQueuedSendInThread ( item : ChatQueueItem ) : boolean {
311305 if ( typeof item . sendSubmittedAtMs !== "number" || item . sendState === "failed" ) {
312306 return false ;
@@ -356,6 +350,19 @@ function chatItemTimestamp(item: ChatItem): number | null {
356350 return null ;
357351}
358352
353+ function timestampAfterVisibleItems ( items : ChatItem [ ] , desiredTimestamp : number ) : number {
354+ const latestTimestamp = items . reduce < number | null > ( ( latest , item ) => {
355+ const timestamp = chatItemTimestamp ( item ) ;
356+ if ( timestamp == null ) {
357+ return latest ;
358+ }
359+ return latest == null || timestamp > latest ? timestamp : latest ;
360+ } , null ) ;
361+ return latestTimestamp != null && desiredTimestamp <= latestTimestamp
362+ ? latestTimestamp + 1
363+ : desiredTimestamp ;
364+ }
365+
359366function sortChatItemsByVisibleTime ( items : ChatItem [ ] ) : ChatItem [ ] {
360367 return items
361368 . map ( ( item , index ) => ( { item, index, timestamp : chatItemTimestamp ( item ) } ) )
@@ -667,13 +674,14 @@ export function buildChatItems(props: BuildChatItemsProps): Array<ChatItem | Mes
667674 const key = `stream:${ props . sessionKey } :${ props . streamStartedAt ?? "live" } ` ;
668675 const text = sanitizeStreamText ( props . stream ) ;
669676 const visibleText = trimAccumulatedStreamPrefix ( text , previousAccumulatedStreamText ) ;
677+ const startedAt = timestampAfterVisibleItems ( items , props . streamStartedAt ?? Date . now ( ) ) ;
670678 if ( visibleText . length > 0 ) {
671679 if ( ! stripHeartbeatTokenForDisplay ( visibleText ) . shouldSkip ) {
672680 items . push ( {
673681 kind : "stream" ,
674682 key,
675683 text : visibleText ,
676- startedAt : props . streamStartedAt ?? Date . now ( ) ,
684+ startedAt,
677685 isStreaming : true ,
678686 } ) ;
679687 }
0 commit comments