Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
}
},
{
agenticMode: true,
quickActionCommands: $quickActionConfig,
disclaimerAcknowledged: ${MeetQSettings.getInstance().disclaimerAcknowledged},
pairProgrammingAcknowledged: ${!MeetQSettings.getInstance().amazonQChatPairProgramming}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.future.await

Check warning on line 21 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive

Check warning

Code scanning / QDJVMC

Unused import directive Warning

Unused import directive
import kotlinx.coroutines.launch
import org.cef.browser.CefBrowser
import org.eclipse.lsp4j.Position
Expand All @@ -26,6 +27,7 @@
import software.aws.toolkits.core.utils.warn
import software.aws.toolkits.jetbrains.services.amazonq.apps.AppConnection
import software.aws.toolkits.jetbrains.services.amazonq.commands.MessageSerializer
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageClientImpl

Check warning on line 30 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLanguageServer
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager
Expand All @@ -50,6 +52,7 @@
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SOURCE_LINK_CLICK
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_ADD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_BAR_ACTIONS
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_CHANGE
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_REMOVE
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatNotification
Expand All @@ -69,6 +72,8 @@
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FileClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FollowUpClickNotification
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FollowUpClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResponse
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InfoLinkClickNotification
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InfoLinkClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InsertToCursorPositionNotification
Expand All @@ -83,6 +88,8 @@
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickNotification
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionRequest
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabEventParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabEventRequest
import software.aws.toolkits.jetbrains.services.amazonq.util.command
Expand Down Expand Up @@ -224,7 +231,7 @@
requestFromUi.params.tabId,
chatPrompt,
textDocumentIdentifier,
cursorState
cursorState,
)

val tabId = requestFromUi.params.tabId
Expand Down Expand Up @@ -341,6 +348,24 @@
}
}

GET_SERIALIZED_CHAT_REQUEST_METHOD -> {
val response = serializer.deserializeChatMessages<GetSerializedChatResponse>(node)
ChatCommunicationManager.completeSerializedChatResponse(
response.requestId,
response.params.result.content
)
}

CHAT_TAB_BAR_ACTIONS -> {
handleChatNotification<TabBarActionRequest, TabBarActionParams>(node) {
server, params ->
val result = server.tabBarActions(params)
result.whenComplete { params1, error ->
val res = ChatCommunicationManager.convertNotificationToJsonForChat(CHAT_TAB_BAR_ACTIONS, params1)
browser.postChat(res)
}
}
}
CHAT_CREATE_PROMPT -> {
handleChatNotification<CreatePromptNotification, CreatePromptParams>(node) {
server, params ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp

import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
import org.eclipse.lsp4j.services.LanguageClient
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata
import java.util.concurrent.CompletableFuture

Expand All @@ -20,4 +26,10 @@ interface AmazonQLanguageClient : LanguageClient {

@JsonRequest("aws/chat/openTab")
fun openTab(params: OpenTabParams): CompletableFuture<OpenTabResult>

@JsonRequest(SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD)
fun showSaveFileDialog(params: ShowSaveFileDialogParams): CompletableFuture<ShowSaveFileDialogResult>

@JsonRequest(GET_SERIALIZED_CHAT_REQUEST_METHOD)
fun getSerializedChat(params: GetSerializedChatParams): CompletableFuture<GetSerializedChatResult>
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

@file:Suppress("BannedImports")
package software.aws.toolkits.jetbrains.services.amazonq.lsp

import com.google.gson.Gson
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.fileChooser.FileChooserFactory
import com.intellij.openapi.fileChooser.FileSaverDescriptor
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
Expand All @@ -23,14 +27,22 @@
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.services.amazonq.lsp.flareChat.AsyncChatUiListener
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.SsoProfileData
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator
import software.aws.toolkits.jetbrains.settings.CodeWhispererSettings
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit

/**
* Concrete implementation of [AmazonQLanguageClient] to handle messages sent from server
Expand Down Expand Up @@ -111,6 +123,66 @@
// TODO implement chat history, this is here to unblock chat functionality
CompletableFuture.completedFuture(OpenTabResult(""))

override fun showSaveFileDialog(params: ShowSaveFileDialogParams): CompletableFuture<ShowSaveFileDialogResult> {
val filters = mutableMapOf<String, String>()
val formatMappings = listOf(
FormatMapping("markdown", "Markdown", "md"),
FormatMapping("html", "HTML", "html")
)

params.supportedFormats.forEach { format ->
formatMappings.find { it.format == format }?.let { mapping ->
filters[mapping.key] = mapping.extensions
}
}

val saveAtUri = params.defaultUri ?: "export-chat.html"

return CompletableFuture.supplyAsync {
return@supplyAsync invokeAndWaitIfNeeded {

Check warning on line 142 in plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unstable API Usage

'invokeAndWaitIfNeeded(com.intellij.openapi.application.ModalityState, kotlin.jvm.functions.Function0)' is marked unstable with @ApiStatus.Internal
val descriptor = FileSaverDescriptor("Export", "Choose a location to export").apply {
withFileFilter { file ->
filters.values.any { ext ->
file.name.endsWith(".$ext")
}
}
}

val chosenFile = FileChooserFactory.getInstance().createSaveFileDialog(descriptor, project).save(saveAtUri)

chosenFile?.let {
return@invokeAndWaitIfNeeded ShowSaveFileDialogResult(chosenFile.file.path)
// TODO: Add error state shown in chat ui instead of throwing
} ?: throw Error("Export failed")
}
}
}

override fun getSerializedChat(params: GetSerializedChatParams): CompletableFuture<GetSerializedChatResult> {
val requestId = UUID.randomUUID().toString()
val result = CompletableFuture<GetSerializedChatResult>()

ChatCommunicationManager.pendingSerializedChatRequests[requestId] = result

val uiMessage = """
{
"command": "$GET_SERIALIZED_CHAT_REQUEST_METHOD",
"params": ${Gson().toJson(params)},
"requestId": "$requestId"
}
""".trimIndent()
AsyncChatUiListener.notifyPartialMessageUpdate(uiMessage)

result.orTimeout(30000, TimeUnit.MILLISECONDS)
.whenComplete { _, error ->
if (error != null) {
ChatCommunicationManager.pendingSerializedChatRequests.remove(requestId)
}
}

return result
}

override fun configuration(params: ConfigurationParams): CompletableFuture<List<Any>> {
if (params.items.isEmpty()) {
return CompletableFuture.completedFuture(null)
Expand Down Expand Up @@ -168,3 +240,9 @@
private val LOG = getLogger<AmazonQLanguageClientImpl>()
}
}

data class FormatMapping(
val format: String,
val key: String,
val extensions: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SOURCE_LINK_CLICK
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_ADD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_BAR_ACTIONS
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_CHANGE
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_REMOVE
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyCodeToClipboardParams
Expand All @@ -34,13 +35,18 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Encry
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FeedbackParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FileClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FollowUpClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InfoLinkClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.InsertToCursorPositionParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SourceLinkClickParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabBarActionResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TabEventParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.UpdateCredentialsPayload
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.dependencies.DidChangeDependencyPathsParams
Expand Down Expand Up @@ -114,6 +120,12 @@ interface AmazonQLanguageServer : LanguageServer {
@JsonRequest(CHAT_BUTTON_CLICK)
fun buttonClick(params: ButtonClickParams): CompletableFuture<ButtonClickResult>

@JsonRequest(CHAT_TAB_BAR_ACTIONS)
fun tabBarActions(params: TabBarActionParams): CompletableFuture<TabBarActionResult>

@JsonRequest(GET_SERIALIZED_CHAT_REQUEST_METHOD)
fun getSerializedActions(params: GetSerializedChatParams): CompletableFuture<GetSerializedChatResult>

@JsonNotification(CHAT_CREATE_PROMPT)
fun createPrompt(params: CreatePromptParams): CompletableFuture<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

@file:Suppress("BannedImports")
package software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat

import com.google.gson.Gson
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import org.eclipse.lsp4j.ProgressParams
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ProgressNotificationUtils.getObject
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap

@Service(Service.Level.PROJECT)
Expand Down Expand Up @@ -56,6 +59,11 @@ class ChatCommunicationManager {
companion object {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be in companion object? I moved my openTab map into ChatCommunicationManager but just made it part of the class.
https://github.com/aws/aws-toolkit-jetbrains/pull/5658/files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- might be going away anyways. I'll move mine to companion so we are aligned

fun getInstance(project: Project) = project.service<ChatCommunicationManager>()

val pendingSerializedChatRequests = ConcurrentHashMap<String, CompletableFuture<GetSerializedChatResult>>()
fun completeSerializedChatResponse(requestId: String, content: String) {
pendingSerializedChatRequests.remove(requestId)?.complete(GetSerializedChatResult((content)))
}

fun convertToJsonToSendToChat(command: String, tabId: String, params: String, isPartialResult: Boolean): String =
"""
{
Expand All @@ -65,5 +73,13 @@ class ChatCommunicationManager {
"isPartialResult": $isPartialResult
}
""".trimIndent()

inline fun <reified T> convertNotificationToJsonForChat(command: String, params: T? = null) =
"""
{
"command":"$command",
"params": ${if (params != null) Gson().toJson(params) else "{}"}
}
""".trimIndent()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ data class AwsMetadata(

data class AwsClientCapabilities(
val q: DeveloperProfiles,
val window: WindowSettings,
)

data class DeveloperProfiles(
val developerProfiles: Boolean,
)

data class WindowSettings(
val showSaveFileDialog: Boolean,
)

data class ClientInfoMetadata(
val extension: ExtensionMetadata,
val clientId: String,
Expand Down Expand Up @@ -50,6 +55,9 @@ fun createExtendedClientMetadata(): ExtendedClientMetadata {
awsClientCapabilities = AwsClientCapabilities(
q = DeveloperProfiles(
developerProfiles = true
),
window = WindowSettings(
showSaveFileDialog = true
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ data class InnerChatPrompt(

data class InnerChatOptions(
@JsonProperty("pair-programmer-mode")
val pairProgrammingMode: String,
val pairProgrammingMode: String?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ const val CHAT_COPY_CODE_TO_CLIPBOARD = "copyToClipboard"
const val CHAT_COPY_CODE_TO_CLIPBOARD_NOTIFICATION = "aws/chat/copyCodeToClipboard"
const val CHAT_INSERT_TO_CURSOR = "insertToCursorPosition"
const val CHAT_INSERT_TO_CURSOR_NOTIFICATION = "aws/chat/insertToCursorPosition"
const val CHAT_TAB_BAR_ACTIONS = "aws/chat/tabBarAction"
const val CHAT_CREATE_PROMPT = "aws/chat/createPrompt"
const val SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD = "aws/showSaveFileDialog"
const val GET_SERIALIZED_CHAT_REQUEST_METHOD = "aws/chat/getSerializedChat"
Loading
Loading