diff --git a/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json b/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json new file mode 100644 index 00000000000..cf4ba893c91 --- /dev/null +++ b/.changes/next-release/feature-7e2ed4ba-b795-4c82-a99a-da610a0432c8.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "Amazon Q Chat: Pin context items in chat and manage workspace rules" +} \ No newline at end of file diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index f030d69aa3d..89b02987bae 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -60,6 +60,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LIST_CONVERSATIONS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PROMPT_OPTION_ACKNOWLEDGED import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_QUICK_ACTION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_READY @@ -73,6 +75,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.Encry 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.LIST_MCP_SERVERS_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_RULES_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY @@ -83,6 +86,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenTabResultSuccess 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.QuickChatActionRequest +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.RULE_CLICK_REQUEST_METHOD 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.STOP_CHAT_RESPONSE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest @@ -485,6 +489,34 @@ class BrowserConnector( ) } } + LIST_RULES_REQUEST_METHOD -> { + handleChat(AmazonQChatServer.listRules, node) + .whenComplete { response, _ -> + browser.postChat( + FlareUiMessage( + command = LIST_RULES_REQUEST_METHOD, + params = response + ) + ) + } + } + RULE_CLICK_REQUEST_METHOD -> { + handleChat(AmazonQChatServer.ruleClick, node) + .whenComplete { response, _ -> + browser.postChat( + FlareUiMessage( + command = RULE_CLICK_REQUEST_METHOD, + params = response + ) + ) + } + } + CHAT_PINNED_CONTEXT_ADD -> { + handleChat(AmazonQChatServer.pinnedContextAdd, node) + } + CHAT_PINNED_CONTEXT_REMOVE -> { + handleChat(AmazonQChatServer.pinnedContextRemove, node) + } } } diff --git a/plugins/amazonq/mynah-ui/package-lock.json b/plugins/amazonq/mynah-ui/package-lock.json index a16f304d31b..b78f76b4250 100644 --- a/plugins/amazonq/mynah-ui/package-lock.json +++ b/plugins/amazonq/mynah-ui/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.30.3", + "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.35.5", "@types/node": "^14.18.5", "fs-extra": "^10.0.1", "sanitize-html": "^2.12.1", @@ -18,7 +18,7 @@ "web-tree-sitter": "^0.20.7" }, "devDependencies": { - "@aws/chat-client": "^0.1.4", + "@aws/chat-client": "^0.1.18", "@aws/fully-qualified-names": "^2.1.1", "@types/sanitize-html": "^2.8.0", "@typescript-eslint/eslint-plugin": "^5.38.0", @@ -48,25 +48,23 @@ } }, "node_modules/@aws/chat-client": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@aws/chat-client/-/chat-client-0.1.4.tgz", - "integrity": "sha512-5iqo9f/FjipyWxVPByVcI4yF9NPDOFInuS2ak4bK+j4d6ca1n20CnQrEQcMOdGjl5mde51s7X4Jqvlu3smgHGA==", + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@aws/chat-client/-/chat-client-0.1.18.tgz", + "integrity": "sha512-fyeBvYmw7ppvJ7y+k5s5fVNF7DBKaoEO5PUCwlkm+QPnTkm8qfGpMNDsMXsDQJoIYqHcgmwzdRmcZZ6NVcqgNA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws/chat-client-ui-types": "^0.1.12", - "@aws/language-server-runtimes-types": "^0.1.10", - "@aws/mynah-ui": "^4.28.0" + "@aws/chat-client-ui-types": "^0.1.40", + "@aws/language-server-runtimes-types": "^0.1.39", + "@aws/mynah-ui": "^4.35.4" } }, "node_modules/@aws/chat-client-ui-types": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.32.tgz", - "integrity": "sha512-axJymxFQhXh8AOnhek61VL5va917TjIvfHF5sHpyQay+znILAs65osdIMeqHs6VTjZCKtzIEp5iCd6uZbvYRVw==", + "version": "0.1.46", + "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.46.tgz", + "integrity": "sha512-IG/fyMqBfaTPy2swgEVAJ8PgwL3x0rWFYFbj9VxKCIsn6LgYisF8KuKtTg8p0d62H0rGV9SCsziH1nNRufTpKA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.26" + "@aws/language-server-runtimes-types": "^0.1.40" } }, "node_modules/@aws/fully-qualified-names": { @@ -79,23 +77,21 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.26.tgz", - "integrity": "sha512-c63rpUbcrtLqaC33t6elRApQqLbQvFgKzIQ2z/VCavE5F7HSLBfzhHkhgUFd775fBpsF4MHrIzwNitYLhDGobw==", + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.40.tgz", + "integrity": "sha512-GWZaoWwQQkBj21zB+1QXws7W6kP+V0jRGn6Lmwq3apfCrGGRRYpEYjEE7l3Qk/emAjgLs2rhZ7Z0nj/pbFrSAQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5" } }, "node_modules/@aws/mynah-ui": { - "version": "4.30.3", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.30.3.tgz", - "integrity": "sha512-Xy22dzCaFUqpdSHMpLa8Dsq98DiAUq49dm7Iu8Yj2YZXSCyfKQiYMJOfwU8IoqeNcEney5JRMJpf+/RysWugbA==", + "version": "4.35.5", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.35.5.tgz", + "integrity": "sha512-HFzNiVexMLPt4GUBcCBgObr2WKjmLg0EKH7/nPPaThEvQAVZYOapMYKoxaS/IrEa6BqWsE36V4++F3Bh7Vf7uw==", "dev": true, "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -115,11 +111,10 @@ }, "node_modules/@aws/mynah-ui-chat": { "name": "@aws/mynah-ui", - "version": "4.30.3", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.30.3.tgz", - "integrity": "sha512-Xy22dzCaFUqpdSHMpLa8Dsq98DiAUq49dm7Iu8Yj2YZXSCyfKQiYMJOfwU8IoqeNcEney5JRMJpf+/RysWugbA==", + "version": "4.35.5", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.35.5.tgz", + "integrity": "sha512-HFzNiVexMLPt4GUBcCBgObr2WKjmLg0EKH7/nPPaThEvQAVZYOapMYKoxaS/IrEa6BqWsE36V4++F3Bh7Vf7uw==", "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -3577,15 +3572,13 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/watchpack": { "version": "2.4.2", diff --git a/plugins/amazonq/mynah-ui/package.json b/plugins/amazonq/mynah-ui/package.json index 953b82bc434..59013b87ffd 100644 --- a/plugins/amazonq/mynah-ui/package.json +++ b/plugins/amazonq/mynah-ui/package.json @@ -12,7 +12,7 @@ "lintfix": "eslint -c .eslintrc.js --fix --ext .ts ." }, "dependencies": { - "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.30.3", + "@aws/mynah-ui-chat": "npm:@aws/mynah-ui@4.35.5", "@types/node": "^14.18.5", "fs-extra": "^10.0.1", "sanitize-html": "^2.12.1", @@ -21,8 +21,8 @@ "web-tree-sitter": "^0.20.7" }, "devDependencies": { + "@aws/chat-client": "^0.1.18", "@aws/fully-qualified-names": "^2.1.1", - "@aws/chat-client": "^0.1.4", "@types/sanitize-html": "^2.8.0", "@typescript-eslint/eslint-plugin": "^5.38.0", "@typescript-eslint/parser": "^5.38.0", diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts index 4734b37d7b9..b700b38ff6d 100644 --- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts +++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts @@ -395,7 +395,7 @@ private handleDocCommand(chatPrompt: ChatPrompt, tabID: string, taskName: string cancelButtonWhenLoading: false, }) } else { - this.mynahUI?.updateStore(affectedTabId, { promptInputOptions: [] }) + this.mynahUI?.updateStore(affectedTabId, { promptInputOptions: [], promptTopBarTitle: '' }) } if (affectedTabId && this.isHybridChatEnabled) { diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt index 7c644894bb4..b2c8854cf6d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt @@ -18,6 +18,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_INSERT_TO_CURSOR_NOTIFICATION import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LINK_CLICK import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_LIST_CONVERSATIONS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_QUICK_ACTION 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 @@ -39,11 +41,13 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSe 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.LIST_MCP_SERVERS_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_RULES_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ListConversationsParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD 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.RULE_CLICK_REQUEST_METHOD 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.TELEMETRY_EVENT @@ -189,6 +193,18 @@ object AmazonQChatServer : JsonRpcMethodProvider { LSPAny::class.java ) + val listRules = JsonRpcRequest( + LIST_RULES_REQUEST_METHOD, + LSPAny::class.java, + LSPAny::class.java + ) + + val ruleClick = JsonRpcRequest( + RULE_CLICK_REQUEST_METHOD, + LSPAny::class.java, + LSPAny::class.java + ) + val conversationClick = JsonRpcRequest( CHAT_CONVERSATION_CLICK, ConversationClickParams::class.java, @@ -218,6 +234,16 @@ object AmazonQChatServer : JsonRpcMethodProvider { CreatePromptParams::class.java ) + val pinnedContextAdd = JsonRpcNotification( + CHAT_PINNED_CONTEXT_ADD, + LSPAny::class.java + ) + + val pinnedContextRemove = JsonRpcNotification( + CHAT_PINNED_CONTEXT_REMOVE, + LSPAny::class.java + ) + val telemetryEvent = JsonRpcNotification( TELEMETRY_EVENT, Any::class.java diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt index c5141c4446b..4eeafc4cea2 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt @@ -9,7 +9,10 @@ import org.eclipse.lsp4j.services.LanguageClient import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPTIONS_UPDATE_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyFileParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.DID_APPEND_FILE @@ -54,6 +57,15 @@ interface AmazonQLanguageClient : LanguageClient { @JsonNotification(CHAT_SEND_CONTEXT_COMMANDS) fun sendContextCommands(params: LSPAny): CompletableFuture + @JsonNotification(CHAT_SEND_PINNED_CONTEXT) + fun sendPinnedContext(params: LSPAny) + + @JsonNotification(CHAT_PINNED_CONTEXT_ADD) + fun pinnedContextAdd(params: LSPAny) + + @JsonNotification(CHAT_PINNED_CONTEXT_REMOVE) + fun pinnedContextRemove(params: LSPAny) + @JsonNotification(DID_COPY_FILE) fun copyFile(params: CopyFileParams) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 6eab2f54841..07b985c96ca 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFileManager import migration.software.aws.toolkits.jetbrains.settings.AwsSettings import org.eclipse.lsp4j.ConfigurationParams @@ -27,6 +28,7 @@ import org.eclipse.lsp4j.PublishDiagnosticsParams import org.eclipse.lsp4j.ShowDocumentParams import org.eclipse.lsp4j.ShowDocumentResult import org.eclipse.lsp4j.ShowMessageRequestParams +import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.jsonrpc.ResponseErrorException import org.eclipse.lsp4j.jsonrpc.messages.ResponseError import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode @@ -44,7 +46,10 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMes import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.LSPAny import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPEN_TAB import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_OPTIONS_UPDATE_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_ADD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_PINNED_CONTEXT_REMOVE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_CONTEXT_COMMANDS +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_PINNED_CONTEXT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_SEND_UPDATE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CopyFileParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FileParams @@ -74,7 +79,8 @@ import java.util.concurrent.TimeUnit * Concrete implementation of [AmazonQLanguageClient] to handle messages sent from server */ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageClient { - + private val chatManager + get() = ChatCommunicationManager.getInstance(project) private fun handleTelemetryMap(telemetryMap: Map<*, *>) { try { val name = telemetryMap["name"] as? String ?: return @@ -201,7 +207,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun openTab(params: LSPAny): CompletableFuture { val requestId = UUID.randomUUID().toString() val result = CompletableFuture() - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.addTabOpenRequest(requestId, result) chatManager.notifyUi( @@ -252,7 +257,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun getSerializedChat(params: LSPAny): CompletableFuture { val requestId = UUID.randomUUID().toString() val result = CompletableFuture() - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.addSerializedChatRequest(requestId, result) chatManager.notifyUi( @@ -317,9 +321,8 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun notifyProgress(params: ProgressParams?) { if (params == null) return - val chatCommunicationManager = ChatCommunicationManager.getInstance(project) try { - chatCommunicationManager.handlePartialResultProgressNotification(project, params) + chatManager.handlePartialResultProgressNotification(project, params) } catch (e: Exception) { LOG.error(e) { "Cannot handle partial chat" } } @@ -415,7 +418,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC ) override fun sendContextCommands(params: LSPAny): CompletableFuture { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_SEND_CONTEXT_COMMANDS, @@ -425,6 +427,55 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC return CompletableFuture.completedFuture(Unit) } + override fun sendPinnedContext(params: LSPAny) { + // Send the active text file path with pinned context + val editor = FileEditorManager.getInstance(project).selectedTextEditor + val textDocument = editor?.let { + val relativePath = VfsUtilCore.getRelativePath(it.virtualFile, project.baseDir) + ?: it.virtualFile.path // Use absolute path if not in project + TextDocumentIdentifier(relativePath) + } + + // Create updated params with text document information + // Since params is LSPAny, we need to handle it as a generic object + val updatedParams = when (params) { + is Map<*, *> -> { + val mutableParams = params.toMutableMap() + mutableParams["textDocument"] = textDocument + mutableParams + } + else -> mapOf( + "params" to params, + "textDocument" to textDocument + ) + } + + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_SEND_PINNED_CONTEXT, + params = updatedParams, + ) + ) + } + + override fun pinnedContextAdd(params: LSPAny) { + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_PINNED_CONTEXT_ADD, + params = params, + ) + ) + } + + override fun pinnedContextRemove(params: LSPAny) { + chatManager.notifyUi( + FlareUiMessage( + command = CHAT_PINNED_CONTEXT_REMOVE, + params = params, + ) + ) + } + override fun appendFile(params: FileParams) = refreshVfs(params.path) override fun createDirectory(params: FileParams) = refreshVfs(params.path) @@ -439,7 +490,6 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC } override fun sendChatOptionsUpdate(params: LSPAny) { - val chatManager = ChatCommunicationManager.getInstance(project) chatManager.notifyUi( FlareUiMessage( command = CHAT_OPTIONS_UPDATE_NOTIFICATION, diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt index db49b158c41..b304a3cff88 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/ExtendedClientMetadata.kt @@ -24,6 +24,7 @@ data class AwsClientCapabilities( data class DeveloperProfiles( val developerProfiles: Boolean, val mcp: Boolean, + val pinnedContextEnabled: Boolean, ) data class WindowSettings( @@ -62,7 +63,8 @@ fun createExtendedClientMetadata(project: Project): ExtendedClientMetadata { awsClientCapabilities = AwsClientCapabilities( q = DeveloperProfiles( developerProfiles = true, - mcp = true + mcp = true, + pinnedContextEnabled = true, ), window = WindowSettings( showSaveFileDialog = true diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt index 8c089dabde6..cb95ca7106b 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/CreatePromptParams.kt @@ -5,6 +5,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat data class CreatePromptParams( val promptName: String, + val isRule: Boolean? = null, ) data class CreatePromptNotification( diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt index e53835701a2..4de4c4501c2 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat +const val ACTIVE_EDITOR_CHANGED_NOTIFICATION = "aws/chat/activeEditorChanged" const val AUTH_FOLLOW_UP_CLICKED = "authFollowUpClicked" const val CHAT_BUTTON_CLICK = "aws/chat/buttonClick" const val CHAT_CONVERSATION_CLICK = "aws/chat/conversationClick" @@ -25,7 +26,10 @@ const val CHAT_PROMPT_OPTION_ACKNOWLEDGED = "chatPromptOptionAcknowledged" const val CHAT_QUICK_ACTION = "aws/chat/sendChatQuickAction" const val CHAT_READY = "aws/chat/ready" const val CHAT_SEND_CONTEXT_COMMANDS = "aws/chat/sendContextCommands" +const val CHAT_SEND_PINNED_CONTEXT = "aws/chat/sendPinnedContext" const val CHAT_SEND_UPDATE = "aws/chat/sendChatUpdate" +const val CHAT_PINNED_CONTEXT_ADD = "aws/chat/pinnedContextAdd" +const val CHAT_PINNED_CONTEXT_REMOVE = "aws/chat/pinnedContextRemove" const val CHAT_SOURCE_LINK_CLICK = "aws/chat/sourceLinkClick" const val CHAT_TAB_ADD = "aws/chat/tabAdd" const val CHAT_TAB_BAR_ACTIONS = "aws/chat/tabBarAction" @@ -55,3 +59,5 @@ const val TELEMETRY_EVENT = "telemetry/event" // https://github.com/aws/language-server-runtimes/blob/112feba70219a98a12f13727d67c540205fa9c9f/types/chat.ts#L32 const val LIST_MCP_SERVERS_REQUEST_METHOD = "aws/chat/listMcpServers" const val MCP_SERVER_CLICK_REQUEST_METHOD = "aws/chat/mcpServerClick" +const val LIST_RULES_REQUEST_METHOD = "aws/chat/listRules" +const val RULE_CLICK_REQUEST_METHOD = "aws/chat/ruleClick" diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt index 500626d1440..387ee603557 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/textdocument/TextDocumentServiceHandler.kt @@ -10,8 +10,11 @@ import com.intellij.openapi.editor.event.DocumentEvent import com.intellij.openapi.editor.event.DocumentListener import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManagerListener +import com.intellij.openapi.fileEditor.FileEditor import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerEvent import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.fileEditor.TextEditor import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.vfs.VirtualFile @@ -28,6 +31,8 @@ import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.TextDocumentItem import org.eclipse.lsp4j.VersionedTextDocumentIdentifier import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ACTIVE_EDITOR_CHANGED_NOTIFICATION +import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.getCursorState import software.aws.toolkits.jetbrains.services.amazonq.lsp.util.LspEditorUtil.toUriString import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread @@ -166,6 +171,27 @@ class TextDocumentServiceHandler( } } + override fun selectionChanged(event: FileEditorManagerEvent) { + handleActiveEditorChange(event.newEditor) + } + + private fun handleActiveEditorChange(fileEditor: FileEditor?) { + // Extract text editor if it's a TextEditor, otherwise null + val editor = (fileEditor as? TextEditor)?.editor + val textDocumentIdentifier = editor?.let { TextDocumentIdentifier(toUriString(it.virtualFile)) } + val cursorState = editor?.let { getCursorState(it) } + + val params = mapOf( + "textDocument" to textDocumentIdentifier, + "cursorState" to cursorState + ) + + // Send notification to the language server + AmazonQLspService.executeIfRunning(project) { _ -> + rawEndpoint.notify(ACTIVE_EDITOR_CHANGED_NOTIFICATION, params) + } + } + private fun realTimeEdit(event: DocumentEvent) { AmazonQLspService.executeIfRunning(project) { languageServer -> pluginAwareExecuteOnPooledThread {