Skip to content

Commit 4eb2943

Browse files
authored
feat(amazonq): support in editor chat (#5004)
1 parent 39c13ea commit 4eb2943

File tree

32 files changed

+1474
-51
lines changed

32 files changed

+1474
-51
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" : "Added inline chat support. Select some code and hit ⌘+I on Mac or Ctrl+I on Windows to start"
4+
}

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ assertJ = "3.26.3"
66
awsSdk = "2.26.25"
77
commonmark = "0.22.0"
88
detekt = "1.23.7"
9+
diff-util = "4.12"
910
intellijExt = "1.1.8"
1011
# match with <root>/settings.gradle.kts
1112
intellijGradle = "2.1.0"
@@ -71,6 +72,7 @@ commons-collections = { module = "org.apache.commons:commons-collections4", vers
7172
commons-io = { module = "commons-io:commons-io", version.ref = "apache-commons-io" }
7273
detekt-api = { module = "io.gitlab.arturbosch.detekt:detekt-api", version.ref = "detekt" }
7374
detekt-formattingRules = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
75+
diff-util = { module = "io.github.java-diff-utils:java-diff-utils", version.ref = "diff-util" }
7476
detekt-test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version.ref = "detekt" }
7577
gradlePlugin-detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
7678
gradlePlugin-ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "intellijExt" }

plugins/amazonq/chat/jetbrains-community/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
implementation(project(":plugin-amazonq:shared:jetbrains-community"))
2020
// everything references codewhisperer, which is not ideal
2121
implementation(project(":plugin-amazonq:codewhisperer:jetbrains-community"))
22+
implementation(libs.diff.util)
2223

2324
compileOnly(project(":plugin-core:jetbrains-community"))
2425

plugins/amazonq/chat/jetbrains-community/resources/META-INF/plugin-chat.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@
7979
class="software.aws.toolkits.jetbrains.services.cwc.commands.SendToPromptAction">
8080
<keyboard-shortcut keymap="$default" first-keystroke="meta alt S" />
8181
</action>
82+
83+
<action id="aws.toolkit.jetbrains.core.services.cwc.inline.openChat"
84+
class="software.aws.toolkits.jetbrains.services.cwc.inline.OpenChatInputAction">
85+
<keyboard-shortcut keymap="Mac OS X" first-keystroke="meta I"/>
86+
<keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="meta I"/>
87+
<keyboard-shortcut keymap="$default" first-keystroke="control I"/>
88+
</action>
8289
</group>
8390
</actions>
8491
</idea-plugin>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextCo
1919
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindow
2020
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
2121
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager
22+
import software.aws.toolkits.jetbrains.services.cwc.inline.InlineChatController
2223
import java.lang.management.ManagementFactory
2324
import java.time.Duration
2425
import java.util.concurrent.atomic.AtomicBoolean
@@ -31,6 +32,7 @@ class AmazonQStartupActivity : ProjectActivity {
3132

3233
// initialize html contents in BGT so users don't have to wait when they open the tool window
3334
AmazonQToolWindow.getInstance(project)
35+
InlineChatController.getInstance(project)
3436

3537
if (CodeWhispererExplorerActionManager.getInstance().getIsFirstRestartAfterQInstall()) {
3638
runInEdt {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum class TriggerType {
1414
ContextMenu,
1515
Hotkeys,
1616
CodeScanButton,
17+
Inline,
1718
}
1819

1920
data class ChatRequestData(

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.Recommend
5151
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.Reference
5252
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.SuggestedFollowUp
5353
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.Suggestion
54+
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.TriggerType
5455
import software.aws.toolkits.jetbrains.services.cwc.editor.context.ActiveFileContext
5556

5657
class ChatSessionV1(
@@ -200,6 +201,7 @@ class ChatSessionV1(
200201
val userInputMessageContextBuilder = UserInputMessageContext.builder()
201202
userInputMessageContextBuilder.editorState(activeFileContext.toEditorState(relevantTextDocuments, useRelevantDocuments))
202203
val userInputMessageContext = userInputMessageContextBuilder.build()
204+
val chatTriggerType = if (triggerType == TriggerType.Inline) ChatTriggerType.INLINE_CHAT else ChatTriggerType.MANUAL
203205

204206
val userInput = UserInputMessage.builder()
205207
.content(message.take(ChatConstants.CUSTOMER_MESSAGE_SIZE_LIMIT))
@@ -209,7 +211,7 @@ class ChatSessionV1(
209211
val conversationState = ConversationState.builder()
210212
.conversationId(conversationId)
211213
.currentMessage(ChatMessage.fromUserInputMessage(userInput))
212-
.chatTriggerType(ChatTriggerType.MANUAL)
214+
.chatTriggerType(chatTriggerType)
213215
.customizationArn(customization?.arn)
214216
.build()
215217
return GenerateAssistantResponseRequest.builder()

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class ChatController private constructor(
9292
) : InboundAppMessagesHandler {
9393

9494
private val messagePublisher: MessagePublisher = context.messagesFromAppToUi
95-
private val telemetryHelper = TelemetryHelper(context, chatSessionStorage)
95+
private val telemetryHelper = TelemetryHelper(context.project, chatSessionStorage)
9696
constructor(
9797
context: AmazonQAppInitContext,
9898
) : this(
@@ -217,7 +217,7 @@ class ChatController private constructor(
217217

218218
editor.document.insertString(offset, message.code)
219219

220-
ReferenceLogController.addReferenceLog(message.code, message.codeReference, editor, context.project)
220+
ReferenceLogController.addReferenceLog(message.code, message.codeReference, editor, context.project, null)
221221

222222
CodeWhispererUserModificationTracker.getInstance(context.project).enqueue(
223223
InsertedCodeModificationEntry(

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Reference
99
import software.amazon.awssdk.services.codewhispererruntime.model.Span
1010
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.CodeReferenceGenerated
1111
import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil
12+
import software.aws.toolkits.jetbrains.services.codewhisperer.model.CaretPosition
1213
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
1314
import software.aws.toolkits.jetbrains.services.cwc.messages.CodeReference
1415

1516
object ReferenceLogController {
16-
fun addReferenceLog(originalCode: String, codeReferences: List<CodeReference>?, editor: Editor, project: Project) {
17+
fun addReferenceLog(originalCode: String, codeReferences: List<CodeReference>?, editor: Editor, project: Project, inlineChatStartPosition: CaretPosition?) {
1718
codeReferences?.let { references ->
1819
val cwReferences = references.map { reference ->
1920
Reference.builder()
@@ -36,7 +37,7 @@ object ReferenceLogController {
3637
originalCode,
3738
cwReferences,
3839
editor,
39-
CodeWhispererEditorUtil.getCaretPosition(editor),
40+
inlineChatStartPosition ?: CodeWhispererEditorUtil.getCaretPosition(editor),
4041
null,
4142
)
4243
}

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

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import kotlinx.coroutines.CancellationException
77
import kotlinx.coroutines.flow.catch
88
import kotlinx.coroutines.flow.flow
99
import kotlinx.coroutines.flow.onCompletion
10+
import kotlinx.coroutines.flow.onEach
1011
import kotlinx.coroutines.flow.onStart
1112
import software.amazon.awssdk.awscore.exception.AwsServiceException
1213
import software.amazon.awssdk.services.codewhispererstreaming.model.CodeWhispererStreamingException
@@ -55,6 +56,7 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
5556
data: ChatRequestData,
5657
sessionInfo: ChatSessionInfo,
5758
shouldAddIndexInProgressMessage: Boolean,
59+
isInlineChat: Boolean = false,
5860
) = flow {
5961
val session = sessionInfo.session
6062
session.chat(data)
@@ -135,14 +137,19 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
135137
)
136138
}
137139
}
140+
.onEach { responseEvent ->
141+
if (isInlineChat) processChatEvent(tabId, triggerId, data, responseEvent, shouldAddIndexInProgressMessage)?.let { emit(it) }
142+
}
138143
.collect { responseEvent ->
139-
processChatEvent(
140-
tabId,
141-
triggerId,
142-
data,
143-
responseEvent,
144-
shouldAddIndexInProgressMessage
145-
)?.let { emit(it) }
144+
if (!isInlineChat) {
145+
processChatEvent(
146+
tabId,
147+
triggerId,
148+
data,
149+
responseEvent,
150+
shouldAddIndexInProgressMessage
151+
)?.let { emit(it) }
152+
}
146153
}
147154
}
148155

0 commit comments

Comments
 (0)