Skip to content

Commit debb1fb

Browse files
Merge master into feature/amazonqLSP
2 parents 9a0cf8f + bcdfcdd commit debb1fb

File tree

10 files changed

+149
-130
lines changed

10 files changed

+149
-130
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q /doc: Prevent users from requesting changes if no iterations remain"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q /doc: Ask for user prompt if error occurs while updating documentation"
4+
}

packages/amazonq/test/e2e/amazonq/doc.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,33 @@ describe('Amazon Q Doc', async function () {
146146
FollowUpTypes.RejectChanges,
147147
])
148148
})
149+
150+
it('Handle unrelated prompt error', async () => {
151+
await tab.waitForButtons([FollowUpTypes.UpdateDocumentation])
152+
153+
tab.clickButton(FollowUpTypes.UpdateDocumentation)
154+
155+
await tab.waitForButtons([FollowUpTypes.SynchronizeDocumentation, FollowUpTypes.EditDocumentation])
156+
157+
tab.clickButton(FollowUpTypes.EditDocumentation)
158+
159+
await tab.waitForButtons([FollowUpTypes.ProceedFolderSelection])
160+
161+
tab.clickButton(FollowUpTypes.ProceedFolderSelection)
162+
163+
tab.addChatMessage({ prompt: 'tell me about the weather' })
164+
165+
await tab.waitForEvent(() =>
166+
tab.getChatItems().some(({ body }) => body?.startsWith(i18n('AWS.amazonq.doc.error.promptUnrelated')))
167+
)
168+
169+
await tab.waitForEvent(() => {
170+
const store = tab.getStore()
171+
return (
172+
!store.promptInputDisabledState &&
173+
store.promptInputPlaceholder === i18n('AWS.amazonq.doc.placeholder.editReadme')
174+
)
175+
})
176+
})
149177
})
150178
})

packages/core/package.nls.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@
376376
"AWS.amazonq.doc.answer.readmeCreated": "I've created a README for your code.",
377377
"AWS.amazonq.doc.answer.readmeUpdated": "I've updated your README.",
378378
"AWS.amazonq.doc.answer.codeResult": "You can accept the changes to your files, or describe any additional changes you'd like me to make.",
379+
"AWS.amazonq.doc.answer.acceptOrReject": "You can accept or reject the changes to your files.",
379380
"AWS.amazonq.doc.answer.scanning": "Scanning source files",
380381
"AWS.amazonq.doc.answer.summarizing": "Summarizing source files",
381382
"AWS.amazonq.doc.answer.generating": "Generating documentation",
@@ -385,7 +386,7 @@
385386
"AWS.amazonq.doc.error.noFolderSelected": "It looks like you didn't choose a folder. Choose a folder to continue.",
386387
"AWS.amazonq.doc.error.contentLengthError": "Your workspace is too large for me to review. Your workspace must be within the quota, even if you choose a smaller folder. For more information on quotas, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html#quotas\" target=\"_blank\">Amazon Q Developer documentation.</a>",
387388
"AWS.amazonq.doc.error.readmeTooLarge": "The README in your folder is too large for me to review. Try reducing the size of your README, or choose a folder with a smaller README. For more information on quotas, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html#quotas\" target=\"_blank\">Amazon Q Developer documentation.</a>",
388-
"AWS.amazonq.doc.error.readmeUpdateTooLarge": "The updated README is too large. Try reducing the size of your README, or asking for a smaller update. For more information on quotas, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html#quotas\" target=\"_blank\">Amazon Q Developer documentation.</a>",
389+
"AWS.amazonq.doc.error.readmeUpdateTooLarge": "The updated README exceeds document size limits. Try reducing the size of your current README or working on a smaller task that won't produce as much content. For more information on quotas, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html#quotas\" target=\"_blank\">Amazon Q Developer documentation.</a>",
389390
"AWS.amazonq.doc.error.workspaceEmpty": "The folder you chose did not contain any source files in a supported language. Choose another folder and try again. For more information on supported languages, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html\" target=\"_blank\">Amazon Q Developer documentation.</a>",
390391
"AWS.amazonq.doc.error.promptTooVague": "I need more information to make changes to your README. Try providing some of the following details:\n- Which sections you want to modify\n- The content you want to add or remove\n- Specific issues that need correcting\n\nFor more information on prompt best practices, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html\" target=\"_blank\">Amazon Q Developer documentation.</a>",
391392
"AWS.amazonq.doc.error.promptUnrelated": "These changes don't seem related to documentation. Try describing your changes again, using the following best practices:\n- Changes should relate to how project functionality is reflected in the README\n- Content you refer to should be available in your codebase\n\n For more information on prompt best practices, see the <a href=\"https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation.html\" target=\"_blank\">Amazon Q Developer documentation.</a>",
@@ -397,6 +398,9 @@
397398
"AWS.amazonq.doc.pillText.newTask": "Start a new documentation task",
398399
"AWS.amazonq.doc.pillText.update": "Update README to reflect code",
399400
"AWS.amazonq.doc.pillText.makeChange": "Make a specific change",
401+
"AWS.amazonq.doc.pillText.accept": "Accept",
402+
"AWS.amazonq.doc.pillText.reject": "Reject",
403+
"AWS.amazonq.doc.pillText.makeChanges": "Make changes",
400404
"AWS.amazonq.inline.invokeChat": "Inline chat",
401405
"AWS.toolkit.lambda.walkthrough.quickpickTitle": "Application Builder Walkthrough",
402406
"AWS.toolkit.lambda.walkthrough.title": "Get started building your application",

packages/core/src/amazonq/commons/connector/baseMessenger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export class Messenger {
8585
type: 'answer',
8686
tabID: tabID,
8787
message: i18n('AWS.amazonq.featureDev.error.monthlyLimitReached'),
88+
disableChatInput: true,
8889
})
8990
this.sendUpdatePlaceholder(tabID, i18n('AWS.amazonq.featureDev.placeholder.chatInputDisabled'))
9091
}

packages/core/src/amazonqDoc/constants.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,43 @@ export const FolderSelectorFollowUps = [
9292
},
9393
]
9494

95+
export const CodeChangeFollowUps = [
96+
{
97+
pillText: i18n('AWS.amazonq.doc.pillText.accept'),
98+
prompt: i18n('AWS.amazonq.doc.pillText.accept'),
99+
type: FollowUpTypes.AcceptChanges,
100+
icon: 'ok' as MynahIcons,
101+
status: 'success' as Status,
102+
},
103+
{
104+
pillText: i18n('AWS.amazonq.doc.pillText.makeChanges'),
105+
prompt: i18n('AWS.amazonq.doc.pillText.makeChanges'),
106+
type: FollowUpTypes.MakeChanges,
107+
icon: 'refresh' as MynahIcons,
108+
status: 'info' as Status,
109+
},
110+
{
111+
pillText: i18n('AWS.amazonq.doc.pillText.reject'),
112+
prompt: i18n('AWS.amazonq.doc.pillText.reject'),
113+
type: FollowUpTypes.RejectChanges,
114+
icon: 'cancel' as MynahIcons,
115+
status: 'error' as Status,
116+
},
117+
]
118+
119+
export const NewSessionFollowUps = [
120+
{
121+
pillText: i18n('AWS.amazonq.doc.pillText.newTask'),
122+
type: FollowUpTypes.NewTask,
123+
status: 'info' as Status,
124+
},
125+
{
126+
pillText: i18n('AWS.amazonq.doc.pillText.closeSession'),
127+
type: FollowUpTypes.CloseSession,
128+
status: 'info' as Status,
129+
},
130+
]
131+
95132
export const SynchronizeDocumentation = {
96133
pillText: i18n('AWS.amazonq.doc.pillText.update'),
97134
prompt: i18n('AWS.amazonq.doc.pillText.update'),

packages/core/src/amazonqDoc/controllers/chat/controller.ts

Lines changed: 29 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
EditDocumentation,
1111
FolderSelectorFollowUps,
1212
Mode,
13+
NewSessionFollowUps,
1314
SynchronizeDocumentation,
15+
CodeChangeFollowUps,
1416
docScheme,
1517
featureName,
1618
findReadmePath,
@@ -22,7 +24,6 @@ import { Session } from '../../session/session'
2224
import { i18n } from '../../../shared/i18n-helper'
2325
import path from 'path'
2426
import { createSingleFileDialog } from '../../../shared/ui/common/openDialog'
25-
import { MynahIcons } from '@aws/mynah-ui'
2627

2728
import {
2829
MonthlyConversationLimitError,
@@ -298,18 +299,7 @@ export class DocController {
298299
tabID: data?.tabID,
299300
disableChatInput: true,
300301
message: 'Your changes have been discarded.',
301-
followUps: [
302-
{
303-
pillText: i18n('AWS.amazonq.doc.pillText.newTask'),
304-
type: FollowUpTypes.NewTask,
305-
status: 'info',
306-
},
307-
{
308-
pillText: i18n('AWS.amazonq.doc.pillText.closeSession'),
309-
type: FollowUpTypes.CloseSession,
310-
status: 'info',
311-
},
312-
],
302+
followUps: NewSessionFollowUps,
313303
})
314304
break
315305
case FollowUpTypes.ProceedFolderSelection:
@@ -412,13 +402,19 @@ export class DocController {
412402
const errorMessage = createUserFacingErrorMessage(`${err.cause?.message ?? err.message}`)
413403
// eslint-disable-next-line unicorn/no-null
414404
this.messenger.sendUpdatePromptProgress(message.tabID, null)
405+
if (err.constructor.name === MonthlyConversationLimitError.name) {
406+
this.messenger.sendMonthlyLimitError(message.tabID)
407+
} else {
408+
const enableUserInput = this.mode === Mode.EDIT && err.remainingIterations > 0
415409

416-
switch (err.constructor.name) {
417-
case MonthlyConversationLimitError.name:
418-
this.messenger.sendMonthlyLimitError(message.tabID)
419-
break
420-
default:
421-
this.messenger.sendErrorMessage(errorMessage, message.tabID, 0, session?.conversationIdUnsafe, false)
410+
this.messenger.sendErrorMessage(
411+
errorMessage,
412+
message.tabID,
413+
0,
414+
session?.conversationIdUnsafe,
415+
false,
416+
enableUserInput
417+
)
422418
}
423419
}
424420

@@ -427,8 +423,6 @@ export class DocController {
427423
await this.onDocsGeneration(session, message.message, message.tabID)
428424
} catch (err: any) {
429425
this.processErrorChatMessage(err, message, session)
430-
// Lock the chat input until they explicitly click one of the follow ups
431-
this.messenger.sendChatInputEnabled(message.tabID, false)
432426
}
433427
}
434428

@@ -461,12 +455,8 @@ export class DocController {
461455
}
462456

463457
await this.generateDocumentation({ message, session })
464-
this.messenger.sendChatInputEnabled(message?.tabID, false)
465-
this.messenger.sendUpdatePlaceholder(message.tabID, i18n('AWS.amazonq.doc.pillText.selectOption'))
466458
} catch (err: any) {
467459
this.processErrorChatMessage(err, message, session)
468-
// Lock the chat input until they explicitly click one of the follow ups
469-
this.messenger.sendChatInputEnabled(message.tabID, false)
470460
}
471461
}
472462

@@ -590,40 +580,21 @@ export class DocController {
590580
this.messenger.sendAnswer({
591581
type: 'answer',
592582
tabID: tabID,
593-
message: `${this.mode === Mode.CREATE ? i18n('AWS.amazonq.doc.answer.readmeCreated') : i18n('AWS.amazonq.doc.answer.readmeUpdated')} ${i18n('AWS.amazonq.doc.answer.codeResult')}`,
583+
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')}`,
594584
disableChatInput: true,
595585
})
596-
}
597586

598-
this.messenger.sendAnswer({
599-
message: undefined,
600-
type: 'system-prompt',
601-
disableChatInput: true,
602-
followUps: [
603-
{
604-
pillText: 'Accept',
605-
prompt: 'Accept',
606-
type: FollowUpTypes.AcceptChanges,
607-
icon: 'ok' as MynahIcons,
608-
status: 'success',
609-
},
610-
{
611-
pillText: 'Make changes',
612-
prompt: 'Make changes',
613-
type: FollowUpTypes.MakeChanges,
614-
icon: 'refresh' as MynahIcons,
615-
status: 'info',
616-
},
617-
{
618-
pillText: 'Reject',
619-
prompt: 'Reject',
620-
type: FollowUpTypes.RejectChanges,
621-
icon: 'cancel' as MynahIcons,
622-
status: 'error',
623-
},
624-
],
625-
tabID: tabID,
626-
})
587+
this.messenger.sendAnswer({
588+
message: undefined,
589+
type: 'system-prompt',
590+
disableChatInput: true,
591+
followUps:
592+
remainingIterations > 0
593+
? CodeChangeFollowUps
594+
: CodeChangeFollowUps.filter((followUp) => followUp.type !== FollowUpTypes.MakeChanges),
595+
tabID: tabID,
596+
})
597+
}
627598
} finally {
628599
if (session?.state?.tokenSource?.token.isCancellationRequested) {
629600
await this.newTask({ tabID })
@@ -642,10 +613,8 @@ export class DocController {
642613
type: 'answer',
643614
tabID: message.tabID,
644615
message: 'Follow instructions to re-authenticate ...',
616+
disableChatInput: true,
645617
})
646-
647-
// Explicitly ensure the user goes through the re-authenticate flow
648-
this.messenger.sendChatInputEnabled(message.tabID, false)
649618
}
650619

651620
private tabClosed(message: any) {
@@ -670,18 +639,7 @@ export class DocController {
670639
type: 'answer',
671640
disableChatInput: true,
672641
tabID: message.tabID,
673-
followUps: [
674-
{
675-
pillText: i18n('AWS.amazonq.doc.pillText.newTask'),
676-
type: FollowUpTypes.NewTask,
677-
status: 'info',
678-
},
679-
{
680-
pillText: i18n('AWS.amazonq.doc.pillText.closeSession'),
681-
type: FollowUpTypes.CloseSession,
682-
status: 'info',
683-
},
684-
],
642+
followUps: NewSessionFollowUps,
685643
})
686644

687645
this.messenger.sendUpdatePlaceholder(message.tabID, i18n('AWS.amazonq.doc.pillText.selectOption'))

packages/core/src/amazonqDoc/errors.ts

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,57 @@ import { ToolkitError } from '../shared/errors'
77
import { i18n } from '../shared/i18n-helper'
88

99
export class DocServiceError extends ToolkitError {
10-
constructor(message: string, code: string) {
10+
remainingIterations?: number
11+
constructor(message: string, code: string, remainingIterations?: number) {
1112
super(message, { code })
13+
this.remainingIterations = remainingIterations
1214
}
1315
}
1416

15-
export class ReadmeTooLargeError extends ToolkitError {
17+
export class ReadmeTooLargeError extends DocServiceError {
1618
constructor() {
17-
super(i18n('AWS.amazonq.doc.error.readmeTooLarge'), {
18-
code: ReadmeTooLargeError.name,
19-
})
19+
super(i18n('AWS.amazonq.doc.error.readmeTooLarge'), ReadmeTooLargeError.name)
2020
}
2121
}
2222

23-
export class ReadmeUpdateTooLargeError extends ToolkitError {
24-
constructor() {
25-
super(i18n('AWS.amazonq.doc.error.readmeUpdateTooLarge'), {
26-
code: ReadmeUpdateTooLargeError.name,
27-
})
23+
export class ReadmeUpdateTooLargeError extends DocServiceError {
24+
constructor(remainingIterations: number) {
25+
super(i18n('AWS.amazonq.doc.error.readmeUpdateTooLarge'), ReadmeUpdateTooLargeError.name, remainingIterations)
2826
}
2927
}
3028

31-
export class WorkspaceEmptyError extends ToolkitError {
29+
export class WorkspaceEmptyError extends DocServiceError {
3230
constructor() {
33-
super(i18n('AWS.amazonq.doc.error.workspaceEmpty'), {
34-
code: WorkspaceEmptyError.name,
35-
})
31+
super(i18n('AWS.amazonq.doc.error.workspaceEmpty'), WorkspaceEmptyError.name)
3632
}
3733
}
3834

39-
export class NoChangeRequiredException extends ToolkitError {
35+
export class NoChangeRequiredException extends DocServiceError {
4036
constructor() {
41-
super(i18n('AWS.amazonq.doc.error.noChangeRequiredException'), {
42-
code: NoChangeRequiredException.name,
43-
})
37+
super(i18n('AWS.amazonq.doc.error.noChangeRequiredException'), NoChangeRequiredException.name)
4438
}
4539
}
4640

47-
export class PromptRefusalException extends ToolkitError {
48-
constructor() {
49-
super(i18n('AWS.amazonq.doc.error.promptRefusal'), {
50-
code: PromptRefusalException.name,
51-
})
41+
export class PromptRefusalException extends DocServiceError {
42+
constructor(remainingIterations: number) {
43+
super(i18n('AWS.amazonq.doc.error.promptRefusal'), PromptRefusalException.name, remainingIterations)
5244
}
5345
}
5446

55-
export class ContentLengthError extends ToolkitError {
47+
export class ContentLengthError extends DocServiceError {
5648
constructor() {
57-
super(i18n('AWS.amazonq.doc.error.contentLengthError'), { code: ContentLengthError.name })
49+
super(i18n('AWS.amazonq.doc.error.contentLengthError'), ContentLengthError.name)
5850
}
5951
}
6052

61-
export class PromptTooVagueError extends ToolkitError {
62-
constructor() {
63-
super(i18n('AWS.amazonq.doc.error.promptTooVague'), {
64-
code: PromptTooVagueError.name,
65-
})
53+
export class PromptTooVagueError extends DocServiceError {
54+
constructor(remainingIterations: number) {
55+
super(i18n('AWS.amazonq.doc.error.promptTooVague'), PromptTooVagueError.name, remainingIterations)
6656
}
6757
}
6858

69-
export class PromptUnrelatedError extends ToolkitError {
70-
constructor() {
71-
super(i18n('AWS.amazonq.doc.error.promptUnrelated'), {
72-
code: PromptUnrelatedError.name,
73-
})
59+
export class PromptUnrelatedError extends DocServiceError {
60+
constructor(remainingIterations: number) {
61+
super(i18n('AWS.amazonq.doc.error.promptUnrelated'), PromptUnrelatedError.name, remainingIterations)
7462
}
7563
}

0 commit comments

Comments
 (0)