Skip to content

Commit 15f3054

Browse files
authored
Merge branch 'feature/q-lsp-chat' into chatITem
2 parents d736081 + 7c2ca19 commit 15f3054

File tree

9 files changed

+94
-95
lines changed

9 files changed

+94
-95
lines changed

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

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,6 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
6969
.executeJavaScript("window.postMessage($message)", jcefBrowser.cefBrowser.url, 0)
7070
}
7171

72-
// TODO: Remove this once chat has been integrated with agents
73-
fun post(message: String) =
74-
jcefBrowser
75-
.cefBrowser
76-
.executeJavaScript("window.postMessage(JSON.stringify($message))", jcefBrowser.cefBrowser.url, 0)
77-
7872
// Load the chat web app into the jcefBrowser
7973
private fun loadWebView(
8074
isCodeTransformAvailable: Boolean,
@@ -118,10 +112,11 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
118112
val postMessageToJavaJsCode = receiveMessageQuery.inject("JSON.stringify(message)")
119113
val connectorAdapterPath = "http://mynah/js/connectorAdapter.js"
120114
generateQuickActionConfig()
115+
// https://github.com/highlightjs/highlight.js/issues/1387
121116
// language=HTML
122117
val jsScripts = """
123-
<script type="text/javascript" src="$connectorAdapterPath"></script>
124-
<script type="text/javascript" src="$webUri" defer onload="init()"></script>
118+
<script type="text/javascript" charset="UTF-8" src="$connectorAdapterPath"></script>
119+
<script type="text/javascript" charset="UTF-8" src="$webUri" defer onload="init()"></script>
125120
126121
<script type="text/javascript">
127122
@@ -155,8 +150,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
155150
pairProgrammingAcknowledged: ${!MeetQSettings.getInstance().amazonQChatPairProgramming}
156151
},
157152
hybridChatConnector,
158-
${CodeWhispererFeatureConfigService.getInstance().getFeatureConfigJsonString()}
159-
153+
${CodeWhispererFeatureConfigService.getInstance().getFeatureConfigJsonString()}
160154
);
161155
}
162156
</script>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp
66
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification
77
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
88
import org.eclipse.lsp4j.services.LanguageClient
9+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny
10+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS
911
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE
1012
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatUpdateParams
1113
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
@@ -43,4 +45,7 @@ interface AmazonQLanguageClient : LanguageClient {
4345

4446
@JsonNotification(OPEN_FILE_DIFF)
4547
fun openFileDiff(params: OpenFileDiffParams): CompletableFuture<Unit>
48+
49+
@JsonNotification(CHAT_SEND_CONTEXT_COMMANDS)
50+
fun sendContextCommands(params: LSPAny): CompletableFuture<Unit>
4651
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
3333
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
3434
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AsyncChatUiListener
3535
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
36+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny
3637
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB
38+
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS
3739
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE
3840
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ChatUpdateParams
3941
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD
@@ -340,6 +342,19 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC
340342
ApplicationManager.getApplication()::invokeLater
341343
)
342344

345+
override fun sendContextCommands(params: LSPAny): CompletableFuture<Unit> {
346+
val showContextCommands = """
347+
{
348+
"command":"$CHAT_SEND_CONTEXT_COMMANDS",
349+
"params": ${Gson().toJson(params)}
350+
}
351+
""".trimIndent()
352+
353+
AsyncChatUiListener.notifyPartialMessageUpdate(showContextCommands)
354+
355+
return CompletableFuture.completedFuture(Unit)
356+
}
357+
343358
companion object {
344359
private val LOG = getLogger<AmazonQLanguageClientImpl>()
345360
}

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

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
@file:Suppress("BannedImports")
44
package software.aws.toolkits.jetbrains.services.amazonq.lsp
55

6-
import com.google.gson.Gson
76
import com.google.gson.ToNumberPolicy
87
import com.intellij.execution.configurations.GeneralCommandLine
98
import com.intellij.execution.impl.ExecutionManagerImpl
@@ -24,7 +23,6 @@ import com.intellij.util.animation.consumer
2423
import com.intellij.util.io.await
2524
import kotlinx.coroutines.CoroutineScope
2625
import kotlinx.coroutines.Deferred
27-
import kotlinx.coroutines.TimeoutCancellationException
2826
import kotlinx.coroutines.async
2927
import kotlinx.coroutines.future.asCompletableFuture
3028
import kotlinx.coroutines.runBlocking
@@ -44,7 +42,6 @@ import org.eclipse.lsp4j.WorkspaceClientCapabilities
4442
import org.eclipse.lsp4j.jsonrpc.Launcher
4543
import org.eclipse.lsp4j.jsonrpc.Launcher.Builder
4644
import org.eclipse.lsp4j.jsonrpc.MessageConsumer
47-
import org.eclipse.lsp4j.jsonrpc.messages.NotificationMessage
4845
import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage
4946
import org.eclipse.lsp4j.launch.LSPLauncher
5047
import org.slf4j.event.Level
@@ -57,7 +54,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.auth.DefaultAuthCred
5754
import software.aws.toolkits.jetbrains.services.amazonq.lsp.dependencies.DefaultModuleDependenciesService
5855
import software.aws.toolkits.jetbrains.services.amazonq.lsp.encryption.JwtEncryptionManager
5956
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AmazonQLspTypeAdapterFactory
60-
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AsyncChatUiListener
6157
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsExtendedInitializeResult
6258
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider
6359
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.createExtendedClientMetadata
@@ -282,23 +278,12 @@ private class AmazonQServerInstance(private val project: Project, private val cs
282278

283279
launcher = LSPLauncher.Builder<AmazonQLanguageServer>()
284280
.wrapMessages { consumer ->
285-
MessageConsumer {
286-
message ->
281+
MessageConsumer { message ->
287282
if (message is ResponseMessage && message.result is AwsExtendedInitializeResult) {
288283
val result = message.result as AwsExtendedInitializeResult
289284
AwsServerCapabilitiesProvider.getInstance(project).setAwsServerCapabilities(result.getAwsServerCapabilities())
290285
AmazonQLspService.getInstance(project).notifyInitializeMessageReceived()
291286
}
292-
if (message is NotificationMessage && message.method == "aws/chat/sendContextCommands") {
293-
val showContextCommands = """
294-
{
295-
"command":"aws/chat/sendContextCommands",
296-
"params": ${Gson().toJson(message.params)}
297-
}
298-
""".trimIndent()
299-
300-
AsyncChatUiListener.notifyPartialMessageUpdate(showContextCommands)
301-
}
302287
consumer?.consume(message)
303288
}
304289
}
@@ -334,12 +319,7 @@ private class AmazonQServerInstance(private val project: Project, private val cs
334319
encryptionManager.writeInitializationPayload(launcherHandler.process.outputStream)
335320

336321
val initializeResult = try {
337-
withTimeout(5.seconds) {
338-
languageServer.initialize(createInitializeParams()).await()
339-
}
340-
} catch (_: TimeoutCancellationException) {
341-
LOG.warn { "LSP initialization timed out" }
342-
null
322+
languageServer.initialize(createInitializeParams()).await()
343323
} catch (e: Exception) {
344324
LOG.warn(e) { "LSP initialization failed" }
345325
null

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactHelper.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ class ArtifactHelper(private val lspArtifactsPath: Path = DEFAULT_ARTIFACT_PATH,
8181
.sortedByDescending { (_, semVer) -> semVer }
8282
}
8383

84-
fun getExistingLspArtifacts(versions: List<Version>, target: VersionTarget?): Boolean {
85-
if (versions.isEmpty() || target?.contents == null) return false
84+
fun getExistingLspArtifacts(targetVersion: Version, target: VersionTarget): Boolean {
85+
if (target.contents == null) return false
8686

87-
val localLSPPath = lspArtifactsPath.resolve(versions.first().serverVersion.toString())
87+
val localLSPPath = lspArtifactsPath.resolve(targetVersion.serverVersion.toString())
8888
if (!localLSPPath.exists()) return false
8989

9090
val hasInvalidFiles = target.contents.any { content ->
@@ -105,9 +105,9 @@ class ArtifactHelper(private val lspArtifactsPath: Path = DEFAULT_ARTIFACT_PATH,
105105
return !hasInvalidFiles
106106
}
107107

108-
suspend fun tryDownloadLspArtifacts(project: Project, versions: List<Version>, target: VersionTarget?): Path? {
108+
suspend fun tryDownloadLspArtifacts(project: Project, targetVersion: Version, target: VersionTarget): Path? {
109109
val temporaryDownloadPath = Files.createTempDirectory("lsp-dl")
110-
val downloadPath = lspArtifactsPath.resolve(versions.first().serverVersion.toString())
110+
val downloadPath = lspArtifactsPath.resolve(targetVersion.serverVersion.toString())
111111

112112
while (currentAttempt.get() < maxDownloadAttempts) {
113113
currentAttempt.incrementAndGet()
@@ -119,13 +119,19 @@ class ArtifactHelper(private val lspArtifactsPath: Path = DEFAULT_ARTIFACT_PATH,
119119
AwsCoreBundle.message("amazonqFeatureDev.placeholder.downloading_and_extracting_lsp_artifacts"),
120120
cancellable = true
121121
) {
122-
if (downloadLspArtifacts(temporaryDownloadPath, target) && target != null && !target.contents.isNullOrEmpty()) {
122+
if (downloadLspArtifacts(temporaryDownloadPath, target) && !target.contents.isNullOrEmpty()) {
123123
moveFilesFromSourceToDestination(temporaryDownloadPath, downloadPath)
124124
target.contents
125125
.mapNotNull { it.filename }
126126
.forEach { filename -> extractZipFile(downloadPath.resolve(filename), downloadPath) }
127127
logger.info { "Successfully downloaded and moved LSP artifacts to $downloadPath" }
128128

129+
val thirdPartyLicenses = targetVersion.thirdPartyLicenses
130+
logger.info {
131+
"Installing Amazon Q Language Server v${targetVersion.serverVersion} to: $downloadPath. " +
132+
if (thirdPartyLicenses == null) "" else "Attribution notice can be found at $thirdPartyLicenses"
133+
}
134+
129135
return@withBackgroundProgress downloadPath
130136
}
131137

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ArtifactManager.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,15 @@ class ArtifactManager @NonInjectable internal constructor(private val manifestFe
7171
throw LspException("Language server versions not found in manifest.", LspException.ErrorCode.NO_COMPATIBLE_LSP_VERSION)
7272
}
7373

74+
val targetVersion = lspVersions.inRangeVersions.first()
75+
7476
// If there is an LSP Manifest with the same version
75-
val target = getTargetFromLspManifest(lspVersions.inRangeVersions)
77+
val target = getTargetFromLspManifest(targetVersion)
7678
// Get Local LSP files and check if we can re-use existing LSP Artifacts
77-
val artifactPath: Path = if (artifactHelper.getExistingLspArtifacts(lspVersions.inRangeVersions, target)) {
79+
val artifactPath: Path = if (artifactHelper.getExistingLspArtifacts(targetVersion, target)) {
7880
artifactHelper.getAllLocalLspArtifactsWithinManifestRange(DEFAULT_VERSION_RANGE).first().first
7981
} else {
80-
artifactHelper.tryDownloadLspArtifacts(project, lspVersions.inRangeVersions, target)
82+
artifactHelper.tryDownloadLspArtifacts(project, targetVersion, target)
8183
?: throw LspException("Failed to download LSP artifacts", LspException.ErrorCode.DOWNLOAD_FAILED)
8284
}
8385
artifactHelper.deleteOlderLspArtifacts(DEFAULT_VERSION_RANGE)
@@ -111,18 +113,18 @@ class ArtifactManager @NonInjectable internal constructor(private val manifestFe
111113
)
112114
}
113115

114-
private fun getTargetFromLspManifest(versions: List<Version>): VersionTarget {
116+
private fun getTargetFromLspManifest(targetVersion: Version): VersionTarget {
115117
val currentOS = getCurrentOS()
116118
val currentArchitecture = getCurrentArchitecture()
117119

118-
val currentTarget = versions.first().targets?.find { target ->
120+
val currentTarget = targetVersion.targets?.find { target ->
119121
target.platform == currentOS && target.arch == currentArchitecture
120122
}
121123
if (currentTarget == null) {
122124
logger.error { "Failed to obtain target for $currentOS and $currentArchitecture" }
123-
throw LspException("Target not found in the current Version: ${versions.first().serverVersion}", LspException.ErrorCode.TARGET_NOT_FOUND)
125+
throw LspException("Target not found in the current Version: ${targetVersion.serverVersion}", LspException.ErrorCode.TARGET_NOT_FOUND)
124126
}
125-
logger.info { "Target found in the current Version: ${versions.first().serverVersion}" }
127+
logger.info { "Target found in the current Version: ${targetVersion.serverVersion}" }
126128
return currentTarget
127129
}
128130
}

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/artifacts/ManifestFetcher.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ data class Version(
155155
val isDelisted: Boolean? = null,
156156
@JsonProperty("targets")
157157
val targets: List<VersionTarget>? = emptyList(),
158+
@JsonProperty("thirdPartyLicenses")
159+
val thirdPartyLicenses: String? = null,
158160
)
159161

160162
data class Manifest(

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,40 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat
55

6-
const val SEND_CHAT_COMMAND_PROMPT = "aws/chat/sendChatPrompt"
7-
const val CHAT_QUICK_ACTION = "aws/chat/sendChatQuickAction"
8-
const val CHAT_READY = "aws/chat/ready"
9-
const val CHAT_LINK_CLICK = "aws/chat/linkClick"
10-
const val CHAT_INFO_LINK_CLICK = "aws/chat/infoLinkClick"
11-
const val CHAT_SOURCE_LINK_CLICK = "aws/chat/sourceLinkClick"
12-
const val PROMPT_INPUT_OPTIONS_CHANGE = "aws/chat/promptInputOptionChange"
13-
const val CHAT_PROMPT_OPTION_ACKNOWLEDGED = "chatPromptOptionAcknowledged"
14-
const val CHAT_FEEDBACK = "aws/chat/feedback"
15-
const val CHAT_FOLLOW_UP_CLICK = "aws/chat/followUpClick"
16-
const val CHAT_LIST_CONVERSATIONS = "aws/chat/listConversations"
17-
const val CHAT_CONVERSATION_CLICK = "aws/chat/conversationClick"
18-
const val CHAT_FILE_CLICK = "aws/chat/fileClick"
19-
const val CHAT_TAB_ADD = "aws/chat/tabAdd"
20-
const val CHAT_TAB_CHANGE = "aws/chat/tabChange"
21-
const val CHAT_TAB_REMOVE = "aws/chat/tabRemove"
22-
const val CHAT_OPEN_TAB = "aws/chat/openTab"
236
const val CHAT_BUTTON_CLICK = "aws/chat/buttonClick"
24-
const val CHAT_DISCLAIMER_ACKNOWLEDGED = "disclaimerAcknowledged"
7+
const val CHAT_CONVERSATION_CLICK = "aws/chat/conversationClick"
258
const val CHAT_COPY_CODE_TO_CLIPBOARD = "copyToClipboard"
269
const val CHAT_COPY_CODE_TO_CLIPBOARD_NOTIFICATION = "aws/chat/copyCodeToClipboard"
10+
const val CHAT_CREATE_PROMPT = "aws/chat/createPrompt"
11+
const val CHAT_DISCLAIMER_ACKNOWLEDGED = "disclaimerAcknowledged"
12+
const val CHAT_ERROR_PARAMS = "errorMessage"
13+
const val CHAT_FEEDBACK = "aws/chat/feedback"
14+
const val CHAT_FILE_CLICK = "aws/chat/fileClick"
15+
const val CHAT_FOLLOW_UP_CLICK = "aws/chat/followUpClick"
16+
const val CHAT_INFO_LINK_CLICK = "aws/chat/infoLinkClick"
2717
const val CHAT_INSERT_TO_CURSOR = "insertToCursorPosition"
2818
const val CHAT_INSERT_TO_CURSOR_NOTIFICATION = "aws/chat/insertToCursorPosition"
29-
const val CHAT_TAB_BAR_ACTIONS = "aws/chat/tabBarAction"
19+
const val CHAT_LINK_CLICK = "aws/chat/linkClick"
20+
const val CHAT_LIST_CONVERSATIONS = "aws/chat/listConversations"
21+
const val CHAT_OPEN_TAB = "aws/chat/openTab"
22+
const val CHAT_PROMPT_OPTION_ACKNOWLEDGED = "chatPromptOptionAcknowledged"
23+
const val CHAT_QUICK_ACTION = "aws/chat/sendChatQuickAction"
24+
const val CHAT_READY = "aws/chat/ready"
25+
const val CHAT_SEND_CONTEXT_COMMANDS = "aws/chat/sendContextCommands"
3026
const val CHAT_SEND_UPDATE = "aws/chat/sendChatUpdate"
31-
const val CHAT_CREATE_PROMPT = "aws/chat/createPrompt"
32-
const val SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD = "aws/showSaveFileDialog"
27+
const val CHAT_SOURCE_LINK_CLICK = "aws/chat/sourceLinkClick"
28+
const val CHAT_TAB_ADD = "aws/chat/tabAdd"
29+
const val CHAT_TAB_BAR_ACTIONS = "aws/chat/tabBarAction"
30+
const val CHAT_TAB_CHANGE = "aws/chat/tabChange"
31+
const val CHAT_TAB_REMOVE = "aws/chat/tabRemove"
32+
3333
const val GET_SERIALIZED_CHAT_REQUEST_METHOD = "aws/chat/getSerializedChat"
34+
3435
const val OPEN_FILE_DIFF = "aws/openFileDiff"
35-
const val CHAT_ERROR_PARAMS = "errorMessage"
36+
37+
const val PROMPT_INPUT_OPTIONS_CHANGE = "aws/chat/promptInputOptionChange"
38+
39+
const val SEND_CHAT_COMMAND_PROMPT = "aws/chat/sendChatPrompt"
40+
const val SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD = "aws/showSaveFileDialog"
3641
const val STOP_CHAT_RESPONSE = "stopChatResponse"
3742
const val OPEN_SETTINGS = "openSettings"

0 commit comments

Comments
 (0)