Skip to content

Commit 08367d4

Browse files
committed
fix(dev): messaging
1 parent 7f84621 commit 08367d4

File tree

9 files changed

+94
-47
lines changed

9 files changed

+94
-47
lines changed

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevControllerExtensions.kt

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.controller
55

66
import com.intellij.notification.NotificationAction
77
import org.gradle.tooling.GradleConnector
8+
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
89
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CODE_GENERATION_RETRY_LIMIT
910
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.FeatureDevMessageType
1011
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.FollowUp
@@ -21,6 +22,7 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Delete
2122
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
2223
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.PrepareCodeGenerationState
2324
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Session
25+
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionState
2426
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getFollowUpOptions
2527
import software.aws.toolkits.jetbrains.utils.notifyInfo
2628
import software.aws.toolkits.resources.message
@@ -44,19 +46,26 @@ suspend fun FeatureDevController.onCodeGeneration(session: Session, message: Str
4446
message = message("amazonqFeatureDev.chat_message.requesting_changes"),
4547
messageType = FeatureDevMessageType.AnswerStream,
4648
)
49+
val state = session.sessionState
50+
51+
var remainingIterations: Int? = state.codeGenerationRemainingIterationCount
52+
var totalIterations: Int? = state.codeGenerationTotalIterationCount
53+
54+
55+
if (state.token?.token()?.isCancellationRequested == true) {
56+
this.disposeToken(state, messenger, tabId, remainingIterations, totalIterations)
57+
return
58+
}
4759

4860
messenger.sendUpdatePlaceholder(tabId = tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.generating_code"))
4961

5062
session.send(message) // Trigger code generation
5163

52-
val state = session.sessionState
5364

5465
var filePaths: List<NewFileZipInfo> = emptyList()
5566
var deletedFiles: List<DeletedFileInfo> = emptyList()
5667
var references: List<CodeReferenceGenerated> = emptyList()
5768
var uploadId = ""
58-
var remainingIterations: Int? = null
59-
var totalIterations: Int? = null
6069

6170
when (state) {
6271
is PrepareCodeGenerationState -> {
@@ -70,17 +79,7 @@ suspend fun FeatureDevController.onCodeGeneration(session: Session, message: Str
7079
}
7180

7281
if (state.token?.token()?.isCancellationRequested == true) {
73-
messenger.sendAnswer(
74-
tabId = tabId,
75-
messageType = FeatureDevMessageType.Answer,
76-
message = message("amazonqFeatureDev.code_generation.stopped_code_generation")
77-
)
78-
messenger.sendChatInputEnabledMessage(tabId = tabId, enabled = true)
79-
80-
messenger.sendUpdatePlaceholder(
81-
tabId = tabId,
82-
newPlaceholder = message("amazonqFeatureDev.placeholder.new_plan")
83-
)
82+
disposeToken(state, messenger, tabId, remainingIterations, totalIterations)
8483
return
8584
}
8685

@@ -149,6 +148,32 @@ suspend fun FeatureDevController.onCodeGeneration(session: Session, message: Str
149148
}
150149
}
151150

151+
private suspend fun FeatureDevController.disposeToken(state: SessionState, messenger: MessagePublisher, tabId: String, remainingIterations: Number?, totalIterations: Number?) {
152+
if (state.codeGenerationRemainingIterationCount !== null) {
153+
messenger.sendAnswer(
154+
tabId = tabId,
155+
messageType = FeatureDevMessageType.Answer,
156+
message = message("amazonqFeatureDev.code_generation.stopped_code_generation", remainingIterations ?: state.currentIteration as Any,
157+
totalIterations ?: CODE_GENERATION_RETRY_LIMIT
158+
)
159+
)
160+
} else {
161+
messenger.sendAnswer(
162+
tabId = tabId,
163+
messageType = FeatureDevMessageType.Answer,
164+
message = message("amazonqFeatureDev.code_generation.stopped_code_generation_without_total", state.currentIteration as Any)
165+
)
166+
}
167+
168+
messenger.sendChatInputEnabledMessage(tabId = tabId, enabled = true)
169+
170+
messenger.sendUpdatePlaceholder(
171+
tabId = tabId,
172+
newPlaceholder = message("amazonqFeatureDev.placeholder.new_plan")
173+
)
174+
}
175+
176+
152177
private fun FeatureDevController.openChatNotificationAction() = NotificationAction.createSimple(
153178
message("amazonqFeatureDev.code_generation.notification_open_link")
154179
) {

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ class CodeGenerationState(
3333
override var approach: String,
3434
val config: SessionStateConfig,
3535
val uploadId: String,
36-
val currentIteration: Int,
36+
override var currentIteration: Int? = 0,
3737
val repositorySize: Double,
3838
val messenger: MessagePublisher,
39-
var codeGenerationRemainingIterationCount: Int? = null,
40-
var codeGenerationTotalIterationCount: Int? = null,
39+
override var codeGenerationRemainingIterationCount: Int? = null,
40+
override var codeGenerationTotalIterationCount: Int? = null,
4141
var currentCodeGenerationId: UUID? = null,
4242
override var token: CancellationTokenSource?
4343
) : SessionState {
@@ -88,7 +88,7 @@ class CodeGenerationState(
8888
filePaths = codeGenerationResult.newFiles,
8989
deletedFiles = codeGenerationResult.deletedFiles,
9090
references = codeGenerationResult.references,
91-
currentIteration = currentIteration + 1,
91+
currentIteration = currentIteration?.plus(1),
9292
uploadId = uploadId,
9393
messenger = messenger,
9494
codeGenerationRemainingIterationCount = codeGenerationRemainingIterationCount,
@@ -114,20 +114,22 @@ class CodeGenerationState(
114114

115115
throw e
116116
} finally {
117-
AmazonqTelemetry.codeGenerationInvoke(
118-
amazonqConversationId = config.conversationId,
119-
amazonqCodeGenerationResult = codeGenerationWorkflowStatus.toString(),
120-
amazonqGenerateCodeIteration = currentIteration.toDouble(),
121-
amazonqNumberOfReferences = numberOfReferencesGenerated?.toDouble(),
122-
amazonqGenerateCodeResponseLatency = (System.currentTimeMillis() - startTime).toDouble(),
123-
amazonqNumberOfFilesGenerated = numberOfFilesGenerated?.toDouble(),
124-
amazonqRepositorySize = repositorySize,
125-
result = result,
126-
reason = failureReason,
127-
reasonDesc = failureReasonDesc,
128-
duration = (System.currentTimeMillis() - startTime).toDouble(),
129-
credentialStartUrl = getStartUrl(config.featureDevService.project)
130-
)
117+
currentIteration?.let {
118+
AmazonqTelemetry.codeGenerationInvoke(
119+
amazonqConversationId = config.conversationId,
120+
amazonqCodeGenerationResult = codeGenerationWorkflowStatus.toString(),
121+
amazonqGenerateCodeIteration = it.toDouble(),
122+
amazonqNumberOfReferences = numberOfReferencesGenerated?.toDouble(),
123+
amazonqGenerateCodeResponseLatency = (System.currentTimeMillis() - startTime).toDouble(),
124+
amazonqNumberOfFilesGenerated = numberOfFilesGenerated?.toDouble(),
125+
amazonqRepositorySize = repositorySize,
126+
result = result,
127+
reason = failureReason,
128+
reasonDesc = failureReasonDesc,
129+
duration = (System.currentTimeMillis() - startTime).toDouble(),
130+
credentialStartUrl = getStartUrl(config.featureDevService.project)
131+
)
132+
}
131133
}
132134
}
133135
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/ConversationNotStartedState.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class ConversationNotStartedState(
99
override var approach: String,
1010
override val tabID: String,
1111
override var token: CancellationTokenSource?,
12+
override var codeGenerationRemainingIterationCount: Int?,
13+
override var codeGenerationTotalIterationCount: Int?,
14+
override var currentIteration: Int?,
1215
) : SessionState {
1316
override val phase = SessionStatePhase.INIT
1417

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/PrepareCodeGenerationState.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ class PrepareCodeGenerationState(
3030
val deletedFiles: List<DeletedFileInfo>,
3131
val references: List<CodeReferenceGenerated>,
3232
var uploadId: String,
33-
private val currentIteration: Int,
33+
override var currentIteration: Int?,
3434
private var messenger: MessagePublisher,
35-
var codeGenerationRemainingIterationCount: Int? = null,
36-
var codeGenerationTotalIterationCount: Int? = null,
35+
override var codeGenerationRemainingIterationCount: Int? = null,
36+
override var codeGenerationTotalIterationCount: Int? = null,
3737
) : SessionState {
3838
override val phase = SessionStatePhase.CODEGEN
3939
override suspend fun interact(action: SessionStateAction): SessionStateInteraction {

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/Session.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Session(val tabID: String, val project: Project) {
4242
context = FeatureDevSessionContext(project, MAX_PROJECT_SIZE_BYTES)
4343
proxyClient = FeatureDevClient.getInstance(project)
4444
featureDevService = FeatureDevService(proxyClient, project)
45-
_state = ConversationNotStartedState("", tabID, null)
45+
_state = ConversationNotStartedState("", tabID, null, 0, CODE_GENERATION_RETRY_LIMIT, 0)
4646
isAuthenticating = false
4747
codegenRetries = CODE_GENERATION_RETRY_LIMIT
4848
}
@@ -79,7 +79,7 @@ class Session(val tabID: String, val project: Project) {
7979
filePaths = emptyList(),
8080
deletedFiles = emptyList(),
8181
references = emptyList(),
82-
currentIteration = 0, // first code gen iteration
82+
currentIteration = 1, // first code gen iteration
8383
uploadId = "", // There is no code gen uploadId so far
8484
messenger = messenger,
8585
token = GradleConnector.newCancellationTokenSource()

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/SessionState.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ interface SessionState {
99
val tabID: String
1010
val phase: SessionStatePhase?
1111
var token: CancellationTokenSource?
12+
var codeGenerationRemainingIterationCount: Int?
13+
var codeGenerationTotalIterationCount: Int?
14+
var currentIteration: Int?
1215
var approach: String
1316
suspend fun interact(action: SessionStateAction): SessionStateInteraction
1417
}

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/controller/FeatureDevControllerTest.kt

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import io.mockk.coVerify
1010
import io.mockk.coVerifyOrder
1111
import io.mockk.every
1212
import io.mockk.just
13+
import io.mockk.mockk
1314
import io.mockk.mockkObject
1415
import io.mockk.mockkStatic
1516
import io.mockk.runs
1617
import io.mockk.unmockkAll
1718
import io.mockk.verify
1819
import kotlinx.coroutines.test.runTest
1920
import org.assertj.core.api.Assertions.assertThat
21+
import org.gradle.tooling.CancellationTokenSource
2022
import org.junit.After
2123
import org.junit.Before
2224
import org.junit.Rule
@@ -29,6 +31,7 @@ import org.mockito.kotlin.reset
2931
import org.mockito.kotlin.spy
3032
import org.mockito.kotlin.times
3133
import org.mockito.kotlin.whenever
34+
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
3235
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
3336
import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthController
3437
import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthNeededStates
@@ -47,13 +50,16 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendC
4750
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendSystemPrompt
4851
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendUpdatePlaceholder
4952
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.updateFileComponent
53+
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.CodeReferenceGenerated
5054
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DeletedFileInfo
5155
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Interaction
5256
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
5357
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.PrepareCodeGenerationState
5458
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Session
59+
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStateConfig
5560
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStatePhase
5661
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.storage.ChatSessionStorage
62+
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.FeatureDevService
5763
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getFollowUpOptions
5864
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.selectFolder
5965
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.uploadArtifactToS3
@@ -86,6 +92,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
8692
@Before
8793
override fun setup() {
8894
super.setup()
95+
8996
featureDevClient = mock()
9097
messenger = mock()
9198
chatSessionStorage = mock()
@@ -199,6 +206,9 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
199206
val followUp = FollowUp(FollowUpTypes.INSERT_CODE, pillText = "Insert code")
200207
val message = IncomingFeatureDevMessage.FollowupClicked(followUp, testTabId, "", "test-command")
201208

209+
var featureDevService = mockk<FeatureDevService>()
210+
val repoContext = mock<FeatureDevSessionContext>()
211+
val sessionStateConfig = SessionStateConfig(testConversationId, repoContext, featureDevService)
202212
mockkObject(AmazonqTelemetry)
203213
every {
204214
AmazonqTelemetry.isAcceptedCodeChanges(amazonqNumberOfFilesAccepted = any(), amazonqConversationId = any(), enabled = any())
@@ -209,7 +219,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
209219
whenever(chatSessionStorage.getSession(any(), any())).thenReturn(spySession)
210220
whenever(spySession.sessionState).thenReturn(
211221
PrepareCodeGenerationState(
212-
testTabId, "", mock(), newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger
222+
testTabId, null, mock(), sessionStateConfig, newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger
213223
)
214224
)
215225
doNothing().`when`(spySession).insertChanges(any(), any(), any())
@@ -248,13 +258,16 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
248258
@Test
249259
fun `test handleChat onCodeGeneration succeeds to create files`() = runTest {
250260
val mockInteraction = mock<Interaction>()
251-
261+
var featureDevService = mockk<FeatureDevService>()
262+
val repoContext = mock<FeatureDevSessionContext>()
263+
val sessionStateConfig = SessionStateConfig(testConversationId, repoContext, featureDevService)
264+
mockkObject(AmazonqTelemetry)
252265
val mockSession = mock<Session>()
253266
whenever(mockSession.send(userMessage)).thenReturn(mockInteraction)
254267
whenever(mockSession.conversationId).thenReturn(testConversationId)
255268
whenever(mockSession.sessionState).thenReturn(
256269
PrepareCodeGenerationState(
257-
testTabId, "", mock(), newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger
270+
testTabId, null, "test-command", sessionStateConfig, newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger,
258271
)
259272
)
260273

@@ -302,7 +315,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
302315
whenever(mockSession.conversationId).thenReturn(testConversationId)
303316
whenever(mockSession.sessionState).thenReturn(
304317
PrepareCodeGenerationState(
305-
testTabId, "", mock(), filePaths, deletedFiles, testReferences, testUploadId, 0, messenger
318+
testTabId, null, "", mock(), filePaths, deletedFiles, testReferences, testUploadId, 0, messenger
306319
)
307320
)
308321
whenever(mockSession.retries).thenReturn(3)
@@ -331,7 +344,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
331344
whenever(mockSession.conversationId).thenReturn(testConversationId)
332345
whenever(mockSession.sessionState).thenReturn(
333346
PrepareCodeGenerationState(
334-
testTabId, "", mock(), filePaths, deletedFiles, testReferences, testUploadId, 0, messenger
347+
testTabId, null, "", mock(), filePaths, deletedFiles, testReferences, testUploadId, 0, messenger
335348
)
336349
)
337350
whenever(mockSession.retries).thenReturn(0)
@@ -353,7 +366,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
353366
whenever(chatSessionStorage.getSession(any(), any())).thenReturn(spySession)
354367
whenever(spySession.sessionState).thenReturn(
355368
PrepareCodeGenerationState(
356-
testTabId, "", mock(), newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger
369+
testTabId, null, "", mock(), newFileContents, deletedFiles, testReferences, testUploadId, 0, messenger
357370
)
358371
)
359372

plugins/amazonq/mynah-ui/src/mynah-ui/ui/texts/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const uiComponentsTexts = {
1919
save: 'Save',
2020
cancel: 'Cancel',
2121
submit: 'Submit',
22-
stopGenerating: 'Stop generating',
22+
stopGenerating: 'Stop',
2323
copyToClipboard: 'Copied to clipboard',
2424
noMoreTabsTooltip: 'You can only open ten conversation tabs at a time.',
2525
codeSuggestionWithReferenceTitle: 'Some suggestions contain code with references.',

plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ amazonqFeatureDev.code_generation.notification_message=Your code suggestions fro
5757
amazonqFeatureDev.code_generation.notification_open_link=Open chat
5858
amazonqFeatureDev.code_generation.notification_title=Amazon Q Developer Agent for software development
5959
amazonqFeatureDev.code_generation.provide_code_feedback=How can I improve the code for your use case?
60-
amazonqFeatureDev.code_generation.stopping_code_generation=Stopping code generation ...
61-
amazonqFeatureDev.code_generation.stopped_code_generation=You've stopped code generation.
60+
amazonqFeatureDev.code_generation.stopping_code_generation=Stopping code generation...
61+
amazonqFeatureDev.code_generation.stopped_code_generation=I stopped generating your code. If you want to continue working on this task, provide another description. You have {0} out of {1} code generations left.
62+
amazonqFeatureDev.code_generation.stopped_code_generation_without_total=I stopped generating your code. If you want to continue working on this task, provide another description. You have started {0} code generations.
6263
amazonqFeatureDev.code_generation.updated_code=Okay, I updated your code files. Would you like to work on another task?
6364
amazonqFeatureDev.content_length.error_text=The folder you selected is too large for me to use as context. Please choose a smaller folder to work on. For more information on quotas, see the [Amazon Q Developer documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/software-dev.html#quotas).
6465
amazonqFeatureDev.error_text=Sorry, we encountered a problem when processing your request.
@@ -87,7 +88,7 @@ amazonqFeatureDev.follow_up.provide_feedback_and_regenerate=Provide feedback & r
8788
amazonqFeatureDev.follow_up.retry=Retry
8889
amazonqFeatureDev.follow_up.send_feedback=Send feedback
8990
amazonqFeatureDev.no_retries.error_text=I'm sorry, I'm having technical difficulties and can't continue at the moment. Please try again later, and share feedback to help me improve.
90-
amazonqFeatureDev.placeholder.additional_improvements=Choose an option to proceed
91+
amazonqFeatureDev.placeholder.additional_improvements=Describe your task or issue in detail
9192
amazonqFeatureDev.placeholder.after_code_generation=Choose an option to proceed
9293
amazonqFeatureDev.placeholder.after_monthly_limit=Chat input is disabled
9394
amazonqFeatureDev.placeholder.closed_session=Open a new chat tab to continue

0 commit comments

Comments
 (0)