Skip to content

Commit 8cc0752

Browse files
Merge branch 'feature/q-lsp-chat' into samgst/q-lsp-chat-showDiff
2 parents 1ab3489 + fdcae23 commit 8cc0752

File tree

40 files changed

+891
-109
lines changed

40 files changed

+891
-109
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Do not always show 'Amazon Q Code Issues' tab when switching to the 'Problems' tool window"
4+
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
1818
import kotlinx.coroutines.flow.launchIn
1919
import kotlinx.coroutines.flow.merge
2020
import kotlinx.coroutines.flow.onEach
21-
import kotlinx.coroutines.future.await
2221
import kotlinx.coroutines.launch
2322
import org.cef.browser.CefBrowser
2423
import org.eclipse.lsp4j.Position
@@ -32,6 +31,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
3231
import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager
3332
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider
3433
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
34+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager.Companion.convertToJsonToSendToChat
3535
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.getTextDocumentIdentifier
3636
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickNotification
3737
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ButtonClickParams
@@ -61,6 +61,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatN
6161
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatParams
6262
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatPrompt
6363
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatReadyNotification
64+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatUiMessageParams
6465
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ConversationClickRequest
6566
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyCodeToClipboardNotification
6667
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyCodeToClipboardParams
@@ -90,9 +91,11 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Promp
9091
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeParams
9192
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.QuickChatActionRequest
9293
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT
94+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.STOP_CHAT_RESPONSE
9395
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest
9496
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickNotification
9597
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickParams
98+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.StopResponseMessage
9699
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionParams
97100
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionRequest
98101
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabEventParams
@@ -102,6 +105,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.util.tabType
102105
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.AmazonQTheme
103106
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.ThemeBrowserAdapter
104107
import software.aws.toolkits.jetbrains.settings.MeetQSettings
108+
import software.aws.toolkits.resources.AwsCoreBundle
105109
import software.aws.toolkits.telemetry.MetricResult
106110
import software.aws.toolkits.telemetry.Telemetry
107111
import java.util.concurrent.CompletableFuture
@@ -245,6 +249,10 @@ class BrowserConnector(
245249
encryptionManager = this.encryptionManager
246250
encryptionManager?.encrypt(chatParams)?.let { EncryptedChatParams(it, partialResultToken) }?.let { server.sendChatPrompt(it) }
247251
} ?: (CompletableFuture.failedFuture(IllegalStateException("LSP Server not running")))
252+
253+
// We assume there is only one outgoing request per tab because the input is
254+
// blocked when there is an outgoing request
255+
chatCommunicationManager.setInflightRequestForTab(tabId, result)
248256
showResult(result, partialResultToken, tabId, encryptionManager, browser)
249257
}
250258
CHAT_QUICK_ACTION -> {
@@ -262,6 +270,10 @@ class BrowserConnector(
262270
}
263271
} ?: (CompletableFuture.failedFuture(IllegalStateException("LSP Server not running")))
264272

273+
// We assume there is only one outgoing request per tab because the input is
274+
// blocked when there is an outgoing request
275+
chatCommunicationManager.setInflightRequestForTab(tabId, result)
276+
265277
showResult(result, partialResultToken, tabId, encryptionManager, browser)
266278
}
267279
CHAT_LIST_CONVERSATIONS -> {
@@ -318,6 +330,7 @@ class BrowserConnector(
318330
CHAT_TAB_REMOVE -> {
319331
handleChatNotification<TabEventRequest, TabEventParams>(node) { server, params ->
320332
chatCommunicationManager.removePartialChatMessage(params.tabId)
333+
cancelInflightRequests(params.tabId)
321334
server.tabRemove(params)
322335
}
323336
}
@@ -414,6 +427,30 @@ class BrowserConnector(
414427
server.createPrompt(params)
415428
}
416429
}
430+
STOP_CHAT_RESPONSE -> {
431+
val stopResponseRequest = serializer.deserializeChatMessages<StopResponseMessage>(node)
432+
if (!chatCommunicationManager.hasInflightRequest(stopResponseRequest.params.tabId)) {
433+
return
434+
}
435+
cancelInflightRequests(stopResponseRequest.params.tabId)
436+
chatCommunicationManager.removePartialChatMessage(stopResponseRequest.params.tabId)
437+
438+
val paramsJson = Gson().toJson(
439+
// https://github.com/aws/language-servers/blob/1c0d88806087125b6fc561f610cc15e98127c6bf/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts#L403
440+
ChatUiMessageParams(
441+
title = AwsCoreBundle.message("amazonqChat.stopChatResponse"),
442+
body = ""
443+
)
444+
)
445+
446+
val uiMessage = convertToJsonToSendToChat(
447+
command = SEND_CHAT_COMMAND_PROMPT,
448+
tabId = stopResponseRequest.params.tabId,
449+
params = paramsJson.toString(),
450+
isPartialResult = false
451+
)
452+
browser.postChat(uiMessage)
453+
}
417454
}
418455
}
419456

@@ -433,6 +470,14 @@ class BrowserConnector(
433470
isPartialResult = false
434471
)
435472
browser.postChat(messageToChat)
473+
chatCommunicationManager.removeInflightRequestForTab(tabId)
474+
}
475+
}
476+
477+
private fun cancelInflightRequests(tabId: String) {
478+
chatCommunicationManager.getInflightRequestForTab(tabId)?.let { request ->
479+
request.cancel(true)
480+
chatCommunicationManager.removeInflightRequestForTab(tabId)
436481
}
437482
}
438483

plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<projectService serviceImplementation="software.aws.toolkits.jetbrains.services.codemodernizer.panels.managers.CodeModernizerBottomWindowPanelManager"/>
1919
<toolWindow id="aws.codewhisperer.codetransform" anchor="bottom" doNotActivateOnStart="true" canCloseContents="false"
2020
factoryClass="software.aws.toolkits.jetbrains.services.codemodernizer.toolwindow.CodeModernizerBottomToolWindowFactory"
21-
icon="AllIcons.Actions.Preview"/>
21+
icon="AllIcons.Actions.Properties"/>
2222
<fileEditorProvider implementation="software.aws.toolkits.jetbrains.services.codemodernizer.plan.CodeModernizerPlanEditorProvider"/>
2323
<fileEditorProvider implementation="software.aws.toolkits.jetbrains.services.codemodernizer.summary.CodeModernizerSummaryEditorProvider"/>
2424
</extensions>

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import software.aws.toolkits.core.utils.exists
2424
import software.aws.toolkits.core.utils.getLogger
2525
import software.aws.toolkits.core.utils.info
2626
import software.aws.toolkits.jetbrains.core.coroutines.EDT
27-
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
2827
import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
2928
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException
3029
import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW
@@ -50,13 +49,13 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModerni
5049
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir
5150
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection
5251
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction
52+
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.zipToPath
5353
import software.aws.toolkits.jetbrains.utils.notifyInfo
5454
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
5555
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
5656
import software.aws.toolkits.resources.message
5757
import software.aws.toolkits.telemetry.CodeTransformArtifactType
5858
import java.io.File
59-
import java.nio.file.Files
6059
import java.nio.file.Path
6160
import java.time.Instant
6261
import java.util.concurrent.atomic.AtomicBoolean
@@ -112,32 +111,12 @@ class ArtifactHandler(
112111
}
113112
}
114113

115-
suspend fun unzipToPath(byteArrayList: List<ByteArray>, outputDirPath: Path? = null): Pair<Path, Int> {
116-
val zipFilePath = withContext(getCoroutineBgContext()) {
117-
if (outputDirPath == null) {
118-
Files.createTempFile(null, ".zip")
119-
} else {
120-
Files.createTempFile(outputDirPath, null, ".zip")
121-
}
122-
}
123-
var totalDownloadBytes = 0
124-
withContext(getCoroutineBgContext()) {
125-
Files.newOutputStream(zipFilePath).use {
126-
for (bytes in byteArrayList) {
127-
it.write(bytes)
128-
totalDownloadBytes += bytes.size
129-
}
130-
}
131-
}
132-
return zipFilePath to totalDownloadBytes
133-
}
134-
135114
suspend fun downloadHilArtifact(jobId: JobId, artifactId: String, tmpDir: File): CodeTransformHilDownloadArtifact? {
136115
val downloadResultsResponse = clientAdaptor.downloadExportResultArchive(jobId, artifactId)
137116

138117
return try {
139118
val tmpPath = tmpDir.toPath()
140-
val (downloadZipFilePath, _) = unzipToPath(downloadResultsResponse, tmpPath)
119+
val (downloadZipFilePath, _) = zipToPath(downloadResultsResponse, tmpPath)
141120
LOG.info { "Successfully converted the hil artifact download to a zip at ${downloadZipFilePath.toAbsolutePath()}." }
142121
CodeTransformHilDownloadArtifact.create(downloadZipFilePath, getPathToHilArtifactDir(tmpPath))
143122
} catch (e: Exception) {
@@ -211,7 +190,7 @@ class ArtifactHandler(
211190
val totalDownloadBytes: Int
212191
val zipPath: String
213192
try {
214-
val result = unzipToPath(downloadResultsResponse)
193+
val result = zipToPath(downloadResultsResponse)
215194
path = result.first
216195
totalDownloadBytes = result.second
217196
zipPath = path.toAbsolutePath().toString()

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
909909
// Add delay between upload complete and trying to resume
910910
delay(500)
911911

912-
codeTransformationSession?.resumeTransformFromHil()
912+
codeTransformationSession?.resumeTransformation()
913913
} else {
914914
throw CodeModernizerException("Cannot create dependency zip for HIL")
915915
}

plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
2020
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdateStatus
2121
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
2222
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUserActionStatus
23+
import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
2324
import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType
2425
import software.amazon.awssdk.services.ssooidc.model.SsoOidcException
2526
import software.aws.toolkits.core.utils.Waiters.waitUntil
@@ -174,6 +175,7 @@ class CodeModernizerSession(
174175
}
175176
// for language upgrades, copyResult should always be Successful here, failure cases already handled
176177
val result = sessionContext.createZipWithModuleFiles(copyResult)
178+
sessionContext.originalUploadZipPath = result.payload.toPath()
177179

178180
if (result is ZipCreationResult.Missing1P) {
179181
telemetryErrorMessage = "Missing 1p dependencies"
@@ -283,9 +285,7 @@ class CodeModernizerSession(
283285
return CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER(e.localizedMessage))
284286
} finally {
285287
telemetry.uploadProject(payloadSize, startTime, true, telemetryErrorMessage)
286-
if (payload != null) {
287-
deleteUploadArtifact(payload)
288-
}
288+
// do not delete upload ZIP; re-used for client-side build
289289
}
290290

291291
// Send upload completion message to chat (only if successful)
@@ -309,12 +309,6 @@ class CodeModernizerSession(
309309
}
310310
}
311311

312-
internal fun deleteUploadArtifact(payload: File) {
313-
if (!payload.delete()) {
314-
LOG.warn { "Unable to delete upload artifact." }
315-
}
316-
}
317-
318312
private fun startJob(uploadId: String): StartTransformationResponse {
319313
val sourceLanguage = sessionContext.sourceJavaVersion.name.toTransformationLanguage()
320314
val targetLanguage = sessionContext.targetJavaVersion.name.toTransformationLanguage()
@@ -341,9 +335,10 @@ class CodeModernizerSession(
341335
*/
342336
fun resumeJob(startTime: Instant, jobId: JobId) = state.putJobHistory(sessionContext, TransformationStatus.STARTED, jobId.id, startTime)
343337

344-
fun resumeTransformFromHil() {
338+
fun resumeTransformation() {
345339
val clientAdaptor = GumbyClient.getInstance(sessionContext.project)
346340
clientAdaptor.resumeCodeTransformation(state.currentJobId as JobId, TransformationUserActionStatus.COMPLETED)
341+
getLogger<CodeModernizerManager>().info { "Successfully resumed transformation with status of COMPLETED" }
347342
}
348343

349344
fun rejectHilAndContinue(): ResumeTransformationResponse {
@@ -390,7 +385,7 @@ class CodeModernizerSession(
390385
/**
391386
* Adapted from [CodeWhispererCodeScanSession]
392387
*/
393-
suspend fun uploadPayload(payload: File): String {
388+
suspend fun uploadPayload(payload: File, uploadContext: UploadContext? = null): String {
394389
val sha256checksum: String = Base64.getEncoder().encodeToString(
395390
withContext(getCoroutineBgContext()) {
396391
DigestUtils.sha256(FileInputStream(payload))
@@ -400,7 +395,7 @@ class CodeModernizerSession(
400395
throw AlreadyDisposedException("Disposed when about to create upload URL")
401396
}
402397
val clientAdaptor = GumbyClient.getInstance(sessionContext.project)
403-
val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum)
398+
val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum, uploadContext)
404399

405400
LOG.info {
406401
"Uploading project artifact at ${payload.path} with checksum $sha256checksum using uploadId: ${
@@ -428,9 +423,9 @@ class CodeModernizerSession(
428423
createUploadUrlResponse.kmsKeyArn().orEmpty(),
429424
) { shouldStop.get() }
430425
}
431-
LOG.info { "Upload to S3 succeeded" }
426+
LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of $uploadContext" }
432427
if (!shouldStop.get()) {
433-
LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())}ms" }
428+
LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())} ms" }
434429
}
435430
return createUploadUrlResponse.uploadId()
436431
}

0 commit comments

Comments
 (0)