From 91052432b7d76d1292b20a1deff0263814b200e2 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 10:16:56 -0700 Subject: [PATCH 01/35] call if --- .../services/amazonq/QLoginWebview.kt | 38 ++++++++++--------- .../amazonq/profile/QRegionProfileManager.kt | 2 +- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt index ceda1545ea1..e17b0ea5d50 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt @@ -264,23 +264,6 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos // TODO: pass "REAUTH" if connection expires // Perform the potentially blocking AWS call outside the EDT to fetch available region profiles. ApplicationManager.getApplication().executeOnPooledThread { - var errorMessage: String? = null - val profiles: List = try { - QRegionProfileManager.getInstance().listRegionProfiles(project).orEmpty() - } catch (e: Exception) { - errorMessage = e.message - LOG.warn { "Failed to call listRegionProfiles API" } - val qConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) - Telemetry.amazonq.didSelectProfile.use { span -> - span.source(QProfileSwitchIntent.Auth.value) - .amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set") - .ssoRegion((qConn as? AwsBearerTokenConnection)?.region) - .credentialStartUrl((qConn as? AwsBearerTokenConnection)?.startUrl) - .result(MetricResult.Failed) - .reason(e.message) - } - emptyList() - } val stage = if (isQExpired(project)) { "REAUTH" @@ -290,6 +273,27 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos "START" } + var errorMessage: String? = null + var profiles: List = emptyList() + + if (stage == "PROFILE_SELECT") { + try { + profiles = QRegionProfileManager.getInstance().listRegionProfiles(project).orEmpty() + } catch (e: Exception) { + errorMessage = e.message + LOG.warn { "Failed to call listRegionProfiles API" } + val qConn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) + Telemetry.amazonq.didSelectProfile.use { span -> + span.source(QProfileSwitchIntent.Auth.value) + .amazonQProfileRegion(QRegionProfileManager.getInstance().activeProfile(project)?.region ?: "not-set") + .ssoRegion((qConn as? AwsBearerTokenConnection)?.region) + .credentialStartUrl((qConn as? AwsBearerTokenConnection)?.startUrl) + .result(MetricResult.Failed) + .reason(e.message) + } + } + } + val jsonData = """ { stage: '$stage', diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index a835a145a24..6b2659c198e 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -74,7 +74,7 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl .awsClient() .listAvailableProfilesPaginator {} .profiles() - .map { p -> QRegionProfile(arn = p.arn(), profileName = p.profileName()) } + .map { p -> QRegionProfile(arn = p.arn(), profileName = p.profileName()?: "") } } if (mappedProfiles.size == 1) { switchProfile(project, mappedProfiles.first(), intent = QProfileSwitchIntent.Update) From ae016bd9ccde0bba99be2cbc1cb601c89f6a75f6 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 10:41:33 -0700 Subject: [PATCH 02/35] add cache --- .../amazonq/profile/QProfileResources.kt | 39 +++++++++++++++++++ .../amazonq/profile/QRegionProfileManager.kt | 22 +++++------ 2 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt new file mode 100644 index 00000000000..2421515c9bd --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt @@ -0,0 +1,39 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.profile + +import software.amazon.awssdk.services.codewhispererruntime.CodeWhispererRuntimeClient +import software.aws.toolkits.core.ClientConnectionSettings +import software.aws.toolkits.jetbrains.core.AwsClientManager +import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider +import software.aws.toolkits.jetbrains.core.Resource +import java.time.Duration + +/** + * Save Amazon Q Profile Resource Cache + */ +object QProfileResources { + /** + * save available Q Profile list as cache with default duration 60 s。 + */ + val LIST_REGION_PROFILES = object : Resource.Cached>() { + override val id: String = "amazonq.allProfiles" + + override fun fetch(connectionSettings: ClientConnectionSettings<*>): List { + val mappedProfiles = QEndpoints.listRegionEndpoints().flatMap { (regionKey, _) -> + val awsRegion = AwsRegionProvider.getInstance()[regionKey] ?: return@flatMap emptyList() + val client = AwsClientManager + .getInstance() + .getClient(CodeWhispererRuntimeClient::class, connectionSettings.withRegion(awsRegion)) + + client.listAvailableProfilesPaginator {} + .profiles() + .map { p -> QRegionProfile(arn = p.arn(), profileName = p.profileName() ?: "") } + } + return mappedProfiles + } + + override fun expiry(): Duration = Duration.ofSeconds(60) + } +} diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index 6b2659c198e..2d345cc6df0 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -14,14 +14,13 @@ import com.intellij.openapi.project.Project import com.intellij.util.xmlb.annotations.MapAnnotation import com.intellij.util.xmlb.annotations.Property import software.amazon.awssdk.core.SdkClient -import software.amazon.awssdk.services.codewhispererruntime.CodeWhispererRuntimeClient import software.aws.toolkits.core.TokenConnectionSettings import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.tryOrNull import software.aws.toolkits.core.utils.warn import software.aws.toolkits.jetbrains.core.AwsClientManager -import software.aws.toolkits.jetbrains.core.awsClient +import software.aws.toolkits.jetbrains.core.AwsResourceCache import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection @@ -31,6 +30,7 @@ import software.aws.toolkits.jetbrains.utils.notifyInfo import software.aws.toolkits.resources.AmazonQBundle.message import software.aws.toolkits.telemetry.MetricResult import software.aws.toolkits.telemetry.Telemetry +import java.time.Duration import java.util.Collections import kotlin.reflect.KClass @@ -66,16 +66,14 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl fun listRegionProfiles(project: Project): List? { val connection = getIdcConnectionOrNull(project) ?: return null return try { - val mappedProfiles = QEndpoints.listRegionEndpoints() - .flatMap { (regionKey, _) -> - val awsRegion = AwsRegionProvider.getInstance()[regionKey] ?: return@flatMap emptyList() - connection.getConnectionSettings() - .withRegion(awsRegion) - .awsClient() - .listAvailableProfilesPaginator {} - .profiles() - .map { p -> QRegionProfile(arn = p.arn(), profileName = p.profileName()?: "") } - } + val connectionSettings = connection.getConnectionSettings() + val mappedProfiles = AwsResourceCache.getInstance().getResourceNow( + resource = QProfileResources.LIST_REGION_PROFILES, + connectionSettings = connectionSettings, + timeout = Duration.ofSeconds(30), + useStale = true, + forceFetch = false + ) if (mappedProfiles.size == 1) { switchProfile(project, mappedProfiles.first(), intent = QProfileSwitchIntent.Update) } From c1474fe789f65366e38f9128aab49de5f42a5331 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 11:11:16 -0700 Subject: [PATCH 03/35] linter --- .../aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt | 1 - .../jetbrains/services/amazonq/profile/QProfileResources.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt index e17b0ea5d50..bb56a5e06d1 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt @@ -264,7 +264,6 @@ class QWebviewBrowser(val project: Project, private val parentDisposable: Dispos // TODO: pass "REAUTH" if connection expires // Perform the potentially blocking AWS call outside the EDT to fetch available region profiles. ApplicationManager.getApplication().executeOnPooledThread { - val stage = if (isQExpired(project)) { "REAUTH" } else if (isQConnected(project) && QRegionProfileManager.getInstance().isPendingProfileSelection(project)) { diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt index 2421515c9bd..79cbdb38a27 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileResources.kt @@ -6,8 +6,8 @@ package software.aws.toolkits.jetbrains.services.amazonq.profile import software.amazon.awssdk.services.codewhispererruntime.CodeWhispererRuntimeClient import software.aws.toolkits.core.ClientConnectionSettings import software.aws.toolkits.jetbrains.core.AwsClientManager -import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider import software.aws.toolkits.jetbrains.core.Resource +import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider import java.time.Duration /** From 07e63ca62bd127138ab006735980d806c3423cf6 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 12:54:34 -0700 Subject: [PATCH 04/35] delete ut --- .../QRegionProfileManagerTest.kt | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt index 511e4e5272b..0453cf3a766 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt @@ -124,36 +124,7 @@ class QRegionProfileManagerTest { assertThat(cnt).isEqualTo(2) } - @Test - fun `listProfiles will call each client to get profiles`() { - val client = clientRule.create() - val mockResponse: SdkIterable = SdkIterable { - listOf( - Profile.builder().profileName("FOO").arn("foo").build(), - ).toMutableList().iterator() - } - - val mockResponse2: SdkIterable = SdkIterable { - listOf( - Profile.builder().profileName("BAR").arn("bar").build(), - ).toMutableList().iterator() - } - - val iterable: ListAvailableProfilesIterable = mock { - on { it.profiles() } doReturn mockResponse doReturn mockResponse2 - } - - // TODO: not sure if we can mock client with different region different response? - client.stub { - onGeneric { listAvailableProfilesPaginator(any>()) } doReturn iterable - } - - val r = sut.listRegionProfiles(project) - assertThat(r).hasSize(2) - - assertThat(r).contains(QRegionProfile("FOO", "foo")) - assertThat(r).contains(QRegionProfile("BAR", "bar")) - } + // TODO: Add two unit tests for listProfiles — one with cache hit, one without @Test fun `validateProfile should cross validate selected profile with latest API response for current project and remove it if its not longer accessible`() { From 7a35aae1824d12326abc2c6f649a285807f71b7b Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 20:31:09 -0700 Subject: [PATCH 05/35] revise auth --- .../amazonq/toolwindow/AmazonQToolWindowFactory.kt | 6 +++++- .../amazonq/profile/QRegionProfileManager.kt | 14 +++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt index 7137d4f966c..726944ad923 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt @@ -66,6 +66,7 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware { ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let { qConn -> openMeetQPage(project) } + println("activeProfile connect:${QRegionProfileManager.getInstance().activeProfile(project)}") prepareChatContent(project, qPanel) } } @@ -85,7 +86,10 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware { object : BearerTokenProviderListener { override fun onChange(providerId: String, newScopes: List?) { if (ToolkitConnectionManager.getInstance(project).connectionStateForFeature(QConnection.getInstance()) == BearerTokenAuthState.AUTHORIZED) { - prepareChatContent(project, qPanel) + val qComponent = AmazonQToolWindow.getInstance(project).component + runInEdt { + qPanel.setContent(qComponent) + } } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index c9014d16d20..5b09ab8325d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -27,6 +27,7 @@ import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection import software.aws.toolkits.jetbrains.core.credentials.sono.isSono +import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProviderListener import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider import software.aws.toolkits.jetbrains.utils.notifyInfo @@ -191,11 +192,15 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl } private fun getIdcConnectionOrNull(project: Project): AwsBearerTokenConnection? { - val connection = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) - if (connection is AwsBearerTokenConnection && !connection.isSono()) { - return connection + val manager = ToolkitConnectionManager.getInstance(project) + val connection = manager.activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection + val state = manager.connectionStateForFeature(QConnection.getInstance()) + + return if (connection != null && !connection.isSono() && state == BearerTokenAuthState.AUTHORIZED) { + connection + } else { + null } - return null } companion object { @@ -215,7 +220,6 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl override fun loadState(state: QProfileState) { connectionIdToActiveProfile.clear() connectionIdToActiveProfile.putAll(state.connectionIdToActiveProfile) - connectionIdToProfileCount.clear() connectionIdToProfileCount.putAll(state.connectionIdToProfileList) } From b5d3299943f9d1c4ba566d394364d1df5fcf25a7 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 20:33:33 -0700 Subject: [PATCH 06/35] re --- .../jetbrains/services/amazonq/profile/QRegionProfileManager.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index 5b09ab8325d..30e8a7bd775 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -220,6 +220,7 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl override fun loadState(state: QProfileState) { connectionIdToActiveProfile.clear() connectionIdToActiveProfile.putAll(state.connectionIdToActiveProfile) + connectionIdToProfileCount.clear() connectionIdToProfileCount.putAll(state.connectionIdToProfileList) } From 29b297a3d829e7b39a0beaa35dbdd9ec92be60a1 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 20:34:05 -0700 Subject: [PATCH 07/35] delete --- .../services/amazonq/toolwindow/AmazonQToolWindowFactory.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt index 726944ad923..5ad6ebaf6f8 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt @@ -66,7 +66,6 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware { ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.let { qConn -> openMeetQPage(project) } - println("activeProfile connect:${QRegionProfileManager.getInstance().activeProfile(project)}") prepareChatContent(project, qPanel) } } From 3c4d39a16abaa99deeafb46248df5f2afd771c34 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 9 Apr 2025 20:40:17 -0700 Subject: [PATCH 08/35] revert --- .../services/amazonq/toolwindow/AmazonQToolWindowFactory.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt index 5ad6ebaf6f8..7137d4f966c 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt @@ -85,10 +85,7 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware { object : BearerTokenProviderListener { override fun onChange(providerId: String, newScopes: List?) { if (ToolkitConnectionManager.getInstance(project).connectionStateForFeature(QConnection.getInstance()) == BearerTokenAuthState.AUTHORIZED) { - val qComponent = AmazonQToolWindow.getInstance(project).component - runInEdt { - qPanel.setContent(qComponent) - } + prepareChatContent(project, qPanel) } } } From bbc7ccef29d97ffade921a4edda1ab026d43142e Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 10 Apr 2025 00:19:24 -0700 Subject: [PATCH 09/35] ut --- .../QRegionProfileManagerTest.kt | 34 ++++++++++++++++++- .../amazonq/profile/QRegionProfileManager.kt | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt index e8bb0398ad7..a4533141fca 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt @@ -6,6 +6,7 @@ package software.aws.toolkits.jetbrains.services.codewhisperer import com.intellij.openapi.project.Project import com.intellij.testFramework.DisposableRule import com.intellij.testFramework.ProjectRule +import com.intellij.testFramework.replaceService import com.intellij.util.xmlb.XmlSerializer import org.assertj.core.api.Assertions.assertThat import org.jdom.output.XMLOutputter @@ -15,7 +16,9 @@ import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock +import org.mockito.kotlin.spy import org.mockito.kotlin.stub +import org.mockito.kotlin.whenever import software.amazon.awssdk.core.pagination.sync.SdkIterable import software.amazon.awssdk.regions.Region import software.amazon.awssdk.services.codewhispererruntime.CodeWhispererRuntimeClient @@ -33,6 +36,7 @@ import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.logoutFromSsoConnection import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection import software.aws.toolkits.jetbrains.core.credentials.sono.Q_SCOPES +import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.profile.QEndpoints import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileState @@ -80,6 +84,10 @@ class QRegionProfileManagerTest { sut = QRegionProfileManager() val conn = authRule.createConnection(ManagedSsoProfile(ssoRegion = "us-east-1", startUrl = "", scopes = Q_SCOPES)) ToolkitConnectionManager.getInstance(project).switchConnection(conn) + val realManager = ToolkitConnectionManager.getInstance(project) + val managerSpy = spy(realManager) + doReturn(BearerTokenAuthState.AUTHORIZED).whenever(managerSpy).connectionStateForFeature(QConnection.getInstance()) + project.replaceService(ToolkitConnectionManager::class.java, managerSpy, disposableRule.disposable) } @Test @@ -101,7 +109,7 @@ class QRegionProfileManagerTest { logoutFromSsoConnection(project, it) } } - + ToolkitConnectionManager.getInstance(project).switchConnection(null) assertThat(ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())).isNull() assertThat(sut.activeProfile(project)).isNull() } @@ -347,4 +355,28 @@ class QRegionProfileManagerTest { val profileList = actualState.connectionIdToProfileList["conn-123"] assertThat(profileList).isEqualTo(2) } + + @Test + fun `getIdcConnectionOrNull handles NOT_AUTH and AUTHORIZED correctly`() { + val managerSpy = ToolkitConnectionManager.getInstance(project) + doReturn(BearerTokenAuthState.NOT_AUTHENTICATED).whenever(managerSpy) + .connectionStateForFeature(QConnection.getInstance()) + + // NOT AUTHORIZED + val notAuthConn = sut.getIdcConnectionOrNull(project) + assertThat(notAuthConn).isNull() + + doReturn(BearerTokenAuthState.AUTHORIZED) + .whenever(managerSpy).connectionStateForFeature(QConnection.getInstance()) + + // AUTHORIZED + val normalConn = authRule.createConnection( + ManagedSsoProfile(ssoRegion = "us-east-1", startUrl = "", scopes = Q_SCOPES) + ) + managerSpy.switchConnection(normalConn) + + val normalConnectionResult = sut.getIdcConnectionOrNull(project) + assertThat(normalConnectionResult).isNotNull() + assertThat(normalConnectionResult).isEqualTo(normalConn) + } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index 30e8a7bd775..60f98c26d0f 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -191,7 +191,7 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl return client } - private fun getIdcConnectionOrNull(project: Project): AwsBearerTokenConnection? { + fun getIdcConnectionOrNull(project: Project): AwsBearerTokenConnection? { val manager = ToolkitConnectionManager.getInstance(project) val connection = manager.activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection val state = manager.connectionStateForFeature(QConnection.getInstance()) From d3c76bd10ac7e2a38487b494328a90083cc9aca6 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 10 Apr 2025 11:07:14 -0700 Subject: [PATCH 10/35] reintialize q ui --- .../services/amazonq/toolwindow/AmazonQToolWindowFactory.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt index 7137d4f966c..6f5f8331307 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQToolWindowFactory.kt @@ -85,7 +85,8 @@ class AmazonQToolWindowFactory : ToolWindowFactory, DumbAware { object : BearerTokenProviderListener { override fun onChange(providerId: String, newScopes: List?) { if (ToolkitConnectionManager.getInstance(project).connectionStateForFeature(QConnection.getInstance()) == BearerTokenAuthState.AUTHORIZED) { - prepareChatContent(project, qPanel) + AmazonQToolWindow.getInstance(project).disposeAndRecreate() + qPanel.setContent(AmazonQToolWindow.getInstance(project).component) } } } From 790de97ecb506e89c3acff0ef60f9d045c59f8b0 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 10 Apr 2025 14:39:24 -0700 Subject: [PATCH 11/35] add url --- .../src/software/aws/toolkits/jetbrains/core/help/HelpIds.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/help/HelpIds.kt b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/help/HelpIds.kt index 73bf084b04b..bb87abad15a 100644 --- a/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/help/HelpIds.kt +++ b/plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/help/HelpIds.kt @@ -126,10 +126,9 @@ enum class HelpIds(shortId: String, val url: String) { "https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/setup-credentials.html" ), - // TODO: update this Q_SWITCH_PROFILES_DIALOG( "QSwitchProfilesDialog", - "https://aws.amazon.com/q/developer/" + "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/subscribe-understanding-profile.html" ), ; From 1673db3890ed056acb416960cf5c5f33175039ff Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 11 Apr 2025 15:36:36 -0700 Subject: [PATCH 12/35] update sdk --- .../codewhispererstreaming/service-2.json | 1313 +++++++++++++++-- 1 file changed, 1220 insertions(+), 93 deletions(-) diff --git a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json index 1e7898a48d7..48aea822e55 100644 --- a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json +++ b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json @@ -2,9 +2,14 @@ "version":"2.0", "metadata":{ "apiVersion":"2023-11-27", + "auth":["smithy.api#httpBearerAuth"], "endpointPrefix":"amazoncodewhispererstreamingservice", "jsonVersion":"1.0", "protocol":"json", + "protocols":[ + "json", + "rest-json" + ], "serviceFullName":"Amazon CodeWhisperer Streaming", "serviceId":"CodeWhispererStreaming", "signatureVersion":"bearer", @@ -55,8 +60,27 @@ "output":{"shape":"GenerateTaskAssistPlanResponse"}, "errors":[ {"shape":"ThrottlingException"}, + {"shape":"ConflictException"}, {"shape":"ServiceQuotaExceededException"}, + {"shape":"ResourceNotFoundException"}, + {"shape":"InternalServerException"}, + {"shape":"ValidationException"}, + {"shape":"AccessDeniedException"} + ] + }, + "SendMessage":{ + "name":"SendMessage", + "http":{ + "method":"POST", + "requestUri":"/" + }, + "input":{"shape":"SendMessageRequest"}, + "output":{"shape":"SendMessageResponse"}, + "errors":[ + {"shape":"DryRunOperationException"}, + {"shape":"ThrottlingException"}, {"shape":"ConflictException"}, + {"shape":"ServiceQuotaExceededException"}, {"shape":"ResourceNotFoundException"}, {"shape":"InternalServerException"}, {"shape":"ValidationException"}, @@ -69,10 +93,126 @@ "type":"structure", "required":["message"], "members":{ - "message":{"shape":"String"} + "message":{"shape":"String"}, + "reason":{"shape":"AccessDeniedExceptionReason"} }, "exception":true }, + "AccessDeniedExceptionReason":{ + "type":"string", + "enum":["UNAUTHORIZED_CUSTOMIZATION_RESOURCE_ACCESS"] + }, + "Action":{ + "type":"structure", + "members":{ + "webLink":{"shape":"WebLink"}, + "moduleLink":{"shape":"ModuleLink"} + } + }, + "AdditionalContentEntry":{ + "type":"structure", + "required":[ + "name", + "description" + ], + "members":{ + "name":{"shape":"AdditionalContentEntryNameString"}, + "description":{"shape":"AdditionalContentEntryDescriptionString"}, + "innerContext":{"shape":"AdditionalContentEntryInnerContextString"} + } + }, + "AdditionalContentEntryDescriptionString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "AdditionalContentEntryInnerContextString":{ + "type":"string", + "max":8192, + "min":1, + "sensitive":true + }, + "AdditionalContentEntryNameString":{ + "type":"string", + "max":1024, + "min":1, + "pattern":"[a-z]+(?:-[a-z0-9]+)*", + "sensitive":true + }, + "AdditionalContentList":{ + "type":"list", + "member":{"shape":"AdditionalContentEntry"}, + "max":20, + "min":0 + }, + "Alert":{ + "type":"structure", + "required":[ + "type", + "content" + ], + "members":{ + "type":{"shape":"AlertType"}, + "content":{"shape":"AlertComponentList"} + } + }, + "AlertComponent":{ + "type":"structure", + "members":{ + "text":{"shape":"Text"} + } + }, + "AlertComponentList":{ + "type":"list", + "member":{"shape":"AlertComponent"} + }, + "AlertType":{ + "type":"string", + "enum":[ + "INFO", + "ERROR", + "WARNING" + ] + }, + "AppStudioState":{ + "type":"structure", + "required":[ + "namespace", + "propertyName", + "propertyContext" + ], + "members":{ + "namespace":{"shape":"AppStudioStateNamespaceString"}, + "propertyName":{"shape":"AppStudioStatePropertyNameString"}, + "propertyValue":{"shape":"AppStudioStatePropertyValueString"}, + "propertyContext":{"shape":"AppStudioStatePropertyContextString"} + } + }, + "AppStudioStateNamespaceString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "AppStudioStatePropertyContextString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "AppStudioStatePropertyNameString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "AppStudioStatePropertyValueString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, "ArtifactId":{ "type":"string", "max":126, @@ -97,24 +237,20 @@ "type":"structure", "required":["content"], "members":{ - "messageId":{"shape":"AssistantResponseMessageMessageIdString"}, + "messageId":{"shape":"MessageId"}, "content":{"shape":"AssistantResponseMessageContentString"}, "supplementaryWebLinks":{"shape":"SupplementaryWebLinks"}, "references":{"shape":"References"}, - "followupPrompt":{"shape":"FollowupPrompt"} + "followupPrompt":{"shape":"FollowupPrompt"}, + "toolUses":{"shape":"ToolUses"} } }, "AssistantResponseMessageContentString":{ "type":"string", - "max":4096, + "max":100000, "min":0, "sensitive":true }, - "AssistantResponseMessageMessageIdString":{ - "type":"string", - "max":128, - "min":0 - }, "BinaryMetadataEvent":{ "type":"structure", "members":{ @@ -141,7 +277,7 @@ "ChatHistory":{ "type":"list", "member":{"shape":"ChatMessage"}, - "max":10, + "max":100, "min":0 }, "ChatMessage":{ @@ -157,10 +293,16 @@ "members":{ "messageMetadataEvent":{"shape":"MessageMetadataEvent"}, "assistantResponseEvent":{"shape":"AssistantResponseEvent"}, + "dryRunSucceedEvent":{"shape":"DryRunSucceedEvent"}, "codeReferenceEvent":{"shape":"CodeReferenceEvent"}, "supplementaryWebLinksEvent":{"shape":"SupplementaryWebLinksEvent"}, "followupPromptEvent":{"shape":"FollowupPromptEvent"}, - "invalidStateEvent": {"shape": "InvalidStateEvent"}, + "codeEvent":{"shape":"CodeEvent"}, + "intentsEvent":{"shape":"IntentsEvent"}, + "interactionComponentsEvent":{"shape":"InteractionComponentsEvent"}, + "toolUseEvent":{"shape":"ToolUseEvent"}, + "citationEvent":{"shape":"CitationEvent"}, + "invalidStateEvent":{"shape":"InvalidStateEvent"}, "error":{"shape":"InternalServerException"} }, "eventstream":true @@ -173,6 +315,71 @@ "INLINE_CHAT" ] }, + "CitationEvent":{ + "type":"structure", + "required":[ + "target", + "citationLink" + ], + "members":{ + "target":{"shape":"CitationTarget"}, + "citationText":{"shape":"SensitiveString"}, + "citationLink":{"shape":"SensitiveString"} + }, + "event":true + }, + "CitationTarget":{ + "type":"structure", + "members":{ + "location":{"shape":"Offset"}, + "range":{"shape":"Span"} + }, + "union":true + }, + "CloudWatchTroubleshootingLink":{ + "type":"structure", + "required":[ + "label", + "investigationPayload" + ], + "members":{ + "label":{"shape":"CloudWatchTroubleshootingLinkLabelString"}, + "investigationPayload":{"shape":"CloudWatchTroubleshootingLinkInvestigationPayloadString"}, + "defaultText":{"shape":"CloudWatchTroubleshootingLinkDefaultTextString"} + } + }, + "CloudWatchTroubleshootingLinkDefaultTextString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "CloudWatchTroubleshootingLinkInvestigationPayloadString":{ + "type":"string", + "max":16384, + "min":0, + "sensitive":true + }, + "CloudWatchTroubleshootingLinkLabelString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "CodeEvent":{ + "type":"structure", + "required":["content"], + "members":{ + "content":{"shape":"CodeEventContentString"} + }, + "event":true + }, + "CodeEventContentString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, "CodeReferenceEvent":{ "type":"structure", "members":{ @@ -184,10 +391,30 @@ "type":"structure", "required":["message"], "members":{ - "message":{"shape":"String"} + "message":{"shape":"String"}, + "reason":{"shape":"ConflictExceptionReason"} }, "exception":true }, + "ConflictExceptionReason":{ + "type":"string", + "enum":[ + "CUSTOMER_KMS_KEY_INVALID_KEY_POLICY", + "CUSTOMER_KMS_KEY_DISABLED", + "MISMATCHED_KMS_KEY" + ] + }, + "ConsoleState":{ + "type":"structure", + "members":{ + "region":{"shape":"String"}, + "consoleUrl":{"shape":"SensitiveString"}, + "serviceId":{"shape":"String"}, + "serviceConsolePage":{"shape":"String"}, + "serviceSubconsolePage":{"shape":"String"}, + "taskName":{"shape":"SensitiveString"} + } + }, "ContentChecksum":{ "type":"string", "max":512, @@ -220,7 +447,7 @@ "history":{"shape":"ChatHistory"}, "currentMessage":{"shape":"ChatMessage"}, "chatTriggerType":{"shape":"ChatTriggerType"}, - "customizationArn":{"shape": "ResourceArn"} + "customizationArn":{"shape":"ResourceArn"} } }, "CursorState":{ @@ -276,15 +503,81 @@ "max":1000, "min":0 }, + "DryRunOperationException":{ + "type":"structure", + "members":{ + "message":{"shape":"String"}, + "responseCode":{"shape":"Integer"} + }, + "exception":true + }, + "DryRunSucceedEvent":{ + "type":"structure", + "members":{ + }, + "event":true + }, "EditorState":{ "type":"structure", "members":{ "document":{"shape":"TextDocument"}, "cursorState":{"shape":"CursorState"}, - "relevantDocuments": {"shape": "RelevantDocumentList"}, - "useRelevantDocuments": {"shape": "Boolean"} + "relevantDocuments":{"shape":"RelevantDocumentList"}, + "useRelevantDocuments":{"shape":"Boolean"} } }, + "EnvState":{ + "type":"structure", + "members":{ + "operatingSystem":{"shape":"EnvStateOperatingSystemString"}, + "currentWorkingDirectory":{"shape":"EnvStateCurrentWorkingDirectoryString"}, + "environmentVariables":{"shape":"EnvironmentVariables"}, + "timezoneOffset":{"shape":"EnvStateTimezoneOffsetInteger"} + } + }, + "EnvStateCurrentWorkingDirectoryString":{ + "type":"string", + "max":256, + "min":1, + "sensitive":true + }, + "EnvStateOperatingSystemString":{ + "type":"string", + "max":32, + "min":1, + "pattern":"(macos|linux|windows)" + }, + "EnvStateTimezoneOffsetInteger":{ + "type":"integer", + "box":true, + "max":1440, + "min":-1440 + }, + "EnvironmentVariable":{ + "type":"structure", + "members":{ + "key":{"shape":"EnvironmentVariableKeyString"}, + "value":{"shape":"EnvironmentVariableValueString"} + } + }, + "EnvironmentVariableKeyString":{ + "type":"string", + "max":256, + "min":1, + "sensitive":true + }, + "EnvironmentVariableValueString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "EnvironmentVariables":{ + "type":"list", + "member":{"shape":"EnvironmentVariable"}, + "max":100, + "min":0 + }, "ExportContext":{ "type":"structure", "members":{ @@ -308,11 +601,17 @@ "exportIntent" ], "members":{ - "exportId":{"shape":"String"}, + "exportId":{"shape":"ExportResultArchiveRequestExportIdString"}, "exportIntent":{"shape":"ExportIntent"}, - "exportContext":{"shape":"ExportContext"} + "exportContext":{"shape":"ExportContext"}, + "profileArn":{"shape":"ProfileArn"} } }, + "ExportResultArchiveRequestExportIdString":{ + "type":"string", + "max":1024, + "min":0 + }, "ExportResultArchiveResponse":{ "type":"structure", "required":["body"], @@ -345,7 +644,8 @@ "type":"structure", "required":["conversationState"], "members":{ - "conversationState":{"shape":"ConversationState"} + "conversationState":{"shape":"ConversationState"}, + "profileArn":{"shape":"ProfileArn"} } }, "GenerateAssistantResponseResponse":{ @@ -367,7 +667,8 @@ ], "members":{ "conversationState":{"shape":"ConversationState"}, - "workspaceState":{"shape":"WorkspaceState"} + "workspaceState":{"shape":"WorkspaceState"}, + "profileArn":{"shape":"ProfileArn"} } }, "GenerateTaskAssistPlanResponse":{ @@ -376,66 +677,282 @@ "planningResponseStream":{"shape":"ChatResponseStream"} } }, - "Integer":{ - "type":"integer", - "box":true - }, - "InternalServerException":{ + "GitState":{ "type":"structure", - "required":["message"], "members":{ - "message":{"shape":"String"} - }, - "exception":true, - "fault":true, - "retryable":{"throttling":false} + "status":{"shape":"GitStateStatusString"} + } }, - "InvalidStateEvent":{ + "GitStateStatusString":{ + "type":"string", + "max":4096, + "min":0, + "sensitive":true + }, + "ImageBlock":{ "type":"structure", + "required":[ + "format", + "source" + ], "members":{ - "reason":{"shape":"InvalidStateReason"}, - "message":{"shape": "String"} - }, - "event":true + "format":{"shape":"ImageFormat"}, + "source":{"shape":"ImageSource"} + } }, - "InvalidStateReason":{ - "type":"string", - "enum":["INVALID_TASK_ASSIST_PLAN"] + "ImageBlocks":{ + "type":"list", + "member":{"shape":"ImageBlock"}, + "max":10, + "min":0 }, - "Long":{ - "type":"long", - "box":true + "ImageFormat":{ + "type":"string", + "enum":[ + "png", + "jpeg", + "gif", + "webp" + ] }, - "MessageMetadataEvent":{ + "ImageSource":{ "type":"structure", "members":{ - "conversationId":{"shape":"MessageMetadataEventConversationIdString"} + "bytes":{"shape":"ImageSourceBytesBlob"} }, - "event":true - }, - "MessageMetadataEventConversationIdString":{ - "type":"string", - "max":128, - "min":0 + "sensitive":true, + "union":true }, - "PartBody":{ + "ImageSourceBytesBlob":{ "type":"blob", - "max":1000000, - "min":0, - "sensitive":true + "max":1500000, + "min":1 }, - "Position":{ + "InfrastructureUpdate":{ + "type":"structure", + "members":{ + "transition":{"shape":"InfrastructureUpdateTransition"} + } + }, + "InfrastructureUpdateTransition":{ "type":"structure", "required":[ - "line", - "character" + "currentState", + "nextState" ], "members":{ - "line":{"shape":"Integer"}, - "character":{"shape":"Integer"} + "currentState":{"shape":"InfrastructureUpdateTransitionCurrentStateString"}, + "nextState":{"shape":"InfrastructureUpdateTransitionNextStateString"} } }, - "ProgrammingLanguage":{ + "InfrastructureUpdateTransitionCurrentStateString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "InfrastructureUpdateTransitionNextStateString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "Integer":{ + "type":"integer", + "box":true + }, + "IntentData":{ + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"IntentDataType"}, + "max":100, + "min":0, + "sensitive":true + }, + "IntentDataType":{ + "type":"structure", + "members":{ + "string":{"shape":"String"} + }, + "union":true + }, + "IntentMap":{ + "type":"map", + "key":{"shape":"IntentType"}, + "value":{"shape":"IntentData"}, + "max":5, + "min":0 + }, + "IntentType":{ + "type":"string", + "enum":[ + "SUPPORT", + "GLUE_SENSEI", + "RESOURCE_DATA" + ] + }, + "IntentsEvent":{ + "type":"structure", + "members":{ + "intents":{"shape":"IntentMap"} + }, + "event":true + }, + "InteractionComponent":{ + "type":"structure", + "members":{ + "text":{"shape":"Text"}, + "alert":{"shape":"Alert"}, + "infrastructureUpdate":{"shape":"InfrastructureUpdate"}, + "progress":{"shape":"Progress"}, + "step":{"shape":"Step"}, + "taskDetails":{"shape":"TaskDetails"}, + "taskReference":{"shape":"TaskReference"}, + "suggestions":{"shape":"Suggestions"}, + "section":{"shape":"Section"}, + "resource":{"shape":"Resource"}, + "resourceList":{"shape":"ResourceList"}, + "action":{"shape":"Action"} + } + }, + "InteractionComponentEntry":{ + "type":"structure", + "required":["interactionComponent"], + "members":{ + "interactionComponentId":{"shape":"InteractionComponentId"}, + "interactionComponent":{"shape":"InteractionComponent"} + } + }, + "InteractionComponentEntryList":{ + "type":"list", + "member":{"shape":"InteractionComponentEntry"} + }, + "InteractionComponentId":{ + "type":"string", + "max":128, + "min":0 + }, + "InteractionComponentsEvent":{ + "type":"structure", + "required":["interactionComponentEntries"], + "members":{ + "interactionComponentEntries":{"shape":"InteractionComponentEntryList"} + }, + "event":true + }, + "InternalServerException":{ + "type":"structure", + "required":["message"], + "members":{ + "message":{"shape":"String"} + }, + "exception":true, + "fault":true, + "retryable":{"throttling":false} + }, + "InvalidStateEvent":{ + "type":"structure", + "required":[ + "reason", + "message" + ], + "members":{ + "reason":{"shape":"InvalidStateReason"}, + "message":{"shape":"InvalidStateEventMessageString"} + }, + "event":true + }, + "InvalidStateEventMessageString":{ + "type":"string", + "max":10240, + "min":0 + }, + "InvalidStateReason":{ + "type":"string", + "enum":["INVALID_TASK_ASSIST_PLAN"] + }, + "Long":{ + "type":"long", + "box":true + }, + "MessageId":{ + "type":"string", + "max":128, + "min":0 + }, + "MessageMetadataEvent":{ + "type":"structure", + "members":{ + "conversationId":{"shape":"MessageMetadataEventConversationIdString"}, + "utteranceId":{"shape":"MessageMetadataEventUtteranceIdString"} + }, + "event":true + }, + "MessageMetadataEventConversationIdString":{ + "type":"string", + "max":128, + "min":0 + }, + "MessageMetadataEventUtteranceIdString":{ + "type":"string", + "max":128, + "min":0 + }, + "ModuleLink":{ + "type":"structure", + "members":{ + "cloudWatchTroubleshootingLink":{"shape":"CloudWatchTroubleshootingLink"} + } + }, + "Offset":{ + "type":"integer", + "box":true, + "min":0 + }, + "Origin":{ + "type":"string", + "enum":[ + "CHATBOT", + "CONSOLE", + "DOCUMENTATION", + "MARKETING", + "MOBILE", + "SERVICE_INTERNAL", + "UNIFIED_SEARCH", + "UNKNOWN", + "MD", + "IDE", + "SAGE_MAKER", + "CLI", + "AI_EDITOR", + "OPENSEARCH_DASHBOARD", + "GITLAB" + ] + }, + "PartBody":{ + "type":"blob", + "max":1000000, + "min":0, + "sensitive":true + }, + "Position":{ + "type":"structure", + "required":[ + "line", + "character" + ], + "members":{ + "line":{"shape":"Integer"}, + "character":{"shape":"Integer"} + } + }, + "ProfileArn":{ + "type":"string", + "max":950, + "min":0, + "pattern":"arn:aws:codewhisperer:[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" + }, + "ProgrammingLanguage":{ "type":"structure", "required":["languageName"], "members":{ @@ -446,7 +963,24 @@ "type":"string", "max":128, "min":1, - "pattern":"(python|javascript|java|csharp|typescript|c|cpp|go|kotlin|php|ruby|rust|scala|shell|sql|json|yaml|vue|tf)" + "pattern":"(python|javascript|java|csharp|typescript|c|cpp|go|kotlin|php|ruby|rust|scala|shell|sql|json|yaml|vue|tf|tsx|jsx|plaintext|systemverilog|dart|lua|swift|powershell|r)" + }, + "Progress":{ + "type":"structure", + "required":["content"], + "members":{ + "content":{"shape":"ProgressComponentList"} + } + }, + "ProgressComponent":{ + "type":"structure", + "members":{ + "step":{"shape":"Step"} + } + }, + "ProgressComponentList":{ + "type":"list", + "member":{"shape":"ProgressComponent"} }, "Range":{ "type":"structure", @@ -489,23 +1023,58 @@ "max":10, "min":0 }, - "RelevantTextDocument": { - "type": "structure", - "required": [ - "relativeFilePath" + "RelevantDocumentList":{ + "type":"list", + "member":{"shape":"RelevantTextDocument"}, + "max":30, + "min":0 + }, + "RelevantTextDocument":{ + "type":"structure", + "required":["relativeFilePath"], + "members":{ + "relativeFilePath":{"shape":"RelevantTextDocumentRelativeFilePathString"}, + "programmingLanguage":{"shape":"ProgrammingLanguage"}, + "text":{"shape":"RelevantTextDocumentTextString"}, + "documentSymbols":{"shape":"DocumentSymbols"} + } + }, + "RelevantTextDocumentRelativeFilePathString":{ + "type":"string", + "max":4096, + "min":1, + "sensitive":true + }, + "RelevantTextDocumentTextString":{ + "type":"string", + "max":40960, + "min":0, + "sensitive":true + }, + "Resource":{ + "type":"structure", + "required":[ + "title", + "link", + "description", + "type", + "ARN", + "resourceJsonString" ], - "members": { - "relativeFilePath": {"shape": "SensitiveString"}, - "programmingLanguage": {"shape": "ProgrammingLanguage"}, - "text": {"shape": "SensitiveString"}, - "documentSymbols": {"shape": "DocumentSymbols"} + "members":{ + "title":{"shape":"ResourceTitleString"}, + "link":{"shape":"ResourceLinkString"}, + "description":{"shape":"ResourceDescriptionString"}, + "type":{"shape":"ResourceTypeString"}, + "ARN":{"shape":"ResourceARNString"}, + "resourceJsonString":{"shape":"ResourceResourceJsonStringString"} } }, - "RelevantDocumentList": { - "type": "list", - "member": {"shape": "RelevantTextDocument"}, - "max": 5, - "min": 0 + "ResourceARNString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true }, "ResourceArn":{ "type":"string", @@ -513,6 +1082,32 @@ "min":0, "pattern":"arn:([-.a-z0-9]{1,63}:){2}([-.a-z0-9]{0,63}:){2}([a-zA-Z0-9-_:/]){1,1023}" }, + "ResourceDescriptionString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "ResourceLinkString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "ResourceList":{ + "type":"structure", + "required":["items"], + "members":{ + "action":{"shape":"Action"}, + "items":{"shape":"ResourceListItemsList"} + } + }, + "ResourceListItemsList":{ + "type":"list", + "member":{"shape":"Resource"}, + "max":10, + "min":0 + }, "ResourceNotFoundException":{ "type":"structure", "required":["message"], @@ -521,6 +1116,24 @@ }, "exception":true }, + "ResourceResourceJsonStringString":{ + "type":"string", + "max":8192, + "min":0, + "sensitive":true + }, + "ResourceTitleString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "ResourceTypeString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, "ResultArchiveStream":{ "type":"structure", "members":{ @@ -543,21 +1156,141 @@ "message":{"shape":"RuntimeDiagnosticMessageString"} } }, - "RuntimeDiagnosticMessageString":{ + "RuntimeDiagnosticMessageString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "RuntimeDiagnosticSourceString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "Section":{ + "type":"structure", + "required":[ + "title", + "content" + ], + "members":{ + "title":{"shape":"SectionTitleString"}, + "content":{"shape":"SectionContentList"}, + "action":{"shape":"Action"} + } + }, + "SectionComponent":{ + "type":"structure", + "members":{ + "text":{"shape":"Text"}, + "alert":{"shape":"Alert"}, + "resource":{"shape":"Resource"}, + "resourceList":{"shape":"ResourceList"} + } + }, + "SectionContentList":{ + "type":"list", + "member":{"shape":"SectionComponent"}, + "max":5, + "min":0 + }, + "SectionTitleString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "SendMessageRequest":{ + "type":"structure", + "required":["conversationState"], + "members":{ + "conversationState":{"shape":"ConversationState"}, + "profileArn":{"shape":"ProfileArn"}, + "source":{"shape":"Origin"}, + "dryRun":{"shape":"Boolean"} + } + }, + "SendMessageResponse":{ + "type":"structure", + "required":["sendMessageResponse"], + "members":{ + "sendMessageResponse":{"shape":"ChatResponseStream"} + } + }, + "SensitiveDocument":{ + "type":"structure", + "members":{ + }, + "document":true, + "sensitive":true + }, + "SensitiveString":{ + "type":"string", + "sensitive":true + }, + "ServiceQuotaExceededException":{ + "type":"structure", + "required":["message"], + "members":{ + "message":{"shape":"String"} + }, + "exception":true + }, + "ShellHistory":{ + "type":"list", + "member":{"shape":"ShellHistoryEntry"}, + "max":20, + "min":0 + }, + "ShellHistoryEntry":{ + "type":"structure", + "required":["command"], + "members":{ + "command":{"shape":"ShellHistoryEntryCommandString"}, + "directory":{"shape":"ShellHistoryEntryDirectoryString"}, + "exitCode":{"shape":"Integer"}, + "stdout":{"shape":"ShellHistoryEntryStdoutString"}, + "stderr":{"shape":"ShellHistoryEntryStderrString"} + } + }, + "ShellHistoryEntryCommandString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "ShellHistoryEntryDirectoryString":{ + "type":"string", + "max":256, + "min":1, + "sensitive":true + }, + "ShellHistoryEntryStderrString":{ "type":"string", - "max":1024, + "max":4096, "min":0, "sensitive":true }, - "RuntimeDiagnosticSourceString":{ + "ShellHistoryEntryStdoutString":{ "type":"string", - "max":1024, + "max":4096, "min":0, "sensitive":true }, - "SensitiveString":{ + "ShellState":{ + "type":"structure", + "required":["shellName"], + "members":{ + "shellName":{"shape":"ShellStateShellNameString"}, + "shellHistory":{"shape":"ShellHistory"} + } + }, + "ShellStateShellNameString":{ "type":"string", - "sensitive":true + "max":32, + "min":1, + "pattern":"(zsh|bash|fish|pwsh|nu)" }, "Span":{ "type":"structure", @@ -576,7 +1309,79 @@ "box":true, "min":0 }, + "Step":{ + "type":"structure", + "required":[ + "id", + "state", + "label" + ], + "members":{ + "id":{"shape":"StepIdInteger"}, + "state":{"shape":"StepState"}, + "label":{"shape":"StepLabelString"}, + "content":{"shape":"StepComponentList"} + } + }, + "StepComponent":{ + "type":"structure", + "members":{ + "text":{"shape":"Text"} + } + }, + "StepComponentList":{ + "type":"list", + "member":{"shape":"StepComponent"} + }, + "StepIdInteger":{ + "type":"integer", + "box":true, + "max":128, + "min":0 + }, + "StepLabelString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "StepState":{ + "type":"string", + "enum":[ + "FAILED", + "SUCCEEDED", + "STOPPED", + "PENDING", + "IN_PROGRESS", + "LOADING", + "PAUSED" + ] + }, "String":{"type":"string"}, + "Suggestion":{ + "type":"structure", + "required":["value"], + "members":{ + "value":{"shape":"SuggestionValueString"} + } + }, + "SuggestionList":{ + "type":"list", + "member":{"shape":"Suggestion"} + }, + "SuggestionValueString":{ + "type":"string", + "max":1000, + "min":1, + "sensitive":true + }, + "Suggestions":{ + "type":"structure", + "required":["items"], + "members":{ + "items":{"shape":"SuggestionList"} + } + }, "SupplementaryWebLink":{ "type":"structure", "required":[ @@ -627,12 +1432,161 @@ "USAGE" ] }, + "TaskAction":{ + "type":"structure", + "required":[ + "label", + "payload" + ], + "members":{ + "label":{"shape":"TaskActionLabelString"}, + "note":{"shape":"TaskActionNote"}, + "primary":{"shape":"Boolean"}, + "disabled":{"shape":"Boolean"}, + "payload":{"shape":"TaskActionPayload"}, + "confirmation":{"shape":"TaskActionConfirmation"} + } + }, + "TaskActionConfirmation":{ + "type":"structure", + "members":{ + "content":{"shape":"TaskActionConfirmationContentString"} + } + }, + "TaskActionConfirmationContentString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "TaskActionLabelString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "TaskActionList":{ + "type":"list", + "member":{"shape":"TaskAction"} + }, + "TaskActionNote":{ + "type":"structure", + "required":["content"], + "members":{ + "content":{"shape":"TaskActionNoteContentString"}, + "type":{"shape":"TaskActionNoteType"} + } + }, + "TaskActionNoteContentString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "TaskActionNoteType":{ + "type":"string", + "enum":[ + "INFO", + "WARNING" + ] + }, + "TaskActionPayload":{ + "type":"map", + "key":{"shape":"TaskActionPayloadKeyString"}, + "value":{"shape":"TaskActionPayloadValueString"}, + "max":32, + "min":0 + }, + "TaskActionPayloadKeyString":{ + "type":"string", + "max":1024, + "min":1 + }, + "TaskActionPayloadValueString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "TaskComponent":{ + "type":"structure", + "members":{ + "text":{"shape":"Text"}, + "infrastructureUpdate":{"shape":"InfrastructureUpdate"}, + "alert":{"shape":"Alert"}, + "progress":{"shape":"Progress"} + } + }, + "TaskComponentList":{ + "type":"list", + "member":{"shape":"TaskComponent"} + }, + "TaskDetails":{ + "type":"structure", + "required":[ + "overview", + "content" + ], + "members":{ + "overview":{"shape":"TaskOverview"}, + "content":{"shape":"TaskComponentList"}, + "actions":{"shape":"TaskActionList"} + } + }, + "TaskOverview":{ + "type":"structure", + "required":[ + "label", + "description" + ], + "members":{ + "label":{"shape":"TaskOverviewLabelString"}, + "description":{"shape":"TaskOverviewDescriptionString"} + } + }, + "TaskOverviewDescriptionString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "TaskOverviewLabelString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "TaskReference":{ + "type":"structure", + "required":["taskId"], + "members":{ + "taskId":{"shape":"TaskReferenceTaskIdString"} + } + }, + "TaskReferenceTaskIdString":{ + "type":"string", + "max":128, + "min":1 + }, "TestGenerationJobGroupName":{ "type":"string", "max":128, "min":1, "pattern":"[a-zA-Z0-9-_]+" }, + "Text":{ + "type":"structure", + "required":["content"], + "members":{ + "content":{"shape":"TextContentString"} + } + }, + "TextContentString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, "TextDocument":{ "type":"structure", "required":["relativeFilePath"], @@ -674,7 +1628,7 @@ }, "TextDocumentTextString":{ "type":"string", - "max":10240, + "max":40000, "min":0, "sensitive":true }, @@ -682,25 +1636,152 @@ "type":"structure", "required":["message"], "members":{ - "message":{"shape":"String"} + "message":{"shape":"String"}, + "reason":{"shape":"ThrottlingExceptionReason"} }, "exception":true, "retryable":{"throttling":true} }, - "ServiceQuotaExceededException":{ + "ThrottlingExceptionReason":{ + "type":"string", + "enum":["MONTHLY_REQUEST_COUNT"] + }, + "Tool":{ "type":"structure", - "required":["message"], "members":{ - "message":{"shape":"String"} + "toolSpecification":{"shape":"ToolSpecification"} }, - "exception":true, - "retryable":{"throttling":true} + "union":true + }, + "ToolDescription":{ + "type":"string", + "max":10240, + "min":1, + "sensitive":true + }, + "ToolInputSchema":{ + "type":"structure", + "members":{ + "json":{"shape":"SensitiveDocument"} + } + }, + "ToolName":{ + "type":"string", + "max":64, + "min":0, + "pattern":"[a-zA-Z][a-zA-Z0-9_]*", + "sensitive":true + }, + "ToolResult":{ + "type":"structure", + "required":[ + "toolUseId", + "content" + ], + "members":{ + "toolUseId":{"shape":"ToolUseId"}, + "content":{"shape":"ToolResultContent"}, + "status":{"shape":"ToolResultStatus"} + } + }, + "ToolResultContent":{ + "type":"list", + "member":{"shape":"ToolResultContentBlock"} + }, + "ToolResultContentBlock":{ + "type":"structure", + "members":{ + "text":{"shape":"ToolResultContentBlockTextString"}, + "json":{"shape":"SensitiveDocument"} + }, + "union":true + }, + "ToolResultContentBlockTextString":{ + "type":"string", + "max":30720, + "min":0, + "sensitive":true + }, + "ToolResultStatus":{ + "type":"string", + "enum":[ + "success", + "error" + ] + }, + "ToolResults":{ + "type":"list", + "member":{"shape":"ToolResult"}, + "max":10, + "min":0 + }, + "ToolSpecification":{ + "type":"structure", + "required":[ + "inputSchema", + "name" + ], + "members":{ + "inputSchema":{"shape":"ToolInputSchema"}, + "name":{"shape":"ToolName"}, + "description":{"shape":"ToolDescription"} + } + }, + "ToolUse":{ + "type":"structure", + "required":[ + "toolUseId", + "name", + "input" + ], + "members":{ + "toolUseId":{"shape":"ToolUseId"}, + "name":{"shape":"ToolName"}, + "input":{"shape":"SensitiveDocument"} + } + }, + "ToolUseEvent":{ + "type":"structure", + "required":[ + "toolUseId", + "name" + ], + "members":{ + "toolUseId":{"shape":"ToolUseId"}, + "name":{"shape":"ToolName"}, + "input":{"shape":"ToolUseEventInputString"}, + "stop":{"shape":"Boolean"} + }, + "event":true + }, + "ToolUseEventInputString":{ + "type":"string", + "max":10240, + "min":0, + "sensitive":true + }, + "ToolUseId":{ + "type":"string", + "max":64, + "min":0, + "pattern":"[a-zA-Z0-9_-]+" + }, + "ToolUses":{ + "type":"list", + "member":{"shape":"ToolUse"}, + "max":10, + "min":0 + }, + "Tools":{ + "type":"list", + "member":{"shape":"Tool"} }, "TransformationDownloadArtifactType":{ "type":"string", "enum":[ "ClientInstructions", - "Logs" + "Logs", + "GeneratedCode" ] }, "TransformationExportContext":{ @@ -738,12 +1819,14 @@ "members":{ "content":{"shape":"UserInputMessageContentString"}, "userInputMessageContext":{"shape":"UserInputMessageContext"}, - "userIntent":{"shape":"UserIntent"} + "userIntent":{"shape":"UserIntent"}, + "origin":{"shape":"Origin"}, + "images":{"shape":"ImageBlocks"} } }, "UserInputMessageContentString":{ "type":"string", - "max":4096, + "max":600000, "min":0, "sensitive":true }, @@ -751,7 +1834,16 @@ "type":"structure", "members":{ "editorState":{"shape":"EditorState"}, - "diagnostic":{"shape":"Diagnostic"} + "shellState":{"shape":"ShellState"}, + "gitState":{"shape":"GitState"}, + "envState":{"shape":"EnvState"}, + "appStudioContext":{"shape":"AppStudioState"}, + "diagnostic":{"shape":"Diagnostic"}, + "consoleState":{"shape":"ConsoleState"}, + "userSettings":{"shape":"UserSettings"}, + "additionalContext":{"shape":"AdditionalContentList"}, + "toolResults":{"shape":"ToolResults"}, + "tools":{"shape":"Tools"} } }, "UserIntent":{ @@ -764,9 +1856,17 @@ "CITE_SOURCES", "EXPLAIN_LINE_BY_LINE", "EXPLAIN_CODE_SELECTION", - "GENERATE_UNIT_TESTS" + "GENERATE_CLOUDFORMATION_TEMPLATE", + "GENERATE_UNIT_TESTS", + "CODE_GENERATION" ] }, + "UserSettings":{ + "type":"structure", + "members":{ + "hasConsentedToCrossRegionCalls":{"shape":"Boolean"} + } + }, "ValidationException":{ "type":"structure", "required":["message"], @@ -778,7 +1878,34 @@ }, "ValidationExceptionReason":{ "type":"string", - "enum":["INVALID_CONVERSATION_ID"] + "enum":[ + "INVALID_CONVERSATION_ID", + "CONTENT_LENGTH_EXCEEDS_THRESHOLD", + "INVALID_KMS_GRANT" + ] + }, + "WebLink":{ + "type":"structure", + "required":[ + "label", + "url" + ], + "members":{ + "label":{"shape":"WebLinkLabelString"}, + "url":{"shape":"WebLinkUrlString"} + } + }, + "WebLinkLabelString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, + "WebLinkUrlString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true }, "WorkspaceState":{ "type":"structure", From 4fb182151f40039b9588a1a7903d66c6293cccc5 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 11 Apr 2025 15:47:08 -0700 Subject: [PATCH 13/35] add profilearn --- .../jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt index bfba92510f2..6fb6381f21d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt @@ -61,6 +61,7 @@ class AmazonQStreamingClient(private val project: Project) { it.exportId(exportId) it.exportIntent(exportIntent) it.exportContext(exportContext) + it.profileArn(QRegionProfileManager.getInstance().getProfileArn(project)) }, ExportResultArchiveResponseHandler.builder().subscriber( ExportResultArchiveResponseHandler.Visitor.builder() From 4b92efa61bc7e3e2f0fe42680950e0fa34b7700d Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 11 Apr 2025 15:54:59 -0700 Subject: [PATCH 14/35] recover api --- .../codewhispererstreaming/service-2.json | 1224 +++++++++++++---- 1 file changed, 986 insertions(+), 238 deletions(-) diff --git a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json index 48aea822e55..778dbff05d9 100644 --- a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json +++ b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json @@ -2,14 +2,9 @@ "version":"2.0", "metadata":{ "apiVersion":"2023-11-27", - "auth":["smithy.api#httpBearerAuth"], "endpointPrefix":"amazoncodewhispererstreamingservice", "jsonVersion":"1.0", "protocol":"json", - "protocols":[ - "json", - "rest-json" - ], "serviceFullName":"Amazon CodeWhisperer Streaming", "serviceId":"CodeWhispererStreaming", "signatureVersion":"bearer", @@ -33,7 +28,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to export operation result as an archive

" }, "GenerateAssistantResponse":{ "name":"GenerateAssistantResponse", @@ -48,7 +44,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to generate assistant response.

" }, "GenerateTaskAssistPlan":{ "name":"GenerateTaskAssistPlan", @@ -66,7 +63,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to generate task assist plan.

" }, "SendMessage":{ "name":"SendMessage", @@ -96,10 +94,12 @@ "message":{"shape":"String"}, "reason":{"shape":"AccessDeniedExceptionReason"} }, + "documentation":"

This exception is thrown when the user does not have sufficient access to perform this action.

", "exception":true }, "AccessDeniedExceptionReason":{ "type":"string", + "documentation":"

Reason for AccessDeniedException

", "enum":["UNAUTHORIZED_CUSTOMIZATION_RESOURCE_ACCESS"] }, "Action":{ @@ -116,10 +116,20 @@ "description" ], "members":{ - "name":{"shape":"AdditionalContentEntryNameString"}, - "description":{"shape":"AdditionalContentEntryDescriptionString"}, - "innerContext":{"shape":"AdditionalContentEntryInnerContextString"} - } + "name":{ + "shape":"AdditionalContentEntryNameString", + "documentation":"

The name/identifier for this context entry

" + }, + "description":{ + "shape":"AdditionalContentEntryDescriptionString", + "documentation":"

A description of what this context entry represents

" + }, + "innerContext":{ + "shape":"AdditionalContentEntryInnerContextString", + "documentation":"

The actual contextual content

" + } + }, + "documentation":"

Structure representing a single entry of additional contextual content

" }, "AdditionalContentEntryDescriptionString":{ "type":"string", @@ -143,6 +153,7 @@ "AdditionalContentList":{ "type":"list", "member":{"shape":"AdditionalContentEntry"}, + "documentation":"

A list of additional content entries, limited to 20 items

", "max":20, "min":0 }, @@ -154,8 +165,12 @@ ], "members":{ "type":{"shape":"AlertType"}, - "content":{"shape":"AlertComponentList"} - } + "content":{ + "shape":"AlertComponentList", + "documentation":"

Contains the content of the alert, which may include sensitive information.

" + } + }, + "documentation":"

Structure representing an alert with a type and content.

" }, "AlertComponent":{ "type":"structure", @@ -169,6 +184,7 @@ }, "AlertType":{ "type":"string", + "documentation":"

Enum defining types of alerts that can be issued.

", "enum":[ "INFO", "ERROR", @@ -183,11 +199,24 @@ "propertyContext" ], "members":{ - "namespace":{"shape":"AppStudioStateNamespaceString"}, - "propertyName":{"shape":"AppStudioStatePropertyNameString"}, - "propertyValue":{"shape":"AppStudioStatePropertyValueString"}, - "propertyContext":{"shape":"AppStudioStatePropertyContextString"} - } + "namespace":{ + "shape":"AppStudioStateNamespaceString", + "documentation":"

The namespace of the context. Examples: 'ui.Button', 'ui.Table.DataSource', 'ui.Table.RowActions.Button', 'logic.invokeAWS', 'logic.JavaScript'

" + }, + "propertyName":{ + "shape":"AppStudioStatePropertyNameString", + "documentation":"

The name of the property. Examples: 'visibility', 'disability', 'value', 'code'

" + }, + "propertyValue":{ + "shape":"AppStudioStatePropertyValueString", + "documentation":"

The value of the property.

" + }, + "propertyContext":{ + "shape":"AppStudioStatePropertyContextString", + "documentation":"

Context about how the property is used

" + } + }, + "documentation":"

Description of a user's context when they are calling Q Chat from AppStudio

" }, "AppStudioStateNamespaceString":{ "type":"string", @@ -223,8 +252,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"AssistantResponseEventContentString"} + "content":{ + "shape":"AssistantResponseEventContentString", + "documentation":"

The content of the text message in markdown format.

" + } }, + "documentation":"

Streaming Response Event for Assistant Markdown text message.

", "event":true }, "AssistantResponseEventContentString":{ @@ -238,12 +271,28 @@ "required":["content"], "members":{ "messageId":{"shape":"MessageId"}, - "content":{"shape":"AssistantResponseMessageContentString"}, - "supplementaryWebLinks":{"shape":"SupplementaryWebLinks"}, - "references":{"shape":"References"}, - "followupPrompt":{"shape":"FollowupPrompt"}, - "toolUses":{"shape":"ToolUses"} - } + "content":{ + "shape":"AssistantResponseMessageContentString", + "documentation":"

The content of the text message in markdown format.

" + }, + "supplementaryWebLinks":{ + "shape":"SupplementaryWebLinks", + "documentation":"

Web References

" + }, + "references":{ + "shape":"References", + "documentation":"

Code References

" + }, + "followupPrompt":{ + "shape":"FollowupPrompt", + "documentation":"

Followup Prompt

" + }, + "toolUses":{ + "shape":"ToolUses", + "documentation":"

ToolUse Request

" + } + }, + "documentation":"

Markdown text message.

" }, "AssistantResponseMessageContentString":{ "type":"string", @@ -254,11 +303,24 @@ "BinaryMetadataEvent":{ "type":"structure", "members":{ - "size":{"shape":"Long"}, - "mimeType":{"shape":"String"}, - "contentChecksum":{"shape":"ContentChecksum"}, - "contentChecksumType":{"shape":"ContentChecksumType"} + "size":{ + "shape":"Long", + "documentation":"

Content length of the binary payload

" + }, + "mimeType":{ + "shape":"String", + "documentation":"

Content type of the response

" + }, + "contentChecksum":{ + "shape":"ContentChecksum", + "documentation":"

Content checksum of the binary payload

" + }, + "contentChecksumType":{ + "shape":"ContentChecksumType", + "documentation":"

Content checksum type of the binary payload

" + } }, + "documentation":"

Payload Part

", "event":true, "sensitive":true }, @@ -267,6 +329,7 @@ "members":{ "bytes":{"shape":"PartBody"} }, + "documentation":"

Payload Part

", "event":true, "sensitive":true }, @@ -277,7 +340,8 @@ "ChatHistory":{ "type":"list", "member":{"shape":"ChatMessage"}, - "max":100, + "documentation":"

Indicates Participant in Chat conversation

", + "max":250, "min":0 }, "ChatMessage":{ @@ -291,24 +355,69 @@ "ChatResponseStream":{ "type":"structure", "members":{ - "messageMetadataEvent":{"shape":"MessageMetadataEvent"}, - "assistantResponseEvent":{"shape":"AssistantResponseEvent"}, - "dryRunSucceedEvent":{"shape":"DryRunSucceedEvent"}, - "codeReferenceEvent":{"shape":"CodeReferenceEvent"}, - "supplementaryWebLinksEvent":{"shape":"SupplementaryWebLinksEvent"}, - "followupPromptEvent":{"shape":"FollowupPromptEvent"}, - "codeEvent":{"shape":"CodeEvent"}, - "intentsEvent":{"shape":"IntentsEvent"}, - "interactionComponentsEvent":{"shape":"InteractionComponentsEvent"}, - "toolUseEvent":{"shape":"ToolUseEvent"}, - "citationEvent":{"shape":"CitationEvent"}, - "invalidStateEvent":{"shape":"InvalidStateEvent"}, - "error":{"shape":"InternalServerException"} + "messageMetadataEvent":{ + "shape":"MessageMetadataEvent", + "documentation":"

Message Metadata event

" + }, + "assistantResponseEvent":{ + "shape":"AssistantResponseEvent", + "documentation":"

Assistant response event - Text / Code snippet

" + }, + "dryRunSucceedEvent":{ + "shape":"DryRunSucceedEvent", + "documentation":"

DryRun Succeed Event

" + }, + "codeReferenceEvent":{ + "shape":"CodeReferenceEvent", + "documentation":"

Code References event

" + }, + "supplementaryWebLinksEvent":{ + "shape":"SupplementaryWebLinksEvent", + "documentation":"

Web Reference links event

" + }, + "followupPromptEvent":{ + "shape":"FollowupPromptEvent", + "documentation":"

Followup prompt event

" + }, + "codeEvent":{ + "shape":"CodeEvent", + "documentation":"

Code Generated event

" + }, + "intentsEvent":{ + "shape":"IntentsEvent", + "documentation":"

Intents event

" + }, + "interactionComponentsEvent":{ + "shape":"InteractionComponentsEvent", + "documentation":"

Interactions components event

" + }, + "toolUseEvent":{ + "shape":"ToolUseEvent", + "documentation":"

ToolUse event

" + }, + "toolResultEvent":{ + "shape":"ToolResultEvent", + "documentation":"

Tool use result

" + }, + "citationEvent":{ + "shape":"CitationEvent", + "documentation":"

Citation event

" + }, + "invalidStateEvent":{ + "shape":"InvalidStateEvent", + "documentation":"

Invalid State event

" + }, + "error":{ + "shape":"InternalServerException", + "documentation":"

Internal Server Exception

" + } }, + "documentation":"

Streaming events from UniDirectional Streaming Conversational APIs.

", "eventstream":true }, "ChatTriggerType":{ "type":"string", + "documentation":"

Trigger Reason for Chat

", "enum":[ "MANUAL", "DIAGNOSTIC", @@ -322,18 +431,35 @@ "citationLink" ], "members":{ - "target":{"shape":"CitationTarget"}, - "citationText":{"shape":"SensitiveString"}, - "citationLink":{"shape":"SensitiveString"} + "target":{ + "shape":"CitationTarget", + "documentation":"

The position or the range of the response text to be cited

" + }, + "citationText":{ + "shape":"SensitiveString", + "documentation":"

The text inside the citation '1' in [1]

" + }, + "citationLink":{ + "shape":"SensitiveString", + "documentation":"

The link to the document being cited

" + } }, + "documentation":"

Streaming response event for citations

", "event":true }, "CitationTarget":{ "type":"structure", "members":{ - "location":{"shape":"Offset"}, - "range":{"shape":"Span"} + "location":{ + "shape":"Offset", + "documentation":"

Represents a position in the response text where a citation should be added

" + }, + "range":{ + "shape":"Span", + "documentation":"

Represents the range in the response text to be targetted by a citation

" + } }, + "documentation":"

Represents the target of a citation event

", "union":true }, "CloudWatchTroubleshootingLink":{ @@ -343,10 +469,20 @@ "investigationPayload" ], "members":{ - "label":{"shape":"CloudWatchTroubleshootingLinkLabelString"}, - "investigationPayload":{"shape":"CloudWatchTroubleshootingLinkInvestigationPayloadString"}, - "defaultText":{"shape":"CloudWatchTroubleshootingLinkDefaultTextString"} - } + "label":{ + "shape":"CloudWatchTroubleshootingLinkLabelString", + "documentation":"

A label for the link.

" + }, + "investigationPayload":{ + "shape":"CloudWatchTroubleshootingLinkInvestigationPayloadString", + "documentation":"

Stringified JSON payload. See spec here https://code.amazon.com/packages/CloudWatchOdysseyModel/blobs/50c0832f0e393e4ab68827eb4f04d832366821c1/--/model/events.smithy#L28 .

" + }, + "defaultText":{ + "shape":"CloudWatchTroubleshootingLinkDefaultTextString", + "documentation":"

Fallback string, if target channel does not support the CloudWatchTroubleshootingLink.

" + } + }, + "documentation":"

For CloudWatch Troubleshooting Link Module

" }, "CloudWatchTroubleshootingLinkDefaultTextString":{ "type":"string", @@ -366,12 +502,33 @@ "min":0, "sensitive":true }, + "CodeDescription":{ + "type":"structure", + "required":["href"], + "members":{ + "href":{ + "shape":"CodeDescriptionHrefString", + "documentation":"

An URI to open with more information about the diagnostic error.

" + } + }, + "documentation":"

Structure to capture a description for an error code.

" + }, + "CodeDescriptionHrefString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, "CodeEvent":{ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"CodeEventContentString"} + "content":{ + "shape":"CodeEventContentString", + "documentation":"

Generated code snippet.

" + } }, + "documentation":"

Streaming response event for generated code text.

", "event":true }, "CodeEventContentString":{ @@ -383,8 +540,12 @@ "CodeReferenceEvent":{ "type":"structure", "members":{ - "references":{"shape":"References"} + "references":{ + "shape":"References", + "documentation":"

Code References for Assistant Response Message

" + } }, + "documentation":"

Streaming Response Event for CodeReferences

", "event":true }, "ConflictException":{ @@ -394,10 +555,12 @@ "message":{"shape":"String"}, "reason":{"shape":"ConflictExceptionReason"} }, + "documentation":"

This exception is thrown when the action to perform could not be completed because the resource is in a conflicting state.

", "exception":true }, "ConflictExceptionReason":{ "type":"string", + "documentation":"

Reason for ConflictException

", "enum":[ "CUSTOMER_KMS_KEY_INVALID_KEY_POLICY", "CUSTOMER_KMS_KEY_DISABLED", @@ -413,7 +576,8 @@ "serviceConsolePage":{"shape":"String"}, "serviceSubconsolePage":{"shape":"String"}, "taskName":{"shape":"SensitiveString"} - } + }, + "documentation":"

Information about the state of the AWS management console page from which the user is calling

" }, "ContentChecksum":{ "type":"string", @@ -426,6 +590,7 @@ }, "ContextTruncationScheme":{ "type":"string", + "documentation":"

Workspace context truncation schemes based on usecase

", "enum":[ "ANALYSIS", "GUMBY" @@ -433,6 +598,7 @@ }, "ConversationId":{ "type":"string", + "documentation":"

ID which represents a multi-turn conversation

", "max":128, "min":1 }, @@ -443,31 +609,108 @@ "chatTriggerType" ], "members":{ - "conversationId":{"shape":"ConversationId"}, - "history":{"shape":"ChatHistory"}, - "currentMessage":{"shape":"ChatMessage"}, - "chatTriggerType":{"shape":"ChatTriggerType"}, + "conversationId":{ + "shape":"ConversationId", + "documentation":"

Unique identifier for the chat conversation stream

" + }, + "history":{ + "shape":"ChatHistory", + "documentation":"

Holds the history of chat messages.

" + }, + "currentMessage":{ + "shape":"ChatMessage", + "documentation":"

Holds the current message being processed or displayed.

" + }, + "chatTriggerType":{ + "shape":"ChatTriggerType", + "documentation":"

Trigger Reason for Chat

" + }, "customizationArn":{"shape":"ResourceArn"} - } + }, + "documentation":"

Structure to represent the current state of a chat conversation.

" }, "CursorState":{ "type":"structure", "members":{ - "position":{"shape":"Position"}, - "range":{"shape":"Range"} + "position":{ + "shape":"Position", + "documentation":"

Represents a cursor position in a Text Document

" + }, + "range":{ + "shape":"Range", + "documentation":"

Represents a text selection in a Text Document

" + } }, + "documentation":"

Represents the state of the Cursor in an Editor

", "union":true }, "Diagnostic":{ "type":"structure", "members":{ - "textDocumentDiagnostic":{"shape":"TextDocumentDiagnostic"}, - "runtimeDiagnostic":{"shape":"RuntimeDiagnostic"} + "textDocumentDiagnostic":{ + "shape":"TextDocumentDiagnostic", + "documentation":"

Diagnostics originating from a TextDocument

" + }, + "runtimeDiagnostic":{ + "shape":"RuntimeDiagnostic", + "documentation":"

Diagnostics originating from a Runtime

" + } }, + "documentation":"

Represents a Diagnostic message

", "union":true }, + "DiagnosticLocation":{ + "type":"structure", + "required":[ + "uri", + "range" + ], + "members":{ + "uri":{"shape":"DiagnosticLocationUriString"}, + "range":{"shape":"Range"} + }, + "documentation":"

Represents a location inside a resource, such as a line inside a text file.

" + }, + "DiagnosticLocationUriString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "DiagnosticRelatedInformation":{ + "type":"structure", + "required":[ + "location", + "message" + ], + "members":{ + "location":{ + "shape":"DiagnosticLocation", + "documentation":"

The location of this related diagnostic information.

" + }, + "message":{ + "shape":"DiagnosticRelatedInformationMessageString", + "documentation":"

The message of this related diagnostic information.

" + } + }, + "documentation":"

Represents a related message and source code location for a diagnostic.

" + }, + "DiagnosticRelatedInformationList":{ + "type":"list", + "member":{"shape":"DiagnosticRelatedInformation"}, + "documentation":"

List of DiagnosticRelatedInformation

", + "max":1024, + "min":0 + }, + "DiagnosticRelatedInformationMessageString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, "DiagnosticSeverity":{ "type":"string", + "documentation":"

Diagnostic Error types

", "enum":[ "ERROR", "WARNING", @@ -475,6 +718,21 @@ "HINT" ] }, + "DiagnosticTag":{ + "type":"string", + "documentation":"

The diagnostic tags.

", + "enum":[ + "UNNECESSARY", + "DEPRECATED" + ] + }, + "DiagnosticTagList":{ + "type":"list", + "member":{"shape":"DiagnosticTag"}, + "documentation":"

List of DiagnosticTag

", + "max":1024, + "min":0 + }, "DocumentSymbol":{ "type":"structure", "required":[ @@ -482,9 +740,18 @@ "type" ], "members":{ - "name":{"shape":"DocumentSymbolNameString"}, - "type":{"shape":"SymbolType"}, - "source":{"shape":"DocumentSymbolSourceString"} + "name":{ + "shape":"DocumentSymbolNameString", + "documentation":"

Name of the Document Symbol

" + }, + "type":{ + "shape":"SymbolType", + "documentation":"

Symbol type - DECLARATION / USAGE

" + }, + "source":{ + "shape":"DocumentSymbolSourceString", + "documentation":"

Symbol package / source for FullyQualified names

" + } } }, "DocumentSymbolNameString":{ @@ -509,31 +776,63 @@ "message":{"shape":"String"}, "responseCode":{"shape":"Integer"} }, + "documentation":"

This exception is translated to a 204 as it succeeded the IAM Auth.

", "exception":true }, "DryRunSucceedEvent":{ "type":"structure", "members":{ }, + "documentation":"

Streaming Response Event when DryRun is succeessful

", "event":true }, "EditorState":{ "type":"structure", "members":{ - "document":{"shape":"TextDocument"}, - "cursorState":{"shape":"CursorState"}, - "relevantDocuments":{"shape":"RelevantDocumentList"}, - "useRelevantDocuments":{"shape":"Boolean"} - } + "document":{ + "shape":"TextDocument", + "documentation":"

Represents currently edited file

" + }, + "cursorState":{ + "shape":"CursorState", + "documentation":"

Position of the cursor

" + }, + "relevantDocuments":{ + "shape":"RelevantDocumentList", + "documentation":"

Represents IDE provided relevant files

" + }, + "useRelevantDocuments":{ + "shape":"Boolean", + "documentation":"

Whether service should use relevant document in prompt

" + }, + "workspaceFolders":{ + "shape":"WorkspaceFolderList", + "documentation":"

Represents IDE provided list of workspace folders

" + } + }, + "documentation":"

Represents the state of an Editor

" }, "EnvState":{ "type":"structure", "members":{ - "operatingSystem":{"shape":"EnvStateOperatingSystemString"}, - "currentWorkingDirectory":{"shape":"EnvStateCurrentWorkingDirectoryString"}, - "environmentVariables":{"shape":"EnvironmentVariables"}, - "timezoneOffset":{"shape":"EnvStateTimezoneOffsetInteger"} - } + "operatingSystem":{ + "shape":"EnvStateOperatingSystemString", + "documentation":"

The name of the operating system in use

" + }, + "currentWorkingDirectory":{ + "shape":"EnvStateCurrentWorkingDirectoryString", + "documentation":"

The current working directory of the environment

" + }, + "environmentVariables":{ + "shape":"EnvironmentVariables", + "documentation":"

The environment variables set in the current environment

" + }, + "timezoneOffset":{ + "shape":"EnvStateTimezoneOffsetInteger", + "documentation":"

Local timezone offset of the client. For more information, see documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset

" + } + }, + "documentation":"

State related to the user's environment

" }, "EnvStateCurrentWorkingDirectoryString":{ "type":"string", @@ -556,9 +855,16 @@ "EnvironmentVariable":{ "type":"structure", "members":{ - "key":{"shape":"EnvironmentVariableKeyString"}, - "value":{"shape":"EnvironmentVariableValueString"} - } + "key":{ + "shape":"EnvironmentVariableKeyString", + "documentation":"

The key of an environment variable

" + }, + "value":{ + "shape":"EnvironmentVariableValueString", + "documentation":"

The value of an environment variable

" + } + }, + "documentation":"

An environment variable

" }, "EnvironmentVariableKeyString":{ "type":"string", @@ -575,6 +881,7 @@ "EnvironmentVariables":{ "type":"list", "member":{"shape":"EnvironmentVariable"}, + "documentation":"

A list of environment variables

", "max":100, "min":0 }, @@ -584,10 +891,12 @@ "transformationExportContext":{"shape":"TransformationExportContext"}, "unitTestGenerationExportContext":{"shape":"UnitTestGenerationExportContext"} }, + "documentation":"

Export Context

", "union":true }, "ExportIntent":{ "type":"string", + "documentation":"

Export Intent

", "enum":[ "TRANSFORMATION", "TASK_ASSIST", @@ -605,7 +914,8 @@ "exportIntent":{"shape":"ExportIntent"}, "exportContext":{"shape":"ExportContext"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent a new ExportResultArchive request.

" }, "ExportResultArchiveRequestExportIdString":{ "type":"string", @@ -617,15 +927,23 @@ "required":["body"], "members":{ "body":{"shape":"ResultArchiveStream"} - } + }, + "documentation":"

Structure to represent ExportResultArchive response.

" }, "FollowupPrompt":{ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"FollowupPromptContentString"}, - "userIntent":{"shape":"UserIntent"} - } + "content":{ + "shape":"FollowupPromptContentString", + "documentation":"

The content of the text message in markdown format.

" + }, + "userIntent":{ + "shape":"UserIntent", + "documentation":"

User Intent

" + } + }, + "documentation":"

Followup Prompt for the Assistant Response

" }, "FollowupPromptContentString":{ "type":"string", @@ -638,6 +956,7 @@ "members":{ "followupPrompt":{"shape":"FollowupPrompt"} }, + "documentation":"

Streaming Response Event for Followup Prompt.

", "event":true }, "GenerateAssistantResponseRequest":{ @@ -646,7 +965,8 @@ "members":{ "conversationState":{"shape":"ConversationState"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent a new generate assistant response request.

" }, "GenerateAssistantResponseResponse":{ "type":"structure", @@ -657,7 +977,8 @@ "members":{ "conversationId":{"shape":"ConversationId"}, "generateAssistantResponseResponse":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent generate assistant response response.

" }, "GenerateTaskAssistPlanRequest":{ "type":"structure", @@ -669,19 +990,25 @@ "conversationState":{"shape":"ConversationState"}, "workspaceState":{"shape":"WorkspaceState"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent execute planning interaction request.

" }, "GenerateTaskAssistPlanResponse":{ "type":"structure", "members":{ "planningResponseStream":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent execute planning interaction response.

" }, "GitState":{ "type":"structure", "members":{ - "status":{"shape":"GitStateStatusString"} - } + "status":{ + "shape":"GitStateStatusString", + "documentation":"

The output of the command git status --porcelain=v1 -b

" + } + }, + "documentation":"

State related to the Git VSC

" }, "GitStateStatusString":{ "type":"string", @@ -698,7 +1025,8 @@ "members":{ "format":{"shape":"ImageFormat"}, "source":{"shape":"ImageSource"} - } + }, + "documentation":"

Represents the image source itself and the format of the image.

" }, "ImageBlocks":{ "type":"list", @@ -720,6 +1048,7 @@ "members":{ "bytes":{"shape":"ImageSourceBytesBlob"} }, + "documentation":"

Image bytes limited to ~10MB considering overhead of base64 encoding

", "sensitive":true, "union":true }, @@ -732,7 +1061,8 @@ "type":"structure", "members":{ "transition":{"shape":"InfrastructureUpdateTransition"} - } + }, + "documentation":"

Structure representing different types of infrastructure updates.

" }, "InfrastructureUpdateTransition":{ "type":"structure", @@ -741,9 +1071,16 @@ "nextState" ], "members":{ - "currentState":{"shape":"InfrastructureUpdateTransitionCurrentStateString"}, - "nextState":{"shape":"InfrastructureUpdateTransitionNextStateString"} - } + "currentState":{ + "shape":"InfrastructureUpdateTransitionCurrentStateString", + "documentation":"

The current state of the infrastructure before the update.

" + }, + "nextState":{ + "shape":"InfrastructureUpdateTransitionNextStateString", + "documentation":"

The next state of the infrastructure following the update.

" + } + }, + "documentation":"

Structure describing a transition between two states in an infrastructure update.

" }, "InfrastructureUpdateTransitionCurrentStateString":{ "type":"string", @@ -794,8 +1131,12 @@ "IntentsEvent":{ "type":"structure", "members":{ - "intents":{"shape":"IntentMap"} + "intents":{ + "shape":"IntentMap", + "documentation":"

A map of Intent objects

" + } }, + "documentation":"

Streaming Response Event for Intents

", "event":true }, "InteractionComponent":{ @@ -813,22 +1154,32 @@ "resource":{"shape":"Resource"}, "resourceList":{"shape":"ResourceList"}, "action":{"shape":"Action"} - } + }, + "documentation":"

Structure representing different types of interaction components.

" }, "InteractionComponentEntry":{ "type":"structure", "required":["interactionComponent"], "members":{ - "interactionComponentId":{"shape":"InteractionComponentId"}, - "interactionComponent":{"shape":"InteractionComponent"} - } + "interactionComponentId":{ + "shape":"InteractionComponentId", + "documentation":"

Identifier that can uniquely identify the interaction component within stream response. This field is optional.

" + }, + "interactionComponent":{ + "shape":"InteractionComponent", + "documentation":"

Interaction component

" + } + }, + "documentation":"

Interaction component with an identifier

" }, "InteractionComponentEntryList":{ "type":"list", - "member":{"shape":"InteractionComponentEntry"} + "member":{"shape":"InteractionComponentEntry"}, + "documentation":"

List of identifiable interaction components

" }, "InteractionComponentId":{ "type":"string", + "documentation":"

Unique identifier for interaction component

", "max":128, "min":0 }, @@ -836,8 +1187,12 @@ "type":"structure", "required":["interactionComponentEntries"], "members":{ - "interactionComponentEntries":{"shape":"InteractionComponentEntryList"} + "interactionComponentEntries":{ + "shape":"InteractionComponentEntryList", + "documentation":"

List of identifiable interaction components

" + } }, + "documentation":"

Streaming Event for interaction components list

", "event":true }, "InternalServerException":{ @@ -846,6 +1201,7 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when an unexpected error occurred during the processing of a request.

", "exception":true, "fault":true, "retryable":{"throttling":false} @@ -860,6 +1216,7 @@ "reason":{"shape":"InvalidStateReason"}, "message":{"shape":"InvalidStateEventMessageString"} }, + "documentation":"

Streaming Response Event when an Invalid State is reached

", "event":true }, "InvalidStateEventMessageString":{ @@ -869,6 +1226,7 @@ }, "InvalidStateReason":{ "type":"string", + "documentation":"

Reasons for Invalid State Event

", "enum":["INVALID_TASK_ASSIST_PLAN"] }, "Long":{ @@ -877,15 +1235,23 @@ }, "MessageId":{ "type":"string", + "documentation":"

Unique identifier for the chat message

", "max":128, "min":0 }, "MessageMetadataEvent":{ "type":"structure", "members":{ - "conversationId":{"shape":"MessageMetadataEventConversationIdString"}, - "utteranceId":{"shape":"MessageMetadataEventUtteranceIdString"} + "conversationId":{ + "shape":"MessageMetadataEventConversationIdString", + "documentation":"

Unique identifier for the conversation

" + }, + "utteranceId":{ + "shape":"MessageMetadataEventUtteranceIdString", + "documentation":"

Unique identifier for the utterance

" + } }, + "documentation":"

Streaming Response Event for AssistantResponse Metadata

", "event":true }, "MessageMetadataEventConversationIdString":{ @@ -906,11 +1272,13 @@ }, "Offset":{ "type":"integer", + "documentation":"

Offset in the response text

", "box":true, "min":0 }, "Origin":{ "type":"string", + "documentation":"

Enum to represent the origin application conversing with Sidekick.

", "enum":[ "CHATBOT", "CONSOLE", @@ -931,6 +1299,7 @@ }, "PartBody":{ "type":"blob", + "documentation":"

Payload Part's body

", "max":1000000, "min":0, "sensitive":true @@ -942,9 +1311,16 @@ "character" ], "members":{ - "line":{"shape":"Integer"}, - "character":{"shape":"Integer"} - } + "line":{ + "shape":"Integer", + "documentation":"

Line position in a document.

" + }, + "character":{ + "shape":"Integer", + "documentation":"

Character offset on a line in a document (zero-based)

" + } + }, + "documentation":"

Indicates Cursor postion in a Text Document

" }, "ProfileArn":{ "type":"string", @@ -957,7 +1333,8 @@ "required":["languageName"], "members":{ "languageName":{"shape":"ProgrammingLanguageLanguageNameString"} - } + }, + "documentation":"

Programming Languages supported by CodeWhisperer

" }, "ProgrammingLanguageLanguageNameString":{ "type":"string", @@ -969,8 +1346,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"ProgressComponentList"} - } + "content":{ + "shape":"ProgressComponentList", + "documentation":"

A collection of steps that make up a process. Each step is detailed using the Step structure.

" + } + }, + "documentation":"

Structure representing a collection of steps in a process.

" }, "ProgressComponent":{ "type":"structure", @@ -989,18 +1370,38 @@ "end" ], "members":{ - "start":{"shape":"Position"}, - "end":{"shape":"Position"} - } + "start":{ + "shape":"Position", + "documentation":"

The range's start position.

" + }, + "end":{ + "shape":"Position", + "documentation":"

The range's end position.

" + } + }, + "documentation":"

Indicates Range / Span in a Text Document

" }, "Reference":{ "type":"structure", "members":{ - "licenseName":{"shape":"ReferenceLicenseNameString"}, - "repository":{"shape":"ReferenceRepositoryString"}, - "url":{"shape":"ReferenceUrlString"}, - "recommendationContentSpan":{"shape":"Span"} - } + "licenseName":{ + "shape":"ReferenceLicenseNameString", + "documentation":"

License name

" + }, + "repository":{ + "shape":"ReferenceRepositoryString", + "documentation":"

Code Repsitory for the associated reference

" + }, + "url":{ + "shape":"ReferenceUrlString", + "documentation":"

Respository URL

" + }, + "recommendationContentSpan":{ + "shape":"Span", + "documentation":"

Span / Range for the Reference

" + } + }, + "documentation":"

Code Reference / Repository details

" }, "ReferenceLicenseNameString":{ "type":"string", @@ -1033,11 +1434,24 @@ "type":"structure", "required":["relativeFilePath"], "members":{ - "relativeFilePath":{"shape":"RelevantTextDocumentRelativeFilePathString"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "text":{"shape":"RelevantTextDocumentTextString"}, - "documentSymbols":{"shape":"DocumentSymbols"} - } + "relativeFilePath":{ + "shape":"RelevantTextDocumentRelativeFilePathString", + "documentation":"

Filepath relative to the root of the workspace

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

The text document's language identifier.

" + }, + "text":{ + "shape":"RelevantTextDocumentTextString", + "documentation":"

Content of the text document

" + }, + "documentSymbols":{ + "shape":"DocumentSymbols", + "documentation":"

DocumentSymbols parsed from a text document

" + } + }, + "documentation":"

Represents an IDE retrieved relevant Text Document / File

" }, "RelevantTextDocumentRelativeFilePathString":{ "type":"string", @@ -1062,13 +1476,32 @@ "resourceJsonString" ], "members":{ - "title":{"shape":"ResourceTitleString"}, - "link":{"shape":"ResourceLinkString"}, - "description":{"shape":"ResourceDescriptionString"}, - "type":{"shape":"ResourceTypeString"}, - "ARN":{"shape":"ResourceARNString"}, - "resourceJsonString":{"shape":"ResourceResourceJsonStringString"} - } + "title":{ + "shape":"ResourceTitleString", + "documentation":"

Card title.

" + }, + "link":{ + "shape":"ResourceLinkString", + "documentation":"

Link for the resource item

" + }, + "description":{ + "shape":"ResourceDescriptionString", + "documentation":"

Short text about that resource for example Region: us-east-1

" + }, + "type":{ + "shape":"ResourceTypeString", + "documentation":"

Resource type e.g AWS EC2

" + }, + "ARN":{ + "shape":"ResourceARNString", + "documentation":"

Amazon resource number e.g arn:aws:aec:.....

" + }, + "resourceJsonString":{ + "shape":"ResourceResourceJsonStringString", + "documentation":"

A stringified object

" + } + }, + "documentation":"

Structure representing a resource item

" }, "ResourceARNString":{ "type":"string", @@ -1098,13 +1531,21 @@ "type":"structure", "required":["items"], "members":{ - "action":{"shape":"Action"}, - "items":{"shape":"ResourceListItemsList"} - } + "action":{ + "shape":"Action", + "documentation":"

Action associated with the list

" + }, + "items":{ + "shape":"ResourceListItemsList", + "documentation":"

List of resources

" + } + }, + "documentation":"

Structure representing a list of Items

" }, "ResourceListItemsList":{ "type":"list", "member":{"shape":"Resource"}, + "documentation":"

List for resources

", "max":10, "min":0 }, @@ -1114,6 +1555,7 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when describing a resource that does not exist.

", "exception":true }, "ResourceResourceJsonStringString":{ @@ -1141,6 +1583,7 @@ "binaryPayloadEvent":{"shape":"BinaryPayloadEvent"}, "internalServerException":{"shape":"InternalServerException"} }, + "documentation":"

Response Stream

", "eventstream":true }, "RuntimeDiagnostic":{ @@ -1151,10 +1594,20 @@ "message" ], "members":{ - "source":{"shape":"RuntimeDiagnosticSourceString"}, - "severity":{"shape":"DiagnosticSeverity"}, - "message":{"shape":"RuntimeDiagnosticMessageString"} - } + "source":{ + "shape":"RuntimeDiagnosticSourceString", + "documentation":"

A human-readable string describing the source of the diagnostic

" + }, + "severity":{ + "shape":"DiagnosticSeverity", + "documentation":"

Diagnostic Error type

" + }, + "message":{ + "shape":"RuntimeDiagnosticMessageString", + "documentation":"

The diagnostic's message.

" + } + }, + "documentation":"

Structure to represent metadata about a Runtime Diagnostics

" }, "RuntimeDiagnosticMessageString":{ "type":"string", @@ -1175,10 +1628,20 @@ "content" ], "members":{ - "title":{"shape":"SectionTitleString"}, - "content":{"shape":"SectionContentList"}, - "action":{"shape":"Action"} - } + "title":{ + "shape":"SectionTitleString", + "documentation":"

Contains text content that may include sensitive information and can support Markdown formatting.

" + }, + "content":{ + "shape":"SectionContentList", + "documentation":"

Contains a list of interaction components e.g Text, Alert, List, etc.

" + }, + "action":{ + "shape":"Action", + "documentation":"

Action associated with the Section

" + } + }, + "documentation":"

Structure representing a collapsable section

" }, "SectionComponent":{ "type":"structure", @@ -1207,16 +1670,21 @@ "members":{ "conversationState":{"shape":"ConversationState"}, "profileArn":{"shape":"ProfileArn"}, - "source":{"shape":"Origin"}, + "source":{ + "shape":"Origin", + "documentation":"

The origin of the caller

" + }, "dryRun":{"shape":"Boolean"} - } + }, + "documentation":"

Structure to represent a SendMessage request.

" }, "SendMessageResponse":{ "type":"structure", "required":["sendMessageResponse"], "members":{ "sendMessageResponse":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent a SendMessage response.

" }, "SensitiveDocument":{ "type":"structure", @@ -1235,11 +1703,13 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when request was denied due to caller exceeding their usage limits

", "exception":true }, "ShellHistory":{ "type":"list", "member":{"shape":"ShellHistoryEntry"}, + "documentation":"

A list of shell history entries

", "max":20, "min":0 }, @@ -1247,12 +1717,28 @@ "type":"structure", "required":["command"], "members":{ - "command":{"shape":"ShellHistoryEntryCommandString"}, - "directory":{"shape":"ShellHistoryEntryDirectoryString"}, - "exitCode":{"shape":"Integer"}, - "stdout":{"shape":"ShellHistoryEntryStdoutString"}, - "stderr":{"shape":"ShellHistoryEntryStderrString"} - } + "command":{ + "shape":"ShellHistoryEntryCommandString", + "documentation":"

The shell command that was run

" + }, + "directory":{ + "shape":"ShellHistoryEntryDirectoryString", + "documentation":"

The directory the command was ran in

" + }, + "exitCode":{ + "shape":"Integer", + "documentation":"

The exit code of the command after it finished

" + }, + "stdout":{ + "shape":"ShellHistoryEntryStdoutString", + "documentation":"

The stdout from the command

" + }, + "stderr":{ + "shape":"ShellHistoryEntryStderrString", + "documentation":"

The stderr from the command

" + } + }, + "documentation":"

An single entry in the shell history

" }, "ShellHistoryEntryCommandString":{ "type":"string", @@ -1282,9 +1768,16 @@ "type":"structure", "required":["shellName"], "members":{ - "shellName":{"shape":"ShellStateShellNameString"}, - "shellHistory":{"shape":"ShellHistory"} - } + "shellName":{ + "shape":"ShellStateShellNameString", + "documentation":"

The name of the current shell

" + }, + "shellHistory":{ + "shape":"ShellHistory", + "documentation":"

The history previous shell commands for the current shell

" + } + }, + "documentation":"

Represents the state of a shell

" }, "ShellStateShellNameString":{ "type":"string", @@ -1297,7 +1790,8 @@ "members":{ "start":{"shape":"SpanStartInteger"}, "end":{"shape":"SpanEndInteger"} - } + }, + "documentation":"

Represents span in a text.

" }, "SpanEndInteger":{ "type":"integer", @@ -1317,11 +1811,21 @@ "label" ], "members":{ - "id":{"shape":"StepIdInteger"}, + "id":{ + "shape":"StepIdInteger", + "documentation":"

A unique identifier for the step. It must be a non-negative integer to ensure each step is distinct.

" + }, "state":{"shape":"StepState"}, - "label":{"shape":"StepLabelString"}, - "content":{"shape":"StepComponentList"} - } + "label":{ + "shape":"StepLabelString", + "documentation":"

A label for the step, providing a concise description.

" + }, + "content":{ + "shape":"StepComponentList", + "documentation":"

Optional content providing additional details about the step.

" + } + }, + "documentation":"

Structure representing an individual step in a process.

" }, "StepComponent":{ "type":"structure", @@ -1347,6 +1851,7 @@ }, "StepState":{ "type":"string", + "documentation":"

Enum representing all possible step states, combining terminal and non-terminal states.

", "enum":[ "FAILED", "SUCCEEDED", @@ -1363,7 +1868,8 @@ "required":["value"], "members":{ "value":{"shape":"SuggestionValueString"} - } + }, + "documentation":"

Structure representing a suggestion for follow-ups.

" }, "SuggestionList":{ "type":"list", @@ -1380,7 +1886,8 @@ "required":["items"], "members":{ "items":{"shape":"SuggestionList"} - } + }, + "documentation":"

Structure containing a list of suggestions.

" }, "SupplementaryWebLink":{ "type":"structure", @@ -1389,10 +1896,20 @@ "title" ], "members":{ - "url":{"shape":"SupplementaryWebLinkUrlString"}, - "title":{"shape":"SupplementaryWebLinkTitleString"}, - "snippet":{"shape":"SupplementaryWebLinkSnippetString"} - } + "url":{ + "shape":"SupplementaryWebLinkUrlString", + "documentation":"

URL of the web reference link.

" + }, + "title":{ + "shape":"SupplementaryWebLinkTitleString", + "documentation":"

Title of the web reference link.

" + }, + "snippet":{ + "shape":"SupplementaryWebLinkSnippetString", + "documentation":"

Relevant text snippet from the link.

" + } + }, + "documentation":"

Represents an additional reference link retured with the Chat message

" }, "SupplementaryWebLinkSnippetString":{ "type":"string", @@ -1421,8 +1938,12 @@ "SupplementaryWebLinksEvent":{ "type":"structure", "members":{ - "supplementaryWebLinks":{"shape":"SupplementaryWebLinks"} + "supplementaryWebLinks":{ + "shape":"SupplementaryWebLinks", + "documentation":"

Web References for Assistant Response Message

" + } }, + "documentation":"

Streaming Response Event for SupplementaryWebLinks

", "event":true }, "SymbolType":{ @@ -1439,19 +1960,33 @@ "payload" ], "members":{ - "label":{"shape":"TaskActionLabelString"}, + "label":{ + "shape":"TaskActionLabelString", + "documentation":"

A label for the action.

" + }, "note":{"shape":"TaskActionNote"}, - "primary":{"shape":"Boolean"}, - "disabled":{"shape":"Boolean"}, + "primary":{ + "shape":"Boolean", + "documentation":"

Indicates whether the action is primary or not.

" + }, + "disabled":{ + "shape":"Boolean", + "documentation":"

Indicates whether the action is disabled or not.

" + }, "payload":{"shape":"TaskActionPayload"}, "confirmation":{"shape":"TaskActionConfirmation"} - } + }, + "documentation":"

Structure representing an action associated with a task.

" }, "TaskActionConfirmation":{ "type":"structure", "members":{ - "content":{"shape":"TaskActionConfirmationContentString"} - } + "content":{ + "shape":"TaskActionConfirmationContentString", + "documentation":"

Confirmation message related to the action note, which may include sensitive information.

" + } + }, + "documentation":"

Structure representing a confirmation message related to a task action.

" }, "TaskActionConfirmationContentString":{ "type":"string", @@ -1473,9 +2008,13 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"TaskActionNoteContentString"}, + "content":{ + "shape":"TaskActionNoteContentString", + "documentation":"

Content of the note, which may include sensitive information.

" + }, "type":{"shape":"TaskActionNoteType"} - } + }, + "documentation":"

Structure representing a note associated with a task action.

" }, "TaskActionNoteContentString":{ "type":"string", @@ -1485,6 +2024,7 @@ }, "TaskActionNoteType":{ "type":"string", + "documentation":"

Enum defining the types of notes that can be associated with a task action.

", "enum":[ "INFO", "WARNING" @@ -1492,8 +2032,15 @@ }, "TaskActionPayload":{ "type":"map", - "key":{"shape":"TaskActionPayloadKeyString"}, - "value":{"shape":"TaskActionPayloadValueString"}, + "key":{ + "shape":"TaskActionPayloadKeyString", + "documentation":"

The key for the payload entry.

" + }, + "value":{ + "shape":"TaskActionPayloadValueString", + "documentation":"

The sensitive value associated with the key.

" + }, + "documentation":"

Map representing key-value pairs for the payload of a task action.

", "max":32, "min":0 }, @@ -1515,7 +2062,8 @@ "infrastructureUpdate":{"shape":"InfrastructureUpdate"}, "alert":{"shape":"Alert"}, "progress":{"shape":"Progress"} - } + }, + "documentation":"

Structure representing different types of components that can be part of a task.

" }, "TaskComponentList":{ "type":"list", @@ -1529,9 +2077,16 @@ ], "members":{ "overview":{"shape":"TaskOverview"}, - "content":{"shape":"TaskComponentList"}, - "actions":{"shape":"TaskActionList"} - } + "content":{ + "shape":"TaskComponentList", + "documentation":"

Lists the components that can be used to form the task's content.

" + }, + "actions":{ + "shape":"TaskActionList", + "documentation":"

Optional list of actions associated with the task.

" + } + }, + "documentation":"

Structure containing details about a task.

" }, "TaskOverview":{ "type":"structure", @@ -1540,9 +2095,16 @@ "description" ], "members":{ - "label":{"shape":"TaskOverviewLabelString"}, - "description":{"shape":"TaskOverviewDescriptionString"} - } + "label":{ + "shape":"TaskOverviewLabelString", + "documentation":"

A label for the task overview.

" + }, + "description":{ + "shape":"TaskOverviewDescriptionString", + "documentation":"

Text description providing details about the task. This field may include sensitive information and supports Markdown formatting.

" + } + }, + "documentation":"

Structure representing an overview of a task, including a label and description.

" }, "TaskOverviewDescriptionString":{ "type":"string", @@ -1560,8 +2122,12 @@ "type":"structure", "required":["taskId"], "members":{ - "taskId":{"shape":"TaskReferenceTaskIdString"} - } + "taskId":{ + "shape":"TaskReferenceTaskIdString", + "documentation":"

Unique identifier for the task.

" + } + }, + "documentation":"

Structure representing a reference to a task.

" }, "TaskReferenceTaskIdString":{ "type":"string", @@ -1570,6 +2136,7 @@ }, "TestGenerationJobGroupName":{ "type":"string", + "documentation":"

Test generation job group name

", "max":128, "min":1, "pattern":"[a-zA-Z0-9-_]+" @@ -1578,8 +2145,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"TextContentString"} - } + "content":{ + "shape":"TextContentString", + "documentation":"

Contains text content that may include sensitive information and can support Markdown formatting.

" + } + }, + "documentation":"

Structure representing a simple text component with sensitive content, which can include Markdown formatting.

" }, "TextContentString":{ "type":"string", @@ -1591,11 +2162,24 @@ "type":"structure", "required":["relativeFilePath"], "members":{ - "relativeFilePath":{"shape":"TextDocumentRelativeFilePathString"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "text":{"shape":"TextDocumentTextString"}, - "documentSymbols":{"shape":"DocumentSymbols"} - } + "relativeFilePath":{ + "shape":"TextDocumentRelativeFilePathString", + "documentation":"

Filepath relative to the root of the workspace

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

The text document's language identifier.

" + }, + "text":{ + "shape":"TextDocumentTextString", + "documentation":"

Content of the text document

" + }, + "documentSymbols":{ + "shape":"DocumentSymbols", + "documentation":"

DocumentSymbols parsed from a text document

" + } + }, + "documentation":"

Represents a Text Document / File

" }, "TextDocumentDiagnostic":{ "type":"structure", @@ -1607,12 +2191,54 @@ "message" ], "members":{ - "document":{"shape":"TextDocument"}, - "range":{"shape":"Range"}, - "source":{"shape":"SensitiveString"}, - "severity":{"shape":"DiagnosticSeverity"}, - "message":{"shape":"TextDocumentDiagnosticMessageString"} - } + "document":{ + "shape":"TextDocument", + "documentation":"

Represents a Text Document associated with Diagnostic

" + }, + "range":{ + "shape":"Range", + "documentation":"

The range at which the message applies.

" + }, + "source":{ + "shape":"SensitiveString", + "documentation":"

A human-readable string describing the source of the diagnostic

" + }, + "severity":{ + "shape":"DiagnosticSeverity", + "documentation":"

Diagnostic Error type

" + }, + "message":{ + "shape":"TextDocumentDiagnosticMessageString", + "documentation":"

The diagnostic's message.

" + }, + "code":{ + "shape":"Integer", + "documentation":"

The diagnostic's code, which might appear in the user interface.

" + }, + "codeDescription":{ + "shape":"CodeDescription", + "documentation":"

An optional property to describe the error code.

" + }, + "tags":{ + "shape":"DiagnosticTagList", + "documentation":"

Additional metadata about the diagnostic.

" + }, + "relatedInformation":{ + "shape":"DiagnosticRelatedInformationList", + "documentation":"

an array of related diagnostic information, e.g. when symbol-names within a scope collide all definitions can be marked via this property.

" + }, + "data":{ + "shape":"TextDocumentDiagnosticDataString", + "documentation":"

A data entry field that is preserved between a textDocument/publishDiagnostics notification and textDocument/codeAction request.

" + } + }, + "documentation":"

Structure to represent metadata about a TextDocument Diagnostic

" + }, + "TextDocumentDiagnosticDataString":{ + "type":"string", + "max":4096, + "min":0, + "sensitive":true }, "TextDocumentDiagnosticMessageString":{ "type":"string", @@ -1639,11 +2265,13 @@ "message":{"shape":"String"}, "reason":{"shape":"ThrottlingExceptionReason"} }, + "documentation":"

This exception is thrown when request was denied due to request throttling.

", "exception":true, "retryable":{"throttling":true} }, "ThrottlingExceptionReason":{ "type":"string", + "documentation":"

Reason for ThrottlingException

", "enum":["MONTHLY_REQUEST_COUNT"] }, "Tool":{ @@ -1651,10 +2279,12 @@ "members":{ "toolSpecification":{"shape":"ToolSpecification"} }, + "documentation":"

Information about a tool that can be used.

", "union":true }, "ToolDescription":{ "type":"string", + "documentation":"

The description for the tool.

", "max":10240, "min":1, "sensitive":true @@ -1663,10 +2293,12 @@ "type":"structure", "members":{ "json":{"shape":"SensitiveDocument"} - } + }, + "documentation":"

The input schema for the tool in JSON format.

" }, "ToolName":{ "type":"string", + "documentation":"

The name for the tool.

", "max":64, "min":0, "pattern":"[a-zA-Z][a-zA-Z0-9_]*", @@ -1680,9 +2312,13 @@ ], "members":{ "toolUseId":{"shape":"ToolUseId"}, - "content":{"shape":"ToolResultContent"}, + "content":{ + "shape":"ToolResultContent", + "documentation":"

Content of the tool result.

" + }, "status":{"shape":"ToolResultStatus"} - } + }, + "documentation":"

A tool result that contains the results for a tool request that was previously made.

" }, "ToolResultContent":{ "type":"list", @@ -1691,19 +2327,33 @@ "ToolResultContentBlock":{ "type":"structure", "members":{ - "text":{"shape":"ToolResultContentBlockTextString"}, - "json":{"shape":"SensitiveDocument"} + "text":{ + "shape":"ToolResultContentBlockTextString", + "documentation":"

A tool result that is text.

" + }, + "json":{ + "shape":"SensitiveDocument", + "documentation":"

A tool result that is JSON format data.

" + } }, "union":true }, "ToolResultContentBlockTextString":{ "type":"string", - "max":30720, + "max":800000, "min":0, "sensitive":true }, + "ToolResultEvent":{ + "type":"structure", + "members":{ + "toolResult":{"shape":"ToolResult"} + }, + "event":true + }, "ToolResultStatus":{ "type":"string", + "documentation":"

Status of the tools result.

", "enum":[ "success", "error" @@ -1725,7 +2375,8 @@ "inputSchema":{"shape":"ToolInputSchema"}, "name":{"shape":"ToolName"}, "description":{"shape":"ToolDescription"} - } + }, + "documentation":"

The specification for the tool.

" }, "ToolUse":{ "type":"structure", @@ -1737,8 +2388,12 @@ "members":{ "toolUseId":{"shape":"ToolUseId"}, "name":{"shape":"ToolName"}, - "input":{"shape":"SensitiveDocument"} - } + "input":{ + "shape":"SensitiveDocument", + "documentation":"

The input to pass to the tool.

" + } + }, + "documentation":"

Contains information about a tool that the model is requesting be run. The model uses the result from the tool to generate a response.

" }, "ToolUseEvent":{ "type":"structure", @@ -1749,19 +2404,27 @@ "members":{ "toolUseId":{"shape":"ToolUseId"}, "name":{"shape":"ToolName"}, - "input":{"shape":"ToolUseEventInputString"}, - "stop":{"shape":"Boolean"} + "input":{ + "shape":"ToolUseEventInputString", + "documentation":"

Represents the serialized json input for the ToolUse request. This field should be concatenated until 'stop' is true.

" + }, + "stop":{ + "shape":"Boolean", + "documentation":"

This field is true when all of the serialized input for this ToolUse request has been sent.

" + } }, + "documentation":"

Event for a ToolUse request. Multiple ToolUse requests can be returned from a single request, so each ToolUse has a unique 'toolUseId'.

", "event":true }, "ToolUseEventInputString":{ "type":"string", - "max":10240, + "max":30720, "min":0, "sensitive":true }, "ToolUseId":{ "type":"string", + "documentation":"

The ID for the tool request.

", "max":64, "min":0, "pattern":"[a-zA-Z0-9_-]+" @@ -1793,7 +2456,8 @@ "members":{ "downloadArtifactId":{"shape":"ArtifactId"}, "downloadArtifactType":{"shape":"TransformationDownloadArtifactType"} - } + }, + "documentation":"

Transformation export context

" }, "UUID":{ "type":"string", @@ -1806,10 +2470,12 @@ "members":{ "testGenerationJobGroupName":{"shape":"TestGenerationJobGroupName"}, "testGenerationJobId":{"shape":"UUID"} - } + }, + "documentation":"

Unit test generation export context

" }, "UploadId":{ "type":"string", + "documentation":"

Upload ID returned by CreateUploadUrl API

", "max":128, "min":1 }, @@ -1817,12 +2483,28 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"UserInputMessageContentString"}, - "userInputMessageContext":{"shape":"UserInputMessageContext"}, - "userIntent":{"shape":"UserIntent"}, - "origin":{"shape":"Origin"}, - "images":{"shape":"ImageBlocks"} - } + "content":{ + "shape":"UserInputMessageContentString", + "documentation":"

The content of the chat message.

" + }, + "userInputMessageContext":{ + "shape":"UserInputMessageContext", + "documentation":"

Chat message context associated with the Chat Message.

" + }, + "userIntent":{ + "shape":"UserIntent", + "documentation":"

User Intent.

" + }, + "origin":{ + "shape":"Origin", + "documentation":"

User Input Origin.

" + }, + "images":{ + "shape":"ImageBlocks", + "documentation":"

Images associated with the Chat Message.

" + } + }, + "documentation":"

Structure to represent a chat input message from User.

" }, "UserInputMessageContentString":{ "type":"string", @@ -1833,21 +2515,56 @@ "UserInputMessageContext":{ "type":"structure", "members":{ - "editorState":{"shape":"EditorState"}, - "shellState":{"shape":"ShellState"}, - "gitState":{"shape":"GitState"}, - "envState":{"shape":"EnvState"}, - "appStudioContext":{"shape":"AppStudioState"}, - "diagnostic":{"shape":"Diagnostic"}, - "consoleState":{"shape":"ConsoleState"}, - "userSettings":{"shape":"UserSettings"}, - "additionalContext":{"shape":"AdditionalContentList"}, - "toolResults":{"shape":"ToolResults"}, - "tools":{"shape":"Tools"} - } + "editorState":{ + "shape":"EditorState", + "documentation":"

Editor state chat message context.

" + }, + "shellState":{ + "shape":"ShellState", + "documentation":"

Shell state chat message context.

" + }, + "gitState":{ + "shape":"GitState", + "documentation":"

Git state chat message context.

" + }, + "envState":{ + "shape":"EnvState", + "documentation":"

Environment state chat message context.

" + }, + "appStudioContext":{ + "shape":"AppStudioState", + "documentation":"

The state of a user's AppStudio UI when sending a message.

" + }, + "diagnostic":{ + "shape":"Diagnostic", + "documentation":"

Diagnostic chat message context.

" + }, + "consoleState":{ + "shape":"ConsoleState", + "documentation":"

Contextual information about the environment from which the user is calling.

" + }, + "userSettings":{ + "shape":"UserSettings", + "documentation":"

Settings information, e.g., whether the user has enabled cross-region API calls.

" + }, + "additionalContext":{ + "shape":"AdditionalContentList", + "documentation":"

List of additional contextual content entries that can be included with the message.

" + }, + "toolResults":{ + "shape":"ToolResults", + "documentation":"

ToolResults for the requested ToolUses.

" + }, + "tools":{ + "shape":"Tools", + "documentation":"

Tools that can be used.

" + } + }, + "documentation":"

Additional Chat message context associated with the Chat Message

" }, "UserIntent":{ "type":"string", + "documentation":"

User Intent

", "enum":[ "SUGGEST_ALTERNATE_IMPLEMENTATION", "APPLY_COMMON_BEST_PRACTICES", @@ -1865,7 +2582,8 @@ "type":"structure", "members":{ "hasConsentedToCrossRegionCalls":{"shape":"Boolean"} - } + }, + "documentation":"

Settings information passed by the Q widget

" }, "ValidationException":{ "type":"structure", @@ -1874,10 +2592,12 @@ "message":{"shape":"String"}, "reason":{"shape":"ValidationExceptionReason"} }, + "documentation":"

This exception is thrown when the input fails to satisfy the constraints specified by the service.

", "exception":true }, "ValidationExceptionReason":{ "type":"string", + "documentation":"

Reason for ValidationException

", "enum":[ "INVALID_CONVERSATION_ID", "CONTENT_LENGTH_EXCEEDS_THRESHOLD", @@ -1891,8 +2611,14 @@ "url" ], "members":{ - "label":{"shape":"WebLinkLabelString"}, - "url":{"shape":"WebLinkUrlString"} + "label":{ + "shape":"WebLinkLabelString", + "documentation":"

A label for the link

" + }, + "url":{ + "shape":"WebLinkUrlString", + "documentation":"

URL of the Weblink

" + } } }, "WebLinkLabelString":{ @@ -1907,6 +2633,18 @@ "min":1, "sensitive":true }, + "WorkspaceFolderList":{ + "type":"list", + "member":{"shape":"WorkspaceFolderListMemberString"}, + "max":100, + "min":0 + }, + "WorkspaceFolderListMemberString":{ + "type":"string", + "max":4096, + "min":1, + "sensitive":true + }, "WorkspaceState":{ "type":"structure", "required":[ @@ -1914,10 +2652,20 @@ "programmingLanguage" ], "members":{ - "uploadId":{"shape":"UploadId"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "contextTruncationScheme":{"shape":"ContextTruncationScheme"} - } + "uploadId":{ + "shape":"UploadId", + "documentation":"

Upload ID representing an Upload using a PreSigned URL

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

Primary programming language of the Workspace

" + }, + "contextTruncationScheme":{ + "shape":"ContextTruncationScheme", + "documentation":"

Workspace context truncation schemes based on usecase

" + } + }, + "documentation":"

Represents a Workspace state uploaded to S3 for Async Code Actions

" } } } From 8433ddbca8c11140cd04f343f008470d1f0e261b Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 11 Apr 2025 15:56:35 -0700 Subject: [PATCH 15/35] up --- .../services/amazonq/clients/AmazonQStreamingClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt index 6fb6381f21d..f4f31f715c6 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt @@ -61,7 +61,7 @@ class AmazonQStreamingClient(private val project: Project) { it.exportId(exportId) it.exportIntent(exportIntent) it.exportContext(exportContext) - it.profileArn(QRegionProfileManager.getInstance().getProfileArn(project)) + it.profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn) }, ExportResultArchiveResponseHandler.builder().subscriber( ExportResultArchiveResponseHandler.Visitor.builder() From 06ebea2e450f6a337e43129d69e9e636837adc1b Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 11 Apr 2025 16:11:01 -0700 Subject: [PATCH 16/35] add --- .../amazonqCodeTest/controller/CodeTestChatController.kt | 1 + .../jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt index f2906970f20..2e8c9be12a7 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt @@ -409,6 +409,7 @@ class CodeTestChatController( .build() return GenerateAssistantResponseRequest.builder() .conversationState(conversationState) + .profileArn(QRegionProfileManager.getInstance().activeProfile(context.project)?.arn) .build() } diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt index d5e3da5edc2..e8d967a8e65 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/clients/chat/v1/ChatSessionV1.kt @@ -210,6 +210,7 @@ class ChatSessionV1( .build() return GenerateAssistantResponseRequest.builder() .conversationState(conversationState) + .profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn) .build() } From 0164a615e3ad327b7bdb8dc4eba9923aa5693a15 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 16:37:59 -0700 Subject: [PATCH 17/35] add a listner in cofig --- .../CodeWhispererModelConfigurator.kt | 15 ++++++ .../CodeWhispererModelConfiguratorTest.kt | 50 +++++++++++++++++++ .../amazonq/profile/QRegionProfileManager.kt | 2 +- .../profile/QRegionProfileSelectedListener.kt | 2 +- 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index f19df1595bf..5541d008170 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -22,7 +22,10 @@ import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.calculateIfIamIdentityCenterConnection +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor +import software.aws.toolkits.jetbrains.services.codewhisperer.status.CodeWhispererStatusBarWidget.Companion.ID import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants import software.aws.toolkits.jetbrains.utils.notifyInfo import software.aws.toolkits.jetbrains.utils.notifyWarn @@ -81,6 +84,18 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe private var customizationArnOverrideV2: String? = null + init { + ApplicationManager.getApplication().messageBus.connect(this).subscribe( + QRegionProfileSelectedListener.TOPIC, + object : QRegionProfileSelectedListener { + override fun onProfileSelected(project: Project, profile: QRegionProfile?) { + pluginAwareExecuteOnPooledThread { + CodeWhispererModelConfigurator.getInstance().listCustomizations(project, passive = true) + } + } + } + ) + } override fun showConfigDialog(project: Project) { runInEdt { calculateIfIamIdentityCenterConnection(project) { diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index b1fa0ef5592..cf79e0668ca 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.testFramework.ApplicationRule import com.intellij.testFramework.DisposableRule import com.intellij.testFramework.ProjectRule +import com.intellij.testFramework.registerServiceInstance import com.intellij.testFramework.replaceService import com.intellij.util.xmlb.XmlSerializer import org.assertj.core.api.Assertions.assertThat @@ -40,6 +41,8 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener +import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomizationState import software.aws.toolkits.jetbrains.services.codewhisperer.customization.DefaultCodeWhispererModelConfigurator @@ -75,6 +78,7 @@ class CodeWhispererModelConfiguratorTest { private lateinit var sut: DefaultCodeWhispererModelConfigurator private lateinit var mockClient: CodeWhispererRuntimeClient private lateinit var abManager: CodeWhispererFeatureConfigService + private lateinit var mockClintAdaptor: CodeWhispererClientAdaptor @Before fun setup() { @@ -110,6 +114,9 @@ class CodeWhispererModelConfiguratorTest { abManager, disposableRule.disposable ) + + mockClintAdaptor = mock() + projectRule.project.registerServiceInstance(CodeWhispererClientAdaptor::class.java, mockClintAdaptor) } @Test @@ -550,4 +557,47 @@ class CodeWhispererModelConfiguratorTest { assertThat(actual.previousAvailableCustomizations).hasSize(1) assertThat(actual.previousAvailableCustomizations["fake-sso-url"]).isEqualTo(listOf("arn_1", "arn_2", "arn_3")) } + + @Test + fun `profile switch should keep using existing customization if new list still contains that arn`() { + val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) + ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) + val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + sut.switchCustomization(projectRule.project, oldCustomization) + + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + + val fakeCustomizations = listOf( + CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + ) + + mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations} + + ApplicationManager.getApplication().messageBus + .syncPublisher(QRegionProfileSelectedListener.TOPIC) + .onProfileSelected(projectRule.project, null) + + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + } + + @Test + fun `profile switch should invalidate obsolete customization if it's not in the new list`() { + val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) + ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) + val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + sut.switchCustomization(projectRule.project, oldCustomization) + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + + val fakeCustomizations = listOf( + CodeWhispererCustomization("newArn", "newName", "oldDescription") + ) + mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations} + + ApplicationManager.getApplication().messageBus + .syncPublisher(QRegionProfileSelectedListener.TOPIC) + .onProfileSelected(projectRule.project, null) + + assertThat(sut.activeCustomization(projectRule.project)).isNull() + } + } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index 60f98c26d0f..b3b242c363d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -144,7 +144,7 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl } } - project.messageBus + ApplicationManager.getApplication().messageBus .syncPublisher(QRegionProfileSelectedListener.TOPIC) .onProfileSelected(project, newProfile) } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileSelectedListener.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileSelectedListener.kt index f107d883169..e507cd04a13 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileSelectedListener.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileSelectedListener.kt @@ -8,7 +8,7 @@ import com.intellij.util.messages.Topic interface QRegionProfileSelectedListener { companion object { - @Topic.ProjectLevel + @Topic.AppLevel val TOPIC = Topic.create("QRegionProfileSelected", QRegionProfileSelectedListener::class.java) } From 46d718873daa063ab4619d2be95868a908def29a Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 16:43:06 -0700 Subject: [PATCH 18/35] recover service.json --- .../codewhispererstreaming/service-2.json | 1224 +++++++++++++---- 1 file changed, 986 insertions(+), 238 deletions(-) diff --git a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json index 48aea822e55..778dbff05d9 100644 --- a/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json +++ b/plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json @@ -2,14 +2,9 @@ "version":"2.0", "metadata":{ "apiVersion":"2023-11-27", - "auth":["smithy.api#httpBearerAuth"], "endpointPrefix":"amazoncodewhispererstreamingservice", "jsonVersion":"1.0", "protocol":"json", - "protocols":[ - "json", - "rest-json" - ], "serviceFullName":"Amazon CodeWhisperer Streaming", "serviceId":"CodeWhispererStreaming", "signatureVersion":"bearer", @@ -33,7 +28,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to export operation result as an archive

" }, "GenerateAssistantResponse":{ "name":"GenerateAssistantResponse", @@ -48,7 +44,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to generate assistant response.

" }, "GenerateTaskAssistPlan":{ "name":"GenerateTaskAssistPlan", @@ -66,7 +63,8 @@ {"shape":"InternalServerException"}, {"shape":"ValidationException"}, {"shape":"AccessDeniedException"} - ] + ], + "documentation":"

API to generate task assist plan.

" }, "SendMessage":{ "name":"SendMessage", @@ -96,10 +94,12 @@ "message":{"shape":"String"}, "reason":{"shape":"AccessDeniedExceptionReason"} }, + "documentation":"

This exception is thrown when the user does not have sufficient access to perform this action.

", "exception":true }, "AccessDeniedExceptionReason":{ "type":"string", + "documentation":"

Reason for AccessDeniedException

", "enum":["UNAUTHORIZED_CUSTOMIZATION_RESOURCE_ACCESS"] }, "Action":{ @@ -116,10 +116,20 @@ "description" ], "members":{ - "name":{"shape":"AdditionalContentEntryNameString"}, - "description":{"shape":"AdditionalContentEntryDescriptionString"}, - "innerContext":{"shape":"AdditionalContentEntryInnerContextString"} - } + "name":{ + "shape":"AdditionalContentEntryNameString", + "documentation":"

The name/identifier for this context entry

" + }, + "description":{ + "shape":"AdditionalContentEntryDescriptionString", + "documentation":"

A description of what this context entry represents

" + }, + "innerContext":{ + "shape":"AdditionalContentEntryInnerContextString", + "documentation":"

The actual contextual content

" + } + }, + "documentation":"

Structure representing a single entry of additional contextual content

" }, "AdditionalContentEntryDescriptionString":{ "type":"string", @@ -143,6 +153,7 @@ "AdditionalContentList":{ "type":"list", "member":{"shape":"AdditionalContentEntry"}, + "documentation":"

A list of additional content entries, limited to 20 items

", "max":20, "min":0 }, @@ -154,8 +165,12 @@ ], "members":{ "type":{"shape":"AlertType"}, - "content":{"shape":"AlertComponentList"} - } + "content":{ + "shape":"AlertComponentList", + "documentation":"

Contains the content of the alert, which may include sensitive information.

" + } + }, + "documentation":"

Structure representing an alert with a type and content.

" }, "AlertComponent":{ "type":"structure", @@ -169,6 +184,7 @@ }, "AlertType":{ "type":"string", + "documentation":"

Enum defining types of alerts that can be issued.

", "enum":[ "INFO", "ERROR", @@ -183,11 +199,24 @@ "propertyContext" ], "members":{ - "namespace":{"shape":"AppStudioStateNamespaceString"}, - "propertyName":{"shape":"AppStudioStatePropertyNameString"}, - "propertyValue":{"shape":"AppStudioStatePropertyValueString"}, - "propertyContext":{"shape":"AppStudioStatePropertyContextString"} - } + "namespace":{ + "shape":"AppStudioStateNamespaceString", + "documentation":"

The namespace of the context. Examples: 'ui.Button', 'ui.Table.DataSource', 'ui.Table.RowActions.Button', 'logic.invokeAWS', 'logic.JavaScript'

" + }, + "propertyName":{ + "shape":"AppStudioStatePropertyNameString", + "documentation":"

The name of the property. Examples: 'visibility', 'disability', 'value', 'code'

" + }, + "propertyValue":{ + "shape":"AppStudioStatePropertyValueString", + "documentation":"

The value of the property.

" + }, + "propertyContext":{ + "shape":"AppStudioStatePropertyContextString", + "documentation":"

Context about how the property is used

" + } + }, + "documentation":"

Description of a user's context when they are calling Q Chat from AppStudio

" }, "AppStudioStateNamespaceString":{ "type":"string", @@ -223,8 +252,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"AssistantResponseEventContentString"} + "content":{ + "shape":"AssistantResponseEventContentString", + "documentation":"

The content of the text message in markdown format.

" + } }, + "documentation":"

Streaming Response Event for Assistant Markdown text message.

", "event":true }, "AssistantResponseEventContentString":{ @@ -238,12 +271,28 @@ "required":["content"], "members":{ "messageId":{"shape":"MessageId"}, - "content":{"shape":"AssistantResponseMessageContentString"}, - "supplementaryWebLinks":{"shape":"SupplementaryWebLinks"}, - "references":{"shape":"References"}, - "followupPrompt":{"shape":"FollowupPrompt"}, - "toolUses":{"shape":"ToolUses"} - } + "content":{ + "shape":"AssistantResponseMessageContentString", + "documentation":"

The content of the text message in markdown format.

" + }, + "supplementaryWebLinks":{ + "shape":"SupplementaryWebLinks", + "documentation":"

Web References

" + }, + "references":{ + "shape":"References", + "documentation":"

Code References

" + }, + "followupPrompt":{ + "shape":"FollowupPrompt", + "documentation":"

Followup Prompt

" + }, + "toolUses":{ + "shape":"ToolUses", + "documentation":"

ToolUse Request

" + } + }, + "documentation":"

Markdown text message.

" }, "AssistantResponseMessageContentString":{ "type":"string", @@ -254,11 +303,24 @@ "BinaryMetadataEvent":{ "type":"structure", "members":{ - "size":{"shape":"Long"}, - "mimeType":{"shape":"String"}, - "contentChecksum":{"shape":"ContentChecksum"}, - "contentChecksumType":{"shape":"ContentChecksumType"} + "size":{ + "shape":"Long", + "documentation":"

Content length of the binary payload

" + }, + "mimeType":{ + "shape":"String", + "documentation":"

Content type of the response

" + }, + "contentChecksum":{ + "shape":"ContentChecksum", + "documentation":"

Content checksum of the binary payload

" + }, + "contentChecksumType":{ + "shape":"ContentChecksumType", + "documentation":"

Content checksum type of the binary payload

" + } }, + "documentation":"

Payload Part

", "event":true, "sensitive":true }, @@ -267,6 +329,7 @@ "members":{ "bytes":{"shape":"PartBody"} }, + "documentation":"

Payload Part

", "event":true, "sensitive":true }, @@ -277,7 +340,8 @@ "ChatHistory":{ "type":"list", "member":{"shape":"ChatMessage"}, - "max":100, + "documentation":"

Indicates Participant in Chat conversation

", + "max":250, "min":0 }, "ChatMessage":{ @@ -291,24 +355,69 @@ "ChatResponseStream":{ "type":"structure", "members":{ - "messageMetadataEvent":{"shape":"MessageMetadataEvent"}, - "assistantResponseEvent":{"shape":"AssistantResponseEvent"}, - "dryRunSucceedEvent":{"shape":"DryRunSucceedEvent"}, - "codeReferenceEvent":{"shape":"CodeReferenceEvent"}, - "supplementaryWebLinksEvent":{"shape":"SupplementaryWebLinksEvent"}, - "followupPromptEvent":{"shape":"FollowupPromptEvent"}, - "codeEvent":{"shape":"CodeEvent"}, - "intentsEvent":{"shape":"IntentsEvent"}, - "interactionComponentsEvent":{"shape":"InteractionComponentsEvent"}, - "toolUseEvent":{"shape":"ToolUseEvent"}, - "citationEvent":{"shape":"CitationEvent"}, - "invalidStateEvent":{"shape":"InvalidStateEvent"}, - "error":{"shape":"InternalServerException"} + "messageMetadataEvent":{ + "shape":"MessageMetadataEvent", + "documentation":"

Message Metadata event

" + }, + "assistantResponseEvent":{ + "shape":"AssistantResponseEvent", + "documentation":"

Assistant response event - Text / Code snippet

" + }, + "dryRunSucceedEvent":{ + "shape":"DryRunSucceedEvent", + "documentation":"

DryRun Succeed Event

" + }, + "codeReferenceEvent":{ + "shape":"CodeReferenceEvent", + "documentation":"

Code References event

" + }, + "supplementaryWebLinksEvent":{ + "shape":"SupplementaryWebLinksEvent", + "documentation":"

Web Reference links event

" + }, + "followupPromptEvent":{ + "shape":"FollowupPromptEvent", + "documentation":"

Followup prompt event

" + }, + "codeEvent":{ + "shape":"CodeEvent", + "documentation":"

Code Generated event

" + }, + "intentsEvent":{ + "shape":"IntentsEvent", + "documentation":"

Intents event

" + }, + "interactionComponentsEvent":{ + "shape":"InteractionComponentsEvent", + "documentation":"

Interactions components event

" + }, + "toolUseEvent":{ + "shape":"ToolUseEvent", + "documentation":"

ToolUse event

" + }, + "toolResultEvent":{ + "shape":"ToolResultEvent", + "documentation":"

Tool use result

" + }, + "citationEvent":{ + "shape":"CitationEvent", + "documentation":"

Citation event

" + }, + "invalidStateEvent":{ + "shape":"InvalidStateEvent", + "documentation":"

Invalid State event

" + }, + "error":{ + "shape":"InternalServerException", + "documentation":"

Internal Server Exception

" + } }, + "documentation":"

Streaming events from UniDirectional Streaming Conversational APIs.

", "eventstream":true }, "ChatTriggerType":{ "type":"string", + "documentation":"

Trigger Reason for Chat

", "enum":[ "MANUAL", "DIAGNOSTIC", @@ -322,18 +431,35 @@ "citationLink" ], "members":{ - "target":{"shape":"CitationTarget"}, - "citationText":{"shape":"SensitiveString"}, - "citationLink":{"shape":"SensitiveString"} + "target":{ + "shape":"CitationTarget", + "documentation":"

The position or the range of the response text to be cited

" + }, + "citationText":{ + "shape":"SensitiveString", + "documentation":"

The text inside the citation '1' in [1]

" + }, + "citationLink":{ + "shape":"SensitiveString", + "documentation":"

The link to the document being cited

" + } }, + "documentation":"

Streaming response event for citations

", "event":true }, "CitationTarget":{ "type":"structure", "members":{ - "location":{"shape":"Offset"}, - "range":{"shape":"Span"} + "location":{ + "shape":"Offset", + "documentation":"

Represents a position in the response text where a citation should be added

" + }, + "range":{ + "shape":"Span", + "documentation":"

Represents the range in the response text to be targetted by a citation

" + } }, + "documentation":"

Represents the target of a citation event

", "union":true }, "CloudWatchTroubleshootingLink":{ @@ -343,10 +469,20 @@ "investigationPayload" ], "members":{ - "label":{"shape":"CloudWatchTroubleshootingLinkLabelString"}, - "investigationPayload":{"shape":"CloudWatchTroubleshootingLinkInvestigationPayloadString"}, - "defaultText":{"shape":"CloudWatchTroubleshootingLinkDefaultTextString"} - } + "label":{ + "shape":"CloudWatchTroubleshootingLinkLabelString", + "documentation":"

A label for the link.

" + }, + "investigationPayload":{ + "shape":"CloudWatchTroubleshootingLinkInvestigationPayloadString", + "documentation":"

Stringified JSON payload. See spec here https://code.amazon.com/packages/CloudWatchOdysseyModel/blobs/50c0832f0e393e4ab68827eb4f04d832366821c1/--/model/events.smithy#L28 .

" + }, + "defaultText":{ + "shape":"CloudWatchTroubleshootingLinkDefaultTextString", + "documentation":"

Fallback string, if target channel does not support the CloudWatchTroubleshootingLink.

" + } + }, + "documentation":"

For CloudWatch Troubleshooting Link Module

" }, "CloudWatchTroubleshootingLinkDefaultTextString":{ "type":"string", @@ -366,12 +502,33 @@ "min":0, "sensitive":true }, + "CodeDescription":{ + "type":"structure", + "required":["href"], + "members":{ + "href":{ + "shape":"CodeDescriptionHrefString", + "documentation":"

An URI to open with more information about the diagnostic error.

" + } + }, + "documentation":"

Structure to capture a description for an error code.

" + }, + "CodeDescriptionHrefString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, "CodeEvent":{ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"CodeEventContentString"} + "content":{ + "shape":"CodeEventContentString", + "documentation":"

Generated code snippet.

" + } }, + "documentation":"

Streaming response event for generated code text.

", "event":true }, "CodeEventContentString":{ @@ -383,8 +540,12 @@ "CodeReferenceEvent":{ "type":"structure", "members":{ - "references":{"shape":"References"} + "references":{ + "shape":"References", + "documentation":"

Code References for Assistant Response Message

" + } }, + "documentation":"

Streaming Response Event for CodeReferences

", "event":true }, "ConflictException":{ @@ -394,10 +555,12 @@ "message":{"shape":"String"}, "reason":{"shape":"ConflictExceptionReason"} }, + "documentation":"

This exception is thrown when the action to perform could not be completed because the resource is in a conflicting state.

", "exception":true }, "ConflictExceptionReason":{ "type":"string", + "documentation":"

Reason for ConflictException

", "enum":[ "CUSTOMER_KMS_KEY_INVALID_KEY_POLICY", "CUSTOMER_KMS_KEY_DISABLED", @@ -413,7 +576,8 @@ "serviceConsolePage":{"shape":"String"}, "serviceSubconsolePage":{"shape":"String"}, "taskName":{"shape":"SensitiveString"} - } + }, + "documentation":"

Information about the state of the AWS management console page from which the user is calling

" }, "ContentChecksum":{ "type":"string", @@ -426,6 +590,7 @@ }, "ContextTruncationScheme":{ "type":"string", + "documentation":"

Workspace context truncation schemes based on usecase

", "enum":[ "ANALYSIS", "GUMBY" @@ -433,6 +598,7 @@ }, "ConversationId":{ "type":"string", + "documentation":"

ID which represents a multi-turn conversation

", "max":128, "min":1 }, @@ -443,31 +609,108 @@ "chatTriggerType" ], "members":{ - "conversationId":{"shape":"ConversationId"}, - "history":{"shape":"ChatHistory"}, - "currentMessage":{"shape":"ChatMessage"}, - "chatTriggerType":{"shape":"ChatTriggerType"}, + "conversationId":{ + "shape":"ConversationId", + "documentation":"

Unique identifier for the chat conversation stream

" + }, + "history":{ + "shape":"ChatHistory", + "documentation":"

Holds the history of chat messages.

" + }, + "currentMessage":{ + "shape":"ChatMessage", + "documentation":"

Holds the current message being processed or displayed.

" + }, + "chatTriggerType":{ + "shape":"ChatTriggerType", + "documentation":"

Trigger Reason for Chat

" + }, "customizationArn":{"shape":"ResourceArn"} - } + }, + "documentation":"

Structure to represent the current state of a chat conversation.

" }, "CursorState":{ "type":"structure", "members":{ - "position":{"shape":"Position"}, - "range":{"shape":"Range"} + "position":{ + "shape":"Position", + "documentation":"

Represents a cursor position in a Text Document

" + }, + "range":{ + "shape":"Range", + "documentation":"

Represents a text selection in a Text Document

" + } }, + "documentation":"

Represents the state of the Cursor in an Editor

", "union":true }, "Diagnostic":{ "type":"structure", "members":{ - "textDocumentDiagnostic":{"shape":"TextDocumentDiagnostic"}, - "runtimeDiagnostic":{"shape":"RuntimeDiagnostic"} + "textDocumentDiagnostic":{ + "shape":"TextDocumentDiagnostic", + "documentation":"

Diagnostics originating from a TextDocument

" + }, + "runtimeDiagnostic":{ + "shape":"RuntimeDiagnostic", + "documentation":"

Diagnostics originating from a Runtime

" + } }, + "documentation":"

Represents a Diagnostic message

", "union":true }, + "DiagnosticLocation":{ + "type":"structure", + "required":[ + "uri", + "range" + ], + "members":{ + "uri":{"shape":"DiagnosticLocationUriString"}, + "range":{"shape":"Range"} + }, + "documentation":"

Represents a location inside a resource, such as a line inside a text file.

" + }, + "DiagnosticLocationUriString":{ + "type":"string", + "max":1024, + "min":1, + "sensitive":true + }, + "DiagnosticRelatedInformation":{ + "type":"structure", + "required":[ + "location", + "message" + ], + "members":{ + "location":{ + "shape":"DiagnosticLocation", + "documentation":"

The location of this related diagnostic information.

" + }, + "message":{ + "shape":"DiagnosticRelatedInformationMessageString", + "documentation":"

The message of this related diagnostic information.

" + } + }, + "documentation":"

Represents a related message and source code location for a diagnostic.

" + }, + "DiagnosticRelatedInformationList":{ + "type":"list", + "member":{"shape":"DiagnosticRelatedInformation"}, + "documentation":"

List of DiagnosticRelatedInformation

", + "max":1024, + "min":0 + }, + "DiagnosticRelatedInformationMessageString":{ + "type":"string", + "max":1024, + "min":0, + "sensitive":true + }, "DiagnosticSeverity":{ "type":"string", + "documentation":"

Diagnostic Error types

", "enum":[ "ERROR", "WARNING", @@ -475,6 +718,21 @@ "HINT" ] }, + "DiagnosticTag":{ + "type":"string", + "documentation":"

The diagnostic tags.

", + "enum":[ + "UNNECESSARY", + "DEPRECATED" + ] + }, + "DiagnosticTagList":{ + "type":"list", + "member":{"shape":"DiagnosticTag"}, + "documentation":"

List of DiagnosticTag

", + "max":1024, + "min":0 + }, "DocumentSymbol":{ "type":"structure", "required":[ @@ -482,9 +740,18 @@ "type" ], "members":{ - "name":{"shape":"DocumentSymbolNameString"}, - "type":{"shape":"SymbolType"}, - "source":{"shape":"DocumentSymbolSourceString"} + "name":{ + "shape":"DocumentSymbolNameString", + "documentation":"

Name of the Document Symbol

" + }, + "type":{ + "shape":"SymbolType", + "documentation":"

Symbol type - DECLARATION / USAGE

" + }, + "source":{ + "shape":"DocumentSymbolSourceString", + "documentation":"

Symbol package / source for FullyQualified names

" + } } }, "DocumentSymbolNameString":{ @@ -509,31 +776,63 @@ "message":{"shape":"String"}, "responseCode":{"shape":"Integer"} }, + "documentation":"

This exception is translated to a 204 as it succeeded the IAM Auth.

", "exception":true }, "DryRunSucceedEvent":{ "type":"structure", "members":{ }, + "documentation":"

Streaming Response Event when DryRun is succeessful

", "event":true }, "EditorState":{ "type":"structure", "members":{ - "document":{"shape":"TextDocument"}, - "cursorState":{"shape":"CursorState"}, - "relevantDocuments":{"shape":"RelevantDocumentList"}, - "useRelevantDocuments":{"shape":"Boolean"} - } + "document":{ + "shape":"TextDocument", + "documentation":"

Represents currently edited file

" + }, + "cursorState":{ + "shape":"CursorState", + "documentation":"

Position of the cursor

" + }, + "relevantDocuments":{ + "shape":"RelevantDocumentList", + "documentation":"

Represents IDE provided relevant files

" + }, + "useRelevantDocuments":{ + "shape":"Boolean", + "documentation":"

Whether service should use relevant document in prompt

" + }, + "workspaceFolders":{ + "shape":"WorkspaceFolderList", + "documentation":"

Represents IDE provided list of workspace folders

" + } + }, + "documentation":"

Represents the state of an Editor

" }, "EnvState":{ "type":"structure", "members":{ - "operatingSystem":{"shape":"EnvStateOperatingSystemString"}, - "currentWorkingDirectory":{"shape":"EnvStateCurrentWorkingDirectoryString"}, - "environmentVariables":{"shape":"EnvironmentVariables"}, - "timezoneOffset":{"shape":"EnvStateTimezoneOffsetInteger"} - } + "operatingSystem":{ + "shape":"EnvStateOperatingSystemString", + "documentation":"

The name of the operating system in use

" + }, + "currentWorkingDirectory":{ + "shape":"EnvStateCurrentWorkingDirectoryString", + "documentation":"

The current working directory of the environment

" + }, + "environmentVariables":{ + "shape":"EnvironmentVariables", + "documentation":"

The environment variables set in the current environment

" + }, + "timezoneOffset":{ + "shape":"EnvStateTimezoneOffsetInteger", + "documentation":"

Local timezone offset of the client. For more information, see documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset

" + } + }, + "documentation":"

State related to the user's environment

" }, "EnvStateCurrentWorkingDirectoryString":{ "type":"string", @@ -556,9 +855,16 @@ "EnvironmentVariable":{ "type":"structure", "members":{ - "key":{"shape":"EnvironmentVariableKeyString"}, - "value":{"shape":"EnvironmentVariableValueString"} - } + "key":{ + "shape":"EnvironmentVariableKeyString", + "documentation":"

The key of an environment variable

" + }, + "value":{ + "shape":"EnvironmentVariableValueString", + "documentation":"

The value of an environment variable

" + } + }, + "documentation":"

An environment variable

" }, "EnvironmentVariableKeyString":{ "type":"string", @@ -575,6 +881,7 @@ "EnvironmentVariables":{ "type":"list", "member":{"shape":"EnvironmentVariable"}, + "documentation":"

A list of environment variables

", "max":100, "min":0 }, @@ -584,10 +891,12 @@ "transformationExportContext":{"shape":"TransformationExportContext"}, "unitTestGenerationExportContext":{"shape":"UnitTestGenerationExportContext"} }, + "documentation":"

Export Context

", "union":true }, "ExportIntent":{ "type":"string", + "documentation":"

Export Intent

", "enum":[ "TRANSFORMATION", "TASK_ASSIST", @@ -605,7 +914,8 @@ "exportIntent":{"shape":"ExportIntent"}, "exportContext":{"shape":"ExportContext"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent a new ExportResultArchive request.

" }, "ExportResultArchiveRequestExportIdString":{ "type":"string", @@ -617,15 +927,23 @@ "required":["body"], "members":{ "body":{"shape":"ResultArchiveStream"} - } + }, + "documentation":"

Structure to represent ExportResultArchive response.

" }, "FollowupPrompt":{ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"FollowupPromptContentString"}, - "userIntent":{"shape":"UserIntent"} - } + "content":{ + "shape":"FollowupPromptContentString", + "documentation":"

The content of the text message in markdown format.

" + }, + "userIntent":{ + "shape":"UserIntent", + "documentation":"

User Intent

" + } + }, + "documentation":"

Followup Prompt for the Assistant Response

" }, "FollowupPromptContentString":{ "type":"string", @@ -638,6 +956,7 @@ "members":{ "followupPrompt":{"shape":"FollowupPrompt"} }, + "documentation":"

Streaming Response Event for Followup Prompt.

", "event":true }, "GenerateAssistantResponseRequest":{ @@ -646,7 +965,8 @@ "members":{ "conversationState":{"shape":"ConversationState"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent a new generate assistant response request.

" }, "GenerateAssistantResponseResponse":{ "type":"structure", @@ -657,7 +977,8 @@ "members":{ "conversationId":{"shape":"ConversationId"}, "generateAssistantResponseResponse":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent generate assistant response response.

" }, "GenerateTaskAssistPlanRequest":{ "type":"structure", @@ -669,19 +990,25 @@ "conversationState":{"shape":"ConversationState"}, "workspaceState":{"shape":"WorkspaceState"}, "profileArn":{"shape":"ProfileArn"} - } + }, + "documentation":"

Structure to represent execute planning interaction request.

" }, "GenerateTaskAssistPlanResponse":{ "type":"structure", "members":{ "planningResponseStream":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent execute planning interaction response.

" }, "GitState":{ "type":"structure", "members":{ - "status":{"shape":"GitStateStatusString"} - } + "status":{ + "shape":"GitStateStatusString", + "documentation":"

The output of the command git status --porcelain=v1 -b

" + } + }, + "documentation":"

State related to the Git VSC

" }, "GitStateStatusString":{ "type":"string", @@ -698,7 +1025,8 @@ "members":{ "format":{"shape":"ImageFormat"}, "source":{"shape":"ImageSource"} - } + }, + "documentation":"

Represents the image source itself and the format of the image.

" }, "ImageBlocks":{ "type":"list", @@ -720,6 +1048,7 @@ "members":{ "bytes":{"shape":"ImageSourceBytesBlob"} }, + "documentation":"

Image bytes limited to ~10MB considering overhead of base64 encoding

", "sensitive":true, "union":true }, @@ -732,7 +1061,8 @@ "type":"structure", "members":{ "transition":{"shape":"InfrastructureUpdateTransition"} - } + }, + "documentation":"

Structure representing different types of infrastructure updates.

" }, "InfrastructureUpdateTransition":{ "type":"structure", @@ -741,9 +1071,16 @@ "nextState" ], "members":{ - "currentState":{"shape":"InfrastructureUpdateTransitionCurrentStateString"}, - "nextState":{"shape":"InfrastructureUpdateTransitionNextStateString"} - } + "currentState":{ + "shape":"InfrastructureUpdateTransitionCurrentStateString", + "documentation":"

The current state of the infrastructure before the update.

" + }, + "nextState":{ + "shape":"InfrastructureUpdateTransitionNextStateString", + "documentation":"

The next state of the infrastructure following the update.

" + } + }, + "documentation":"

Structure describing a transition between two states in an infrastructure update.

" }, "InfrastructureUpdateTransitionCurrentStateString":{ "type":"string", @@ -794,8 +1131,12 @@ "IntentsEvent":{ "type":"structure", "members":{ - "intents":{"shape":"IntentMap"} + "intents":{ + "shape":"IntentMap", + "documentation":"

A map of Intent objects

" + } }, + "documentation":"

Streaming Response Event for Intents

", "event":true }, "InteractionComponent":{ @@ -813,22 +1154,32 @@ "resource":{"shape":"Resource"}, "resourceList":{"shape":"ResourceList"}, "action":{"shape":"Action"} - } + }, + "documentation":"

Structure representing different types of interaction components.

" }, "InteractionComponentEntry":{ "type":"structure", "required":["interactionComponent"], "members":{ - "interactionComponentId":{"shape":"InteractionComponentId"}, - "interactionComponent":{"shape":"InteractionComponent"} - } + "interactionComponentId":{ + "shape":"InteractionComponentId", + "documentation":"

Identifier that can uniquely identify the interaction component within stream response. This field is optional.

" + }, + "interactionComponent":{ + "shape":"InteractionComponent", + "documentation":"

Interaction component

" + } + }, + "documentation":"

Interaction component with an identifier

" }, "InteractionComponentEntryList":{ "type":"list", - "member":{"shape":"InteractionComponentEntry"} + "member":{"shape":"InteractionComponentEntry"}, + "documentation":"

List of identifiable interaction components

" }, "InteractionComponentId":{ "type":"string", + "documentation":"

Unique identifier for interaction component

", "max":128, "min":0 }, @@ -836,8 +1187,12 @@ "type":"structure", "required":["interactionComponentEntries"], "members":{ - "interactionComponentEntries":{"shape":"InteractionComponentEntryList"} + "interactionComponentEntries":{ + "shape":"InteractionComponentEntryList", + "documentation":"

List of identifiable interaction components

" + } }, + "documentation":"

Streaming Event for interaction components list

", "event":true }, "InternalServerException":{ @@ -846,6 +1201,7 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when an unexpected error occurred during the processing of a request.

", "exception":true, "fault":true, "retryable":{"throttling":false} @@ -860,6 +1216,7 @@ "reason":{"shape":"InvalidStateReason"}, "message":{"shape":"InvalidStateEventMessageString"} }, + "documentation":"

Streaming Response Event when an Invalid State is reached

", "event":true }, "InvalidStateEventMessageString":{ @@ -869,6 +1226,7 @@ }, "InvalidStateReason":{ "type":"string", + "documentation":"

Reasons for Invalid State Event

", "enum":["INVALID_TASK_ASSIST_PLAN"] }, "Long":{ @@ -877,15 +1235,23 @@ }, "MessageId":{ "type":"string", + "documentation":"

Unique identifier for the chat message

", "max":128, "min":0 }, "MessageMetadataEvent":{ "type":"structure", "members":{ - "conversationId":{"shape":"MessageMetadataEventConversationIdString"}, - "utteranceId":{"shape":"MessageMetadataEventUtteranceIdString"} + "conversationId":{ + "shape":"MessageMetadataEventConversationIdString", + "documentation":"

Unique identifier for the conversation

" + }, + "utteranceId":{ + "shape":"MessageMetadataEventUtteranceIdString", + "documentation":"

Unique identifier for the utterance

" + } }, + "documentation":"

Streaming Response Event for AssistantResponse Metadata

", "event":true }, "MessageMetadataEventConversationIdString":{ @@ -906,11 +1272,13 @@ }, "Offset":{ "type":"integer", + "documentation":"

Offset in the response text

", "box":true, "min":0 }, "Origin":{ "type":"string", + "documentation":"

Enum to represent the origin application conversing with Sidekick.

", "enum":[ "CHATBOT", "CONSOLE", @@ -931,6 +1299,7 @@ }, "PartBody":{ "type":"blob", + "documentation":"

Payload Part's body

", "max":1000000, "min":0, "sensitive":true @@ -942,9 +1311,16 @@ "character" ], "members":{ - "line":{"shape":"Integer"}, - "character":{"shape":"Integer"} - } + "line":{ + "shape":"Integer", + "documentation":"

Line position in a document.

" + }, + "character":{ + "shape":"Integer", + "documentation":"

Character offset on a line in a document (zero-based)

" + } + }, + "documentation":"

Indicates Cursor postion in a Text Document

" }, "ProfileArn":{ "type":"string", @@ -957,7 +1333,8 @@ "required":["languageName"], "members":{ "languageName":{"shape":"ProgrammingLanguageLanguageNameString"} - } + }, + "documentation":"

Programming Languages supported by CodeWhisperer

" }, "ProgrammingLanguageLanguageNameString":{ "type":"string", @@ -969,8 +1346,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"ProgressComponentList"} - } + "content":{ + "shape":"ProgressComponentList", + "documentation":"

A collection of steps that make up a process. Each step is detailed using the Step structure.

" + } + }, + "documentation":"

Structure representing a collection of steps in a process.

" }, "ProgressComponent":{ "type":"structure", @@ -989,18 +1370,38 @@ "end" ], "members":{ - "start":{"shape":"Position"}, - "end":{"shape":"Position"} - } + "start":{ + "shape":"Position", + "documentation":"

The range's start position.

" + }, + "end":{ + "shape":"Position", + "documentation":"

The range's end position.

" + } + }, + "documentation":"

Indicates Range / Span in a Text Document

" }, "Reference":{ "type":"structure", "members":{ - "licenseName":{"shape":"ReferenceLicenseNameString"}, - "repository":{"shape":"ReferenceRepositoryString"}, - "url":{"shape":"ReferenceUrlString"}, - "recommendationContentSpan":{"shape":"Span"} - } + "licenseName":{ + "shape":"ReferenceLicenseNameString", + "documentation":"

License name

" + }, + "repository":{ + "shape":"ReferenceRepositoryString", + "documentation":"

Code Repsitory for the associated reference

" + }, + "url":{ + "shape":"ReferenceUrlString", + "documentation":"

Respository URL

" + }, + "recommendationContentSpan":{ + "shape":"Span", + "documentation":"

Span / Range for the Reference

" + } + }, + "documentation":"

Code Reference / Repository details

" }, "ReferenceLicenseNameString":{ "type":"string", @@ -1033,11 +1434,24 @@ "type":"structure", "required":["relativeFilePath"], "members":{ - "relativeFilePath":{"shape":"RelevantTextDocumentRelativeFilePathString"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "text":{"shape":"RelevantTextDocumentTextString"}, - "documentSymbols":{"shape":"DocumentSymbols"} - } + "relativeFilePath":{ + "shape":"RelevantTextDocumentRelativeFilePathString", + "documentation":"

Filepath relative to the root of the workspace

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

The text document's language identifier.

" + }, + "text":{ + "shape":"RelevantTextDocumentTextString", + "documentation":"

Content of the text document

" + }, + "documentSymbols":{ + "shape":"DocumentSymbols", + "documentation":"

DocumentSymbols parsed from a text document

" + } + }, + "documentation":"

Represents an IDE retrieved relevant Text Document / File

" }, "RelevantTextDocumentRelativeFilePathString":{ "type":"string", @@ -1062,13 +1476,32 @@ "resourceJsonString" ], "members":{ - "title":{"shape":"ResourceTitleString"}, - "link":{"shape":"ResourceLinkString"}, - "description":{"shape":"ResourceDescriptionString"}, - "type":{"shape":"ResourceTypeString"}, - "ARN":{"shape":"ResourceARNString"}, - "resourceJsonString":{"shape":"ResourceResourceJsonStringString"} - } + "title":{ + "shape":"ResourceTitleString", + "documentation":"

Card title.

" + }, + "link":{ + "shape":"ResourceLinkString", + "documentation":"

Link for the resource item

" + }, + "description":{ + "shape":"ResourceDescriptionString", + "documentation":"

Short text about that resource for example Region: us-east-1

" + }, + "type":{ + "shape":"ResourceTypeString", + "documentation":"

Resource type e.g AWS EC2

" + }, + "ARN":{ + "shape":"ResourceARNString", + "documentation":"

Amazon resource number e.g arn:aws:aec:.....

" + }, + "resourceJsonString":{ + "shape":"ResourceResourceJsonStringString", + "documentation":"

A stringified object

" + } + }, + "documentation":"

Structure representing a resource item

" }, "ResourceARNString":{ "type":"string", @@ -1098,13 +1531,21 @@ "type":"structure", "required":["items"], "members":{ - "action":{"shape":"Action"}, - "items":{"shape":"ResourceListItemsList"} - } + "action":{ + "shape":"Action", + "documentation":"

Action associated with the list

" + }, + "items":{ + "shape":"ResourceListItemsList", + "documentation":"

List of resources

" + } + }, + "documentation":"

Structure representing a list of Items

" }, "ResourceListItemsList":{ "type":"list", "member":{"shape":"Resource"}, + "documentation":"

List for resources

", "max":10, "min":0 }, @@ -1114,6 +1555,7 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when describing a resource that does not exist.

", "exception":true }, "ResourceResourceJsonStringString":{ @@ -1141,6 +1583,7 @@ "binaryPayloadEvent":{"shape":"BinaryPayloadEvent"}, "internalServerException":{"shape":"InternalServerException"} }, + "documentation":"

Response Stream

", "eventstream":true }, "RuntimeDiagnostic":{ @@ -1151,10 +1594,20 @@ "message" ], "members":{ - "source":{"shape":"RuntimeDiagnosticSourceString"}, - "severity":{"shape":"DiagnosticSeverity"}, - "message":{"shape":"RuntimeDiagnosticMessageString"} - } + "source":{ + "shape":"RuntimeDiagnosticSourceString", + "documentation":"

A human-readable string describing the source of the diagnostic

" + }, + "severity":{ + "shape":"DiagnosticSeverity", + "documentation":"

Diagnostic Error type

" + }, + "message":{ + "shape":"RuntimeDiagnosticMessageString", + "documentation":"

The diagnostic's message.

" + } + }, + "documentation":"

Structure to represent metadata about a Runtime Diagnostics

" }, "RuntimeDiagnosticMessageString":{ "type":"string", @@ -1175,10 +1628,20 @@ "content" ], "members":{ - "title":{"shape":"SectionTitleString"}, - "content":{"shape":"SectionContentList"}, - "action":{"shape":"Action"} - } + "title":{ + "shape":"SectionTitleString", + "documentation":"

Contains text content that may include sensitive information and can support Markdown formatting.

" + }, + "content":{ + "shape":"SectionContentList", + "documentation":"

Contains a list of interaction components e.g Text, Alert, List, etc.

" + }, + "action":{ + "shape":"Action", + "documentation":"

Action associated with the Section

" + } + }, + "documentation":"

Structure representing a collapsable section

" }, "SectionComponent":{ "type":"structure", @@ -1207,16 +1670,21 @@ "members":{ "conversationState":{"shape":"ConversationState"}, "profileArn":{"shape":"ProfileArn"}, - "source":{"shape":"Origin"}, + "source":{ + "shape":"Origin", + "documentation":"

The origin of the caller

" + }, "dryRun":{"shape":"Boolean"} - } + }, + "documentation":"

Structure to represent a SendMessage request.

" }, "SendMessageResponse":{ "type":"structure", "required":["sendMessageResponse"], "members":{ "sendMessageResponse":{"shape":"ChatResponseStream"} - } + }, + "documentation":"

Structure to represent a SendMessage response.

" }, "SensitiveDocument":{ "type":"structure", @@ -1235,11 +1703,13 @@ "members":{ "message":{"shape":"String"} }, + "documentation":"

This exception is thrown when request was denied due to caller exceeding their usage limits

", "exception":true }, "ShellHistory":{ "type":"list", "member":{"shape":"ShellHistoryEntry"}, + "documentation":"

A list of shell history entries

", "max":20, "min":0 }, @@ -1247,12 +1717,28 @@ "type":"structure", "required":["command"], "members":{ - "command":{"shape":"ShellHistoryEntryCommandString"}, - "directory":{"shape":"ShellHistoryEntryDirectoryString"}, - "exitCode":{"shape":"Integer"}, - "stdout":{"shape":"ShellHistoryEntryStdoutString"}, - "stderr":{"shape":"ShellHistoryEntryStderrString"} - } + "command":{ + "shape":"ShellHistoryEntryCommandString", + "documentation":"

The shell command that was run

" + }, + "directory":{ + "shape":"ShellHistoryEntryDirectoryString", + "documentation":"

The directory the command was ran in

" + }, + "exitCode":{ + "shape":"Integer", + "documentation":"

The exit code of the command after it finished

" + }, + "stdout":{ + "shape":"ShellHistoryEntryStdoutString", + "documentation":"

The stdout from the command

" + }, + "stderr":{ + "shape":"ShellHistoryEntryStderrString", + "documentation":"

The stderr from the command

" + } + }, + "documentation":"

An single entry in the shell history

" }, "ShellHistoryEntryCommandString":{ "type":"string", @@ -1282,9 +1768,16 @@ "type":"structure", "required":["shellName"], "members":{ - "shellName":{"shape":"ShellStateShellNameString"}, - "shellHistory":{"shape":"ShellHistory"} - } + "shellName":{ + "shape":"ShellStateShellNameString", + "documentation":"

The name of the current shell

" + }, + "shellHistory":{ + "shape":"ShellHistory", + "documentation":"

The history previous shell commands for the current shell

" + } + }, + "documentation":"

Represents the state of a shell

" }, "ShellStateShellNameString":{ "type":"string", @@ -1297,7 +1790,8 @@ "members":{ "start":{"shape":"SpanStartInteger"}, "end":{"shape":"SpanEndInteger"} - } + }, + "documentation":"

Represents span in a text.

" }, "SpanEndInteger":{ "type":"integer", @@ -1317,11 +1811,21 @@ "label" ], "members":{ - "id":{"shape":"StepIdInteger"}, + "id":{ + "shape":"StepIdInteger", + "documentation":"

A unique identifier for the step. It must be a non-negative integer to ensure each step is distinct.

" + }, "state":{"shape":"StepState"}, - "label":{"shape":"StepLabelString"}, - "content":{"shape":"StepComponentList"} - } + "label":{ + "shape":"StepLabelString", + "documentation":"

A label for the step, providing a concise description.

" + }, + "content":{ + "shape":"StepComponentList", + "documentation":"

Optional content providing additional details about the step.

" + } + }, + "documentation":"

Structure representing an individual step in a process.

" }, "StepComponent":{ "type":"structure", @@ -1347,6 +1851,7 @@ }, "StepState":{ "type":"string", + "documentation":"

Enum representing all possible step states, combining terminal and non-terminal states.

", "enum":[ "FAILED", "SUCCEEDED", @@ -1363,7 +1868,8 @@ "required":["value"], "members":{ "value":{"shape":"SuggestionValueString"} - } + }, + "documentation":"

Structure representing a suggestion for follow-ups.

" }, "SuggestionList":{ "type":"list", @@ -1380,7 +1886,8 @@ "required":["items"], "members":{ "items":{"shape":"SuggestionList"} - } + }, + "documentation":"

Structure containing a list of suggestions.

" }, "SupplementaryWebLink":{ "type":"structure", @@ -1389,10 +1896,20 @@ "title" ], "members":{ - "url":{"shape":"SupplementaryWebLinkUrlString"}, - "title":{"shape":"SupplementaryWebLinkTitleString"}, - "snippet":{"shape":"SupplementaryWebLinkSnippetString"} - } + "url":{ + "shape":"SupplementaryWebLinkUrlString", + "documentation":"

URL of the web reference link.

" + }, + "title":{ + "shape":"SupplementaryWebLinkTitleString", + "documentation":"

Title of the web reference link.

" + }, + "snippet":{ + "shape":"SupplementaryWebLinkSnippetString", + "documentation":"

Relevant text snippet from the link.

" + } + }, + "documentation":"

Represents an additional reference link retured with the Chat message

" }, "SupplementaryWebLinkSnippetString":{ "type":"string", @@ -1421,8 +1938,12 @@ "SupplementaryWebLinksEvent":{ "type":"structure", "members":{ - "supplementaryWebLinks":{"shape":"SupplementaryWebLinks"} + "supplementaryWebLinks":{ + "shape":"SupplementaryWebLinks", + "documentation":"

Web References for Assistant Response Message

" + } }, + "documentation":"

Streaming Response Event for SupplementaryWebLinks

", "event":true }, "SymbolType":{ @@ -1439,19 +1960,33 @@ "payload" ], "members":{ - "label":{"shape":"TaskActionLabelString"}, + "label":{ + "shape":"TaskActionLabelString", + "documentation":"

A label for the action.

" + }, "note":{"shape":"TaskActionNote"}, - "primary":{"shape":"Boolean"}, - "disabled":{"shape":"Boolean"}, + "primary":{ + "shape":"Boolean", + "documentation":"

Indicates whether the action is primary or not.

" + }, + "disabled":{ + "shape":"Boolean", + "documentation":"

Indicates whether the action is disabled or not.

" + }, "payload":{"shape":"TaskActionPayload"}, "confirmation":{"shape":"TaskActionConfirmation"} - } + }, + "documentation":"

Structure representing an action associated with a task.

" }, "TaskActionConfirmation":{ "type":"structure", "members":{ - "content":{"shape":"TaskActionConfirmationContentString"} - } + "content":{ + "shape":"TaskActionConfirmationContentString", + "documentation":"

Confirmation message related to the action note, which may include sensitive information.

" + } + }, + "documentation":"

Structure representing a confirmation message related to a task action.

" }, "TaskActionConfirmationContentString":{ "type":"string", @@ -1473,9 +2008,13 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"TaskActionNoteContentString"}, + "content":{ + "shape":"TaskActionNoteContentString", + "documentation":"

Content of the note, which may include sensitive information.

" + }, "type":{"shape":"TaskActionNoteType"} - } + }, + "documentation":"

Structure representing a note associated with a task action.

" }, "TaskActionNoteContentString":{ "type":"string", @@ -1485,6 +2024,7 @@ }, "TaskActionNoteType":{ "type":"string", + "documentation":"

Enum defining the types of notes that can be associated with a task action.

", "enum":[ "INFO", "WARNING" @@ -1492,8 +2032,15 @@ }, "TaskActionPayload":{ "type":"map", - "key":{"shape":"TaskActionPayloadKeyString"}, - "value":{"shape":"TaskActionPayloadValueString"}, + "key":{ + "shape":"TaskActionPayloadKeyString", + "documentation":"

The key for the payload entry.

" + }, + "value":{ + "shape":"TaskActionPayloadValueString", + "documentation":"

The sensitive value associated with the key.

" + }, + "documentation":"

Map representing key-value pairs for the payload of a task action.

", "max":32, "min":0 }, @@ -1515,7 +2062,8 @@ "infrastructureUpdate":{"shape":"InfrastructureUpdate"}, "alert":{"shape":"Alert"}, "progress":{"shape":"Progress"} - } + }, + "documentation":"

Structure representing different types of components that can be part of a task.

" }, "TaskComponentList":{ "type":"list", @@ -1529,9 +2077,16 @@ ], "members":{ "overview":{"shape":"TaskOverview"}, - "content":{"shape":"TaskComponentList"}, - "actions":{"shape":"TaskActionList"} - } + "content":{ + "shape":"TaskComponentList", + "documentation":"

Lists the components that can be used to form the task's content.

" + }, + "actions":{ + "shape":"TaskActionList", + "documentation":"

Optional list of actions associated with the task.

" + } + }, + "documentation":"

Structure containing details about a task.

" }, "TaskOverview":{ "type":"structure", @@ -1540,9 +2095,16 @@ "description" ], "members":{ - "label":{"shape":"TaskOverviewLabelString"}, - "description":{"shape":"TaskOverviewDescriptionString"} - } + "label":{ + "shape":"TaskOverviewLabelString", + "documentation":"

A label for the task overview.

" + }, + "description":{ + "shape":"TaskOverviewDescriptionString", + "documentation":"

Text description providing details about the task. This field may include sensitive information and supports Markdown formatting.

" + } + }, + "documentation":"

Structure representing an overview of a task, including a label and description.

" }, "TaskOverviewDescriptionString":{ "type":"string", @@ -1560,8 +2122,12 @@ "type":"structure", "required":["taskId"], "members":{ - "taskId":{"shape":"TaskReferenceTaskIdString"} - } + "taskId":{ + "shape":"TaskReferenceTaskIdString", + "documentation":"

Unique identifier for the task.

" + } + }, + "documentation":"

Structure representing a reference to a task.

" }, "TaskReferenceTaskIdString":{ "type":"string", @@ -1570,6 +2136,7 @@ }, "TestGenerationJobGroupName":{ "type":"string", + "documentation":"

Test generation job group name

", "max":128, "min":1, "pattern":"[a-zA-Z0-9-_]+" @@ -1578,8 +2145,12 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"TextContentString"} - } + "content":{ + "shape":"TextContentString", + "documentation":"

Contains text content that may include sensitive information and can support Markdown formatting.

" + } + }, + "documentation":"

Structure representing a simple text component with sensitive content, which can include Markdown formatting.

" }, "TextContentString":{ "type":"string", @@ -1591,11 +2162,24 @@ "type":"structure", "required":["relativeFilePath"], "members":{ - "relativeFilePath":{"shape":"TextDocumentRelativeFilePathString"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "text":{"shape":"TextDocumentTextString"}, - "documentSymbols":{"shape":"DocumentSymbols"} - } + "relativeFilePath":{ + "shape":"TextDocumentRelativeFilePathString", + "documentation":"

Filepath relative to the root of the workspace

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

The text document's language identifier.

" + }, + "text":{ + "shape":"TextDocumentTextString", + "documentation":"

Content of the text document

" + }, + "documentSymbols":{ + "shape":"DocumentSymbols", + "documentation":"

DocumentSymbols parsed from a text document

" + } + }, + "documentation":"

Represents a Text Document / File

" }, "TextDocumentDiagnostic":{ "type":"structure", @@ -1607,12 +2191,54 @@ "message" ], "members":{ - "document":{"shape":"TextDocument"}, - "range":{"shape":"Range"}, - "source":{"shape":"SensitiveString"}, - "severity":{"shape":"DiagnosticSeverity"}, - "message":{"shape":"TextDocumentDiagnosticMessageString"} - } + "document":{ + "shape":"TextDocument", + "documentation":"

Represents a Text Document associated with Diagnostic

" + }, + "range":{ + "shape":"Range", + "documentation":"

The range at which the message applies.

" + }, + "source":{ + "shape":"SensitiveString", + "documentation":"

A human-readable string describing the source of the diagnostic

" + }, + "severity":{ + "shape":"DiagnosticSeverity", + "documentation":"

Diagnostic Error type

" + }, + "message":{ + "shape":"TextDocumentDiagnosticMessageString", + "documentation":"

The diagnostic's message.

" + }, + "code":{ + "shape":"Integer", + "documentation":"

The diagnostic's code, which might appear in the user interface.

" + }, + "codeDescription":{ + "shape":"CodeDescription", + "documentation":"

An optional property to describe the error code.

" + }, + "tags":{ + "shape":"DiagnosticTagList", + "documentation":"

Additional metadata about the diagnostic.

" + }, + "relatedInformation":{ + "shape":"DiagnosticRelatedInformationList", + "documentation":"

an array of related diagnostic information, e.g. when symbol-names within a scope collide all definitions can be marked via this property.

" + }, + "data":{ + "shape":"TextDocumentDiagnosticDataString", + "documentation":"

A data entry field that is preserved between a textDocument/publishDiagnostics notification and textDocument/codeAction request.

" + } + }, + "documentation":"

Structure to represent metadata about a TextDocument Diagnostic

" + }, + "TextDocumentDiagnosticDataString":{ + "type":"string", + "max":4096, + "min":0, + "sensitive":true }, "TextDocumentDiagnosticMessageString":{ "type":"string", @@ -1639,11 +2265,13 @@ "message":{"shape":"String"}, "reason":{"shape":"ThrottlingExceptionReason"} }, + "documentation":"

This exception is thrown when request was denied due to request throttling.

", "exception":true, "retryable":{"throttling":true} }, "ThrottlingExceptionReason":{ "type":"string", + "documentation":"

Reason for ThrottlingException

", "enum":["MONTHLY_REQUEST_COUNT"] }, "Tool":{ @@ -1651,10 +2279,12 @@ "members":{ "toolSpecification":{"shape":"ToolSpecification"} }, + "documentation":"

Information about a tool that can be used.

", "union":true }, "ToolDescription":{ "type":"string", + "documentation":"

The description for the tool.

", "max":10240, "min":1, "sensitive":true @@ -1663,10 +2293,12 @@ "type":"structure", "members":{ "json":{"shape":"SensitiveDocument"} - } + }, + "documentation":"

The input schema for the tool in JSON format.

" }, "ToolName":{ "type":"string", + "documentation":"

The name for the tool.

", "max":64, "min":0, "pattern":"[a-zA-Z][a-zA-Z0-9_]*", @@ -1680,9 +2312,13 @@ ], "members":{ "toolUseId":{"shape":"ToolUseId"}, - "content":{"shape":"ToolResultContent"}, + "content":{ + "shape":"ToolResultContent", + "documentation":"

Content of the tool result.

" + }, "status":{"shape":"ToolResultStatus"} - } + }, + "documentation":"

A tool result that contains the results for a tool request that was previously made.

" }, "ToolResultContent":{ "type":"list", @@ -1691,19 +2327,33 @@ "ToolResultContentBlock":{ "type":"structure", "members":{ - "text":{"shape":"ToolResultContentBlockTextString"}, - "json":{"shape":"SensitiveDocument"} + "text":{ + "shape":"ToolResultContentBlockTextString", + "documentation":"

A tool result that is text.

" + }, + "json":{ + "shape":"SensitiveDocument", + "documentation":"

A tool result that is JSON format data.

" + } }, "union":true }, "ToolResultContentBlockTextString":{ "type":"string", - "max":30720, + "max":800000, "min":0, "sensitive":true }, + "ToolResultEvent":{ + "type":"structure", + "members":{ + "toolResult":{"shape":"ToolResult"} + }, + "event":true + }, "ToolResultStatus":{ "type":"string", + "documentation":"

Status of the tools result.

", "enum":[ "success", "error" @@ -1725,7 +2375,8 @@ "inputSchema":{"shape":"ToolInputSchema"}, "name":{"shape":"ToolName"}, "description":{"shape":"ToolDescription"} - } + }, + "documentation":"

The specification for the tool.

" }, "ToolUse":{ "type":"structure", @@ -1737,8 +2388,12 @@ "members":{ "toolUseId":{"shape":"ToolUseId"}, "name":{"shape":"ToolName"}, - "input":{"shape":"SensitiveDocument"} - } + "input":{ + "shape":"SensitiveDocument", + "documentation":"

The input to pass to the tool.

" + } + }, + "documentation":"

Contains information about a tool that the model is requesting be run. The model uses the result from the tool to generate a response.

" }, "ToolUseEvent":{ "type":"structure", @@ -1749,19 +2404,27 @@ "members":{ "toolUseId":{"shape":"ToolUseId"}, "name":{"shape":"ToolName"}, - "input":{"shape":"ToolUseEventInputString"}, - "stop":{"shape":"Boolean"} + "input":{ + "shape":"ToolUseEventInputString", + "documentation":"

Represents the serialized json input for the ToolUse request. This field should be concatenated until 'stop' is true.

" + }, + "stop":{ + "shape":"Boolean", + "documentation":"

This field is true when all of the serialized input for this ToolUse request has been sent.

" + } }, + "documentation":"

Event for a ToolUse request. Multiple ToolUse requests can be returned from a single request, so each ToolUse has a unique 'toolUseId'.

", "event":true }, "ToolUseEventInputString":{ "type":"string", - "max":10240, + "max":30720, "min":0, "sensitive":true }, "ToolUseId":{ "type":"string", + "documentation":"

The ID for the tool request.

", "max":64, "min":0, "pattern":"[a-zA-Z0-9_-]+" @@ -1793,7 +2456,8 @@ "members":{ "downloadArtifactId":{"shape":"ArtifactId"}, "downloadArtifactType":{"shape":"TransformationDownloadArtifactType"} - } + }, + "documentation":"

Transformation export context

" }, "UUID":{ "type":"string", @@ -1806,10 +2470,12 @@ "members":{ "testGenerationJobGroupName":{"shape":"TestGenerationJobGroupName"}, "testGenerationJobId":{"shape":"UUID"} - } + }, + "documentation":"

Unit test generation export context

" }, "UploadId":{ "type":"string", + "documentation":"

Upload ID returned by CreateUploadUrl API

", "max":128, "min":1 }, @@ -1817,12 +2483,28 @@ "type":"structure", "required":["content"], "members":{ - "content":{"shape":"UserInputMessageContentString"}, - "userInputMessageContext":{"shape":"UserInputMessageContext"}, - "userIntent":{"shape":"UserIntent"}, - "origin":{"shape":"Origin"}, - "images":{"shape":"ImageBlocks"} - } + "content":{ + "shape":"UserInputMessageContentString", + "documentation":"

The content of the chat message.

" + }, + "userInputMessageContext":{ + "shape":"UserInputMessageContext", + "documentation":"

Chat message context associated with the Chat Message.

" + }, + "userIntent":{ + "shape":"UserIntent", + "documentation":"

User Intent.

" + }, + "origin":{ + "shape":"Origin", + "documentation":"

User Input Origin.

" + }, + "images":{ + "shape":"ImageBlocks", + "documentation":"

Images associated with the Chat Message.

" + } + }, + "documentation":"

Structure to represent a chat input message from User.

" }, "UserInputMessageContentString":{ "type":"string", @@ -1833,21 +2515,56 @@ "UserInputMessageContext":{ "type":"structure", "members":{ - "editorState":{"shape":"EditorState"}, - "shellState":{"shape":"ShellState"}, - "gitState":{"shape":"GitState"}, - "envState":{"shape":"EnvState"}, - "appStudioContext":{"shape":"AppStudioState"}, - "diagnostic":{"shape":"Diagnostic"}, - "consoleState":{"shape":"ConsoleState"}, - "userSettings":{"shape":"UserSettings"}, - "additionalContext":{"shape":"AdditionalContentList"}, - "toolResults":{"shape":"ToolResults"}, - "tools":{"shape":"Tools"} - } + "editorState":{ + "shape":"EditorState", + "documentation":"

Editor state chat message context.

" + }, + "shellState":{ + "shape":"ShellState", + "documentation":"

Shell state chat message context.

" + }, + "gitState":{ + "shape":"GitState", + "documentation":"

Git state chat message context.

" + }, + "envState":{ + "shape":"EnvState", + "documentation":"

Environment state chat message context.

" + }, + "appStudioContext":{ + "shape":"AppStudioState", + "documentation":"

The state of a user's AppStudio UI when sending a message.

" + }, + "diagnostic":{ + "shape":"Diagnostic", + "documentation":"

Diagnostic chat message context.

" + }, + "consoleState":{ + "shape":"ConsoleState", + "documentation":"

Contextual information about the environment from which the user is calling.

" + }, + "userSettings":{ + "shape":"UserSettings", + "documentation":"

Settings information, e.g., whether the user has enabled cross-region API calls.

" + }, + "additionalContext":{ + "shape":"AdditionalContentList", + "documentation":"

List of additional contextual content entries that can be included with the message.

" + }, + "toolResults":{ + "shape":"ToolResults", + "documentation":"

ToolResults for the requested ToolUses.

" + }, + "tools":{ + "shape":"Tools", + "documentation":"

Tools that can be used.

" + } + }, + "documentation":"

Additional Chat message context associated with the Chat Message

" }, "UserIntent":{ "type":"string", + "documentation":"

User Intent

", "enum":[ "SUGGEST_ALTERNATE_IMPLEMENTATION", "APPLY_COMMON_BEST_PRACTICES", @@ -1865,7 +2582,8 @@ "type":"structure", "members":{ "hasConsentedToCrossRegionCalls":{"shape":"Boolean"} - } + }, + "documentation":"

Settings information passed by the Q widget

" }, "ValidationException":{ "type":"structure", @@ -1874,10 +2592,12 @@ "message":{"shape":"String"}, "reason":{"shape":"ValidationExceptionReason"} }, + "documentation":"

This exception is thrown when the input fails to satisfy the constraints specified by the service.

", "exception":true }, "ValidationExceptionReason":{ "type":"string", + "documentation":"

Reason for ValidationException

", "enum":[ "INVALID_CONVERSATION_ID", "CONTENT_LENGTH_EXCEEDS_THRESHOLD", @@ -1891,8 +2611,14 @@ "url" ], "members":{ - "label":{"shape":"WebLinkLabelString"}, - "url":{"shape":"WebLinkUrlString"} + "label":{ + "shape":"WebLinkLabelString", + "documentation":"

A label for the link

" + }, + "url":{ + "shape":"WebLinkUrlString", + "documentation":"

URL of the Weblink

" + } } }, "WebLinkLabelString":{ @@ -1907,6 +2633,18 @@ "min":1, "sensitive":true }, + "WorkspaceFolderList":{ + "type":"list", + "member":{"shape":"WorkspaceFolderListMemberString"}, + "max":100, + "min":0 + }, + "WorkspaceFolderListMemberString":{ + "type":"string", + "max":4096, + "min":1, + "sensitive":true + }, "WorkspaceState":{ "type":"structure", "required":[ @@ -1914,10 +2652,20 @@ "programmingLanguage" ], "members":{ - "uploadId":{"shape":"UploadId"}, - "programmingLanguage":{"shape":"ProgrammingLanguage"}, - "contextTruncationScheme":{"shape":"ContextTruncationScheme"} - } + "uploadId":{ + "shape":"UploadId", + "documentation":"

Upload ID representing an Upload using a PreSigned URL

" + }, + "programmingLanguage":{ + "shape":"ProgrammingLanguage", + "documentation":"

Primary programming language of the Workspace

" + }, + "contextTruncationScheme":{ + "shape":"ContextTruncationScheme", + "documentation":"

Workspace context truncation schemes based on usecase

" + } + }, + "documentation":"

Represents a Workspace state uploaded to S3 for Async Code Actions

" } } } From a50938c4e35bc163dd72e63511e5b798324bd3c5 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 17:12:37 -0700 Subject: [PATCH 19/35] recover ut --- .../CodeWhispererModelConfigurator.kt | 1 + .../CodeWhispererModelConfiguratorTest.kt | 50 ------------------- 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 5541d008170..1dca21f3131 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -109,6 +109,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe override fun listCustomizations(project: Project, passive: Boolean): List? = calculateIfIamIdentityCenterConnection(project) { // 1. invoke API and get result + println("invalidate ${activeCustomization(project)}") val listAvailableCustomizationsResult = try { CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations() } catch (e: Exception) { diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index cf79e0668ca..b1fa0ef5592 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -7,7 +7,6 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.testFramework.ApplicationRule import com.intellij.testFramework.DisposableRule import com.intellij.testFramework.ProjectRule -import com.intellij.testFramework.registerServiceInstance import com.intellij.testFramework.replaceService import com.intellij.util.xmlb.XmlSerializer import org.assertj.core.api.Assertions.assertThat @@ -41,8 +40,6 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext -import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener -import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomizationState import software.aws.toolkits.jetbrains.services.codewhisperer.customization.DefaultCodeWhispererModelConfigurator @@ -78,7 +75,6 @@ class CodeWhispererModelConfiguratorTest { private lateinit var sut: DefaultCodeWhispererModelConfigurator private lateinit var mockClient: CodeWhispererRuntimeClient private lateinit var abManager: CodeWhispererFeatureConfigService - private lateinit var mockClintAdaptor: CodeWhispererClientAdaptor @Before fun setup() { @@ -114,9 +110,6 @@ class CodeWhispererModelConfiguratorTest { abManager, disposableRule.disposable ) - - mockClintAdaptor = mock() - projectRule.project.registerServiceInstance(CodeWhispererClientAdaptor::class.java, mockClintAdaptor) } @Test @@ -557,47 +550,4 @@ class CodeWhispererModelConfiguratorTest { assertThat(actual.previousAvailableCustomizations).hasSize(1) assertThat(actual.previousAvailableCustomizations["fake-sso-url"]).isEqualTo(listOf("arn_1", "arn_2", "arn_3")) } - - @Test - fun `profile switch should keep using existing customization if new list still contains that arn`() { - val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) - ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) - val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") - sut.switchCustomization(projectRule.project, oldCustomization) - - assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) - - val fakeCustomizations = listOf( - CodeWhispererCustomization("oldArn", "oldName", "oldDescription") - ) - - mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations} - - ApplicationManager.getApplication().messageBus - .syncPublisher(QRegionProfileSelectedListener.TOPIC) - .onProfileSelected(projectRule.project, null) - - assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) - } - - @Test - fun `profile switch should invalidate obsolete customization if it's not in the new list`() { - val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) - ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) - val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") - sut.switchCustomization(projectRule.project, oldCustomization) - assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) - - val fakeCustomizations = listOf( - CodeWhispererCustomization("newArn", "newName", "oldDescription") - ) - mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations} - - ApplicationManager.getApplication().messageBus - .syncPublisher(QRegionProfileSelectedListener.TOPIC) - .onProfileSelected(projectRule.project, null) - - assertThat(sut.activeCustomization(projectRule.project)).isNull() - } - } From 4e7f6786e5ee5c40fe886bba54e0b6cc8dbc9028 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 17:13:40 -0700 Subject: [PATCH 20/35] remove import --- .../customization/CodeWhispererModelConfigurator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 1dca21f3131..0949418c1af 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -25,7 +25,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.calculateIfIamIdentityCe import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor -import software.aws.toolkits.jetbrains.services.codewhisperer.status.CodeWhispererStatusBarWidget.Companion.ID import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants import software.aws.toolkits.jetbrains.utils.notifyInfo import software.aws.toolkits.jetbrains.utils.notifyWarn From ba3cb42f22974820638d66e91e250e7c1fba1f62 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 17:14:17 -0700 Subject: [PATCH 21/35] recover --- .../customization/CodeWhispererModelConfigurator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 0949418c1af..18c14563ac4 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -108,7 +108,6 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe override fun listCustomizations(project: Project, passive: Boolean): List? = calculateIfIamIdentityCenterConnection(project) { // 1. invoke API and get result - println("invalidate ${activeCustomization(project)}") val listAvailableCustomizationsResult = try { CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations() } catch (e: Exception) { From 5dd8369d54ab1fe9c6f2c8ff26265af626e91342 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 19:26:30 -0700 Subject: [PATCH 22/35] add ut --- .../CodeWhispererModelConfigurator.kt | 1 + .../CodeWhispererModelConfiguratorTest.kt | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 18c14563ac4..6f3a84fcbf9 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -50,6 +50,7 @@ private fun notifyInvalidSelectedCustomization(project: Project) { } private fun notifyNewCustomization(project: Project) { + if (ApplicationManager.getApplication().isUnitTestMode) return notifyInfo( title = message("codewhisperer.custom.dialog.title"), content = message("codewhisperer.notification.custom.new_customization"), diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index b1fa0ef5592..57099bb5d75 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -7,8 +7,10 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.testFramework.ApplicationRule import com.intellij.testFramework.DisposableRule import com.intellij.testFramework.ProjectRule +import com.intellij.testFramework.registerServiceInstance import com.intellij.testFramework.replaceService import com.intellij.util.xmlb.XmlSerializer +import migration.software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator import org.assertj.core.api.Assertions.assertThat import org.jdom.output.XMLOutputter import org.junit.Before @@ -40,10 +42,14 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener +import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomizationState import software.aws.toolkits.jetbrains.services.codewhisperer.customization.DefaultCodeWhispererModelConfigurator import software.aws.toolkits.jetbrains.utils.xmlElement +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit import kotlin.reflect.full.memberProperties import kotlin.reflect.jvm.isAccessible @@ -75,6 +81,7 @@ class CodeWhispererModelConfiguratorTest { private lateinit var sut: DefaultCodeWhispererModelConfigurator private lateinit var mockClient: CodeWhispererRuntimeClient private lateinit var abManager: CodeWhispererFeatureConfigService + private lateinit var mockClintAdaptor: CodeWhispererClientAdaptor @Before fun setup() { @@ -83,7 +90,13 @@ class CodeWhispererModelConfiguratorTest { regionProvider.addRegion(Region.US_EAST_1) regionProvider.addRegion(Region.US_EAST_2) - sut = DefaultCodeWhispererModelConfigurator() + val original = CodeWhispererModelConfigurator.getInstance() + sut = spy(original) as DefaultCodeWhispererModelConfigurator + ApplicationManager.getApplication().replaceService( + DefaultCodeWhispererModelConfigurator::class.java, + sut, + disposableRule.disposable + ) (ToolkitConnectionManager.getInstance(projectRule.project) as DefaultToolkitConnectionManager).loadState(ToolkitConnectionManagerState()) mockClient.stub { @@ -110,6 +123,9 @@ class CodeWhispererModelConfiguratorTest { abManager, disposableRule.disposable ) + + mockClintAdaptor = mock() + projectRule.project.registerServiceInstance(CodeWhispererClientAdaptor::class.java, mockClintAdaptor) } @Test @@ -550,4 +566,48 @@ class CodeWhispererModelConfiguratorTest { assertThat(actual.previousAvailableCustomizations).hasSize(1) assertThat(actual.previousAvailableCustomizations["fake-sso-url"]).isEqualTo(listOf("arn_1", "arn_2", "arn_3")) } + + @Test + fun `profile switch should keep using existing customization if new list still contains that arn`() { + val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) + ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) + val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + sut.switchCustomization(projectRule.project, oldCustomization) + + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + + val fakeCustomizations = listOf( + CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + ) + mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations } + + ApplicationManager.getApplication().messageBus + .syncPublisher(QRegionProfileSelectedListener.TOPIC) + .onProfileSelected(projectRule.project, null) + + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + } + + @Test + fun `profile switch should invalidate obsolete customization if it's not in the new list`() { + val ssoConn = spy(LegacyManagedBearerSsoConnection(region = "us-east-1", startUrl = "url 1", scopes = Q_SCOPES)) + ToolkitConnectionManager.getInstance(projectRule.project).switchConnection(ssoConn) + val oldCustomization = CodeWhispererCustomization("oldArn", "oldName", "oldDescription") + sut.switchCustomization(projectRule.project, oldCustomization) + assertThat(sut.activeCustomization(projectRule.project)).isEqualTo(oldCustomization) + val fakeCustomizations = listOf( + CodeWhispererCustomization("newArn", "newName", "newDescription") + ) + mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations } + + val latch = CountDownLatch(1) + + ApplicationManager.getApplication().messageBus + .syncPublisher(QRegionProfileSelectedListener.TOPIC) + .onProfileSelected(projectRule.project, null) + + latch.await(2, TimeUnit.SECONDS) + + assertThat(sut.activeCustomization(projectRule.project)).isNull() + } } From fb908ccac3ca9feddcd401f66a44459a9a9023f9 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Mon, 14 Apr 2025 19:35:23 -0700 Subject: [PATCH 23/35] log --- .../bugfix-a70cb565-5de8-4302-9f1e-71925f78061b.json | 4 ++++ .../CodeWhispererModelConfiguratorTest.kt | 12 +++++------- 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 .changes/next-release/bugfix-a70cb565-5de8-4302-9f1e-71925f78061b.json diff --git a/.changes/next-release/bugfix-a70cb565-5de8-4302-9f1e-71925f78061b.json b/.changes/next-release/bugfix-a70cb565-5de8-4302-9f1e-71925f78061b.json new file mode 100644 index 00000000000..7c369ea5be3 --- /dev/null +++ b/.changes/next-release/bugfix-a70cb565-5de8-4302-9f1e-71925f78061b.json @@ -0,0 +1,4 @@ +{ + "type" : "bugfix", + "description" : "Amazon Q: Customization now resets with a warning if unavailable in the selected profile." +} \ No newline at end of file diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index 57099bb5d75..751db478b5b 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -90,13 +90,11 @@ class CodeWhispererModelConfiguratorTest { regionProvider.addRegion(Region.US_EAST_1) regionProvider.addRegion(Region.US_EAST_2) - val original = CodeWhispererModelConfigurator.getInstance() - sut = spy(original) as DefaultCodeWhispererModelConfigurator - ApplicationManager.getApplication().replaceService( - DefaultCodeWhispererModelConfigurator::class.java, - sut, - disposableRule.disposable - ) + sut = spy(CodeWhispererModelConfigurator.getInstance() as DefaultCodeWhispererModelConfigurator).also { spyInstance -> + ApplicationManager.getApplication().replaceService( + DefaultCodeWhispererModelConfigurator::class.java, spyInstance, disposableRule.disposable + ) + } (ToolkitConnectionManager.getInstance(projectRule.project) as DefaultToolkitConnectionManager).loadState(ToolkitConnectionManagerState()) mockClient.stub { From a9de9d60957f97d3542d724922de87d481542009 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 16 Apr 2025 15:30:02 -0700 Subject: [PATCH 24/35] list all cus for all profiles and sort --- .../CodeWhispererCustomizationDialog.kt | 28 ++++-- .../CodeWhispererModelConfigurator.kt | 94 ++++++++++++------- .../CodeWhispererCustomization.kt | 4 + 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index eedff33e2c3..9ad0d597e24 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2023 Amazon.com, Inc. or it s affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package software.aws.toolkits.jetbrains.services.codewhisperer.customization @@ -26,6 +26,8 @@ import software.amazon.awssdk.arns.Arn import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.tryOrNull +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.Q_CUSTOM_LEARN_MORE_URI import software.aws.toolkits.jetbrains.ui.AsyncComboBox import software.aws.toolkits.jetbrains.utils.notifyInfo @@ -34,7 +36,7 @@ import javax.swing.JComponent import javax.swing.JList private val NoDataToDisplay = CustomizationUiItem( - CodeWhispererCustomization("", message("codewhisperer.custom.dialog.option.no_data"), ""), + CodeWhispererCustomization("", message("codewhisperer.custom.dialog.option.no_data"), "", QRegionProfile("","")), false, false ) @@ -179,11 +181,19 @@ class CodeWhispererCustomizationDialog( proposeModelUpdate { model -> val activeCustomization = CodeWhispererModelConfigurator.getInstance().activeCustomization(project) val unsorted = myCustomizations ?: CodeWhispererModelConfigurator.getInstance().listCustomizations(project).orEmpty() - - val sorted = activeCustomization?.let { - unsorted.putPickedUpFront(setOf(it)) - } ?: run { - unsorted.sortedBy { it.customization.name } + val activeProfile = QRegionProfileManager.getInstance().activeProfile(project) + // sort customization based on profile name first + val baseSorted = unsorted.sortedWith( + compareBy { + it.customization.profile?.profileName != activeProfile?.profileName + }.thenBy { it.customization.profile?.profileName ?: "" } + .thenBy { it.customization.name } + ) + + val sorted = if (activeCustomization != null) { + baseSorted.putPickedUpFront(setOf(activeCustomization)) + } else { + baseSorted } if ( @@ -259,6 +269,10 @@ private object CustomizationRenderer : ColoredListCellRenderer(mutableMapOf()) // Map to store connectionId to its listAvailableCustomizations result last time + // the customization has format profileArn::customizationArn private val connectionToCustomizationsShownLastTime = mutableMapOf>() private val connectionIdToIsAllowlisted = Collections.synchronizedMap(mutableMapOf()) @@ -107,27 +116,49 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe @RequiresBackgroundThread override fun listCustomizations(project: Project, passive: Boolean): List? = - calculateIfIamIdentityCenterConnection(project) { + calculateIfIamIdentityCenterConnection(project) { it -> // 1. invoke API and get result - val listAvailableCustomizationsResult = try { - CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations() - } catch (e: Exception) { - val requestId = (e as? CodeWhispererRuntimeException)?.requestId() - val logMessage = if (CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e)) { - // TODO: not required for non GP users - "ListAvailableCustomizations: connection ${it.id} is not allowlisted, requestId: ${requestId.orEmpty()}" - } else { - "ListAvailableCustomizations: failed due to unknown error ${e.message}, requestId: ${requestId.orEmpty()}" - } + val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) } ?: emptyList() + + val aggregatedCustomizations = mutableListOf() - LOG.debug { logMessage } - null + for (profile in listAvailableProfilesResult) { + try { + val setting = AwsRegionProvider.getInstance()[profile.region]?.let { it1 -> + ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.getConnectionSettings() + ?.withRegion(it1) + } + val client = setting?.let { it1 -> AwsClientManager.getInstance().getClient(CodeWhispererRuntimeClient::class, it1) } + val perProfileCustomizations = + client?.listAvailableCustomizationsPaginator(ListAvailableCustomizationsRequest.builder().profileArn(profile.arn).build()) + ?.customizations()?.stream()?.toList()?.map { + CodeWhispererCustomization( + arn = it.arn(), + name = it.name(), + description = it.description(), + profile = profile + ) + } + if (perProfileCustomizations != null) { + aggregatedCustomizations.addAll(perProfileCustomizations) + } + } catch (e: Exception) { + val requestId = (e as? CodeWhispererRuntimeException)?.requestId() + val logMessage = if (CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e)) { + // TODO: not required for non GP users + "ListAvailableCustomizations: connection ${it.id} is not allowlisted, requestId: ${requestId.orEmpty()}" + } else { + "ListAvailableCustomizations: failed due to unknown error ${e.message}, requestId: ${requestId.orEmpty()}" + } + + LOG.debug { logMessage } + } } // 2. get diff val previousCustomizationsShapshot = connectionToCustomizationsShownLastTime.getOrElse(it.id) { emptyList() } - val diff = listAvailableCustomizationsResult?.filterNot { customization -> previousCustomizationsShapshot.contains(customization.arn) }?.toSet() - + // calculate new profile+customization list using profile.arn :: customization.arn as the key + val diff = aggregatedCustomizations.filterNot { customization -> previousCustomizationsShapshot.contains("${customization.profile?.arn}::${customization.arn}") }.toSet() // 3 if passive, // (1) update allowlisting // (2) prompt "You have New Customizations" toast notification (only show once) @@ -135,13 +166,13 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe // if not passive, // (1) update the customization list snapshot (seen by users last time) if it will be displayed if (passive) { - connectionIdToIsAllowlisted[it.id] = listAvailableCustomizationsResult != null + connectionIdToIsAllowlisted[it.id] = aggregatedCustomizations.isNotEmpty() if (diff?.isNotEmpty() == true && !hasShownNewCustomizationNotification.getAndSet(true)) { notifyNewCustomization(project) } } else { - listAvailableCustomizationsResult?.let { customizations -> - connectionToCustomizationsShownLastTime[it.id] = customizations.map { customization -> customization.arn }.toMutableList() + aggregatedCustomizations.let { customizations -> + connectionToCustomizationsShownLastTime[it.id] = customizations.map { customization -> "${customization.profile?.arn}::${customization.arn}"}.toMutableList() } } @@ -149,28 +180,25 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe // (1) the API call failed // (2) the selected customization is not in the resultset of API call activeCustomization(project)?.let { activeCustom -> - if (listAvailableCustomizationsResult == null) { + if (aggregatedCustomizations.isEmpty()) { invalidateSelectedAndNotify(project) - } else if (!listAvailableCustomizationsResult.any { latestCustom -> latestCustom.arn == activeCustom.arn }) { + } else if (!aggregatedCustomizations.any { latestCustom -> "${latestCustom.profile?.arn}::${latestCustom.arn}" == "${activeCustom.profile?.arn}::${activeCustom.arn}"} + || activeCustom.profile!= QRegionProfileManager.getInstance().activeProfile(project)){ invalidateSelectedAndNotify(project) } } // 5. transform result to UI items and return - val customizationUiItems = if (diff != null) { - listAvailableCustomizationsResult.let { customizations -> - val nameToCount = customizations.groupingBy { customization -> customization.name }.eachCount() - - customizations.map { customization -> - CustomizationUiItem( - customization, - isNew = diff.contains(customization), - shouldPrefixAccountId = (nameToCount[customization.name] ?: 0) > 1 - ) - } + val customizationUiItems = aggregatedCustomizations.let { customizations -> + val nameToCount = customizations.groupingBy { customization -> customization.name }.eachCount() + + customizations.map { customization -> + CustomizationUiItem( + customization, + isNew = diff.contains(customization), + shouldPrefixAccountId = (nameToCount[customization.name] ?: 0) > 1 + ) } - } else { - null } connectionToCustomizationUiItems[it.id] = customizationUiItems diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt index 92335fec559..5d4bdb2aac3 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package software.aws.toolkits.jetbrains.services.codewhisperer.customization +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile data class CodeWhispererCustomization( @JvmField @@ -12,4 +13,7 @@ data class CodeWhispererCustomization( @JvmField var description: String? = null, + + @JvmField + var profile: QRegionProfile? = null ) From f3192834b0f09f5eee7c1436b539071e586addb0 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 16 Apr 2025 16:30:49 -0700 Subject: [PATCH 25/35] add an optional profile in getQclient --- .../credentials/CodeWhispererClientAdaptor.kt | 12 ++--- .../CodeWhispererCustomizationDialog.kt | 4 +- .../CodeWhispererModelConfigurator.kt | 44 +++++++------------ .../amazonq/profile/QRegionProfileManager.kt | 21 +++++---- .../CodeWhispererCustomization.kt | 2 +- 5 files changed, 36 insertions(+), 47 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt index aabefda3365..36cd74b6d1d 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt @@ -38,6 +38,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.UserIntent import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.jetbrains.services.amazonq.codeWhispererUserContext +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage @@ -78,7 +79,7 @@ interface CodeWhispererClientAdaptor { fun getCodeFixJob(request: GetCodeFixJobRequest): GetCodeFixJobResponse - fun listAvailableCustomizations(): List + fun listAvailableCustomizations(profile: QRegionProfile): List fun startTestGeneration(uploadId: String, targetCode: List, userInput: String): StartTestGenerationResponse @@ -282,9 +283,9 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW override fun getCodeFixJob(request: GetCodeFixJobRequest): GetCodeFixJobResponse = bearerClient().getCodeFixJob(request) // DO NOT directly use this method to fetch customizations, use wrapper [CodeWhispererModelConfigurator.listCustomization()] instead - override fun listAvailableCustomizations(): List = - bearerClient().listAvailableCustomizationsPaginator( - ListAvailableCustomizationsRequest.builder().profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn).build() + override fun listAvailableCustomizations(profile: QRegionProfile): List = + QRegionProfileManager.getInstance().getQClient(project, profile).listAvailableCustomizationsPaginator( + ListAvailableCustomizationsRequest.builder().profileArn(profile.arn).build() ) .stream() .toList() @@ -298,7 +299,8 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW CodeWhispererCustomization( arn = it.arn(), name = it.name(), - description = it.description() + description = it.description(), + profile = profile ) } } diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 9ad0d597e24..3b2a2b662fd 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Amazon.com, Inc. or it s affiliates. All Rights Reserved. +// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package software.aws.toolkits.jetbrains.services.codewhisperer.customization @@ -36,7 +36,7 @@ import javax.swing.JComponent import javax.swing.JList private val NoDataToDisplay = CustomizationUiItem( - CodeWhispererCustomization("", message("codewhisperer.custom.dialog.option.no_data"), "", QRegionProfile("","")), + CodeWhispererCustomization("", message("codewhisperer.custom.dialog.option.no_data"), "", QRegionProfile("", "")), false, false ) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 3bb6c79445c..94dd1143e3e 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -21,10 +21,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererR import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.tryOrNull -import software.aws.toolkits.jetbrains.core.AwsClientManager -import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager -import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection -import software.aws.toolkits.jetbrains.core.region.AwsRegionProvider import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.calculateIfIamIdentityCenterConnection import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile @@ -114,7 +110,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe @RequiresBackgroundThread override fun listCustomizations(project: Project, passive: Boolean): List? = - calculateIfIamIdentityCenterConnection(project) { it -> + calculateIfIamIdentityCenterConnection(project) { // 1. invoke API and get result val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) } ?: emptyList() @@ -122,24 +118,8 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe for (profile in listAvailableProfilesResult) { try { - val setting = AwsRegionProvider.getInstance()[profile.region]?.let { it1 -> - ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())?.getConnectionSettings() - ?.withRegion(it1) - } - val client = setting?.let { it1 -> AwsClientManager.getInstance().getClient(CodeWhispererRuntimeClient::class, it1) } - val perProfileCustomizations = - client?.listAvailableCustomizationsPaginator(ListAvailableCustomizationsRequest.builder().profileArn(profile.arn).build()) - ?.customizations()?.stream()?.toList()?.map { - CodeWhispererCustomization( - arn = it.arn(), - name = it.name(), - description = it.description(), - profile = profile - ) - } - if (perProfileCustomizations != null) { - aggregatedCustomizations.addAll(perProfileCustomizations) - } + val perProfileCustomizations = CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations(profile) + aggregatedCustomizations.addAll(perProfileCustomizations) } catch (e: Exception) { val requestId = (e as? CodeWhispererRuntimeException)?.requestId() val logMessage = if (CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e)) { @@ -148,7 +128,6 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe } else { "ListAvailableCustomizations: failed due to unknown error ${e.message}, requestId: ${requestId.orEmpty()}" } - LOG.debug { logMessage } } } @@ -156,7 +135,11 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe // 2. get diff val previousCustomizationsShapshot = connectionToCustomizationsShownLastTime.getOrElse(it.id) { emptyList() } // calculate new profile+customization list using profile.arn :: customization.arn as the key - val diff = aggregatedCustomizations.filterNot { customization -> previousCustomizationsShapshot.contains("${customization.profile?.arn}::${customization.arn}") }.toSet() + val diff = aggregatedCustomizations.filterNot { customization -> + previousCustomizationsShapshot.contains( + "${customization.profile?.arn}::${customization.arn}" + ) + }.toSet() // 3 if passive, // (1) update allowlisting // (2) prompt "You have New Customizations" toast notification (only show once) @@ -170,7 +153,10 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe } } else { aggregatedCustomizations.let { customizations -> - connectionToCustomizationsShownLastTime[it.id] = customizations.map { customization -> "${customization.profile?.arn}::${customization.arn}"}.toMutableList() + connectionToCustomizationsShownLastTime[it.id] = customizations.map { customization, + -> + "${customization.profile?.arn}::${customization.arn}" + }.toMutableList() } } @@ -180,8 +166,10 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe activeCustomization(project)?.let { activeCustom -> if (aggregatedCustomizations.isEmpty()) { invalidateSelectedAndNotify(project) - } else if (!aggregatedCustomizations.any { latestCustom -> "${latestCustom.profile?.arn}::${latestCustom.arn}" == "${activeCustom.profile?.arn}::${activeCustom.arn}"} - || activeCustom.profile!= QRegionProfileManager.getInstance().activeProfile(project)){ + } else if (!aggregatedCustomizations.any { latestCustom -> + "${latestCustom.profile?.arn}::${latestCustom.arn}" == "${activeCustom.profile?.arn}::${activeCustom.arn}" + } || activeCustom.profile != QRegionProfileManager.getInstance().activeProfile(project) + ) { invalidateSelectedAndNotify(project) } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index b3b242c363d..c1adac44673 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -166,27 +166,26 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl (connectionIdToProfileCount[conn.id] ?: 0) > 1 } ?: false - fun getQClientSettings(project: Project): TokenConnectionSettings { + fun getQClientSettings(project: Project, profile: QRegionProfile?): TokenConnectionSettings { val conn = ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance()) if (conn !is AwsBearerTokenConnection) { error("not a bearer connection") } val settings = conn.getConnectionSettings() - val awsRegion = AwsRegionProvider.getInstance()[QEndpoints.Q_DEFAULT_SERVICE_CONFIG.REGION] ?: error("unknown region from Q default service config") + val defaultRegion = AwsRegionProvider.getInstance()[QEndpoints.Q_DEFAULT_SERVICE_CONFIG.REGION] ?: error("unknown region from Q default service config") - // TODO: different window should be able to select different profile - return activeProfile(project)?.let { profile -> - AwsRegionProvider.getInstance()[profile.region]?.let { region -> - settings.withRegion(region) - } - } ?: settings.withRegion(awsRegion) + val regionId = profile?.region ?: activeProfile(project)?.region + val awsRegion = regionId?.let { AwsRegionProvider.getInstance()[it] } ?: defaultRegion + + return settings.withRegion(awsRegion) } - inline fun getQClient(project: Project): T = getQClient(project, T::class) + inline fun getQClient(project: Project): T = getQClient(project, null, T::class) + inline fun getQClient(project: Project, profile: QRegionProfile?): T = getQClient(project, profile, T::class) - fun getQClient(project: Project, sdkClass: KClass): T { - val settings = getQClientSettings(project) + fun getQClient(project: Project, profile: QRegionProfile?, sdkClass: KClass): T { + val settings = getQClientSettings(project, profile) val client = AwsClientManager.getInstance().getClient(sdkClass, settings) return client } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt index 5d4bdb2aac3..1ca14e6e025 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomization.kt @@ -15,5 +15,5 @@ data class CodeWhispererCustomization( var description: String? = null, @JvmField - var profile: QRegionProfile? = null + var profile: QRegionProfile? = null, ) From 7ec5868cce9719592af6cabb0e0339f7b57c5b18 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Wed, 16 Apr 2025 16:47:02 -0700 Subject: [PATCH 26/35] switch cus will switch profile --- .../customization/CodeWhispererCustomizationDialog.kt | 4 ++++ .../services/amazonq/profile/QProfileSwitchIntent.kt | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 3b2a2b662fd..44b98587fdb 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -26,6 +26,7 @@ import software.amazon.awssdk.arns.Arn import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.core.utils.tryOrNull +import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIntent import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.Q_CUSTOM_LEARN_MORE_URI @@ -108,6 +109,9 @@ class CodeWhispererCustomizationDialog( RadioButtonOption.Customization -> run { CodeWhispererModelConfigurator.getInstance().switchCustomization(project, modal.selectedCustomization?.customization) notifyCustomizationIsSelected(project, modal.selectedCustomization) + if (modal.selectedCustomization?.customization?.profile?.arn != QRegionProfileManager.getInstance().activeProfile(project)?.arn){ + QRegionProfileManager.getInstance().switchProfile(project, modal.selectedCustomization?.customization?.profile, QProfileSwitchIntent.Customization) + } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt index c1a7b4627ab..c088bac1674 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt @@ -8,12 +8,14 @@ package software.aws.toolkits.jetbrains.services.amazonq.profile * 'auth' -> users change the profile through webview profile selector page * 'update' -> plugin auto select the profile on users' behalf as there is only 1 profile * 'reload' -> on plugin restart, plugin will try to reload previous selected profile + * - 'customization' -> users selected a customization tied to a different profile, triggering a profile switch */ enum class QProfileSwitchIntent(val value: String) { User("user"), Auth("auth"), Update("update"), - Reload("reload"), ; + Reload("reload"), + Customization("customization"), ; override fun toString() = value } From e85b0ed54aaea54b91df5fb082e094eb45a9a84a Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 17 Apr 2025 16:34:18 -0700 Subject: [PATCH 27/35] fix ut --- .../CodeWhispererCustomizationDialog.kt | 10 +++++++--- .../customization/CodeWhispererModelConfigurator.kt | 4 ++-- .../codewhisperer/CodeWhispererClientAdaptorTest.kt | 9 +++++---- .../CodeWhispererFeatureConfigServiceTest.kt | 3 ++- .../CodeWhispererModelConfiguratorTest.kt | 13 ++++++++++--- .../codewhisperer/QRegionProfileManagerTest.kt | 10 +++++----- 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 44b98587fdb..61f73ddd3d1 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -109,8 +109,12 @@ class CodeWhispererCustomizationDialog( RadioButtonOption.Customization -> run { CodeWhispererModelConfigurator.getInstance().switchCustomization(project, modal.selectedCustomization?.customization) notifyCustomizationIsSelected(project, modal.selectedCustomization) - if (modal.selectedCustomization?.customization?.profile?.arn != QRegionProfileManager.getInstance().activeProfile(project)?.arn){ - QRegionProfileManager.getInstance().switchProfile(project, modal.selectedCustomization?.customization?.profile, QProfileSwitchIntent.Customization) + if (modal.selectedCustomization?.customization?.profile?.arn != QRegionProfileManager.getInstance().activeProfile(project)?.arn) { + QRegionProfileManager.getInstance().switchProfile( + project, + modal.selectedCustomization?.customization?.profile, + QProfileSwitchIntent.Customization + ) } } } @@ -190,7 +194,7 @@ class CodeWhispererCustomizationDialog( val baseSorted = unsorted.sortedWith( compareBy { it.customization.profile?.profileName != activeProfile?.profileName - }.thenBy { it.customization.profile?.profileName ?: "" } + }.thenBy { it.customization.profile?.profileName.orEmpty() } .thenBy { it.customization.name } ) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 94dd1143e3e..4d04e074d62 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -112,7 +112,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe override fun listCustomizations(project: Project, passive: Boolean): List? = calculateIfIamIdentityCenterConnection(project) { // 1. invoke API and get result - val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) } ?: emptyList() + val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) }.orEmpty() val aggregatedCustomizations = mutableListOf() @@ -148,7 +148,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe // (1) update the customization list snapshot (seen by users last time) if it will be displayed if (passive) { connectionIdToIsAllowlisted[it.id] = aggregatedCustomizations.isNotEmpty() - if (diff?.isNotEmpty() == true && !hasShownNewCustomizationNotification.getAndSet(true)) { + if (diff.isNotEmpty() && !hasShownNewCustomizationNotification.getAndSet(true)) { notifyNewCustomization(project) } } else { diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererClientAdaptorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererClientAdaptorTest.kt index 9a3a455d6e1..246d0ed8c00 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererClientAdaptorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererClientAdaptorTest.kt @@ -65,6 +65,7 @@ import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection import software.aws.toolkits.jetbrains.core.credentials.sono.Q_SCOPES import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_REGION import software.aws.toolkits.jetbrains.services.amazonq.FEATURE_EVALUATION_PRODUCT_NAME +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.metadata import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonRequest import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonResponseWithToken @@ -189,13 +190,13 @@ class CodeWhispererClientAdaptorTest { on { client.listAvailableCustomizationsPaginator(any()) } doReturn sdkIterable } - val actual = sut.listAvailableCustomizations() + val actual = sut.listAvailableCustomizations(QRegionProfile("fake_profile", "fake arn")) assertThat(actual).hasSize(3) assertThat(actual).isEqualTo( listOf( - CodeWhispererCustomization(name = "custom-1", arn = "arn-1"), - CodeWhispererCustomization(name = "custom-2", arn = "arn-2"), - CodeWhispererCustomization(name = "custom-3", arn = "arn-3") + CodeWhispererCustomization(name = "custom-1", arn = "arn-1", profile = QRegionProfile("fake_profile", "fake arn")), + CodeWhispererCustomization(name = "custom-2", arn = "arn-2", profile = QRegionProfile("fake_profile", "fake arn")), + CodeWhispererCustomization(name = "custom-3", arn = "arn-3", profile = QRegionProfile("fake_profile", "fake arn")) ) ) } diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererFeatureConfigServiceTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererFeatureConfigServiceTest.kt index 378e2703756..89de36d53fb 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererFeatureConfigServiceTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererFeatureConfigServiceTest.kt @@ -35,6 +35,7 @@ import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection import software.aws.toolkits.jetbrains.core.credentials.sono.SONO_URL import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import kotlin.reflect.full.memberFunctions import kotlin.test.Test @@ -78,7 +79,7 @@ class CodeWhispererFeatureConfigServiceTest { projectRule.project.replaceService( QRegionProfileManager::class.java, - mock { on { getQClient(any(), eq(CodeWhispererRuntimeClient::class)) } doReturn mockClient }, + mock { on { getQClient(any(), eq(QRegionProfile()), eq(CodeWhispererRuntimeClient::class)) } doReturn mockClient }, disposableRule.disposable ) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index 751db478b5b..ced8ee4496d 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -42,6 +42,7 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization @@ -431,7 +432,7 @@ class CodeWhispererModelConfiguratorTest { this.connectionIdToActiveCustomizationArn.putAll( mapOf( - "fake-sso-url" to CodeWhispererCustomization(arn = "arn_2", name = "name_2", description = "description_2") + "fake-sso-url" to CodeWhispererCustomization(arn = "arn_2", name = "name_2", description = "description_2", profile = QRegionProfile(profileName = "myActiveProfile", arn = "arn:aws:codewhisperer:us-west-2:123456789012:profile/myActiveProfile")) ) ) @@ -450,6 +451,12 @@ class CodeWhispererModelConfiguratorTest { "" + "" + "" + "" + @@ -577,7 +584,7 @@ class CodeWhispererModelConfiguratorTest { val fakeCustomizations = listOf( CodeWhispererCustomization("oldArn", "oldName", "oldDescription") ) - mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations } + mockClintAdaptor.stub { on { listAvailableCustomizations(QRegionProfile("fake_name", "fake_arn")) } doReturn fakeCustomizations } ApplicationManager.getApplication().messageBus .syncPublisher(QRegionProfileSelectedListener.TOPIC) @@ -596,7 +603,7 @@ class CodeWhispererModelConfiguratorTest { val fakeCustomizations = listOf( CodeWhispererCustomization("newArn", "newName", "newDescription") ) - mockClintAdaptor.stub { on { listAvailableCustomizations() } doReturn fakeCustomizations } + mockClintAdaptor.stub { on { listAvailableCustomizations(QRegionProfile("fake_name", "fake_arn")) } doReturn fakeCustomizations } val latch = CountDownLatch(1) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt index 628ab8e36c9..a1a8e186864 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt @@ -178,7 +178,7 @@ class QRegionProfileManagerTest { client.stub { onGeneric { listAvailableProfilesPaginator(any>()) } doReturn iterable } - val connectionSettings = sut.getQClientSettings(project) + val connectionSettings = sut.getQClientSettings(project, null) resourceCache.addEntry(connectionSettings, QProfileResources.LIST_REGION_PROFILES, QProfileResources.LIST_REGION_PROFILES.fetch(connectionSettings)) assertThat(sut.listRegionProfiles(project)) @@ -234,7 +234,7 @@ class QRegionProfileManagerTest { sut.activeProfile(project) ).isEqualTo(QRegionProfile(arn = "arn:aws:codewhisperer:eu-central-1:123456789012:profile/FOO_PROFILE", profileName = "FOO_PROFILE")) - val settings = sut.getQClientSettings(project) + val settings = sut.getQClientSettings(project, null) assertThat(settings.region.id).isEqualTo(Region.EU_CENTRAL_1.id()) sut.switchProfile( @@ -246,7 +246,7 @@ class QRegionProfileManagerTest { sut.activeProfile(project) ).isEqualTo(QRegionProfile(arn = "arn:aws:codewhisperer:us-east-1:123456789012:profile/BAR_PROFILE", profileName = "BAR_PROFILE")) - val settings2 = sut.getQClientSettings(project) + val settings2 = sut.getQClientSettings(project, null) assertThat(settings2.region.id).isEqualTo(Region.US_EAST_1.id()) } @@ -262,7 +262,7 @@ class QRegionProfileManagerTest { assertThat( sut.activeProfile(project) ).isEqualTo(QRegionProfile(arn = "arn:aws:codewhisperer:eu-central-1:123456789012:profile/FOO_PROFILE", profileName = "FOO_PROFILE")) - assertThat(sut.getQClientSettings(project).region.id).isEqualTo(Region.EU_CENTRAL_1.id()) + assertThat(sut.getQClientSettings(project, null).region.id).isEqualTo(Region.EU_CENTRAL_1.id()) val client = sut.getQClient(project) assertThat(client).isInstanceOf(CodeWhispererRuntimeClient::class.java) @@ -279,7 +279,7 @@ class QRegionProfileManagerTest { assertThat( sut.activeProfile(project) ).isEqualTo(QRegionProfile(arn = "arn:aws:codewhisperer:us-east-1:123456789012:profile/BAR_PROFILE", profileName = "BAR_PROFILE")) - assertThat(sut.getQClientSettings(project).region.id).isEqualTo(Region.US_EAST_1.id()) + assertThat(sut.getQClientSettings(project,null).region.id).isEqualTo(Region.US_EAST_1.id()) val client2 = sut.getQClient(project) assertThat(client2).isInstanceOf(CodeWhispererRuntimeClient::class.java) From 593838f79ca1013b1753d63ba0aa1452fda33909 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 17 Apr 2025 22:30:10 -0700 Subject: [PATCH 28/35] fix ut --- .../CodeWhispererModelConfiguratorTest.kt | 12 ++++++++++-- .../codewhisperer/QRegionProfileManagerTest.kt | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index ced8ee4496d..dfd156e741d 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -432,7 +432,10 @@ class CodeWhispererModelConfiguratorTest { this.connectionIdToActiveCustomizationArn.putAll( mapOf( - "fake-sso-url" to CodeWhispererCustomization(arn = "arn_2", name = "name_2", description = "description_2", profile = QRegionProfile(profileName = "myActiveProfile", arn = "arn:aws:codewhisperer:us-west-2:123456789012:profile/myActiveProfile")) + "fake-sso-url" to CodeWhispererCustomization( + arn = "arn_2", name = "name_2", description = "description_2", + profile = QRegionProfile(profileName = "myActiveProfile", arn = "arn:aws:codewhisperer:us-west-2:123456789012:profile/myActiveProfile") + ) ) ) @@ -507,6 +510,10 @@ class CodeWhispererModelConfiguratorTest { @@ -536,7 +543,8 @@ class CodeWhispererModelConfiguratorTest { CodeWhispererCustomization( arn = "arn_2", name = "name_2", - description = "description_2" + description = "description_2", + profile = QRegionProfile("myActiveProfile", "arn:aws:codewhisperer:us-west-2:123456789012:profile/myActiveProfile") ) ) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt index a1a8e186864..cd54f89ee27 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/QRegionProfileManagerTest.kt @@ -279,7 +279,7 @@ class QRegionProfileManagerTest { assertThat( sut.activeProfile(project) ).isEqualTo(QRegionProfile(arn = "arn:aws:codewhisperer:us-east-1:123456789012:profile/BAR_PROFILE", profileName = "BAR_PROFILE")) - assertThat(sut.getQClientSettings(project,null).region.id).isEqualTo(Region.US_EAST_1.id()) + assertThat(sut.getQClientSettings(project, null).region.id).isEqualTo(Region.US_EAST_1.id()) val client2 = sut.getQClient(project) assertThat(client2).isInstanceOf(CodeWhispererRuntimeClient::class.java) From 42aa64131a514f70d52659260d3cb2139ed80b37 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 17 Apr 2025 23:27:10 -0700 Subject: [PATCH 29/35] refactor --- .../CodeWhispererCustomizationDialog.kt | 20 ++---- .../CodeWhispererModelConfigurator.kt | 68 +++++++++---------- 2 files changed, 39 insertions(+), 49 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 61f73ddd3d1..16ac89d4ceb 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -190,19 +190,13 @@ class CodeWhispererCustomizationDialog( val activeCustomization = CodeWhispererModelConfigurator.getInstance().activeCustomization(project) val unsorted = myCustomizations ?: CodeWhispererModelConfigurator.getInstance().listCustomizations(project).orEmpty() val activeProfile = QRegionProfileManager.getInstance().activeProfile(project) - // sort customization based on profile name first - val baseSorted = unsorted.sortedWith( - compareBy { - it.customization.profile?.profileName != activeProfile?.profileName - }.thenBy { it.customization.profile?.profileName.orEmpty() } - .thenBy { it.customization.name } - ) - - val sorted = if (activeCustomization != null) { - baseSorted.putPickedUpFront(setOf(activeCustomization)) - } else { - baseSorted - } + // Group customizations by profile name (active profile first, then alphabetical), with the active customization on top + val sorted = unsorted.sortedWith( + compareBy { it.customization.profile?.profileName != activeProfile?.profileName } + .thenBy { it.customization.profile?.profileName.orEmpty() } + .thenBy { it.customization.name } + ) + .let { list -> activeCustomization?.let { list.putPickedUpFront(setOf(it)) } ?: list } if ( sorted.isNotEmpty() && diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 4d04e074d62..3ec5275dada 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -65,6 +65,13 @@ private fun notifyNewCustomization(project: Project) { ) } +/** + * generate a stable composite key for profile & customization combination for diff/deduplicate/search + * rule: `::` + */ +private fun CodeWhispererCustomization.compositeKey(): String = + "${profile?.arn.orEmpty()}::$arn" + @Service(Service.Level.APP) @State(name = "codewhispererCustomizationStates", storages = [Storage("aws.xml")]) class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, PersistentStateComponent, Disposable { @@ -73,7 +80,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe private val connectionIdToActiveCustomizationArn = Collections.synchronizedMap(mutableMapOf()) // Map to store connectionId to its listAvailableCustomizations result last time - // the customization has format profileArn::customizationArn + // Format of the customization key: profileArn::customizationArn private val connectionToCustomizationsShownLastTime = mutableMapOf>() private val connectionIdToIsAllowlisted = Collections.synchronizedMap(mutableMapOf()) @@ -111,35 +118,32 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe @RequiresBackgroundThread override fun listCustomizations(project: Project, passive: Boolean): List? = calculateIfIamIdentityCenterConnection(project) { - // 1. invoke API and get result + // 1. fetch all profiles, invoke fetch customizations API and get result for each profile and aggregate all the results val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) }.orEmpty() - val aggregatedCustomizations = mutableListOf() - - for (profile in listAvailableProfilesResult) { - try { - val perProfileCustomizations = CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations(profile) - aggregatedCustomizations.addAll(perProfileCustomizations) - } catch (e: Exception) { + val aggregatedCustomizations = listAvailableProfilesResult.flatMap { profile -> + runCatching { + CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations(profile) + }.onFailure { e -> val requestId = (e as? CodeWhispererRuntimeException)?.requestId() - val logMessage = if (CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e)) { + val isNotAllowlisted = (e as? Exception) + ?.let { CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e) } + ?: false + val logMessage = if (isNotAllowlisted) { // TODO: not required for non GP users "ListAvailableCustomizations: connection ${it.id} is not allowlisted, requestId: ${requestId.orEmpty()}" } else { "ListAvailableCustomizations: failed due to unknown error ${e.message}, requestId: ${requestId.orEmpty()}" } LOG.debug { logMessage } - } + }.getOrDefault(emptyList()) } // 2. get diff val previousCustomizationsShapshot = connectionToCustomizationsShownLastTime.getOrElse(it.id) { emptyList() } - // calculate new profile+customization list using profile.arn :: customization.arn as the key - val diff = aggregatedCustomizations.filterNot { customization -> - previousCustomizationsShapshot.contains( - "${customization.profile?.arn}::${customization.arn}" - ) - }.toSet() + // calculate new profile+customization list using compositeKey + val diff = aggregatedCustomizations.filterNot { customization -> previousCustomizationsShapshot.contains(customization.compositeKey()) }.toSet() + // 3 if passive, // (1) update allowlisting // (2) prompt "You have New Customizations" toast notification (only show once) @@ -152,39 +156,31 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe notifyNewCustomization(project) } } else { - aggregatedCustomizations.let { customizations -> - connectionToCustomizationsShownLastTime[it.id] = customizations.map { customization, - -> - "${customization.profile?.arn}::${customization.arn}" - }.toMutableList() - } + connectionToCustomizationsShownLastTime[it.id] = aggregatedCustomizations.map { customization -> customization.compositeKey() }.toMutableList() } // 4. invalidate selected customization if // (1) the API call failed // (2) the selected customization is not in the resultset of API call + // (3) the q region profile associated with the selected customization does not match the currently active profile activeCustomization(project)?.let { activeCustom -> if (aggregatedCustomizations.isEmpty()) { invalidateSelectedAndNotify(project) - } else if (!aggregatedCustomizations.any { latestCustom -> - "${latestCustom.profile?.arn}::${latestCustom.arn}" == "${activeCustom.profile?.arn}::${activeCustom.arn}" - } || activeCustom.profile != QRegionProfileManager.getInstance().activeProfile(project) + } else if (!aggregatedCustomizations.any { latestCustom -> latestCustom.compositeKey() == activeCustom.compositeKey() } || + activeCustom.profile != QRegionProfileManager.getInstance().activeProfile(project) ) { invalidateSelectedAndNotify(project) } } // 5. transform result to UI items and return - val customizationUiItems = aggregatedCustomizations.let { customizations -> - val nameToCount = customizations.groupingBy { customization -> customization.name }.eachCount() - - customizations.map { customization -> - CustomizationUiItem( - customization, - isNew = diff.contains(customization), - shouldPrefixAccountId = (nameToCount[customization.name] ?: 0) > 1 - ) - } + val nameToCount = aggregatedCustomizations.groupingBy { customization -> customization.name }.eachCount() + val customizationUiItems = aggregatedCustomizations.map { customization -> + CustomizationUiItem( + customization, + isNew = diff.contains(customization), + shouldPrefixAccountId = (nameToCount[customization.name] ?: 0) > 1 + ) } connectionToCustomizationUiItems[it.id] = customizationUiItems From 19a315a4bc4524b59bd78fac50321c69c75955c2 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Thu, 17 Apr 2025 23:29:35 -0700 Subject: [PATCH 30/35] refactor --- .../customization/CodeWhispererCustomizationDialog.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 16ac89d4ceb..298f8d4df03 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -192,10 +192,10 @@ class CodeWhispererCustomizationDialog( val activeProfile = QRegionProfileManager.getInstance().activeProfile(project) // Group customizations by profile name (active profile first, then alphabetical), with the active customization on top val sorted = unsorted.sortedWith( - compareBy { it.customization.profile?.profileName != activeProfile?.profileName } - .thenBy { it.customization.profile?.profileName.orEmpty() } - .thenBy { it.customization.name } - ) + compareBy { it.customization.profile?.profileName != activeProfile?.profileName } + .thenBy { it.customization.profile?.profileName.orEmpty() } + .thenBy { it.customization.name } + ) .let { list -> activeCustomization?.let { list.putPickedUpFront(setOf(it)) } ?: list } if ( From 4fb8dc9a46682d74b61fe03e5a3c84e41d6ad0e5 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 18 Apr 2025 13:01:14 -0700 Subject: [PATCH 31/35] Changelog --- .../feature-ae7d15f4-ae07-4faf-963a-6d83a85852e4.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changes/next-release/feature-ae7d15f4-ae07-4faf-963a-6d83a85852e4.json diff --git a/.changes/next-release/feature-ae7d15f4-ae07-4faf-963a-6d83a85852e4.json b/.changes/next-release/feature-ae7d15f4-ae07-4faf-963a-6d83a85852e4.json new file mode 100644 index 00000000000..d11656f96b8 --- /dev/null +++ b/.changes/next-release/feature-ae7d15f4-ae07-4faf-963a-6d83a85852e4.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "Amazon Q: Support selecting customizations across all Q profiles with automatic profile switching for enterprise users" +} \ No newline at end of file From 84fe0515f36ff014fa997a57f46e7e4a933b04fd Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 18 Apr 2025 14:26:51 -0700 Subject: [PATCH 32/35] remove composite key & cr --- .../CodeWhispererCustomizationDialog.kt | 2 ++ .../CodeWhispererModelConfigurator.kt | 31 +++++-------------- .../amazonq/profile/QProfileSwitchIntent.kt | 2 +- .../amazonq/profile/QRegionProfileManager.kt | 2 +- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt index 298f8d4df03..1b04ea7adbb 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererCustomizationDialog.kt @@ -109,6 +109,8 @@ class CodeWhispererCustomizationDialog( RadioButtonOption.Customization -> run { CodeWhispererModelConfigurator.getInstance().switchCustomization(project, modal.selectedCustomization?.customization) notifyCustomizationIsSelected(project, modal.selectedCustomization) + // Switch profile if it doesn't match the customization's profile. + // Customizations are profile-scoped and must be used under the correct context. if (modal.selectedCustomization?.customization?.profile?.arn != QRegionProfileManager.getInstance().activeProfile(project)?.arn) { QRegionProfileManager.getInstance().switchProfile( project, diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 3ec5275dada..8b00ae91503 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -27,7 +27,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor -import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants import software.aws.toolkits.jetbrains.utils.notifyInfo import software.aws.toolkits.jetbrains.utils.notifyWarn import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread @@ -65,13 +64,6 @@ private fun notifyNewCustomization(project: Project) { ) } -/** - * generate a stable composite key for profile & customization combination for diff/deduplicate/search - * rule: `::` - */ -private fun CodeWhispererCustomization.compositeKey(): String = - "${profile?.arn.orEmpty()}::$arn" - @Service(Service.Level.APP) @State(name = "codewhispererCustomizationStates", storages = [Storage("aws.xml")]) class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, PersistentStateComponent, Disposable { @@ -80,7 +72,6 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe private val connectionIdToActiveCustomizationArn = Collections.synchronizedMap(mutableMapOf()) // Map to store connectionId to its listAvailableCustomizations result last time - // Format of the customization key: profileArn::customizationArn private val connectionToCustomizationsShownLastTime = mutableMapOf>() private val connectionIdToIsAllowlisted = Collections.synchronizedMap(mutableMapOf()) @@ -126,23 +117,15 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe CodeWhispererClientAdaptor.getInstance(project).listAvailableCustomizations(profile) }.onFailure { e -> val requestId = (e as? CodeWhispererRuntimeException)?.requestId() - val isNotAllowlisted = (e as? Exception) - ?.let { CodeWhispererConstants.Customization.noAccessToCustomizationExceptionPredicate(e) } - ?: false - val logMessage = if (isNotAllowlisted) { - // TODO: not required for non GP users - "ListAvailableCustomizations: connection ${it.id} is not allowlisted, requestId: ${requestId.orEmpty()}" - } else { - "ListAvailableCustomizations: failed due to unknown error ${e.message}, requestId: ${requestId.orEmpty()}" - } + val logMessage = "ListAvailableCustomizations: failed due to unknown error ${e.message}, " + + "requestId: ${requestId.orEmpty()}, profileName: ${profile.profileName}" LOG.debug { logMessage } }.getOrDefault(emptyList()) } // 2. get diff val previousCustomizationsShapshot = connectionToCustomizationsShownLastTime.getOrElse(it.id) { emptyList() } - // calculate new profile+customization list using compositeKey - val diff = aggregatedCustomizations.filterNot { customization -> previousCustomizationsShapshot.contains(customization.compositeKey()) }.toSet() + val diff = aggregatedCustomizations.filterNot { customization -> previousCustomizationsShapshot.contains(customization.arn) }.toSet() // 3 if passive, // (1) update allowlisting @@ -156,18 +139,18 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe notifyNewCustomization(project) } } else { - connectionToCustomizationsShownLastTime[it.id] = aggregatedCustomizations.map { customization -> customization.compositeKey() }.toMutableList() + connectionToCustomizationsShownLastTime[it.id] = aggregatedCustomizations.map { customization -> customization.arn }.toMutableList() } // 4. invalidate selected customization if // (1) the API call failed // (2) the selected customization is not in the resultset of API call - // (3) the q region profile associated with the selected customization does not match the currently active profile + // (3) the existing q region profile associated with the selected customization does not match the currently active profile activeCustomization(project)?.let { activeCustom -> if (aggregatedCustomizations.isEmpty()) { invalidateSelectedAndNotify(project) - } else if (!aggregatedCustomizations.any { latestCustom -> latestCustom.compositeKey() == activeCustom.compositeKey() } || - activeCustom.profile != QRegionProfileManager.getInstance().activeProfile(project) + } else if (!aggregatedCustomizations.any { latestCustom -> latestCustom.arn == activeCustom.arn } || + (activeCustom.profile != null && activeCustom.profile != QRegionProfileManager.getInstance().activeProfile(project)) ) { invalidateSelectedAndNotify(project) } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt index c088bac1674..a48f33a2692 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QProfileSwitchIntent.kt @@ -8,7 +8,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.profile * 'auth' -> users change the profile through webview profile selector page * 'update' -> plugin auto select the profile on users' behalf as there is only 1 profile * 'reload' -> on plugin restart, plugin will try to reload previous selected profile - * - 'customization' -> users selected a customization tied to a different profile, triggering a profile switch + * 'customization' -> users selected a customization tied to a different profile, triggering a profile switch */ enum class QProfileSwitchIntent(val value: String) { User("user"), diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt index c1adac44673..b2464543f44 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/profile/QRegionProfileManager.kt @@ -182,7 +182,7 @@ class QRegionProfileManager : PersistentStateComponent, Disposabl } inline fun getQClient(project: Project): T = getQClient(project, null, T::class) - inline fun getQClient(project: Project, profile: QRegionProfile?): T = getQClient(project, profile, T::class) + inline fun getQClient(project: Project, profile: QRegionProfile): T = getQClient(project, profile, T::class) fun getQClient(project: Project, profile: QRegionProfile?, sdkClass: KClass): T { val settings = getQClientSettings(project, profile) From 57e8ce4743fd6b7744dc4ef6cf85d8ce1bff08e1 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 18 Apr 2025 14:50:54 -0700 Subject: [PATCH 33/35] cr --- .../customization/CodeWhispererModelConfigurator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index 8b00ae91503..ea44f6efc4b 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -20,7 +20,6 @@ import com.intellij.util.xmlb.annotations.Property import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException import software.aws.toolkits.core.utils.debug import software.aws.toolkits.core.utils.getLogger -import software.aws.toolkits.core.utils.tryOrNull import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.calculateIfIamIdentityCenterConnection import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile @@ -110,7 +109,8 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe override fun listCustomizations(project: Project, passive: Boolean): List? = calculateIfIamIdentityCenterConnection(project) { // 1. fetch all profiles, invoke fetch customizations API and get result for each profile and aggregate all the results - val listAvailableProfilesResult = tryOrNull { QRegionProfileManager.getInstance().listRegionProfiles(project) }.orEmpty() + val listAvailableProfilesResult = QRegionProfileManager.getInstance().listRegionProfiles(project) + ?: error("No profiles available for the current project") val aggregatedCustomizations = listAvailableProfilesResult.flatMap { profile -> runCatching { From f47ac3475dbc4939631246e56121e6edc982a803 Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Fri, 18 Apr 2025 14:53:38 -0700 Subject: [PATCH 34/35] cr --- .../customization/CodeWhispererModelConfigurator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt index ea44f6efc4b..a5af787f4af 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt @@ -110,7 +110,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe calculateIfIamIdentityCenterConnection(project) { // 1. fetch all profiles, invoke fetch customizations API and get result for each profile and aggregate all the results val listAvailableProfilesResult = QRegionProfileManager.getInstance().listRegionProfiles(project) - ?: error("No profiles available for the current project") + ?: error("Attempted to fetch profiles while there does not exist") val aggregatedCustomizations = listAvailableProfilesResult.flatMap { profile -> runCatching { From e3fd998397fdcb78c3f14172daf0a275225c3b3c Mon Sep 17 00:00:00 2001 From: YIFAN LIU Date: Sun, 20 Apr 2025 23:49:03 -0700 Subject: [PATCH 35/35] fix ut --- .../codewhisperer/CodeWhispererModelConfiguratorTest.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt index dfd156e741d..2e03da4cab4 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererModelConfiguratorTest.kt @@ -43,6 +43,7 @@ import software.aws.toolkits.jetbrains.core.region.MockRegionProviderRule import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.FeatureContext import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile +import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileSelectedListener import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererCustomization @@ -83,6 +84,7 @@ class CodeWhispererModelConfiguratorTest { private lateinit var mockClient: CodeWhispererRuntimeClient private lateinit var abManager: CodeWhispererFeatureConfigService private lateinit var mockClintAdaptor: CodeWhispererClientAdaptor + private lateinit var mockQRegionProfileManager: QRegionProfileManager @Before fun setup() { @@ -125,6 +127,11 @@ class CodeWhispererModelConfiguratorTest { mockClintAdaptor = mock() projectRule.project.registerServiceInstance(CodeWhispererClientAdaptor::class.java, mockClintAdaptor) + + mockQRegionProfileManager = mock { + on { listRegionProfiles(any()) }.thenReturn(listOf(QRegionProfile("fake_name", "fake_arn"))) + } + ApplicationManager.getApplication().replaceService(QRegionProfileManager::class.java, mockQRegionProfileManager, disposableRule.disposable) } @Test