Skip to content

Commit de4b199

Browse files
authored
fix(amazonq): validate outdated profile (#2012)
* move validate in factory * centralize all clients
1 parent 066fd1d commit de4b199

File tree

5 files changed

+43
-61
lines changed

5 files changed

+43
-61
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import software.aws.toolkits.jetbrains.utils.isQConnected
4242
import software.aws.toolkits.jetbrains.utils.isQExpired
4343
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable
4444
import software.aws.toolkits.telemetry.FeatureId
45+
import software.aws.toolkits.telemetry.MetricResult
46+
import software.aws.toolkits.telemetry.Telemetry
4547
import software.aws.toolkits.telemetry.UiTelemetry
4648
import software.aws.toolkits.telemetry.WebviewTelemetry
4749
import java.awt.event.ActionListener
@@ -267,6 +269,16 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos
267269
QRegionProfileManager.getInstance().listRegionProfiles(project).orEmpty()
268270
} catch (e: Exception) {
269271
errorMessage = e.message
272+
LOG.warn { "Failed to call listRegionProfiles API" }
273+
val qConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
274+
Telemetry.amazonq.didSelectProfile.use { span ->
275+
span.source(QProfileSwitchIntent.Auth.value)
276+
.amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set")
277+
.ssoRegion((qConn as? AwsBearerTokenConnection)?.region)
278+
.credentialStartUrl((qConn as? AwsBearerTokenConnection)?.startUrl)
279+
.result(MetricResult.Failed)
280+
.reason(e.message)
281+
}
270282
emptyList()
271283
}
272284

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

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import com.intellij.ui.components.panels.Wrapper
1414
import com.intellij.util.ui.components.BorderLayoutPanel
1515
import software.aws.toolkits.core.utils.debug
1616
import software.aws.toolkits.core.utils.getLogger
17-
import software.aws.toolkits.core.utils.warn
18-
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
1917
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
2018
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
2119
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerListener
@@ -28,7 +26,6 @@ import software.aws.toolkits.jetbrains.core.webview.BrowserState
2826
import software.aws.toolkits.jetbrains.services.amazonq.QWebviewPanel
2927
import software.aws.toolkits.jetbrains.services.amazonq.RefreshQChatPanelButtonPressedListener
3028
import software.aws.toolkits.jetbrains.services.amazonq.gettingstarted.openMeetQPage
31-
import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIntent
3229
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile
3330
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
3431
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener
@@ -37,8 +34,6 @@ import software.aws.toolkits.jetbrains.utils.isQExpired
3734
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable
3835
import software.aws.toolkits.resources.message
3936
import software.aws.toolkits.telemetry.FeatureId
40-
import software.aws.toolkits.telemetry.MetricResult
41-
import software.aws.toolkits.telemetry.Telemetry
4237
import java.awt.event.ComponentAdapter
4338
import java.awt.event.ComponentEvent
4439

@@ -70,19 +65,7 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware {
7065
override fun activeConnectionChanged(newConnection: ToolkitConnection?) {
7166
ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let { qConn ->
7267
openMeetQPage(project)
73-
try {
74-
QRegionProfileManager.getInstance().listRegionProfiles(project)
75-
} catch (e: Exception) {
76-
LOG.warn { "Failed to call listRegionProfiles API" }
77-
Telemetry.amazonq.didSelectProfile.use { span ->
78-
span.source(QProfileSwitchIntent.Auth.value)
79-
.amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set")
80-
.ssoRegion((qConn as? AwsBearerTokenConnection)?.region)
81-
.credentialStartUrl((qConn as? AwsBearerTokenConnection)?.startUrl)
82-
.result(MetricResult.Failed)
83-
.reason(e.message)
84-
}
85-
}
68+
QRegionProfileManager.getInstance().validateProfile(project)
8669
}
8770
prepareChatContent(project, qPanel)
8871
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ import software.aws.toolkits.core.utils.debug
5050
import software.aws.toolkits.core.utils.getLogger
5151
import software.aws.toolkits.core.utils.info
5252
import software.aws.toolkits.core.utils.warn
53-
import software.aws.toolkits.jetbrains.core.AwsClientManager
5453
import software.aws.toolkits.jetbrains.core.coroutines.EDT
55-
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
56-
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
5754
import software.aws.toolkits.jetbrains.core.credentials.sono.isInternalUser
5855
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
5956
import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthController
57+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
6058
import software.aws.toolkits.jetbrains.services.amazonq.project.RelevantDocument
6159
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.CodeWhispererUTGChatManager
6260
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.ConversationState
@@ -277,9 +275,6 @@ class CodeTestChatController(
277275
promptInputDisabledState = true,
278276
)
279277
// Send Request to Sync UTG API
280-
val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
281-
// this should never happen because it should have been handled upstream by [AuthController]
282-
?: error("connection was found to be null")
283278
val contextExtractor = ActiveFileContextExtractor.create(fqnWebviewAdapter = null, project = project)
284279
val activeFileContext = ActiveFileContext(
285280
fileContext = FileContext(
@@ -301,7 +296,7 @@ class CodeTestChatController(
301296
useRelevantDocuments = false,
302297
)
303298

304-
val client = AwsClientManager.getInstance().getClient<CodeWhispererStreamingAsyncClient>(connection.getConnectionSettings())
299+
val client = QRegionProfileManager.getInstance().getQClient<CodeWhispererStreamingAsyncClient>(project)
305300
val request = requestData.toChatRequest()
306301
client.generateAssistantResponse(request, responseHandler).await()
307302
// TODO: Need to send isCodeBlockSelected field

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ import software.amazon.awssdk.services.codewhispererstreaming.model.UserInputMes
3636
import software.amazon.awssdk.services.codewhispererstreaming.model.UserIntent
3737
import software.aws.toolkits.core.utils.getLogger
3838
import software.aws.toolkits.core.utils.info
39-
import software.aws.toolkits.jetbrains.core.AwsClientManager
4039
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
41-
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
42-
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
40+
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
4341
import software.aws.toolkits.jetbrains.services.amazonq.project.RelevantDocument
4442
import software.aws.toolkits.jetbrains.services.cwc.ChatConstants
4543
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.ChatSession
@@ -170,11 +168,7 @@ class ChatSessionV1(
170168

171169
try {
172170
withTimeout(ChatConstants.REQUEST_TIMEOUT_MS.toLong()) {
173-
val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
174-
// this should never happen because it should have been handled upstream by [AuthController]
175-
?: error("connection was found to be null")
176-
177-
val client = AwsClientManager.getInstance().getClient<CodeWhispererStreamingAsyncClient>(connection.getConnectionSettings())
171+
val client = QRegionProfileManager.getInstance().getQClient<CodeWhispererStreamingAsyncClient>(project)
178172
val request = data.toChatRequest()
179173
logger.info { "Request from tab: ${data.tabId}, conversationId: $conversationId, request: $request" }
180174
client.generateAssistantResponse(request, responseHandler).await()

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,14 @@ class QRegionProfileManager : PersistentStateComponent<QProfileState>, Disposabl
5252

5353
if (profiles == null || profiles.none { it.arn == selected.arn }) {
5454
invalidateProfile(selected.arn)
55+
switchProfile(project, null, intent = QProfileSwitchIntent.Reload)
5556
Telemetry.amazonq.profileState.use { span ->
5657
span.source(QProfileSwitchIntent.Reload.value)
5758
.amazonQProfileRegion(selected.region)
5859
.ssoRegion(conn?.region)
5960
.credentialStartUrl(conn?.startUrl)
6061
.result(MetricResult.Failed)
6162
}
62-
project.messageBus
63-
.syncPublisher(QRegionProfileSelectedListener.TOPIC)
64-
.onProfileSelected(project, null)
6563
}
6664
}
6765

@@ -94,39 +92,39 @@ class QRegionProfileManager : PersistentStateComponent<QProfileState>, Disposabl
9492

9593
fun hasValidConnectionButNoActiveProfile(project: Project): Boolean = getIdcConnectionOrNull(project) != null && activeProfile(project) == null
9694

97-
fun switchProfile(project: Project, newProfile: QRegionProfile, intent: QProfileSwitchIntent) {
95+
fun switchProfile(project: Project, newProfile: QRegionProfile?, intent: QProfileSwitchIntent) {
9896
val conn = getIdcConnectionOrNull(project) ?: return
9997

100-
if (newProfile.arn.isEmpty()) return
101-
10298
val oldProfile = connectionIdToActiveProfile[conn.id]
10399
if (oldProfile == newProfile) return
104100

105101
connectionIdToActiveProfile[conn.id] = newProfile
106102
LOG.debug { "Switch from profile $oldProfile to $newProfile for project ${project.name}" }
107103

108-
if (intent == QProfileSwitchIntent.User || intent == QProfileSwitchIntent.Auth) {
109-
notifyInfo(
110-
title = message("action.q.profile.usage.text"),
111-
content = message("action.q.profile.usage", newProfile.profileName),
112-
project = project
113-
)
114-
115-
Telemetry.amazonq.didSelectProfile.use { span ->
116-
span.source(intent.value)
117-
.amazonQProfileRegion(newProfile.region)
118-
.profileCount(connectionIdToProfileList[conn.id])
119-
.ssoRegion(conn.region)
120-
.credentialStartUrl(conn.startUrl)
121-
.result(MetricResult.Succeeded)
122-
}
123-
} else {
124-
Telemetry.amazonq.profileState.use { span ->
125-
span.source(intent.value)
126-
.amazonQProfileRegion(newProfile.region)
127-
.ssoRegion(conn.region)
128-
.credentialStartUrl(conn.startUrl)
129-
.result(MetricResult.Succeeded)
104+
if (newProfile != null) {
105+
if (intent == QProfileSwitchIntent.User || intent == QProfileSwitchIntent.Auth) {
106+
notifyInfo(
107+
title = message("action.q.profile.usage.text"),
108+
content = message("action.q.profile.usage", newProfile.profileName),
109+
project = project
110+
)
111+
112+
Telemetry.amazonq.didSelectProfile.use { span ->
113+
span.source(intent.value)
114+
.amazonQProfileRegion(newProfile.region)
115+
.profileCount(connectionIdToProfileList[conn.id])
116+
.ssoRegion(conn.region)
117+
.credentialStartUrl(conn.startUrl)
118+
.result(MetricResult.Succeeded)
119+
}
120+
} else {
121+
Telemetry.amazonq.profileState.use { span ->
122+
span.source(intent.value)
123+
.amazonQProfileRegion(newProfile.region)
124+
.ssoRegion(conn.region)
125+
.credentialStartUrl(conn.startUrl)
126+
.result(MetricResult.Succeeded)
127+
}
130128
}
131129
}
132130

0 commit comments

Comments
 (0)