Skip to content

Commit cf0ba75

Browse files
authored
Merge branch 'feature/q-lsp' into rli/lsp-proxy
2 parents 82f7313 + 345a2c8 commit cf0ba75

File tree

96 files changed

+2425
-197
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+2425
-197
lines changed

.changes/3.63.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"date" : "2025-04-08",
3+
"version" : "3.63",
4+
"entries" : [ {
5+
"type" : "feature",
6+
"description" : "Enterprise users can choose their preferred Amazon Q profile to improve personalization and workflow across different business regions"
7+
}, {
8+
"type" : "bugfix",
9+
"description" : "Amazon Q /doc: close diff tab and open README file in preview mode after user accept changes"
10+
} ]
11+
}

.changes/3.64.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"date" : "2025-04-10",
3+
"version" : "3.64",
4+
"entries" : [ {
5+
"type" : "bugfix",
6+
"description" : "Fix issue where IDE freezes when logging into Amazon Q"
7+
} ]
8+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Fix issue where Amazon Q cannot process chunks from local `@workspace` context"
4+
}

.changes/next-release/bugfix-19118cf8-9378-4bd6-bf5e-7e57520181d0.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# _3.64_ (2025-04-10)
2+
- **(Bug Fix)** Fix issue where IDE freezes when logging into Amazon Q
3+
4+
# _3.63_ (2025-04-08)
5+
- **(Feature)** Enterprise users can choose their preferred Amazon Q profile to improve personalization and workflow across different business regions
6+
- **(Bug Fix)** Amazon Q /doc: close diff tab and open README file in preview mode after user accept changes
7+
18
# _3.62_ (2025-04-03)
29
- **(Feature)** /review: automatically generate fix without clicking Generate Fix button
310
- **(Bug Fix)** /transform: prompt user to re-authenticate if credentials expire during transformation

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# Toolkit Version
5-
toolkitVersion=3.63-SNAPSHOT
5+
toolkitVersion=3.65-SNAPSHOT
66

77
# Publish Settings
88
publishToken=

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/common/clients/AmazonQCodeGenerateClient.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ import software.aws.toolkits.core.utils.error
3131
import software.aws.toolkits.core.utils.getLogger
3232
import software.aws.toolkits.core.utils.info
3333
import software.aws.toolkits.jetbrains.common.session.Intent
34-
import software.aws.toolkits.jetbrains.core.awsClient
3534
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
3635
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
3736
import software.aws.toolkits.jetbrains.services.amazonq.clients.AmazonQStreamingClient
37+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
3838
import software.aws.toolkits.jetbrains.services.amazonqDoc.FEATURE_EVALUATION_PRODUCT_NAME
3939
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency
4040
import software.aws.toolkits.jetbrains.services.telemetry.ClientMetadata
@@ -72,7 +72,7 @@ class AmazonQCodeGenerateClient(private val project: Project) {
7272
fun connection() = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
7373
?: error("Attempted to use connection while one does not exist")
7474

75-
fun bearerClient() = connection().getConnectionSettings().awsClient<CodeWhispererRuntimeClient>()
75+
fun bearerClient() = QRegionProfileManager.getInstance().getQClient<CodeWhispererRuntimeClient>(project)
7676

7777
private val amazonQStreamingClient
7878
get() = AmazonQStreamingClient.getInstance(project)
@@ -88,6 +88,7 @@ class AmazonQCodeGenerateClient(private val project: Project) {
8888
}
8989
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
9090
requestBuilder.userContext(docUserContext)
91+
requestBuilder.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
9192
}
9293

9394
fun sendDocMetricData(operationName: String, result: String): SendTelemetryEventResponse =
@@ -118,7 +119,9 @@ class AmazonQCodeGenerateClient(private val project: Project) {
118119
}
119120

120121
fun createTaskAssistConversation(): CreateTaskAssistConversationResponse = bearerClient().createTaskAssistConversation(
121-
CreateTaskAssistConversationRequest.builder().build()
122+
CreateTaskAssistConversationRequest.builder()
123+
.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
124+
.build()
122125
)
123126

124127
fun createTaskAssistUploadUrl(conversationId: String, contentChecksumSha256: String, contentLength: Long): CreateUploadUrlResponse =
@@ -137,6 +140,7 @@ class AmazonQCodeGenerateClient(private val project: Project) {
137140
)
138141
.build()
139142
)
143+
.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
140144
}
141145

142146
fun startTaskAssistCodeGeneration(conversationId: String, uploadId: String, userMessage: String, intent: Intent): StartTaskAssistCodeGenerationResponse =
@@ -155,6 +159,7 @@ class AmazonQCodeGenerateClient(private val project: Project) {
155159
.uploadId(uploadId)
156160
}
157161
.intent(intent.name)
162+
.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
158163
}
159164

160165
fun getTaskAssistCodeGeneration(conversationId: String, codeGenerationId: String): GetTaskAssistCodeGenerationResponse = bearerClient()

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

Lines changed: 106 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq
55

6+
import com.intellij.ide.BrowserUtil
67
import com.intellij.openapi.Disposable
78
import com.intellij.openapi.actionSystem.AnActionEvent
89
import com.intellij.openapi.actionSystem.DataContext
10+
import com.intellij.openapi.application.ApplicationManager
911
import com.intellij.openapi.application.runInEdt
1012
import com.intellij.openapi.components.Service
1113
import com.intellij.openapi.components.service
@@ -17,6 +19,7 @@ import com.intellij.ui.dsl.builder.Align
1719
import com.intellij.ui.dsl.builder.panel
1820
import com.intellij.ui.jcef.JBCefJSQuery
1921
import org.cef.CefApp
22+
import software.aws.toolkits.core.utils.debug
2023
import software.aws.toolkits.core.utils.error
2124
import software.aws.toolkits.core.utils.getLogger
2225
import software.aws.toolkits.core.utils.warn
@@ -33,14 +36,20 @@ import software.aws.toolkits.jetbrains.core.webview.BrowserState
3336
import software.aws.toolkits.jetbrains.core.webview.LoginBrowser
3437
import software.aws.toolkits.jetbrains.core.webview.WebviewResourceHandlerFactory
3538
import software.aws.toolkits.jetbrains.isDeveloperMode
39+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIntent
40+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile
41+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
3642
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser
3743
import software.aws.toolkits.jetbrains.utils.isQConnected
3844
import software.aws.toolkits.jetbrains.utils.isQExpired
3945
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable
4046
import software.aws.toolkits.telemetry.FeatureId
47+
import software.aws.toolkits.telemetry.MetricResult
48+
import software.aws.toolkits.telemetry.Telemetry
4149
import software.aws.toolkits.telemetry.UiTelemetry
4250
import software.aws.toolkits.telemetry.WebviewTelemetry
4351
import java.awt.event.ActionListener
52+
import java.net.URI
4453
import javax.swing.JButton
4554
import javax.swing.JComponent
4655

@@ -204,6 +213,26 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos
204213
UiTelemetry.click(project, signInOption)
205214
}
206215
}
216+
217+
is BrowserMessage.SwitchProfile -> {
218+
QRegionProfileManager.getInstance().switchProfile(
219+
project,
220+
QRegionProfile(profileName = message.profileName, arn = message.arn),
221+
intent = QProfileSwitchIntent.Auth
222+
)
223+
}
224+
225+
is BrowserMessage.ListProfiles -> {
226+
handleListProfilesMessage()
227+
}
228+
229+
is BrowserMessage.PublishWebviewTelemetry -> {
230+
// publishTelemetry(message)
231+
}
232+
233+
is BrowserMessage.OpenUrl -> {
234+
BrowserUtil.browse(URI(message.externalLink))
235+
}
207236
}
208237
}
209238

@@ -243,28 +272,44 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos
243272
writeValueAsString(it)
244273
}
245274

246-
// TODO: pass "REAUTH" if connection expires
247275
val stage = if (isQExpired(project)) {
248276
"REAUTH"
277+
} else if (isQConnected(project) && QRegionProfileManager.getInstance().isPendingProfileSelection(project)) {
278+
"PROFILE_SELECT"
249279
} else {
250280
"START"
251281
}
252282

253-
val jsonData = """
254-
{
255-
stage: '$stage',
256-
regions: $regions,
257-
idcInfo: {
258-
profileName: '${lastLoginIdcInfo.profileName}',
259-
startUrl: '${lastLoginIdcInfo.startUrl}',
260-
region: '${lastLoginIdcInfo.region}'
261-
},
262-
cancellable: ${state.browserCancellable},
263-
feature: '${state.feature}',
264-
existConnections: ${writeValueAsString(selectionSettings.values.map { it.currentSelection }.toList())}
283+
when (stage) {
284+
"PROFILE_SELECT" -> {
285+
val jsonData = """
286+
{
287+
stage: '$stage',
288+
status: 'pending'
289+
}
290+
""".trimIndent()
291+
executeJS("window.ideClient.prepareUi($jsonData)")
292+
}
293+
294+
else -> {
295+
val jsonData = """
296+
{
297+
stage: '$stage',
298+
regions: $regions,
299+
idcInfo: {
300+
profileName: '${lastLoginIdcInfo.profileName}',
301+
startUrl: '${lastLoginIdcInfo.startUrl}',
302+
region: '${lastLoginIdcInfo.region}'
303+
},
304+
cancellable: ${state.browserCancellable},
305+
feature: '${state.feature}',
306+
existConnections: ${writeValueAsString(selectionSettings.values.map { it.currentSelection }.toList())},
307+
}
308+
""".trimIndent()
309+
310+
executeJS("window.ideClient.prepareUi($jsonData)")
265311
}
266-
""".trimIndent()
267-
executeJS("window.ideClient.prepareUi($jsonData)")
312+
}
268313
}
269314

270315
override fun loginIAM(profileName: String, accessKey: String, secretKey: String) {
@@ -276,6 +321,52 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos
276321
jcefBrowser.loadHTML(getWebviewHTML(webScriptUri, query))
277322
}
278323

324+
private fun handleListProfilesMessage() {
325+
ApplicationManager.getApplication().executeOnPooledThread {
326+
var errorMessage = ""
327+
val profiles = try {
328+
QRegionProfileManager.getInstance().listRegionProfiles(project)
329+
} catch (e: Exception) {
330+
e.message?.let {
331+
errorMessage = it
332+
}
333+
LOG.warn { "Failed to call listRegionProfiles API: $errorMessage" }
334+
val qConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
335+
Telemetry.amazonq.didSelectProfile.use { span ->
336+
span.source(QProfileSwitchIntent.Auth.value)
337+
.amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set")
338+
.ssoRegion((qConn as? AwsBearerTokenConnection)?.region)
339+
.credentialStartUrl((qConn as? AwsBearerTokenConnection)?.startUrl)
340+
.result(MetricResult.Failed)
341+
.reason(e.message)
342+
}
343+
344+
null
345+
}
346+
347+
// auto-select the profile if users only have 1 and don't show the UI
348+
if (profiles?.size == 1) {
349+
LOG.debug { "User only have access to 1 Q profile, auto-selecting profile ${profiles.first().profileName} for ${project.name}" }
350+
QRegionProfileManager.getInstance().switchProfile(project, profiles.first(), QProfileSwitchIntent.Update)
351+
return@executeOnPooledThread
352+
}
353+
354+
// required EDT as this entire block is executed on thread pool
355+
runInEdt {
356+
val jsonData = """
357+
{
358+
stage: 'PROFILE_SELECT',
359+
status: '${if (profiles != null) "succeeded" else "failed"}',
360+
profiles: ${writeValueAsString(profiles ?: "")},
361+
errorMessage: '$errorMessage'
362+
}
363+
""".trimIndent()
364+
365+
executeJS("window.ideClient.prepareUi($jsonData)")
366+
}
367+
}
368+
}
369+
279370
companion object {
280371
private val LOG = getLogger<QWebviewBrowser>()
281372
private const val WEB_SCRIPT_URI = "http://webview/js/getStart.js"

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/startup/AmazonQStartupActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
2020
import software.aws.toolkits.jetbrains.core.gettingstarted.emitUserState
2121
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
2222
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
23+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
2324
import software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextController
2425
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindow
2526
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
@@ -53,6 +54,9 @@ class AmazonQStartupActivity : ProjectActivity {
5354
CodeWhispererExplorerActionManager.getInstance().setIsFirstRestartAfterQInstall(false)
5455
}
5556
}
57+
58+
QRegionProfileManager.getInstance().validateProfile(project)
59+
5660
AmazonQLspService.getInstance(project)
5761
startLsp(project)
5862
if (runOnce.get()) return

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindow.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.messages.AmazonQMessage
2424
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessageConnector
2525
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteraction
2626
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteractionType
27+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
2728
import software.aws.toolkits.jetbrains.services.amazonq.util.highlightCommand
2829
import software.aws.toolkits.jetbrains.services.amazonq.webview.BrowserConnector
2930
import software.aws.toolkits.jetbrains.services.amazonq.webview.FqnWebviewAdapter
@@ -127,7 +128,8 @@ class AmazonQToolWindow private constructor(
127128
isCodeScanAvailable = isCodeScanAvailable(project),
128129
isCodeTestAvailable = isCodeTestAvailable(project),
129130
isDocAvailable = isDocAvailable(project),
130-
highlightCommand = highlightCommand()
131+
highlightCommand = highlightCommand(),
132+
activeProfile = QRegionProfileManager.getInstance().takeIf { it.shouldDisplayProfileInfo(project) }?.activeProfile(project)
131133
)
132134

133135
scope.launch {

0 commit comments

Comments
 (0)