Skip to content

Commit f8c0d03

Browse files
zixlin7rli
andauthored
feat(amazonq): enable workspace context once for selected user (#4771)
* enabled workspace context once for selected users * Update plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt Co-authored-by: Richard Li <[email protected]> --------- Co-authored-by: Richard Li <[email protected]>
1 parent 5e36d15 commit f8c0d03

File tree

8 files changed

+58
-16
lines changed

8 files changed

+58
-16
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ data class ChatRequestData(
2323
val userIntent: UserIntent?,
2424
val triggerType: TriggerType,
2525
val customization: CodeWhispererCustomization?,
26-
val relevantTextDocuments: List<RelevantDocument>
26+
val relevantTextDocuments: List<RelevantDocument>,
27+
val useRelevantDocuments: Boolean
2728
)
2829

2930
interface CodeNames {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class ChatSessionV1(
198198
*/
199199
private fun ChatRequestData.toChatRequest(): GenerateAssistantResponseRequest {
200200
val userInputMessageContextBuilder = UserInputMessageContext.builder()
201-
userInputMessageContextBuilder.editorState(activeFileContext.toEditorState(relevantTextDocuments))
201+
userInputMessageContextBuilder.editorState(activeFileContext.toEditorState(relevantTextDocuments, useRelevantDocuments))
202202
val userInputMessageContext = userInputMessageContextBuilder.build()
203203

204204
val userInput = UserInputMessage.builder()
@@ -217,7 +217,7 @@ class ChatSessionV1(
217217
.build()
218218
}
219219

220-
private fun ActiveFileContext.toEditorState(relevantDocuments: List<RelevantDocument>): EditorState {
220+
private fun ActiveFileContext.toEditorState(relevantDocuments: List<RelevantDocument>, useRelevantDocuments: Boolean): EditorState {
221221
val editorStateBuilder = EditorState.builder()
222222
if (fileContext != null) {
223223
val cursorStateBuilder = CursorState.builder()
@@ -284,6 +284,7 @@ class ChatSessionV1(
284284
}
285285

286286
editorStateBuilder.relevantDocuments(documents)
287+
editorStateBuilder.useRelevantDocuments(useRelevantDocuments)
287288
return editorStateBuilder.build()
288289
}
289290

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/ChatController.kt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthNeededState
4242
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
4343
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteraction
4444
import software.aws.toolkits.jetbrains.services.amazonq.onboarding.OnboardingPageInteractionType
45+
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererFeatureConfigService
4546
import software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable
4647
import software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererSettings
4748
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererUserModificationTracker
@@ -127,16 +128,22 @@ class ChatController private constructor(
127128
var queryResult: List<RelevantDocument> = emptyList()
128129
val triggerId = UUID.randomUUID().toString()
129130
var shouldAddIndexInProgressMessage: Boolean = false
131+
var shouldUseWorkspaceContext: Boolean = false
132+
val isDataCollectionGroup = CodeWhispererFeatureConfigService.getInstance().getIsDataCollectionEnabled()
130133
if (prompt.contains("@workspace")) {
131134
if (CodeWhispererSettings.getInstance().isProjectContextEnabled()) {
132-
val projectContextController = ProjectContextController.getInstance(context.project)
135+
shouldUseWorkspaceContext = true
133136
prompt = prompt.replace("@workspace", "")
137+
val projectContextController = ProjectContextController.getInstance(context.project)
134138
queryResult = projectContextController.query(prompt)
135139
if (!projectContextController.getProjectContextIndexComplete()) shouldAddIndexInProgressMessage = true
136140
logger.info { "project context relevant document count: ${queryResult.size}" }
137141
} else {
138142
sendOpenSettingsMessage(message.tabId)
139143
}
144+
} else if (CodeWhispererSettings.getInstance().isProjectContextEnabled() && isDataCollectionGroup) {
145+
val projectContextController = ProjectContextController.getInstance(context.project)
146+
queryResult = projectContextController.query(prompt)
140147
}
141148

142149
handleChat(
@@ -147,7 +154,8 @@ class ChatController private constructor(
147154
userIntent = intentRecognizer.getUserIntentFromPromptChatMessage(message.chatMessage),
148155
TriggerType.Click,
149156
projectContextQueryResult = queryResult,
150-
shouldAddIndexInProgressMessage = shouldAddIndexInProgressMessage
157+
shouldAddIndexInProgressMessage = shouldAddIndexInProgressMessage,
158+
shouldUseWorkspaceContext = shouldUseWorkspaceContext
151159
)
152160
}
153161

@@ -378,7 +386,8 @@ class ChatController private constructor(
378386
userIntent: UserIntent?,
379387
triggerType: TriggerType,
380388
projectContextQueryResult: List<RelevantDocument>,
381-
shouldAddIndexInProgressMessage: Boolean? = false
389+
shouldAddIndexInProgressMessage: Boolean = false,
390+
shouldUseWorkspaceContext: Boolean = false
382391
) {
383392
val credentialState = authController.getAuthNeededStates(context.project).chat
384393
if (credentialState != null) {
@@ -397,7 +406,8 @@ class ChatController private constructor(
397406
userIntent = userIntent,
398407
triggerType = triggerType,
399408
customization = CodeWhispererModelConfigurator.getInstance().activeCustomization(context.project),
400-
relevantTextDocuments = projectContextQueryResult
409+
relevantTextDocuments = projectContextQueryResult,
410+
useRelevantDocuments = shouldUseWorkspaceContext,
401411
)
402412

403413
val sessionInfo = getSessionInfo(tabId)
@@ -409,7 +419,7 @@ class ChatController private constructor(
409419

410420
// Send the request to the API and publish the responses back to the UI.
411421
// This is launched in a scope attached to the sessionInfo so that the Job can be cancelled on a per-session basis.
412-
ChatPromptHandler(telemetryHelper).handle(tabId, triggerId, requestData, sessionInfo, shouldAddIndexInProgressMessage ?: false)
422+
ChatPromptHandler(telemetryHelper).handle(tabId, triggerId, requestData, sessionInfo, shouldAddIndexInProgressMessage)
413423
.catch { handleError(tabId, it) }
414424
.onEach { context.messagesFromAppToUi.publish(it) }
415425
.launchIn(sessionInfo.scope)

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/controller/chat/telemetry/TelemetryHelper.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
8888
cwsprChatHasCodeSnippet = data.activeFileContext.focusAreaContext?.codeSelection?.isNotEmpty() ?: false,
8989
cwsprChatProgrammingLanguage = data.activeFileContext.fileContext?.fileLanguage,
9090
credentialStartUrl = getStartUrl(context.project),
91-
cwsprChatHasProjectContext = getIsProjectContextEnabled()
91+
cwsprChatHasProjectContext = getIsProjectContextEnabled() && data.useRelevantDocuments && data.relevantTextDocuments.isNotEmpty()
9292
)
9393
}
9494

@@ -116,7 +116,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
116116
cwsprChatConversationType = CwsprChatConversationType.Chat,
117117
credentialStartUrl = getStartUrl(context.project),
118118
codewhispererCustomizationArn = data.customization?.arn,
119-
cwsprChatHasProjectContext = getIsProjectContextEnabled()
119+
cwsprChatHasProjectContext = getIsProjectContextEnabled() && data.useRelevantDocuments && data.relevantTextDocuments.isNotEmpty()
120120
)
121121

122122
val programmingLanguage = data.activeFileContext.fileContext?.fileLanguage
@@ -135,7 +135,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
135135
data.message.length,
136136
responseLength,
137137
numberOfCodeBlocks,
138-
getIsProjectContextEnabled(),
138+
getIsProjectContextEnabled() && data.useRelevantDocuments && data.relevantTextDocuments.isNotEmpty(),
139139
data.customization
140140
).also {
141141
logger.debug {
@@ -265,7 +265,7 @@ class TelemetryHelper(private val context: AmazonQAppInitContext, private val se
265265
cwsprChatInteractionTarget = message.link,
266266
cwsprChatHasReference = null,
267267
credentialStartUrl = getStartUrl(context.project),
268-
cwsprChatHasProjectContext = getIsProjectContextEnabled(),
268+
cwsprChatHasProjectContext = getIsProjectContextEnabled()
269269
)
270270
ChatInteractWithMessageEvent.builder().apply {
271271
conversationId(getConversationId(message.tabId).orEmpty())

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/TelemetryHelperTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ class TelemetryHelperTest {
140140
userIntent = UserIntent.IMPROVE_CODE,
141141
triggerType = TriggerType.Hotkeys,
142142
customization = mockCustomization,
143-
relevantTextDocuments = listOf()
143+
relevantTextDocuments = emptyList(),
144+
useRelevantDocuments = true,
144145
)
145146
private val response = ChatMessage(
146147
tabId = tabId,

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class CodeWhispererFeatureConfigService {
8080
// 6) Add a test case for this feature.
8181
fun getTestFeature(): String = getFeatureValueForKey(TEST_FEATURE_NAME).stringValue()
8282

83+
fun getIsDataCollectionEnabled(): Boolean = getFeatureValueForKey(DATA_COLLECTION_FEATURE).stringValue() == "data-collection"
84+
8385
fun getCustomizationArnOverride(): String = getFeatureValueForKey(CUSTOMIZATION_ARN_OVERRIDE_NAME).stringValue()
8486

8587
// Get the feature value for the given key.
@@ -91,6 +93,7 @@ class CodeWhispererFeatureConfigService {
9193
companion object {
9294
fun getInstance(): CodeWhispererFeatureConfigService = service()
9395
private const val TEST_FEATURE_NAME = "testFeature"
96+
private const val DATA_COLLECTION_FEATURE = "IDEProjectContextDataCollection"
9497
const val CUSTOMIZATION_ARN_OVERRIDE_NAME = "customizationArnOverride"
9598
private val LOG = getLogger<CodeWhispererFeatureConfigService>()
9699

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/settings/CodeWhispererSettings.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.intellij.openapi.components.State
1111
import com.intellij.openapi.components.Storage
1212
import com.intellij.openapi.components.service
1313
import com.intellij.util.xmlb.annotations.Property
14+
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererFeatureConfigService
1415

1516
@Service
1617
@State(name = "codewhispererSettings", storages = [Storage("aws.xml", roamingType = RoamingType.DISABLED)])
@@ -48,7 +49,26 @@ class CodeWhispererSettings : PersistentStateComponent<CodeWhispererConfiguratio
4849
state.value[CodeWhispererConfigurationType.IsProjectContextEnabled] = value
4950
}
5051

51-
fun isProjectContextEnabled() = state.value.getOrDefault(CodeWhispererConfigurationType.IsProjectContextEnabled, false)
52+
fun isProjectContextEnabled() = getIsProjectContextEnabled()
53+
54+
private fun getIsProjectContextEnabled(): Boolean {
55+
val value = state.value.getOrDefault(CodeWhispererConfigurationType.IsProjectContextEnabled, false)
56+
val isDataCollectionGroup = CodeWhispererFeatureConfigService.getInstance().getIsDataCollectionEnabled()
57+
if (!value) {
58+
if (isDataCollectionGroup && !hasEnabledProjectContextOnce()) {
59+
toggleProjectContextEnabled(true)
60+
toggleEnabledProjectContextOnce(true)
61+
return true
62+
}
63+
}
64+
return value
65+
}
66+
67+
private fun hasEnabledProjectContextOnce() = state.value.getOrDefault(CodeWhispererConfigurationType.HasEnabledProjectContextOnce, false)
68+
69+
private fun toggleEnabledProjectContextOnce(value: Boolean) {
70+
state.value[CodeWhispererConfigurationType.HasEnabledProjectContextOnce] = value
71+
}
5272

5373
fun isProjectContextGpu() = state.value.getOrDefault(CodeWhispererConfigurationType.IsProjectContextGpu, false)
5474

@@ -106,6 +126,7 @@ enum class CodeWhispererConfigurationType {
106126
IsAutoUpdateFeatureNotificationShownOnce,
107127
IsProjectContextEnabled,
108128
IsProjectContextGpu,
129+
HasEnabledProjectContextOnce
109130
}
110131

111132
enum class CodeWhispererIntConfigurationType {

plugins/core/sdk-codegen/codegen-resources/codewhispererstreaming/service-2.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@
134134
"event":true,
135135
"sensitive":true
136136
},
137+
"Boolean":{
138+
"type":"boolean",
139+
"box":true
140+
},
137141
"ChatHistory":{
138142
"type":"list",
139143
"member":{"shape":"ChatMessage"},
@@ -276,7 +280,8 @@
276280
"members":{
277281
"document":{"shape":"TextDocument"},
278282
"cursorState":{"shape":"CursorState"},
279-
"relevantDocuments": {"shape": "RelevantDocumentList"}
283+
"relevantDocuments": {"shape": "RelevantDocumentList"},
284+
"useRelevantDocuments": {"shape": "Boolean"}
280285
}
281286
},
282287
"ExportContext":{
@@ -765,4 +770,4 @@
765770
}
766771
}
767772
}
768-
}
773+
}

0 commit comments

Comments
 (0)