Skip to content

Commit 71e10da

Browse files
committed
fix(amazonq): adjust feature config customization arn override logic
1. change poll interval from 30mins to 180 mins 2. Only call listAvailableCustomizations for new customization override for update 3. Use a new field customizationArnOverrideV2 for a clean override plan
1 parent f8fa131 commit 71e10da

File tree

5 files changed

+73
-44
lines changed

5 files changed

+73
-44
lines changed

plugins/amazonq/codewhisperer/jetbrains-community/src/migration/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ interface CodeWhispererModelConfigurator {
3737
*/
3838
fun getNewUpdate(connectionId: String): Collection<CustomizationUiItem>?
3939

40+
/**
41+
* Get any current persisted customization arn override config
42+
*/
43+
fun getPersistedCustomizationOverride(): String?
44+
4045
companion object {
4146
fun getInstance(): CodeWhispererModelConfigurator = service()
4247
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/customization/CodeWhispererModelConfigurator.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe
7878

7979
private var serviceDefaultArn: String? = null
8080

81+
private var customizationArnOverrideV2: String? = null
82+
8183
override fun showConfigDialog(project: Project) {
8284
runInEdt {
8385
calculateIfIamIdentityCenterConnection(project) {
@@ -181,7 +183,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe
181183
*/
182184
override fun switchCustomization(project: Project, newCustomization: CodeWhispererCustomization?, isOverride: Boolean) {
183185
calculateIfIamIdentityCenterConnection(project) {
184-
if (isOverride && (newCustomization == null || newCustomization.arn.isEmpty() || serviceDefaultArn == newCustomization.arn)) {
186+
if (isOverride && (newCustomization == null || newCustomization.arn.isEmpty() || customizationArnOverrideV2 == newCustomization.arn)) {
185187
return@calculateIfIamIdentityCenterConnection
186188
}
187189
val oldCus = connectionIdToActiveCustomizationArn[it.id]
@@ -197,7 +199,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe
197199
CodeWhispererCustomizationListener.notifyCustomUiUpdate()
198200
}
199201
if (isOverride) {
200-
serviceDefaultArn = newCustomization?.arn
202+
customizationArnOverrideV2 = newCustomization?.arn
201203
}
202204
}
203205
}
@@ -249,6 +251,7 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe
249251
state.connectionIdToActiveCustomizationArn.putAll(this.connectionIdToActiveCustomizationArn)
250252
state.previousAvailableCustomizations.putAll(this.connectionToCustomizationsShownLastTime)
251253
state.serviceDefaultArn = this.serviceDefaultArn
254+
state.customizationArnOverrideV2 = this.customizationArnOverrideV2
252255

253256
return state
254257
}
@@ -261,8 +264,12 @@ class DefaultCodeWhispererModelConfigurator : CodeWhispererModelConfigurator, Pe
261264
connectionToCustomizationsShownLastTime.putAll(state.previousAvailableCustomizations)
262265

263266
this.serviceDefaultArn = state.serviceDefaultArn
267+
this.customizationArnOverrideV2 = state.customizationArnOverrideV2
264268
}
265269

270+
// current latest field is customizationArnOverrideV2
271+
override fun getPersistedCustomizationOverride() = customizationArnOverrideV2
272+
266273
override fun dispose() {}
267274

268275
private fun invalidateSelectedAndNotify(project: Project) {
@@ -294,6 +301,9 @@ class CodeWhispererCustomizationState : BaseState() {
294301

295302
@get:Property
296303
var serviceDefaultArn by string()
304+
305+
@get:Property
306+
var customizationArnOverrideV2 by string()
297307
}
298308

299309
data class CustomizationUiItem(

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/startup/CodeWhispererProjectStartupActivity.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,18 @@ class CodeWhispererProjectStartupActivity : StartupActivity.DumbAware {
7474
runOnce = true
7575
}
7676

77-
// Start a job that runs every 30 mins
77+
// Start a job that runs every 180 minutes
7878
private fun initFeatureConfigPollingJob(project: Project) {
7979
projectCoroutineScope(project).launch {
8080
while (isActive) {
8181
CodeWhispererFeatureConfigService.getInstance().fetchFeatureConfigs(project)
8282
CodeWhispererFeatureConfigService.getInstance().getCustomizationFeature()?.let { customization ->
83+
val persistedCustomizationOverride = CodeWhispererModelConfigurator.getInstance().getPersistedCustomizationOverride()
84+
val latestCustomizationOverride = customization.value.stringValue()
85+
if (persistedCustomizationOverride == latestCustomizationOverride) return@let
86+
87+
// latest is different from the currently persisted, need update
88+
CodeWhispererFeatureConfigService.getInstance().validateCustomizationOverride(project, customization)
8389
CodeWhispererModelConfigurator.getInstance().switchCustomization(
8490
project,
8591
CodeWhispererCustomization(arn = customization.value.stringValue(), name = customization.variation),

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ object CodeWhispererConstants {
8888
const val TOTAL_MILLIS_IN_SECOND = 1000
8989
const val TOTAL_SECONDS_IN_MINUTE: Long = 60L
9090
const val ACCOUNTLESS_START_URL = "accountless"
91-
const val FEATURE_CONFIG_POLL_INTERVAL_IN_MS: Long = 30 * 60 * 1000L // 30 mins
91+
const val FEATURE_CONFIG_POLL_INTERVAL_IN_MS: Long = 180 * 60 * 1000L // 180 mins
9292
const val USING: String = "using"
9393
const val GLOBAL_USING: String = "global using"
9494
const val STATIC: String = "static"

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

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,47 +42,8 @@ class CodeWhispererFeatureConfigService {
4242
featureConfigs[it.feature()] = FeatureContext(it.feature(), it.variation(), it.value())
4343
}
4444

45-
// Only apply new auto-trigger UX to BID users
46-
val isNewAutoTriggerUX = getNewAutoTriggerUX()
47-
if (isNewAutoTriggerUX) {
48-
calculateIfIamIdentityCenterConnection(project) {
49-
featureConfigs.remove(NEW_AUTO_TRIGGER_UX)
50-
}
51-
}
52-
53-
val customizationArnOverride = featureConfigs[CUSTOMIZATION_ARN_OVERRIDE_NAME]?.value?.stringValue()
54-
if (customizationArnOverride != null) {
55-
// Double check if server-side wrongly returns a customizationArn to BID users
56-
calculateIfBIDConnection(project) {
57-
featureConfigs.remove(CUSTOMIZATION_ARN_OVERRIDE_NAME)
58-
}
59-
val availableCustomizations =
60-
calculateIfIamIdentityCenterConnection(project) {
61-
try {
62-
connection.getConnectionSettings().awsClient<CodeWhispererRuntimeClient>().listAvailableCustomizationsPaginator(
63-
ListAvailableCustomizationsRequest.builder().build()
64-
)
65-
.stream()
66-
.toList()
67-
.flatMap { resp ->
68-
resp.customizations().map {
69-
it.arn()
70-
}
71-
}
72-
} catch (e: Exception) {
73-
LOG.debug(e) { "Failed to list available customizations" }
74-
null
75-
}
76-
}
45+
validateNewAutoTriggerUX(project)
7746

78-
// If customizationArn from A/B is not available in listAvailableCustomizations response, don't use this value
79-
if (availableCustomizations?.contains(customizationArnOverride) == false) {
80-
LOG.debug {
81-
"Customization arn $customizationArnOverride not available in listAvailableCustomizations, not using"
82-
}
83-
featureConfigs.remove(CUSTOMIZATION_ARN_OVERRIDE_NAME)
84-
}
85-
}
8647
CodeWhispererFeatureConfigListener.notifyUiFeatureConfigsAvailable()
8748
} catch (e: Exception) {
8849
LOG.debug(e) { "Error when fetching feature configs" }
@@ -132,6 +93,53 @@ class CodeWhispererFeatureConfigService {
13293
private fun connection(project: Project) =
13394
ToolkitConnectionManager.getInstance(project).activeConnectionForFeature(QConnection.getInstance())
13495

96+
private fun validateNewAutoTriggerUX(project: Project) {
97+
// Only apply new auto-trigger UX to BID users
98+
val isNewAutoTriggerUX = getNewAutoTriggerUX()
99+
if (isNewAutoTriggerUX) {
100+
calculateIfIamIdentityCenterConnection(project) {
101+
featureConfigs.remove(NEW_AUTO_TRIGGER_UX)
102+
}
103+
}
104+
}
105+
106+
fun validateCustomizationOverride(project: Project, customization: FeatureContext) {
107+
val customizationArnOverride = customization.value.stringValue()
108+
val connection = connection(project) ?: return
109+
if (customizationArnOverride != null) {
110+
// Double check if server-side wrongly returns a customizationArn to BID users
111+
calculateIfBIDConnection(project) {
112+
featureConfigs.remove(CUSTOMIZATION_ARN_OVERRIDE_NAME)
113+
}
114+
val availableCustomizations =
115+
calculateIfIamIdentityCenterConnection(project) {
116+
try {
117+
connection.getConnectionSettings().awsClient<CodeWhispererRuntimeClient>().listAvailableCustomizationsPaginator(
118+
ListAvailableCustomizationsRequest.builder().build()
119+
)
120+
.stream()
121+
.toList()
122+
.flatMap { resp ->
123+
resp.customizations().map {
124+
it.arn()
125+
}
126+
}
127+
} catch (e: Exception) {
128+
LOG.debug(e) { "Failed to list available customizations" }
129+
null
130+
}
131+
}
132+
133+
// If customizationArn from A/B is not available in listAvailableCustomizations response, don't use this value
134+
if (availableCustomizations?.contains(customizationArnOverride) == false) {
135+
LOG.debug {
136+
"Customization arn $customizationArnOverride not available in listAvailableCustomizations, not using"
137+
}
138+
featureConfigs.remove(CUSTOMIZATION_ARN_OVERRIDE_NAME)
139+
}
140+
}
141+
}
142+
135143
companion object {
136144
fun getInstance(): CodeWhispererFeatureConfigService = service()
137145
private const val TEST_FEATURE_NAME = "testFeature"

0 commit comments

Comments
 (0)