@@ -770,8 +770,8 @@ export class CopilotRemoteAgentManager extends Disposable {
770770 return this . createEmptySession ( ) ;
771771 }
772772
773- // Get session logs
774- const sessionLogs = await this . getSessionLogFromPullRequest ( pullRequest ) ;
773+ // Get session logs (including in-progress sessions)
774+ const sessionLogs = await this . getSessionLogFromPullRequest ( pullRequest , 0 , false ) ;
775775 if ( ! sessionLogs ) {
776776 Logger . warn ( `No session logs found for pull request ${ pullRequestId } ` , CopilotRemoteAgentManager . ID ) ;
777777 return this . createEmptySession ( ) ;
@@ -780,8 +780,15 @@ export class CopilotRemoteAgentManager extends Disposable {
780780 // Parse logs and create chat history
781781 const history = await this . parseChatHistoryFromLogs ( sessionLogs . logs , pullRequest . title ) ;
782782
783+ // Check if the session is in progress and provide activeResponseCallback if needed
784+ const isInProgress = sessionLogs . info . state === 'in_progress' ;
785+ const activeResponseCallback = isInProgress
786+ ? this . createActiveResponseCallback ( pullRequest , sessionLogs . info . id )
787+ : undefined ;
788+
783789 return {
784790 history,
791+ activeResponseCallback,
785792 requestHandler : undefined // Read-only session
786793 } ;
787794 } catch ( error ) {
@@ -797,6 +804,114 @@ export class CopilotRemoteAgentManager extends Disposable {
797804 } ;
798805 }
799806
807+ private createActiveResponseCallback ( pullRequest : PullRequestModel , _sessionId : string ) : ( stream : vscode . ChatResponseStream , token : vscode . CancellationToken ) => Thenable < void > {
808+ return async ( stream : vscode . ChatResponseStream , token : vscode . CancellationToken ) => {
809+ const capi = await this . copilotApi ;
810+ if ( ! capi || token . isCancellationRequested ) {
811+ return ;
812+ }
813+
814+ let lastLogLength = 0 ;
815+ let lastProcessedLength = 0 ;
816+ const pollingInterval = 3000 ; // 3 seconds
817+
818+ return new Promise < void > ( ( resolve , reject ) => {
819+ const pollForUpdates = async ( ) : Promise < void > => {
820+ try {
821+ if ( token . isCancellationRequested ) {
822+ resolve ( ) ;
823+ return ;
824+ }
825+
826+ // Get latest session logs
827+ const sessionLogs = await this . getSessionLogFromPullRequest ( pullRequest , 0 , false ) ;
828+ if ( ! sessionLogs || token . isCancellationRequested ) {
829+ resolve ( ) ;
830+ return ;
831+ }
832+
833+ // Check if session is still in progress
834+ if ( sessionLogs . info . state !== 'in_progress' ) {
835+ // Session completed, parse any remaining logs and stream final content
836+ if ( sessionLogs . logs . length > lastProcessedLength ) {
837+ const newLogContent = sessionLogs . logs . slice ( lastProcessedLength ) ;
838+ await this . streamNewLogContent ( stream , newLogContent ) ;
839+ }
840+ resolve ( ) ; // Resolve the promise when session is complete
841+ return ;
842+ }
843+
844+ // Stream new content if logs have grown
845+ if ( sessionLogs . logs . length > lastLogLength ) {
846+ const newLogContent = sessionLogs . logs . slice ( lastProcessedLength ) ;
847+ await this . streamNewLogContent ( stream , newLogContent ) ;
848+ lastProcessedLength = sessionLogs . logs . length ;
849+ }
850+
851+ lastLogLength = sessionLogs . logs . length ;
852+
853+ // Schedule next poll if still in progress and not cancelled
854+ if ( ! token . isCancellationRequested && sessionLogs . info . state === 'in_progress' ) {
855+ setTimeout ( pollForUpdates , pollingInterval ) ;
856+ } else {
857+ resolve ( ) ;
858+ }
859+ } catch ( error ) {
860+ Logger . error ( `Error polling for session updates: ${ error } ` , CopilotRemoteAgentManager . ID ) ;
861+ // Continue polling despite errors
862+ if ( ! token . isCancellationRequested ) {
863+ setTimeout ( pollForUpdates , pollingInterval ) ;
864+ } else {
865+ reject ( error ) ;
866+ }
867+ }
868+ } ;
869+
870+ // Start polling
871+ setTimeout ( pollForUpdates , pollingInterval ) ;
872+ } ) ;
873+ } ;
874+ }
875+
876+ private async streamNewLogContent ( stream : vscode . ChatResponseStream , newLogContent : string ) : Promise < void > {
877+ try {
878+ if ( ! newLogContent . trim ( ) ) {
879+ return ;
880+ }
881+
882+ // Parse the new log content
883+ const logChunks = parseSessionLogs ( newLogContent ) ;
884+
885+ for ( const chunk of logChunks ) {
886+ for ( const choice of chunk . choices ) {
887+ const delta = choice . delta ;
888+
889+ if ( delta . role === 'assistant' ) {
890+ // Stream assistant content
891+ if ( delta . content ) {
892+ stream . markdown ( delta . content ) ;
893+ }
894+
895+ // Handle tool calls
896+ if ( delta . tool_calls ) {
897+ for ( const toolCall of delta . tool_calls ) {
898+ const toolDetails = parseToolCallDetails ( toolCall , '' ) ;
899+ stream . push ( new vscode . ChatToolInvocationPart ( toolCall . id , toolDetails . toolName ) ) ;
900+ }
901+ }
902+ }
903+
904+ // Handle finish reasons
905+ if ( choice . finish_reason && choice . finish_reason !== 'null' ) {
906+ Logger . appendLine ( `Streaming finish_reason: ${ choice . finish_reason } ` , CopilotRemoteAgentManager . ID ) ;
907+ }
908+ }
909+ }
910+ } catch ( error ) {
911+ Logger . error ( `Error streaming new log content: ${ error } ` , CopilotRemoteAgentManager . ID ) ;
912+ }
913+ }
914+
800915 private findPullRequestById ( id : number ) : PullRequestModel | undefined {
801916 for ( const folderManager of this . repositoriesManager . folderManagers ) {
802917 for ( const githubRepo of folderManager . gitHubRepositories ) {
0 commit comments