@@ -43,7 +43,7 @@ import {
4343} from '../../../shared/utilities/workspaceUtils'
4444import { getPathsFromZipFilePath , SvgFileExtension } from '../../../amazonq/util/files'
4545import { FollowUpTypes } from '../../../amazonq/commons/types'
46- import { DocGenerationTask } from '../docGenerationTask'
46+ import { DocGenerationTask , DocGenerationTasks } from '../docGenerationTask'
4747import { DevPhase } from '../../types'
4848
4949export interface ChatControllerEventEmitters {
@@ -67,9 +67,7 @@ export class DocController {
6767 private readonly messenger : DocMessenger
6868 private readonly sessionStorage : BaseChatSessionStorage < Session >
6969 private authController : AuthController
70- private folderPath = ''
71- private mode : Mode = Mode . NONE
72- public docGenerationTask : DocGenerationTask
70+ private docGenerationTasks : DocGenerationTasks
7371
7472 public constructor (
7573 private readonly chatControllerMessageListeners : ChatControllerEventEmitters ,
@@ -80,7 +78,7 @@ export class DocController {
8078 this . messenger = messenger
8179 this . sessionStorage = sessionStorage
8280 this . authController = new AuthController ( )
83- this . docGenerationTask = new DocGenerationTask ( )
81+ this . docGenerationTasks = new DocGenerationTasks ( )
8482
8583 this . chatControllerMessageListeners . processHumanChatMessage . event ( ( data ) => {
8684 this . processUserChatMessage ( data ) . catch ( ( e ) => {
@@ -157,23 +155,23 @@ export class DocController {
157155 } else {
158156 let displayPath = ''
159157 const relativePath = getWorkspaceRelativePath ( uri . fsPath )
160-
158+ const docGenerationTask = this . docGenerationTasks . getTask ( data . tabID )
161159 if ( relativePath ) {
162160 // Display path should always include workspace folder name
163161 displayPath = path . join ( relativePath . workspaceFolder . name , relativePath . relativePath )
164162 // Only include workspace folder name in API call if multi-root workspace
165- this . folderPath = isMultiRootWorkspace ( ) ? displayPath : relativePath . relativePath
163+ docGenerationTask . folderPath = isMultiRootWorkspace ( ) ? displayPath : relativePath . relativePath
166164
167165 if ( ! relativePath . relativePath ) {
168- this . docGenerationTask . folderLevel = 'ENTIRE_WORKSPACE'
166+ docGenerationTask . folderLevel = 'ENTIRE_WORKSPACE'
169167 } else {
170- this . docGenerationTask . folderLevel = 'SUB_FOLDER'
168+ docGenerationTask . folderLevel = 'SUB_FOLDER'
171169 }
172170 }
173171
174172 this . messenger . sendFolderConfirmationMessage (
175173 data . tabID ,
176- this . mode === Mode . CREATE
174+ docGenerationTask . mode === Mode . CREATE
177175 ? i18n ( 'AWS.amazonq.doc.answer.createReadme' )
178176 : i18n ( 'AWS.amazonq.doc.answer.updateReadme' ) ,
179177 displayPath ,
@@ -218,6 +216,7 @@ export class DocController {
218216 private initializeFollowUps ( ) : void {
219217 this . chatControllerMessageListeners . followUpClicked . event ( async ( data ) => {
220218 const session : Session = await this . sessionStorage . getSession ( data . tabID )
219+ const docGenerationTask = this . docGenerationTasks . getTask ( data . tabID )
221220
222221 const workspaceFolders = vscode . workspace . workspaceFolders
223222 if ( workspaceFolders === undefined || workspaceFolders . length === 0 ) {
@@ -245,7 +244,7 @@ export class DocController {
245244
246245 switch ( data . followUp . type ) {
247246 case FollowUpTypes . Retry :
248- if ( this . mode === Mode . EDIT ) {
247+ if ( docGenerationTask . mode === Mode . EDIT ) {
249248 this . enableUserInput ( data ?. tabID )
250249 } else {
251250 await this . tabOpened ( data )
@@ -262,19 +261,19 @@ export class DocController {
262261 case FollowUpTypes . CloseSession :
263262 return this . closeSession ( data )
264263 case FollowUpTypes . CreateDocumentation :
265- this . docGenerationTask . interactionType = 'GENERATE_README'
266- this . mode = Mode . CREATE
264+ docGenerationTask . interactionType = 'GENERATE_README'
265+ docGenerationTask . mode = Mode . CREATE
267266 sendFolderConfirmationMessage ( i18n ( 'AWS.amazonq.doc.answer.createReadme' ) )
268267 break
269268 case FollowUpTypes . ChooseFolder :
270269 await this . folderSelector ( data )
271270 break
272271 case FollowUpTypes . SynchronizeDocumentation :
273- this . mode = Mode . SYNC
272+ docGenerationTask . mode = Mode . SYNC
274273 sendFolderConfirmationMessage ( i18n ( 'AWS.amazonq.doc.answer.updateReadme' ) )
275274 break
276275 case FollowUpTypes . UpdateDocumentation :
277- this . docGenerationTask . interactionType = 'UPDATE_README'
276+ docGenerationTask . interactionType = 'UPDATE_README'
278277 this . messenger . sendAnswer ( {
279278 type : 'answer' ,
280279 tabID : data ?. tabID ,
@@ -283,21 +282,21 @@ export class DocController {
283282 } )
284283 break
285284 case FollowUpTypes . EditDocumentation :
286- this . docGenerationTask . interactionType = 'EDIT_README'
287- this . mode = Mode . EDIT
285+ docGenerationTask . interactionType = 'EDIT_README'
286+ docGenerationTask . mode = Mode . EDIT
288287 sendFolderConfirmationMessage ( i18n ( 'AWS.amazonq.doc.answer.updateReadme' ) )
289288 break
290289 case FollowUpTypes . MakeChanges :
291- this . mode = Mode . EDIT
290+ docGenerationTask . mode = Mode . EDIT
292291 this . enableUserInput ( data . tabID )
293292 break
294293 case FollowUpTypes . AcceptChanges :
295- this . docGenerationTask . userDecision = 'ACCEPT'
294+ docGenerationTask . userDecision = 'ACCEPT'
296295 await this . sendDocAcceptanceEvent ( data )
297296 await this . insertCode ( data )
298297 return
299298 case FollowUpTypes . RejectChanges :
300- this . docGenerationTask . userDecision = 'REJECT'
299+ docGenerationTask . userDecision = 'REJECT'
301300 await this . sendDocAcceptanceEvent ( data )
302301 this . messenger . sendAnswer ( {
303302 type : 'answer' ,
@@ -309,26 +308,27 @@ export class DocController {
309308 break
310309 case FollowUpTypes . ProceedFolderSelection :
311310 // If a user did not change the folder in a multi-root workspace, default to the first workspace folder
312- if ( this . folderPath === '' && isMultiRootWorkspace ( ) ) {
313- this . folderPath = workspaceFolderName
311+ if ( docGenerationTask . folderPath === '' && isMultiRootWorkspace ( ) ) {
312+ docGenerationTask . folderPath = workspaceFolderName
314313 }
315- if ( this . mode === Mode . EDIT ) {
314+ if ( docGenerationTask . mode === Mode . EDIT ) {
316315 this . enableUserInput ( data . tabID )
317316 } else {
318- await this . generateDocumentation ( {
319- message : {
317+ await this . generateDocumentation (
318+ {
320319 ...data ,
321320 message :
322- this . mode === Mode . CREATE
321+ docGenerationTask . mode === Mode . CREATE
323322 ? 'Create documentation for a specific folder'
324323 : 'Sync documentation' ,
325324 } ,
326325 session ,
327- } )
326+ docGenerationTask
327+ )
328328 }
329329 break
330330 case FollowUpTypes . CancelFolderSelection :
331- this . docGenerationTask . folderLevel = 'ENTIRE_WORKSPACE'
331+ docGenerationTask . reset ( )
332332 return this . tabOpened ( data )
333333 }
334334 } )
@@ -383,7 +383,8 @@ export class DocController {
383383
384384 private async newTask ( message : any ) {
385385 // Old session for the tab is ending, delete it so we can create a new one for the message id
386- this . docGenerationTask = new DocGenerationTask ( )
386+
387+ this . docGenerationTasks . deleteTask ( message . tabID )
387388 this . sessionStorage . deleteSession ( message . tabID )
388389
389390 // Re-run the opening flow, where we check auth + create a session
@@ -399,18 +400,22 @@ export class DocController {
399400 } )
400401 this . messenger . sendUpdatePlaceholder ( message . tabID , i18n ( 'AWS.amazonq.featureDev.placeholder.sessionClosed' ) )
401402 this . messenger . sendChatInputEnabled ( message . tabID , false )
402-
403- this . docGenerationTask . reset ( )
403+ this . docGenerationTasks . deleteTask ( message . tabID )
404404 }
405405
406- private processErrorChatMessage = ( err : any , message : any , session : Session | undefined ) => {
406+ private processErrorChatMessage = (
407+ err : any ,
408+ message : any ,
409+ session : Session | undefined ,
410+ docGenerationTask : DocGenerationTask
411+ ) => {
407412 const errorMessage = createUserFacingErrorMessage ( `${ err . cause ?. message ?? err . message } ` )
408413 // eslint-disable-next-line unicorn/no-null
409414 this . messenger . sendUpdatePromptProgress ( message . tabID , null )
410415 if ( err . constructor . name === MonthlyConversationLimitError . name ) {
411416 this . messenger . sendMonthlyLimitError ( message . tabID )
412417 } else {
413- const enableUserInput = this . mode === Mode . EDIT && err . remainingIterations > 0
418+ const enableUserInput = docGenerationTask . mode === Mode . EDIT && err . remainingIterations > 0
414419
415420 this . messenger . sendErrorMessage (
416421 errorMessage ,
@@ -423,11 +428,11 @@ export class DocController {
423428 }
424429 }
425430
426- private async generateDocumentation ( { message, session } : { message : any ; session : any } ) {
431+ private async generateDocumentation ( message : any , session : any , docGenerationTask : DocGenerationTask ) {
427432 try {
428- await this . onDocsGeneration ( session , message . message , message . tabID )
433+ await this . onDocsGeneration ( session , message . message , message . tabID , docGenerationTask )
429434 } catch ( err : any ) {
430- this . processErrorChatMessage ( err , message , session )
435+ this . processErrorChatMessage ( err , message , session , docGenerationTask )
431436 }
432437 }
433438
@@ -448,6 +453,7 @@ export class DocController {
448453 }
449454
450455 const session : Session = await this . sessionStorage . getSession ( message . tabID )
456+ const docGenerationTask = this . docGenerationTasks . getTask ( message . tabID )
451457
452458 try {
453459 getLogger ( ) . debug ( `${ featureName } : Processing message: ${ message . message } ` )
@@ -459,9 +465,9 @@ export class DocController {
459465 return
460466 }
461467
462- await this . generateDocumentation ( { message, session } )
468+ await this . generateDocumentation ( message , session , docGenerationTask )
463469 } catch ( err : any ) {
464- this . processErrorChatMessage ( err , message , session )
470+ this . processErrorChatMessage ( err , message , session , docGenerationTask )
465471 }
466472 }
467473
@@ -483,17 +489,18 @@ export class DocController {
483489 let session : Session | undefined
484490 try {
485491 session = await this . sessionStorage . getSession ( message . tabID )
492+ const docGenerationTask = this . docGenerationTasks . getTask ( message . tabID )
486493 getLogger ( ) . debug ( `${ featureName } : Session created with id: ${ session . tabID } ` )
487- this . folderPath = ''
488- this . mode = Mode . NONE
494+ docGenerationTask . folderPath = ''
495+ docGenerationTask . mode = Mode . NONE
489496
490497 const authState = await AuthUtil . instance . getChatAuthState ( )
491498 if ( authState . amazonQ !== 'connected' ) {
492499 void this . messenger . sendAuthNeededExceptionMessage ( authState , message . tabID )
493500 session . isAuthenticating = true
494501 return
495502 }
496- this . docGenerationTask . numberOfNavigations += 1
503+ docGenerationTask . numberOfNavigations += 1
497504 this . messenger . sendAnswer ( {
498505 type : 'answer' ,
499506 tabID : message . tabID ,
@@ -536,13 +543,18 @@ export class DocController {
536543 await vscode . commands . executeCommand ( 'markdown.showPreview' )
537544 }
538545
539- private async onDocsGeneration ( session : Session , message : string , tabID : string ) {
540- this . messenger . sendDocProgress ( tabID , DocGenerationStep . UPLOAD_TO_S3 , 0 , this . mode )
546+ private async onDocsGeneration (
547+ session : Session ,
548+ message : string ,
549+ tabID : string ,
550+ docGenerationTask : DocGenerationTask
551+ ) {
552+ this . messenger . sendDocProgress ( tabID , DocGenerationStep . UPLOAD_TO_S3 , 0 , docGenerationTask . mode )
541553
542554 await session . preloader ( message )
543555
544556 try {
545- await session . send ( message , this . mode , this . folderPath )
557+ await session . send ( message , docGenerationTask . mode , docGenerationTask . folderPath )
546558 const filePaths = session . state . filePaths ?? [ ]
547559 const deletedFiles = session . state . deletedFiles ?? [ ]
548560
@@ -585,7 +597,7 @@ export class DocController {
585597 this . messenger . sendAnswer ( {
586598 type : 'answer' ,
587599 tabID : tabID ,
588- message : `${ this . mode === Mode . CREATE ? i18n ( 'AWS.amazonq.doc.answer.readmeCreated' ) : i18n ( 'AWS.amazonq.doc.answer.readmeUpdated' ) } ${ remainingIterations > 0 ? i18n ( 'AWS.amazonq.doc.answer.codeResult' ) : i18n ( 'AWS.amazonq.doc.answer.acceptOrReject' ) } ` ,
600+ message : `${ docGenerationTask . mode === Mode . CREATE ? i18n ( 'AWS.amazonq.doc.answer.readmeCreated' ) : i18n ( 'AWS.amazonq.doc.answer.readmeUpdated' ) } ${ remainingIterations > 0 ? i18n ( 'AWS.amazonq.doc.answer.codeResult' ) : i18n ( 'AWS.amazonq.doc.answer.acceptOrReject' ) } ` ,
589601 disableChatInput : true ,
590602 } )
591603
@@ -601,13 +613,14 @@ export class DocController {
601613 } )
602614 }
603615 if ( session ?. state . phase === DevPhase . CODEGEN ) {
616+ const docGenerationTask = this . docGenerationTasks . getTask ( tabID )
604617 const { totalGeneratedChars, totalGeneratedLines, totalGeneratedFiles } =
605- await session . countGeneratedContent ( this . docGenerationTask . interactionType )
606- this . docGenerationTask . conversationId = session . conversationId
607- this . docGenerationTask . numberOfGeneratedChars = totalGeneratedChars
608- this . docGenerationTask . numberOfGeneratedLines = totalGeneratedLines
609- this . docGenerationTask . numberOfGeneratedFiles = totalGeneratedFiles
610- const docGenerationEvent = this . docGenerationTask . docGenerationEventBase ( )
618+ await session . countGeneratedContent ( docGenerationTask . interactionType )
619+ docGenerationTask . conversationId = session . conversationId
620+ docGenerationTask . numberOfGeneratedChars = totalGeneratedChars
621+ docGenerationTask . numberOfGeneratedLines = totalGeneratedLines
622+ docGenerationTask . numberOfGeneratedFiles = totalGeneratedFiles
623+ const docGenerationEvent = docGenerationTask . docGenerationEventBase ( )
611624
612625 await session . sendDocTelemetryEvent ( docGenerationEvent , 'generation' )
613626 }
@@ -635,6 +648,7 @@ export class DocController {
635648
636649 private tabClosed ( message : any ) {
637650 this . sessionStorage . deleteSession ( message . tabID )
651+ this . docGenerationTasks . deleteTask ( message . tabID )
638652 }
639653
640654 private async insertCode ( message : any ) {
@@ -670,14 +684,15 @@ export class DocController {
670684 }
671685 private async sendDocAcceptanceEvent ( message : any ) {
672686 const session = await this . sessionStorage . getSession ( message . tabID )
673- this . docGenerationTask . conversationId = session . conversationId
687+ const docGenerationTask = this . docGenerationTasks . getTask ( message . tabID )
688+ docGenerationTask . conversationId = session . conversationId
674689 const { totalAddedChars, totalAddedLines, totalAddedFiles } = await session . countAddedContent (
675- this . docGenerationTask . interactionType
690+ docGenerationTask . interactionType
676691 )
677- this . docGenerationTask . numberOfAddedChars = totalAddedChars
678- this . docGenerationTask . numberOfAddedLines = totalAddedLines
679- this . docGenerationTask . numberOfAddedFiles = totalAddedFiles
680- const docAcceptanceEvent = this . docGenerationTask . docAcceptanceEventBase ( )
692+ docGenerationTask . numberOfAddedChars = totalAddedChars
693+ docGenerationTask . numberOfAddedLines = totalAddedLines
694+ docGenerationTask . numberOfAddedFiles = totalAddedFiles
695+ const docAcceptanceEvent = docGenerationTask . docAcceptanceEventBase ( )
681696
682697 await session . sendDocTelemetryEvent ( docAcceptanceEvent , 'acceptance' )
683698 }
0 commit comments