@@ -559,6 +559,10 @@ type TreeItem = ChatPromptItem | ChatRequestItem | ChatElementItem | ToolCallIte
559559
560560class ChatRequestProvider extends Disposable implements vscode . TreeDataProvider < TreeItem > {
561561 private readonly filters : LogTreeFilters ;
562+ private rootItems : ( ChatPromptItem | TreeChildItem ) [ ] = [ ] ;
563+ private seenChatRequests = new WeakSet < ChatRequest > ( ) ;
564+ private processedCount = 0 ;
565+ private currentPrompt : ChatPromptItem | undefined ;
562566
563567 constructor (
564568 @IRequestLogger private readonly requestLogger : IRequestLogger ,
@@ -567,8 +571,9 @@ class ChatRequestProvider extends Disposable implements vscode.TreeDataProvider<
567571 super ( ) ;
568572 this . filters = this . _register ( instantiationService . createInstance ( LogTreeFilters ) ) ;
569573 this . _register ( new LogTreeFilterCommands ( this . filters ) ) ;
570- this . _register ( this . requestLogger . onDidChangeRequests ( ( ) => this . _onDidChangeTreeData . fire ( ) ) ) ;
574+ this . _register ( this . requestLogger . onDidChangeRequests ( ( ) => this . handleRequestChange ( ) ) ) ;
571575 this . _register ( this . filters . onDidChangeFilters ( ( ) => this . _onDidChangeTreeData . fire ( ) ) ) ;
576+ this . rebuildFromScratch ( ) ;
572577 }
573578
574579 private readonly _onDidChangeTreeData = new vscode . EventEmitter < TreeItem | undefined | void > ( ) ;
@@ -580,48 +585,80 @@ class ChatRequestProvider extends Disposable implements vscode.TreeDataProvider<
580585
581586 getChildren ( element ?: TreeItem | undefined ) : vscode . ProviderResult < TreeItem [ ] > {
582587 if ( element instanceof ChatPromptItem ) {
583- return element . children ;
584- } else if ( element ) {
588+ return element . children . filter ( child => this . filters . itemIncluded ( child ) ) ;
589+ }
590+
591+ if ( element ) {
585592 return [ ] ;
586- } else {
587- let lastPrompt : ChatPromptItem | undefined ;
588- const result : ( ChatPromptItem | TreeChildItem ) [ ] = [ ] ;
589- const seen = new Set < ChatRequest | undefined > ( ) ;
590-
591- for ( const r of this . requestLogger . getRequests ( ) ) {
592- const item = this . logToTreeItem ( r ) ;
593- if ( r . chatRequest !== lastPrompt ?. request ) {
594- if ( lastPrompt ) {
595- result . push ( lastPrompt ) ;
596- }
597- lastPrompt = r . chatRequest ? ChatPromptItem . create ( r , r . chatRequest , seen . has ( r . chatRequest ) ) : undefined ;
598- seen . add ( r . chatRequest ) ;
593+ }
594+
595+ return this . rootItems . filter ( item => this . filters . itemIncluded ( item ) ) ;
596+ }
597+
598+ private rebuildFromScratch ( ) : void {
599+ this . rootItems = [ ] ;
600+ this . seenChatRequests = new WeakSet < ChatRequest > ( ) ;
601+ this . processedCount = 0 ;
602+ this . currentPrompt = undefined ;
603+ this . appendNewEntries ( ) ;
604+ }
605+
606+ private handleRequestChange ( ) : void {
607+ this . appendNewEntries ( ) ;
608+ }
609+
610+ private appendNewEntries ( ) : void {
611+ const requests = this . requestLogger . getRequests ( ) ;
612+ let rootChanged = false ;
613+ const promptsToRefresh = new Set < ChatPromptItem > ( ) ;
614+ const newPrompts = new Set < ChatPromptItem > ( ) ;
615+
616+ if ( requests . length < this . processedCount ) {
617+ this . rootItems = [ ] ;
618+ this . seenChatRequests = new WeakSet < ChatRequest > ( ) ;
619+ this . processedCount = 0 ;
620+ this . currentPrompt = undefined ;
621+ rootChanged = true ;
622+ }
623+
624+ for ( let i = this . processedCount ; i < requests . length ; i ++ ) {
625+ const info = requests [ i ] ;
626+ const child = this . logToTreeItem ( info ) ;
627+ const request = info . chatRequest ;
628+
629+ if ( request ) {
630+ const hasSeen = this . seenChatRequests . has ( request ) ;
631+ if ( ! this . currentPrompt || this . currentPrompt . request !== request ) {
632+ this . currentPrompt = ChatPromptItem . create ( info , request , hasSeen ) ;
633+ this . currentPrompt . children = [ ] ;
634+ this . rootItems . push ( this . currentPrompt ) ;
635+ this . seenChatRequests . add ( request ) ;
636+ rootChanged = true ;
637+ newPrompts . add ( this . currentPrompt ) ;
599638 }
600639
601- if ( lastPrompt ) {
602- if ( ! lastPrompt . children . find ( c => c . id === item . id ) ) {
603- lastPrompt . children . push ( item ) ;
604- }
605- if ( ! lastPrompt . children . find ( c => c . id === item . id ) ) {
606- lastPrompt . children . push ( item ) ;
607- }
608- } else {
609- result . push ( item ) ;
640+ if ( ! this . currentPrompt . children . some ( c => c . id === child . id ) ) {
641+ this . currentPrompt . children . push ( child ) ;
642+ promptsToRefresh . add ( this . currentPrompt ) ;
610643 }
644+ } else {
645+ this . currentPrompt = undefined ;
646+ this . rootItems . push ( child ) ;
647+ rootChanged = true ;
611648 }
649+ }
612650
613- if ( lastPrompt ) {
614- result . push ( lastPrompt ) ;
615- }
651+ this . processedCount = requests . length ;
616652
617- return result . map ( r => {
618- if ( r instanceof ChatPromptItem ) {
619- return r . withFilteredChildren ( child => this . filters . itemIncluded ( child ) ) ;
620- }
653+ if ( rootChanged ) {
654+ this . _onDidChangeTreeData . fire ( undefined ) ;
655+ }
621656
622- return r ;
623- } )
624- . filter ( r => this . filters . itemIncluded ( r ) ) ;
657+ for ( const prompt of promptsToRefresh ) {
658+ if ( rootChanged && newPrompts . has ( prompt ) ) {
659+ continue ;
660+ }
661+ this . _onDidChangeTreeData . fire ( prompt ) ;
625662 }
626663 }
627664
@@ -824,4 +861,4 @@ class LogTreeFilterCommands extends Disposable {
824861 this . _register ( vscode . commands . registerCommand ( 'github.copilot.chat.debug.showNesRequests' , ( ) => filters . setNesRequestsShown ( true ) ) ) ;
825862 this . _register ( vscode . commands . registerCommand ( 'github.copilot.chat.debug.hideNesRequests' , ( ) => filters . setNesRequestsShown ( false ) ) ) ;
826863 }
827- }
864+ }
0 commit comments