Skip to content

Commit 6370cf2

Browse files
authored
Adds capability to send new context commands to AB groups (#5206)
Add the ability to send a new command that will appear when a user types @ in the chat window
1 parent 2226148 commit 6370cf2

File tree

8 files changed

+108
-10
lines changed

8 files changed

+108
-10
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Adds capability to send new context commands to AB groups"
4+
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.messages.AmazonQMessage
2424
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessageConnector
2525
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteraction
2626
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteractionType
27+
import software.aws.toolkits.jetbrains.services.amazonq.util.highlightCommand
2728
import software.aws.toolkits.jetbrains.services.amazonq.webview.BrowserConnector
2829
import software.aws.toolkits.jetbrains.services.amazonq.webview.FqnWebviewAdapter
2930
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.EditorThemeAdapter
@@ -125,7 +126,8 @@ class AmazonQToolWindow private constructor(
125126
isFeatureDevAvailable = isFeatureDevAvailable(project),
126127
isCodeScanAvailable = isCodeScanAvailable(project),
127128
isCodeTestAvailable = isCodeTestAvailable(project),
128-
isDocAvailable = isDocAvailable(project)
129+
isDocAvailable = isDocAvailable(project),
130+
highlightCommand = highlightCommand()
129131
)
130132

131133
scope.launch {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.util
5+
6+
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
7+
8+
data class HighlightCommand(val command: String, val description: String)
9+
10+
fun highlightCommand(): HighlightCommand? {
11+
val feature = CodeWhispererFeatureConfigService.getInstance().getHighlightCommandFeature()
12+
13+
if (feature == null || feature.value.stringValue().isEmpty()) return null
14+
15+
return HighlightCommand(feature.value.stringValue(), feature.variation)
16+
}

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

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

6+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
67
import com.intellij.openapi.Disposable
78
import com.intellij.openapi.util.Disposer
89
import com.intellij.ui.jcef.JBCefJSQuery
910
import org.cef.CefApp
11+
import software.aws.toolkits.jetbrains.services.amazonq.util.HighlightCommand
1012
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser
1113
import software.aws.toolkits.jetbrains.settings.MeetQSettings
1214

@@ -25,6 +27,7 @@ class Browser(parent: Disposable) : Disposable {
2527
isDocAvailable: Boolean,
2628
isCodeScanAvailable: Boolean,
2729
isCodeTestAvailable: Boolean,
30+
highlightCommand: HighlightCommand?,
2831
) {
2932
// register the scheme handler to route http://mynah/ URIs to the resources/assets directory on classpath
3033
CefApp.getInstance()
@@ -34,7 +37,7 @@ class Browser(parent: Disposable) : Disposable {
3437
AssetResourceHandler.AssetResourceHandlerFactory(),
3538
)
3639

37-
loadWebView(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable)
40+
loadWebView(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand)
3841
}
3942

4043
override fun dispose() {
@@ -55,12 +58,15 @@ class Browser(parent: Disposable) : Disposable {
5558
isDocAvailable: Boolean,
5659
isCodeScanAvailable: Boolean,
5760
isCodeTestAvailable: Boolean,
61+
highlightCommand: HighlightCommand?,
5862
) {
5963
// setup empty state. The message request handlers use this for storing state
6064
// that's persistent between page loads.
6165
jcefBrowser.setProperty("state", "")
6266
// load the web app
63-
jcefBrowser.loadHTML(getWebviewHTML(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable))
67+
jcefBrowser.loadHTML(
68+
getWebviewHTML(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand)
69+
)
6470
}
6571

6672
/**
@@ -73,6 +79,7 @@ class Browser(parent: Disposable) : Disposable {
7379
isDocAvailable: Boolean,
7480
isCodeScanAvailable: Boolean,
7581
isCodeTestAvailable: Boolean,
82+
highlightCommand: HighlightCommand?,
7683
): String {
7784
val postMessageToJavaJsCode = receiveMessageQuery.inject("JSON.stringify(message)")
7885

@@ -92,7 +99,8 @@ class Browser(parent: Disposable) : Disposable {
9299
$isCodeTransformAvailable, // whether /transform is available
93100
$isDocAvailable, // whether /doc is available
94101
$isCodeScanAvailable, // whether /scan is available
95-
$isCodeTestAvailable // whether /test is available
102+
$isCodeTestAvailable, // whether /test is available
103+
${OBJECT_MAPPER.writeValueAsString(highlightCommand)}
96104
);
97105
}
98106
</script>
@@ -114,5 +122,6 @@ class Browser(parent: Disposable) : Disposable {
114122
companion object {
115123
private const val WEB_SCRIPT_URI = "http://mynah/js/mynah-ui.js"
116124
private const val MAX_ONBOARDING_PAGE_COUNT = 3
125+
private val OBJECT_MAPPER = jacksonObjectMapper()
117126
}
118127
}

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererFeatureConfigServiceTest.kt

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import software.amazon.awssdk.services.codewhispererruntime.model.ListAvailableC
2626
import software.amazon.awssdk.services.codewhispererruntime.model.ListFeatureEvaluationsRequest
2727
import software.amazon.awssdk.services.codewhispererruntime.model.ListFeatureEvaluationsResponse
2828
import software.amazon.awssdk.services.codewhispererruntime.paginators.ListAvailableCustomizationsIterable
29+
import software.aws.toolkits.core.TokenConnectionSettings
30+
import software.aws.toolkits.core.region.AwsRegion
2931
import software.aws.toolkits.jetbrains.core.MockClientManagerRule
3032
import software.aws.toolkits.jetbrains.core.credentials.LegacyManagedBearerSsoConnection
3133
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
@@ -58,6 +60,44 @@ class CodeWhispererFeatureConfigServiceTest {
5860
assertThat(CodeWhispererFeatureConfigService.FEATURE_DEFINITIONS).containsKeys("testFeature")
5961
}
6062

63+
@Test
64+
fun `test highlightCommand returns non-empty`() {
65+
mockClientManagerRule.create<CodeWhispererRuntimeClient>().stub {
66+
on { listFeatureEvaluations(any<ListFeatureEvaluationsRequest>()) } doReturn ListFeatureEvaluationsResponse.builder().featureEvaluations(
67+
listOf(
68+
FeatureEvaluation.builder()
69+
.feature("highlightCommand")
70+
.variation("a new command")
71+
.value(FeatureValue.fromStringValue("@highlight"))
72+
.build()
73+
)
74+
).build()
75+
}
76+
77+
val mockTokenSettings = mock<TokenConnectionSettings> {
78+
on { providerId } doReturn "mock"
79+
on { region } doReturn AwsRegion.GLOBAL
80+
}
81+
82+
val mockSsoConnection = mock<LegacyManagedBearerSsoConnection> {
83+
on { startUrl } doReturn "fake sso url"
84+
on { getConnectionSettings() } doReturn mockTokenSettings
85+
}
86+
87+
projectRule.project.replaceService(
88+
ToolkitConnectionManager::class.java,
89+
mock { on { activeConnectionForFeature(eq(QConnection.getInstance())) } doReturn mockSsoConnection },
90+
disposableRule.disposable
91+
)
92+
93+
runBlocking {
94+
CodeWhispererFeatureConfigService.getInstance().fetchFeatureConfigs(projectRule.project)
95+
}
96+
97+
assertThat(CodeWhispererFeatureConfigService.getInstance().getHighlightCommandFeature()?.value?.stringValue()).isEqualTo("@highlight")
98+
assertThat(CodeWhispererFeatureConfigService.getInstance().getHighlightCommandFeature()?.variation).isEqualTo("a new command")
99+
}
100+
61101
@Test
62102
fun `test customizationArnOverride returns empty for BID users`() {
63103
testCustomizationArnOverrideABHelper(isIdc = false, isInListAvailableCustomizations = false)
@@ -80,7 +120,7 @@ class CodeWhispererFeatureConfigServiceTest {
80120
on { listFeatureEvaluations(any<ListFeatureEvaluationsRequest>()) } doReturn ListFeatureEvaluationsResponse.builder().featureEvaluations(
81121
listOf(
82122
FeatureEvaluation.builder()
83-
.feature(CodeWhispererFeatureConfigService.CUSTOMIZATION_ARN_OVERRIDE_NAME)
123+
.feature("customizationArnOverride")
84124
.variation("customization-name")
85125
.value(FeatureValue.fromStringValue("test arn"))
86126
.build()

plugins/amazonq/mynah-ui/src/mynah-ui/ui/main.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
MynahUI,
1111
MynahUIDataModel,
1212
NotificationType,
13-
ProgressField,
13+
ProgressField, QuickActionCommand,
1414
ReferenceTrackerInformation
1515
} from '@aws/mynah-ui-chat'
1616
import './styles/dark.scss'
@@ -40,7 +40,8 @@ export const createMynahUI = (
4040
codeTransformInitEnabled: boolean,
4141
docInitEnabled: boolean,
4242
codeScanEnabled: boolean,
43-
codeTestEnabled: boolean
43+
codeTestEnabled: boolean,
44+
highlightCommand?: QuickActionCommand,
4445
) => {
4546
let disclaimerCardActive = !disclaimerAcknowledged
4647

@@ -87,6 +88,7 @@ export const createMynahUI = (
8788
isDocEnabled,
8889
isCodeScanEnabled,
8990
isCodeTestEnabled,
91+
highlightCommand
9092
})
9193

9294
// eslint-disable-next-line prefer-const

plugins/amazonq/mynah-ui/src/mynah-ui/ui/tabs/generator.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { ChatItemType, MynahUIDataModel, QuickActionCommandGroup } from '@aws/mynah-ui-chat'
6+
import { ChatItemType, MynahUIDataModel, QuickActionCommandGroup, QuickActionCommand } from '@aws/mynah-ui-chat'
77
import { TabType } from '../storages/tabsStorage'
88
import { FollowUpGenerator } from '../followUps/generator'
99
import { QuickActionGenerator } from '../quickActions/generator'
@@ -15,11 +15,13 @@ export interface TabDataGeneratorProps {
1515
isDocEnabled: boolean
1616
isCodeScanEnabled: boolean
1717
isCodeTestEnabled: boolean
18+
highlightCommand?: QuickActionCommand
1819
}
1920

2021
export class TabDataGenerator {
2122
private followUpsGenerator: FollowUpGenerator
2223
public quickActionsGenerator: QuickActionGenerator
24+
private highlightCommand?: QuickActionCommand
2325

2426
private tabTitle: Map<TabType, string> = new Map([
2527
['unknown', 'Chat'],
@@ -88,6 +90,7 @@ What would you like to work on?`,
8890
isCodeScanEnabled: props.isCodeScanEnabled,
8991
isCodeTestEnabled: props.isCodeTestEnabled,
9092
})
93+
this.highlightCommand = props.highlightCommand
9194
}
9295

9396
public getTabData(tabType: TabType, needWelcomeMessages: boolean, taskName?: string): MynahUIDataModel {
@@ -97,7 +100,7 @@ What would you like to work on?`,
97100
'Amazon Q Developer uses generative AI. You may need to verify responses. See the [AWS Responsible AI Policy](https://aws.amazon.com/machine-learning/responsible-ai/policy/).',
98101
quickActionCommands: this.quickActionsGenerator.generateForTab(tabType),
99102
promptInputPlaceholder: this.tabInputPlaceholder.get(tabType),
100-
contextCommands: this.tabContextCommand.get(tabType),
103+
contextCommands: this.getContextCommands(tabType),
101104
chatItems: needWelcomeMessages
102105
? [
103106
{
@@ -112,4 +115,23 @@ What would you like to work on?`,
112115
: [],
113116
}
114117
}
118+
119+
private getContextCommands(tabType: TabType): QuickActionCommandGroup[] | undefined {
120+
const contextCommands = this.tabContextCommand.get(tabType)
121+
122+
if (this.highlightCommand) {
123+
const commandHighlight: QuickActionCommandGroup = {
124+
groupName: 'Additional Commands',
125+
commands: [this.highlightCommand],
126+
}
127+
128+
if (contextCommands !== undefined) {
129+
return [...contextCommands, commandHighlight]
130+
}
131+
132+
return [commandHighlight]
133+
}
134+
135+
return contextCommands
136+
}
115137
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class CodeWhispererFeatureConfigService {
111111

112112
fun getCustomizationFeature(): FeatureContext? = getFeature(CUSTOMIZATION_ARN_OVERRIDE_NAME)
113113

114+
fun getHighlightCommandFeature(): FeatureContext? = getFeature(HIGHLIGHT_COMMAND_NAME)
115+
114116
fun getNewAutoTriggerUX(): Boolean = getFeatureValueForKey(NEW_AUTO_TRIGGER_UX).stringValue() == "TREATMENT"
115117

116118
fun getInlineCompletion(): Boolean = getFeatureValueForKey(INLINE_COMPLETION).stringValue() == "TREATMENT"
@@ -131,7 +133,8 @@ class CodeWhispererFeatureConfigService {
131133
fun getInstance(): CodeWhispererFeatureConfigService = service()
132134
private const val TEST_FEATURE_NAME = "testFeature"
133135
private const val INLINE_COMPLETION = "ProjectContextV2"
134-
const val CUSTOMIZATION_ARN_OVERRIDE_NAME = "customizationArnOverride"
136+
private const val CUSTOMIZATION_ARN_OVERRIDE_NAME = "customizationArnOverride"
137+
private const val HIGHLIGHT_COMMAND_NAME = "highlightCommand"
135138
private const val NEW_AUTO_TRIGGER_UX = "newAutoTriggerUX"
136139
private val LOG = getLogger<CodeWhispererFeatureConfigService>()
137140

0 commit comments

Comments
 (0)