@@ -18,7 +18,7 @@ import { CODING_AGENT, CODING_AGENT_AUTO_COMMIT_AND_PUSH } from '../common/setti
1818import { ITelemetry } from '../common/telemetry' ;
1919import { toOpenPullRequestWebviewUri } from '../common/uri' ;
2020import { copilotEventToSessionStatus , copilotPRStatusToSessionStatus , IAPISessionLogs , ICopilotRemoteAgentCommandArgs , ICopilotRemoteAgentCommandResponse , OctokitCommon , RemoteAgentResult , RepoInfo } from './common' ;
21- import { ChatSessionWithPR , CopilotApi , getCopilotApi , RemoteAgentJobPayload , SessionInfo , SessionSetupStep } from './copilotApi' ;
21+ import { ChatSessionFromSummarizedChat , ChatSessionWithPR , CopilotApi , getCopilotApi , RemoteAgentJobPayload , SessionInfo , SessionSetupStep } from './copilotApi' ;
2222import { CopilotPRWatcher , CopilotStateModel } from './copilotPrWatcher' ;
2323import { ChatSessionContentBuilder } from './copilotRemoteAgent/chatSessionContentBuilder' ;
2424import { GitOperationsManager } from './copilotRemoteAgent/gitOperationsManager' ;
@@ -59,6 +59,7 @@ export class CopilotRemoteAgentManager extends Disposable {
5959 readonly onDidChangeChatSessions = this . _onDidChangeChatSessions . event ;
6060
6161 private readonly gitOperationsManager : GitOperationsManager ;
62+ private readonly ephemeralChatSessions : Map < string , ChatSessionFromSummarizedChat > = new Map ( ) ; // TODO: Clean these up
6263
6364 constructor ( private credentialStore : CredentialStore , public repositoriesManager : RepositoriesManager , private telemetry : ITelemetry , private context : vscode . ExtensionContext ) {
6465 super ( ) ;
@@ -723,11 +724,28 @@ export class CopilotRemoteAgentManager extends Disposable {
723724 return this . _stateModel . getCounts ( ) ;
724725 }
725726
726- public async provideNewChatSessionItem ( options : { prompt ?: string ; history : ReadonlyArray < vscode . ChatRequestTurn | vscode . ChatResponseTurn > ; metadata ?: any ; } , _token : vscode . CancellationToken ) : Promise < ChatSessionWithPR > {
727+ public async provideNewChatSessionItem ( options : { prompt ?: string ; history : ReadonlyArray < vscode . ChatRequestTurn | vscode . ChatResponseTurn > ; metadata ?: any ; } , _token : vscode . CancellationToken ) : Promise < ChatSessionWithPR | ChatSessionFromSummarizedChat > {
727728 const { prompt } = options ;
728729 if ( ! prompt ) {
729730 throw new Error ( `Prompt is expected to provide a new chat session item` ) ;
730731 }
732+
733+ const { source, summary } = options . metadata || { } ;
734+
735+ // Ephemeral session for new session creation flow
736+ if ( source === 'chatExecuteActions' ) {
737+ const id = `new-${ Date . now ( ) } ` ;
738+ const val = {
739+ id,
740+ label : vscode . l10n . t ( 'New coding agent session' ) ,
741+ iconPath : new vscode . ThemeIcon ( 'plus' ) ,
742+ prompt,
743+ summary,
744+ } ;
745+ this . ephemeralChatSessions . set ( id , val ) ;
746+ return val ;
747+ }
748+
731749 const result = await this . invokeRemoteAgent (
732750 prompt ,
733751 prompt ,
@@ -799,21 +817,134 @@ export class CopilotRemoteAgentManager extends Disposable {
799817 return [ ] ;
800818 }
801819
820+
821+ private async newSessionFlowFromPrompt ( id : string ) : Promise < vscode . ChatSession > {
822+ const session = this . ephemeralChatSessions . get ( id ) ;
823+ if ( ! session ) {
824+ return this . createEmptySession ( ) ;
825+ }
826+
827+ const repoInfo = await this . repoInfo ( ) ;
828+ if ( ! repoInfo ) {
829+ return this . createEmptySession ( ) ; // TODO: Explain how to enroll repo in coding agent, etc..?
830+ }
831+ const { repo, owner } = repoInfo ;
832+
833+ // Remove from ephemeral sessions
834+ this . ephemeralChatSessions . delete ( id ) ;
835+
836+ // Create a placeholder session that will invoke the remote agent when confirmed
837+
838+ const { prompt } = session ;
839+ const sessionRequest = new vscode . ChatRequestTurn2 (
840+ prompt ,
841+ undefined ,
842+ [ ] ,
843+ COPILOT_SWE_AGENT ,
844+ [ ] ,
845+ [ ]
846+ ) ;
847+
848+ const placeholderParts = [
849+ new vscode . ChatResponseProgressPart ( vscode . l10n . t ( 'Starting coding agent session...' ) ) ,
850+ new vscode . ChatResponseConfirmationPart (
851+ vscode . l10n . t ( 'Copilot coding agent will continue your work in \'{0}\'.' , `${ owner } /${ repo } ` ) ,
852+ vscode . l10n . t ( 'Your chat context will be used to continue work in a new pull request.' ) ,
853+ 'invoke' , // Next state
854+ [ 'Continue' , 'Cancel' ]
855+ )
856+ ] ;
857+
858+ const placeholderTurn = new vscode . ChatResponseTurn2 ( placeholderParts , { } , COPILOT_SWE_AGENT ) ;
859+ return {
860+ history : [ sessionRequest , placeholderTurn ] ,
861+ requestHandler : async ( request : vscode . ChatRequest , _context : vscode . ChatContext , stream : vscode . ChatResponseStream , token : vscode . CancellationToken ) : Promise < vscode . ChatResult > => {
862+ if ( token . isCancellationRequested ) {
863+ return { } ;
864+ }
865+ if ( request . acceptedConfirmationData ) {
866+ if ( ! Array . isArray ( request . acceptedConfirmationData ) ) {
867+ Logger . error ( `Invalid confirmation data: ${ request . acceptedConfirmationData } ` , CopilotRemoteAgentManager . ID ) ;
868+ return { } ;
869+ }
870+ const states = request . acceptedConfirmationData as string [ ] ;
871+ while ( states . length ) {
872+ const state = states . shift ( ) ;
873+ if ( ! state ) {
874+ continue ;
875+ }
876+ switch ( state ) {
877+ case 'invoke' :
878+ // TODO: Refactor of invokeRemoteAgent needed to extract all user prompts
879+ // Move any user action to a state in this state machine.
880+ stream . progress ( 'Delegating to coding agent' ) ;
881+ const result = await this . invokeRemoteAgent (
882+ prompt ,
883+ prompt ,
884+ false ,
885+ ) ;
886+ if ( result . state !== 'success' ) {
887+ stream . warning ( `Could not create coding agent session: ${ result . error } ` ) ;
888+ return { } ;
889+ }
890+
891+ const pullRequest = await this . findPullRequestById ( result . number , true ) ;
892+ if ( ! pullRequest ) {
893+ stream . warning ( `Could not find coding agent session.` ) ;
894+ return { } ;
895+ }
896+ const capi = await this . copilotApi ;
897+ if ( ! capi ) {
898+ stream . warning ( vscode . l10n . t ( 'Could not initialize Copilot API.' ) ) ;
899+ return { } ;
900+ }
901+ // Poll for the new session
902+ const sessions = await capi . getAllSessions ( pullRequest . id ) ;
903+ const newSession = sessions . find ( s => s . state === 'in_progress' || s . state === 'queued' ) ;
904+ if ( ! newSession ) {
905+ stream . warning ( vscode . l10n . t ( 'Could not find coding agent session in progress.' ) ) ;
906+ return { } ;
907+ }
908+ stream . markdown ( vscode . l10n . t ( 'Coding agent is now working on your request...' ) ) ;
909+ stream . markdown ( '\n\n' ) ;
910+ await this . streamSessionLogs ( stream , pullRequest , newSession . id , token ) ;
911+ return { } ;
912+ default :
913+ Logger . error ( `Unknown confirmation state: ${ state } ` , CopilotRemoteAgentManager . ID ) ;
914+ stream . markdown ( 'error!' ) ;
915+ return { } ;
916+ }
917+ }
918+ }
919+ if ( request . rejectedConfirmationData ) {
920+ stream . push ( new vscode . ChatResponseProgressPart ( vscode . l10n . t ( 'Cancelled starting coding agent session.' ) ) ) ;
921+ return { } ;
922+ }
923+ return { } ;
924+ } ,
925+ activeResponseCallback : undefined ,
926+ } ;
927+ }
928+
802929 public async provideChatSessionContent ( id : string , token : vscode . CancellationToken ) : Promise < vscode . ChatSession > {
803930 try {
804931 const capi = await this . copilotApi ;
805932 if ( ! capi || token . isCancellationRequested ) {
806933 return this . createEmptySession ( ) ;
807934 }
808935
936+ await this . waitRepoManagerInitialization ( ) ;
937+
938+ if ( id . startsWith ( 'new' ) ) {
939+ return await this . newSessionFlowFromPrompt ( id ) ;
940+ }
941+
809942 const pullRequestNumber = parseInt ( id ) ;
810943 if ( isNaN ( pullRequestNumber ) ) {
811944 Logger . error ( `Invalid pull request number: ${ id } ` , CopilotRemoteAgentManager . ID ) ;
812945 return this . createEmptySession ( ) ;
813946 }
814947
815- await this . waitRepoManagerInitialization ( ) ;
816-
817948 const pullRequest = await this . findPullRequestById ( pullRequestNumber , true ) ;
818949 if ( ! pullRequest ) {
819950 Logger . error ( `Pull request not found: ${ pullRequestNumber } ` , CopilotRemoteAgentManager . ID ) ;
0 commit comments