From e9c341100303dbd38e15f8c7694315b3c71171d4 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Fri, 1 Aug 2025 18:08:41 -0700 Subject: [PATCH 1/6] feat(chat-client): add in-context permission update to Mcp tools --- chat-client/package.json | 4 +- chat-client/src/client/mynahUi.ts | 29 ++ chat-client/src/client/withAdapter.ts | 2 + .../src/contracts/chatClientAdapter.ts | 2 + package-lock.json | 266 +++++------------- .../agenticChat/agenticChatController.ts | 125 +++++++- .../agenticChat/constants/toolConstants.ts | 1 + .../agenticChat/tools/mcp/mcpEventHandler.ts | 72 +++-- 8 files changed, 255 insertions(+), 246 deletions(-) diff --git a/chat-client/package.json b/chat-client/package.json index b467e237c7..e75107fa88 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -26,8 +26,8 @@ "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.114", - "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.2" + "@aws/language-server-runtimes-types": "^0.1.52", + "@aws/mynah-ui": "../../mynah-ui" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 3de8842fae..f2888e4dbf 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -52,6 +52,7 @@ import { MynahIcons, CustomQuickActionCommand, ConfigTexts, + DropdownListOption, } from '@aws/mynah-ui' import { VoteParams } from '../contracts/telemetry' import { Messager } from './messager' @@ -675,6 +676,30 @@ export const createMynahUi = ( throw new Error(`Unhandled tab bar button id: ${buttonId}`) }, + onDropDownOptionChange: (tabId: string, messageId: string, value: DropdownListOption[]) => { + // process data before sending + // map data to Record + // value: `${serverName}@${toolName}` + const metadata: Record = {} + const option = value[0] + const [serverName, toolName] = option.value.split('@') + const new_permission = option.id + + metadata['toolName'] = toolName + metadata['serverName'] = serverName + metadata['permission'] = new_permission + + const payload: ButtonClickParams = { + tabId, + messageId, + buttonId: 'trust-command', + metadata, + } + messager.onButtonClick(payload) + }, + onDropDownLinkClick: (tabId: string, actionId: string, destination: string) => { + messager.onMcpServerClick(actionId, destination) + }, onPromptInputOptionChange: (tabId, optionsValues) => { if (agenticMode) { handlePromptInputChange(mynahUi, tabId, optionsValues) @@ -1304,6 +1329,9 @@ export const createMynahUi = ( fileList: undefined, } : undefined, + quickSettings: message.summary.content.quickSettings + ? message.summary.content.quickSettings + : undefined, } : undefined, collapsedContent: @@ -1399,6 +1427,7 @@ export const createMynahUi = ( ? { 'insert-to-cursor': null } : undefined, ...(shouldMute ? { muted: true } : {}), + quickSettings: message.quickSettings ? message.quickSettings : undefined, } } diff --git a/chat-client/src/client/withAdapter.ts b/chat-client/src/client/withAdapter.ts index 3f10e11752..0db386456d 100644 --- a/chat-client/src/client/withAdapter.ts +++ b/chat-client/src/client/withAdapter.ts @@ -64,6 +64,8 @@ export const withAdapter = ( onPromptTopBarItemAdded: addDefaultRouting('onPromptTopBarItemAdded'), onPromptTopBarItemRemoved: addDefaultRouting('onPromptTopBarItemRemoved'), onPromptTopBarButtonClick: addDefaultRouting('onPromptTopBarButtonClick'), + onDropDownOptionChange: addDefaultRouting('onDropDownOptionChange'), + onDropDownLinkClick: addDefaultRouting('onDropDownLinkClick'), /** * Handler with special routing logic diff --git a/chat-client/src/contracts/chatClientAdapter.ts b/chat-client/src/contracts/chatClientAdapter.ts index 01d9d19c22..24fa3ce111 100644 --- a/chat-client/src/contracts/chatClientAdapter.ts +++ b/chat-client/src/contracts/chatClientAdapter.ts @@ -43,6 +43,8 @@ export interface ChatEventHandler | 'onPromptTopBarItemAdded' | 'onPromptTopBarItemRemoved' | 'onPromptTopBarButtonClick' + | 'onDropDownOptionChange' + | 'onDropDownLinkClick' > {} /** diff --git a/package-lock.json b/package-lock.json index 7a703c9b43..f5dc8f65d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,70 @@ "ts-node": "^10.9.1" } }, + "../mynah-ui": { + "name": "@aws/mynah-ui", + "version": "4.36.2", + "hasInstallScript": true, + "license": "Apache License 2.0", + "dependencies": { + "escape-html": "^1.0.3", + "highlight.js": "^11.11.0", + "just-clone": "^6.2.0", + "marked": "^14.1.0", + "sanitize-html": "^2.12.1", + "unescape-html": "^1.1.0" + }, + "devDependencies": { + "@babel/core": "^7.23.5", + "@types/eslint": "^8.44.3", + "@types/eslint-scope": "3.7.0", + "@types/estree": "0.0.49", + "@types/glob": "7.1.3", + "@types/jest": "^29.5.5", + "@types/json-schema": "7.0.7", + "@types/minimatch": "^5.1.2", + "@types/node": "17.0.29", + "@types/sanitize-html": "^2.11.0", + "@typescript-eslint/eslint-plugin": "^5.34.0", + "@typescript-eslint/parser": "^5.62.0", + "babel-jest": "^29.7.0", + "core-js": "^3.33.3", + "css-loader": "6.6.0", + "eslint": "^8.22.0", + "eslint-config-standard-with-typescript": "22.0.0", + "eslint-plugin-header": "^3.1.1", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-n": "15.2.5", + "eslint-plugin-no-null": "^1.0.2", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-promise": "6.0.0", + "husky": "^9.1.6", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-svg-transformer": "^1.0.0", + "npm-run-all": "^4.1.5", + "prettier": "^3.0.3", + "sass": "1.49.8", + "sass-loader": "12.6.0", + "style-loader": "3.3.1", + "svg-url-loader": "^8.0.0", + "ts-jest": "^29.1.1", + "ts-loader": "^9.4.4", + "ts-node": "^10.9.1", + "typedoc": "^0.25.13", + "typescript": "^5.1.6", + "webpack": "5.94.0", + "webpack-cli": "4.7.2" + }, + "peerDependencies": { + "escape-html": "^1.0.3", + "highlight.js": "^11.11.0", + "just-clone": "^6.2.0", + "marked": "^14.1.0", + "sanitize-html": "^2.12.1", + "unescape-html": "^1.1.0" + } + }, "app/aws-lsp-antlr4-runtimes": { "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", @@ -256,8 +320,8 @@ "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.114", - "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.2" + "@aws/language-server-runtimes-types": "^0.1.52", + "@aws/mynah-ui": "../../mynah-ui" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -4067,10 +4131,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.50", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.50.tgz", - "integrity": "sha512-06JBOKQRJJB/Rg7looY6Xxbab6tIzouZ1QUDdOaFj4zjlbDodeGRXr4W1Oo0N7uz0N24tdoMiNvuky3U5fYmPQ==", - "license": "Apache-2.0", + "version": "0.1.52", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.52.tgz", + "integrity": "sha512-9z2OiEcWc3CZ6u/j/ABeoGhkwmNbiRqqCO5GJDvtcJfEi9UsSMmo4+YcJJj93pYW8CEVJy3DOPwQCrtT7ngwcw==", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5" @@ -4203,27 +4266,8 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.2", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.2.tgz", - "integrity": "sha512-3ibfK2CTj7dlFFdgTIE1DdEyDpy+P3hdP/Fmlx76T9GGSYiGHqwunDSi59L1P61Kj46WADBrQ52mLUQ6FR8Rzg==", - "hasInstallScript": true, - "license": "Apache License 2.0", - "dependencies": { - "escape-html": "^1.0.3", - "highlight.js": "^11.11.0", - "just-clone": "^6.2.0", - "marked": "^14.1.0", - "sanitize-html": "^2.12.1", - "unescape-html": "^1.1.0" - }, - "peerDependencies": { - "escape-html": "^1.0.3", - "highlight.js": "^11.11.0", - "just-clone": "^6.2.0", - "marked": "^14.1.0", - "sanitize-html": "^2.12.1", - "unescape-html": "^1.1.0" - } + "resolved": "../mynah-ui", + "link": true }, "node_modules/@aws/q-agentic-chat-server-integration-tests": { "resolved": "integration-tests/q-agentic-chat-server", @@ -14149,6 +14193,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, "funding": [ { "type": "github", @@ -14504,6 +14549,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, "engines": { "node": ">=0.12" }, @@ -14742,6 +14788,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { "node": ">=10" }, @@ -16958,14 +17005,6 @@ "he": "bin/he" } }, - "node_modules/highlight.js": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", - "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -19688,11 +19727,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/just-clone": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", - "integrity": "sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==" - }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", @@ -20356,17 +20390,6 @@ "tmpl": "1.0.5" } }, - "node_modules/marked": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.1.4.tgz", - "integrity": "sha512-vkVZ8ONmUdPnjCKc5uTRvmkRbx4EAi2OkTOXmfTDhZz3OFqMNBM1oTTWwTr4HY4uAEojhzPf+Fy8F1DWa3Sndg==", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -20757,23 +20780,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -22102,11 +22108,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" - }, "node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -22642,33 +22643,6 @@ "node": ">= 0.4" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/prebuild-install": { "version": "5.3.6", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", @@ -24073,85 +24047,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sanitize-html": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz", - "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" - } - }, - "node_modules/sanitize-html/node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/sanitize-html/node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/sanitize-html/node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/sanitize-html/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/sanitize-html/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", @@ -24906,14 +24801,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", @@ -26602,11 +26489,6 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, - "node_modules/unescape-html": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unescape-html/-/unescape-html-1.1.0.tgz", - "integrity": "sha512-O9/yBNqIkArjS597iHez5hAaAdn7b8/230SX8IncgXAX5tWI9XlEQYaz6Qbou0Sloa9n6lx9G5s6hg5qhJyzGg==" - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 00ac935f7c..00e08f6c37 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -37,6 +37,7 @@ import { SUFFIX_PERMISSION, SUFFIX_UNDOALL, SUFFIX_EXPLANATION, + BUTTON_TRUST_COMMAND, } from './constants/toolConstants' import { SendMessageCommandInput, @@ -224,6 +225,7 @@ import { getLatestAvailableModel } from './utils/agenticChatControllerHelper' import { ActiveUserTracker } from '../../shared/activeUserTracker' import { UserContext } from '../../client/token/codewhispererbearertokenclient' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' +import { McpPermissionType } from './tools/mcp/mcpTypes' type ChatHandlers = Omit< LspHandlers, @@ -385,19 +387,67 @@ export class AgenticChatController implements ChatHandlers { params.buttonId === BUTTON_RUN_SHELL_COMMAND || params.buttonId === BUTTON_REJECT_SHELL_COMMAND || params.buttonId === BUTTON_REJECT_MCP_TOOL || - params.buttonId === BUTTON_ALLOW_TOOLS + params.buttonId === BUTTON_ALLOW_TOOLS || + params.buttonId === BUTTON_TRUST_COMMAND ) { if (!session.data) { return { success: false, failureReason: `could not find chat session for tab: ${params.tabId} ` } } + // update permission if it's auto-run + if (params.buttonId === BUTTON_TRUST_COMMAND) { + // get result from metadata + const toolName = params.metadata!['toolName'] + const new_permission = params.metadata!['permission'] + const serverName = params.metadata!['serverName'] + + const current_permission = McpManager.instance.getToolPerm(serverName, toolName) + // only trigger update if curren != previous + if (current_permission !== new_permission) { + // generate perm object + const perm = await this.#mcpEventHandler.generateEmptyBuiltInToolPermission() + + // load updated permission + perm.toolPerms[toolName] = new_permission as McpPermissionType + + // update permission + try { + await McpManager.instance.updateServerPermission(serverName, perm) + // if the new permission is asks --> only update permission, dont continue + if (new_permission === 'ask') { + return { + success: true, + } + } + } catch (error) { + this.#features.logging.error(`Failed to save MCP permissions: ${error}`) + return { + success: false, + failureReason: `Failed to update permission for ${toolName}`, + } + } + } else { + // break, because nothing happen + return { + success: true, + } + } + } // For 'allow-tools', remove suffix as permission card needs to be seperate from file list card const messageId = - params.buttonId === BUTTON_ALLOW_TOOLS && params.messageId.endsWith(SUFFIX_PERMISSION) + (params.buttonId === BUTTON_ALLOW_TOOLS || params.buttonId === BUTTON_TRUST_COMMAND) && + params.messageId.endsWith(SUFFIX_PERMISSION) ? params.messageId.replace(SUFFIX_PERMISSION, '') : params.messageId const handler = session.data.getDeferredToolExecution(messageId) if (!handler?.reject || !handler.resolve) { + if (params.buttonId === BUTTON_TRUST_COMMAND) { + // change permission of a completed task --> no handler + // should not return an error because it's a expected behavior + return { + success: true, + } + } return { success: false, failureReason: `could not find deferred tool execution for message: ${messageId} `, @@ -1616,7 +1666,8 @@ export class AgenticChatController implements ChatHandlers { resultStream: AgenticChatResultStream, promptBlockId: number, session: ChatSessionService, - toolName: string + toolName: string, + tabId?: string ) { const deferred = this.#createDeferred() session.setDeferredToolExecution(toolUse.toolUseId!, deferred.resolve, deferred.reject) @@ -1624,7 +1675,7 @@ export class AgenticChatController implements ChatHandlers { await deferred.promise // Note: we want to overwrite the button block because it already exists in the stream. await resultStream.overwriteResultBlock( - this.#getUpdateToolConfirmResult(toolUse, true, toolName), + this.#getUpdateToolConfirmResult(toolUse, true, toolName, tabId), promptBlockId ) } @@ -1724,7 +1775,10 @@ export class AgenticChatController implements ChatHandlers { toolUse, requiresAcceptance, warning, - commandCategory + commandCategory, + toolUse.name, + undefined, + tabId ) cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult) const isExecuteBash = toolUse.name === EXECUTE_BASH @@ -1744,7 +1798,8 @@ export class AgenticChatController implements ChatHandlers { chatResultStream, cachedButtonBlockId, session, - toolUse.name + toolUse.name, + tabId ) } if (isExecuteBash) { @@ -1797,7 +1852,9 @@ export class AgenticChatController implements ChatHandlers { requiresAcceptance, warning, undefined, - toolName // Pass the original tool name here + toolName, // Pass the original tool name here + undefined, + tabId ) cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmation) await this.waitForToolApproval( @@ -1805,7 +1862,8 @@ export class AgenticChatController implements ChatHandlers { chatResultStream, cachedButtonBlockId, session, - toolName + toolName, + tabId ) } @@ -1944,7 +2002,7 @@ export class AgenticChatController implements ChatHandlers { break // — DEFAULT ⇒ MCP tools default: - await this.#handleMcpToolResult(toolUse, result, session, chatResultStream) + await this.#handleMcpToolResult(toolUse, result, session, chatResultStream, tabId) break } this.#updateUndoAllState(toolUse, session) @@ -2329,7 +2387,8 @@ export class AgenticChatController implements ChatHandlers { toolUse: ToolUse, isAccept: boolean, originalToolName: string, - toolType?: string + toolType?: string, + tabId?: string ): ChatResult { const toolName = originalToolName ?? (toolType || toolUse.name) @@ -2361,7 +2420,6 @@ export class AgenticChatController implements ChatHandlers { status: { status: 'info' | 'success' | 'warning' | 'error'; icon: string; text: string } } let body: string | undefined - switch (toolName) { case FS_REPLACE: case FS_WRITE: @@ -2392,6 +2450,7 @@ export class AgenticChatController implements ChatHandlers { default: // Default tool (not only MCP) + const quickSettings = this.#buildQuickSettings(toolUse, toolName, toolType, tabId) return { type: 'tool', messageId: toolUse.toolUseId!, @@ -2407,6 +2466,7 @@ export class AgenticChatController implements ChatHandlers { }, fileList: undefined, }, + quickSettings, }, collapsedContent: [ { @@ -2568,13 +2628,46 @@ export class AgenticChatController implements ChatHandlers { return defaultKey } + #buildQuickSettings(toolUse: ToolUse, toolName: string, toolType?: string, tabId?: string) { + const originalNames = McpManager.instance.getOriginalToolNames(toolUse.name!) + let serverName = 'Built-in' + let descriptionLinkText = 'More control, modify the commands' + if (originalNames) { + serverName = originalNames.serverName + toolName = originalNames.toolName + descriptionLinkText = 'Advanced' + } + const permission = McpManager.instance.getToolPerm(serverName, toolName) + return { + type: 'select' as 'select' | 'checkbox' | 'radio', // will update this later + messageId: this.#getMessageIdForToolUse(toolType, toolUse), + tabId: tabId!, + description: '', + descriptionLink: { + id: 'open-mcp-server', + text: descriptionLinkText, + destination: serverName, + }, + options: [ + { id: 'ask', label: 'Ask to run', value: `${serverName}@${toolName}`, selected: permission === 'ask' }, + { + id: 'alwaysAllow', + label: 'Always allow', + value: `${serverName}@${toolName}`, + selected: permission === 'alwaysAllow', + }, + ], + } + } + #processToolConfirmation( toolUse: ToolUse, requiresAcceptance: Boolean, warning?: string, commandCategory?: CommandCategory, toolType?: string, - builtInPermission?: boolean + builtInPermission?: boolean, + tabId?: string ): ChatResult { const toolName = toolType || toolUse.name let buttons: Button[] = [] @@ -2592,7 +2685,7 @@ export class AgenticChatController implements ChatHandlers { } } let body: string | undefined - + const quickSettings = this.#buildQuickSettings(toolUse, toolName!, toolType, tabId) // Configure tool-specific UI elements switch (toolName) { case EXECUTE_BASH: { @@ -2779,6 +2872,7 @@ export class AgenticChatController implements ChatHandlers { }, ], }, + quickSettings, }, collapsedContent: [ { @@ -4311,7 +4405,8 @@ export class AgenticChatController implements ChatHandlers { toolUse: ToolUse, result: any, session: ChatSessionService, - chatResultStream: AgenticChatResultStream + chatResultStream: AgenticChatResultStream, + tabId?: string ): Promise { // Early return if name or toolUseId is undefined if (!toolUse.name || !toolUse.toolUseId) { @@ -4321,6 +4416,7 @@ export class AgenticChatController implements ChatHandlers { // Get original server and tool names from the mapping const originalNames = McpManager.instance.getOriginalToolNames(toolUse.name) + const quickSettings = this.#buildQuickSettings(toolUse, toolUse.name, toolUse.name, tabId) if (originalNames) { const { serverName, toolName } = originalNames const def = McpManager.instance @@ -4341,6 +4437,7 @@ export class AgenticChatController implements ChatHandlers { body: `${toolName}`, fileList: undefined, }, + quickSettings, }, collapsedContent: [ { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/toolConstants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/toolConstants.ts index dff24d7fb7..910c50a778 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/toolConstants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/toolConstants.ts @@ -26,6 +26,7 @@ export const BUTTON_RUN_SHELL_COMMAND = 'run-shell-command' export const BUTTON_REJECT_SHELL_COMMAND = 'reject-shell-command' export const BUTTON_REJECT_MCP_TOOL = 'reject-mcp-tool' export const BUTTON_ALLOW_TOOLS = 'allow-tools' +export const BUTTON_TRUST_COMMAND = 'trust-command' export const BUTTON_UNDO_CHANGES = 'undo-changes' export const BUTTON_UNDO_ALL_CHANGES = 'undo-all-changes' export const BUTTON_STOP_SHELL_COMMAND = 'stop-shell-command' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index b4ca871dc6..1fb758490f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -34,6 +34,7 @@ import { URI } from 'vscode-uri' interface PermissionOption { label: string value: string + description: string } export class McpEventHandler { @@ -268,6 +269,17 @@ export class McpEventHandler { return this.#getDefaultMcpResponse(params.id) } + async generateEmptyBuiltInToolPermission() { + const personaPath = await this.#getAgentPath() + const perm: MCPServerPermission = { + enabled: true, + toolPerms: {}, + __configPath__: personaPath, + } + + return perm + } + /** * Returns the default MCP servers response */ @@ -1028,17 +1040,20 @@ export class McpEventHandler { // Add tool select options toolsWithPermissions.forEach(item => { const toolName = item.tool.toolName - const currentPermission = this.#getCurrentPermission(item.permission) // For Built-in server, use a special function that doesn't include the 'Deny' option - const permissionOptions = this.#buildPermissionOptions(item.permission) + let permissionOptions = this.#buildPermissionOptions() + + // if (serverName === 'Built-in') { + // permissionOptions = this.#buildBuiltInPermissionOptions() + // } filterOptions.push({ type: 'select', id: `${toolName}`, title: toolName, description: item.tool.description, - placeholder: currentPermission, options: permissionOptions, + ...{ value: item.permission, boldTitle: true, mandatory: true, hideMandatoryIcon: true }, }) }) @@ -1075,36 +1090,25 @@ export class McpEventHandler { return editingServerName ? this.#handleEditMcpServer(params) : this.#handleAddNewMcp(params) } - /** - * Gets the current permission setting for a tool - */ - #getCurrentPermission(permission: string): string { - if (permission === McpPermissionType.alwaysAllow) { - return 'Always allow' - } else if (permission === McpPermissionType.deny) { - return 'Deny' - } else { - return 'Ask' - } - } - /** * Builds permission options excluding the current one */ - #buildPermissionOptions(currentPermission: string) { + #buildPermissionOptions() { const permissionOptions: PermissionOption[] = [] - if (currentPermission !== McpPermissionType.alwaysAllow) { - permissionOptions.push({ label: 'Always allow', value: McpPermissionType.alwaysAllow }) - } + permissionOptions.push({ + label: 'Ask', + value: McpPermissionType.ask, + description: 'Ask for your approval each time this tool is run', + }) - if (currentPermission !== McpPermissionType.ask) { - permissionOptions.push({ label: 'Ask', value: McpPermissionType.ask }) - } + permissionOptions.push({ + label: 'Always allow', + value: McpPermissionType.alwaysAllow, + description: 'Always allow this tool to run without asking for approval', + }) - if (currentPermission !== McpPermissionType.deny) { - permissionOptions.push({ label: 'Deny', value: McpPermissionType.deny }) - } + permissionOptions.push({ label: 'Deny', value: McpPermissionType.deny, description: 'Never run this tool' }) return permissionOptions } @@ -1152,7 +1156,7 @@ export class McpEventHandler { } } - const mcpServerPermission = await this.#processPermissionUpdates(updatedPermissionConfig) + const mcpServerPermission = await this.#processPermissionUpdates(serverName, updatedPermissionConfig) // Store the permission config instead of applying it immediately this.#pendingPermissionConfig = { @@ -1347,7 +1351,7 @@ export class McpEventHandler { /** * Processes permission updates from the UI */ - async #processPermissionUpdates(updatedPermissionConfig: any) { + async #processPermissionUpdates(serverName: string, updatedPermissionConfig: any) { // Get the appropriate agent path const agentPath = await this.#getAgentPath() @@ -1361,16 +1365,8 @@ export class McpEventHandler { for (const [key, val] of Object.entries(updatedPermissionConfig)) { if (key === 'scope') continue - // // Get the default permission for this tool from McpManager - // let defaultPermission = McpManager.instance.getToolPerm(serverName, key) - - // // If no default permission is found, use 'alwaysAllow' for Built-in and 'ask' for MCP servers - // if (!defaultPermission) { - // defaultPermission = serverName === 'Built-in' ? 'alwaysAllow' : 'ask' - // } - - // If the value is an empty string (''), skip this tool to preserve its existing permission in the persona file - if (val === '') continue + const currentPerm = McpManager.instance.getToolPerm(serverName, key) + if (val === currentPerm) continue switch (val) { case McpPermissionType.alwaysAllow: perm.toolPerms[key] = McpPermissionType.alwaysAllow From 9e496194e8495c6699aa757436c98718bd87d609 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Mon, 11 Aug 2025 14:57:25 -0700 Subject: [PATCH 2/6] feat(amazonq): add handler for in-context deny --- .../agenticChat/agenticChatController.ts | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 00e08f6c37..608ba0ae1b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -397,23 +397,24 @@ export class AgenticChatController implements ChatHandlers { if (params.buttonId === BUTTON_TRUST_COMMAND) { // get result from metadata const toolName = params.metadata!['toolName'] - const new_permission = params.metadata!['permission'] + const newPermission = params.metadata!['permission'] const serverName = params.metadata!['serverName'] - const current_permission = McpManager.instance.getToolPerm(serverName, toolName) + const currentPermission = McpManager.instance.getToolPerm(serverName, toolName) // only trigger update if curren != previous - if (current_permission !== new_permission) { + if (currentPermission !== newPermission) { // generate perm object const perm = await this.#mcpEventHandler.generateEmptyBuiltInToolPermission() // load updated permission - perm.toolPerms[toolName] = new_permission as McpPermissionType + perm.toolPerms[toolName] = newPermission as McpPermissionType // update permission try { await McpManager.instance.updateServerPermission(serverName, perm) // if the new permission is asks --> only update permission, dont continue - if (new_permission === 'ask') { + // this only happen on a completed card + if (newPermission === 'ask') { return { success: true, } @@ -453,6 +454,13 @@ export class AgenticChatController implements ChatHandlers { failureReason: `could not find deferred tool execution for message: ${messageId} `, } } + if (params.buttonId === BUTTON_TRUST_COMMAND && params.metadata!['permission'] === 'deny') { + handler.reject(new ToolApprovalException('Command was denied.', true)) + this.#stoppedToolUses.add(messageId) + return { + success: true, + } + } params.buttonId === BUTTON_REJECT_SHELL_COMMAND || params.buttonId === BUTTON_REJECT_MCP_TOOL ? (() => { handler.reject(new ToolApprovalException('Command was rejected.', true)) @@ -2656,6 +2664,16 @@ export class AgenticChatController implements ChatHandlers { value: `${serverName}@${toolName}`, selected: permission === 'alwaysAllow', }, + ...(serverName !== 'Built-in' + ? [ + { + id: 'deny', + label: 'Deny', + value: `${serverName}@${toolName}`, + selected: permission === 'deny', + }, + ] + : []), ], } } From 2d644c44e6d9303bab2c5baf6a6050a460fe6b62 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Tue, 12 Aug 2025 12:00:26 -0700 Subject: [PATCH 3/6] fix: update package.lock.json --- package-lock.json | 66 +---------------------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6bc704513c..bbfe4024d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,70 +44,6 @@ "ts-node": "^10.9.1" } }, - "../mynah-ui": { - "name": "@aws/mynah-ui", - "version": "4.36.2", - "hasInstallScript": true, - "license": "Apache License 2.0", - "dependencies": { - "escape-html": "^1.0.3", - "highlight.js": "^11.11.0", - "just-clone": "^6.2.0", - "marked": "^14.1.0", - "sanitize-html": "^2.12.1", - "unescape-html": "^1.1.0" - }, - "devDependencies": { - "@babel/core": "^7.23.5", - "@types/eslint": "^8.44.3", - "@types/eslint-scope": "3.7.0", - "@types/estree": "0.0.49", - "@types/glob": "7.1.3", - "@types/jest": "^29.5.5", - "@types/json-schema": "7.0.7", - "@types/minimatch": "^5.1.2", - "@types/node": "17.0.29", - "@types/sanitize-html": "^2.11.0", - "@typescript-eslint/eslint-plugin": "^5.34.0", - "@typescript-eslint/parser": "^5.62.0", - "babel-jest": "^29.7.0", - "core-js": "^3.33.3", - "css-loader": "6.6.0", - "eslint": "^8.22.0", - "eslint-config-standard-with-typescript": "22.0.0", - "eslint-plugin-header": "^3.1.1", - "eslint-plugin-import": "2.26.0", - "eslint-plugin-n": "15.2.5", - "eslint-plugin-no-null": "^1.0.2", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-promise": "6.0.0", - "husky": "^9.1.6", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "jest-svg-transformer": "^1.0.0", - "npm-run-all": "^4.1.5", - "prettier": "^3.0.3", - "sass": "1.49.8", - "sass-loader": "12.6.0", - "style-loader": "3.3.1", - "svg-url-loader": "^8.0.0", - "ts-jest": "^29.1.1", - "ts-loader": "^9.4.4", - "ts-node": "^10.9.1", - "typedoc": "^0.25.13", - "typescript": "^5.1.6", - "webpack": "5.94.0", - "webpack-cli": "4.7.2" - }, - "peerDependencies": { - "escape-html": "^1.0.3", - "highlight.js": "^11.11.0", - "just-clone": "^6.2.0", - "marked": "^14.1.0", - "sanitize-html": "^2.12.1", - "unescape-html": "^1.1.0" - } - }, "app/aws-lsp-antlr4-runtimes": { "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", @@ -320,7 +256,7 @@ "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.123", - "@aws/language-server-runtimes-types": "^0.1.50", + "@aws/language-server-runtimes-types": "^0.1.52", "@aws/mynah-ui": "^4.36.4" }, "devDependencies": { From 09ab529a07b72a00ba79b460d86369c6f3dc63b3 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Tue, 12 Aug 2025 12:02:59 -0700 Subject: [PATCH 4/6] chore: merge main (#2110) * chore: merge agentic version 1.26.0 (#2076) * Bump agentic version: 1.26.0 * chore: format version json --------- Co-authored-by: aws-toolkit-automation <> * fix(amazonq): bundle corect registry.node for windows (#2061) * chore: bump runtimes to 0.2.123 (#2082) * fix: remove edit cache logic (#2079) * fix(amazonq): add fallback classpath generation (#2077) * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle (#2066) * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle * fix(amazonq): skips creating remote workspace at the start --------- Co-authored-by: Jiatong Li * fix: sessionManager misused because there are 2 types of manager now (#2090) * chore: mapping adt plugin to abap to let inline suggestion work (#2085) * chore: support inline suggestion in adt plugin for eclipse * fix: add import URI * chore: add detailed error description for uri is empty for language id * feat(amazonq): read tool ui revamp * feat(amazonq): read tool message revamp (#2049) * feat(amazonq): read tool message revamp * fix tests * feat: file search ui (#2078) * feat: file search ui * fix tests * fix integration tests * remove unnecessary type check * fix: use quotes instead of backticks * fix: creating a new sesion for Edits trigger with next token (#2094) * chore: bump @aws/mynah-ui to 4.36.4 (#2096) * fix(amazonq): leverage lcs to find the chars added and removed (#2092) * fix: update client name to support Sagemaker AI origin for agentic chat (#2093) Co-authored-by: chungjac * chore(release): release packages from branch main (#2073) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: format version.json after incrementing (#2068) * chore: merge agentic version 1.27.0 (#2107) * Bump agentic version: 1.27.0 * Revert "feat(amazonq): read tool ui revamp" This reverts commit c65428bab2cf5e47badf1e3a9453babcf881e60c. * fix: the style in version json (#2106) --------- Co-authored-by: aws-toolkit-automation <> Co-authored-by: Tai Lai Co-authored-by: Christopher Christou <39839589+awschristou@users.noreply.github.com> --------- Co-authored-by: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Co-authored-by: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Co-authored-by: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Co-authored-by: liumofei-amazon <98127670+liumofei-amazon@users.noreply.github.com> Co-authored-by: Jiatong Li Co-authored-by: Jiatong Li Co-authored-by: Tai Lai Co-authored-by: atontb <104926752+atonaamz@users.noreply.github.com> Co-authored-by: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Co-authored-by: Jayakrishna P Co-authored-by: chungjac Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Christopher Christou <39839589+awschristou@users.noreply.github.com> Co-authored-by: Tai Lai --- .../create-release-candidate-branch.yml | 9 +- .release-please-manifest.json | 4 +- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-codewhisperer-runtimes/README.md | 11 + .../registry-js/win32-x64/registry.node | Bin 0 -> 696320 bytes .../package.json | 5 +- .../src/version.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/CHANGELOG.md | 7 + chat-client/package.json | 6 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 107 ++++----- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 20 ++ server/aws-lsp-codewhisperer/package.json | 4 +- .../agenticChat/agenticChatController.test.ts | 10 + .../agenticChat/agenticChatController.ts | 6 + .../inline-completion/codePercentage.ts | 14 +- .../codeWhispererServer.test.ts | 17 ++ .../inline-completion/codeWhispererServer.ts | 107 +++++---- .../inline-completion/constants.ts | 25 +++ .../inline-completion/diffUtils.ts | 67 ++++++ .../editCompletionHandler.ts | 35 +-- .../session/sessionManager.ts | 1 - .../inline-completion/telemetry.ts | 8 +- .../IdleWorkspaceManager.test.ts | 75 +++++++ .../workspaceContext/IdleWorkspaceManager.ts | 38 ++++ .../workspaceContext/artifactManager.ts | 15 ++ .../dependency/dependencyDiscoverer.ts | 3 +- .../workspaceContextServer.ts | 9 +- .../workspaceFolderManager.test.ts | 91 ++++---- .../workspaceFolderManager.ts | 207 ++++++++++-------- .../src/shared/codeWhispererService.ts | 2 +- .../src/shared/utils.test.ts | 18 +- .../aws-lsp-codewhisperer/src/shared/utils.ts | 7 +- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 55 files changed, 662 insertions(+), 316 deletions(-) create mode 100644 app/aws-lsp-codewhisperer-runtimes/_bundle-assets/registry-js/win32-x64/registry.node create mode 100644 server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts diff --git a/.github/workflows/create-release-candidate-branch.yml b/.github/workflows/create-release-candidate-branch.yml index aa37873d2a..2071f69ed4 100644 --- a/.github/workflows/create-release-candidate-branch.yml +++ b/.github/workflows/create-release-candidate-branch.yml @@ -44,6 +44,10 @@ jobs: node-version: '20' cache: 'npm' + # Needed to format the json file being checked in + - name: Install dependencies + run: npm ci + - name: Calculate Release Version id: release-version env: @@ -87,6 +91,9 @@ jobs: git add "$VERSION_FILE" + # Ensure the file does not cause issues when merged to main + npm run format-staged + - name: Create Release Candidate Branch id: release-branch env: @@ -112,5 +119,5 @@ jobs: git config --global user.name "aws-toolkit-automation" # Configure git to use the PAT token for authentication git remote set-url origin "https://x-access-token:${REPO_PAT}@github.com/${{ github.repository }}.git" - git commit -m "Bump agentic version: $RELEASE_VERSION" + git commit -m "chore: bump agentic version: $RELEASE_VERSION" git push --set-upstream origin "$BRANCH_NAME" diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c3df1b76e7..e6abdf7be2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.31", + "chat-client": "0.1.32", "core/aws-lsp-core": "0.0.13", "server/aws-lsp-antlr4": "0.1.17", - "server/aws-lsp-codewhisperer": "0.0.72", + "server/aws-lsp-codewhisperer": "0.0.73", "server/aws-lsp-json": "0.1.17", "server/aws-lsp-partiql": "0.0.16", "server/aws-lsp-yaml": "0.1.17" diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index e283033afb..bf7cf47bf1 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 0fa2217def..b9c36946b2 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index 336e9b48ae..a88386db4e 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/README.md b/app/aws-lsp-codewhisperer-runtimes/README.md index 977d514bd6..71fbcf0456 100644 --- a/app/aws-lsp-codewhisperer-runtimes/README.md +++ b/app/aws-lsp-codewhisperer-runtimes/README.md @@ -76,6 +76,17 @@ The server is managed via scripts/dev-server.js, which ensures: **NOTE**: Tests are currently disabled for Windows as we currently face issues with automatically shutting down devserver and cleaning resources after tests are executed. +## Binary Dependencies + +### registry.node +The file `_bundle-assets/registry-js/win32-x64/registry.node` is a precompiled binary downloaded from the [registry-js](https://github.com/desktop/registry-js) project. + +- **Current version**: v1.16.1 (released May 21, 2024) +- **Source**: https://github.com/desktop/registry-js/releases +- **Purpose**: Provides Windows registry access functionality + +**To update**: Download the latest `registry.node` binary for win32-x64 from the registry-js releases page and replace the existing file. + #### Tests configuration - Test settings are defined in `wdio.conf.ts` - The actual test implementation is in the `test/e2e` folder diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/registry-js/win32-x64/registry.node b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/registry-js/win32-x64/registry.node new file mode 100644 index 0000000000000000000000000000000000000000..d7b5091a2cf02da166341422c54ec9520c2c1b31 GIT binary patch literal 696320 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%0A@3ZZhb^|vb3jk@;Yj9y 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 Q>tTD%WSIJhun)r!*waTEzH3_xazK#r^ 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

|+nUA!_dr|X07_pPrwuYJcWw$h}K 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 literal 0 HcmV?d00001 diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index 6a1721382c..487d2c5b1a 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -10,10 +10,11 @@ "package:prod": "npm run compile && cross-env NODE_OPTIONS=--max_old_space_size=8172 npm run webpack:prod", "webpack": "webpack", "webpack:prod": "webpack --config webpack.config.prod.js", + "copy:native-deps:agent-standalone": "copyfiles -f _bundle-assets/registry-js/win32-x64/registry.node build/private/bundle/agent-standalone", "copy:resources:agent-standalone": "copyfiles -f --error ../../node_modules/@aws/lsp-identity/src/sso/authorizationCodePkce/resources/**/* build/private/bundle/agent-standalone/resources", "generate:node-assets": "./scripts/download-node.sh && ts-node src/scripts/copy-node-assets.ts", "generate:build-archive": "./scripts/package.sh", - "ci:generate:agent-standalone": "npm run package:prod && npm run copy:resources:agent-standalone && npm run generate:node-assets && npm run generate:build-archive", + "ci:generate:agent-standalone": "npm run package:prod && npm run copy:native-deps:agent-standalone && npm run copy:resources:agent-standalone && npm run generate:node-assets && npm run generate:build-archive", "ci:generate:manifest": "ts-node scripts/create-repo-manifest.ts", "start": "cross-env NODE_OPTIONS=--max_old_space_size=8172 node scripts/dev-server.js start", "stop-dev-server": "node scripts/dev-server.js stop", @@ -22,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 3f5ef793d0..4c93c3f549 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.25.0" + "agenticChat": "1.27.0" } diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index b4971eae87..46abf7d958 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 9fa7b7e958..24ae3535ac 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index a355a967bf..1e7641e2a8 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index 1c15a9af5e..ad84f62776 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index bfb5fa6277..7079d1fa3b 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index 86638b8ffc..a59f919477 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 2ccccc694b..54018d89d0 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.121" + "@aws/language-server-runtimes": "^0.2.123" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index aa178a18e6..1cd9acfbe0 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.32](https://github.com/aws/language-servers/compare/chat-client/v0.1.31...chat-client/v0.1.32) (2025-08-11) + + +### Features + +* **amazonq:** read tool ui revamp ([c65428b](https://github.com/aws/language-servers/commit/c65428bab2cf5e47badf1e3a9453babcf881e60c)) + ## [0.1.31](https://github.com/aws/language-servers/compare/chat-client/v0.1.30...chat-client/v0.1.31) (2025-08-06) diff --git a/chat-client/package.json b/chat-client/package.json index 2d3332b597..df0378f3e4 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.31", + "version": "0.1.32", "description": "AWS Chat Client", "main": "out/index.js", "repository": { @@ -25,9 +25,9 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.2" + "@aws/mynah-ui": "^4.36.4" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/client/vscode/package.json b/client/vscode/package.json index 4b8c2fdb4c..975a395d66 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 4c033448eb..aeff582d34 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 26202df0c1..5431142f5c 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index da8006537f..b42f206c44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-notification": "^0.0.1" } }, @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -234,7 +234,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.121" + "@aws/language-server-runtimes": "^0.2.123" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -251,13 +251,13 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.31", + "version": "0.1.32", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.2" + "@aws/mynah-ui": "^4.36.4" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.13", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "*" }, "devDependencies": { @@ -4036,12 +4036,12 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.121", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.121.tgz", - "integrity": "sha512-DDh3ICNVoEi4nhp4JdkkPTsdlHsF0yt6VgxlMGwP90N1hjA4xVESSSla9pB0TcuMPKlmXqOPQGQvkph9FKerVw==", + "version": "0.2.123", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.123.tgz", + "integrity": "sha512-gxjnBcQY+HR9+F1NXQUEQ6ikJhrLMJEbrpIxlBLILtQ75hVtRDsfGET3KW5Nn0dgbrQTx6VqwvXDfolUkmi06g==", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.53", + "@aws/language-server-runtimes-types": "^0.1.55", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.200.0", "@opentelemetry/core": "^2.0.0", @@ -4056,7 +4056,7 @@ "hpagent": "^1.2.0", "jose": "^5.9.6", "mac-ca": "^3.1.1", - "os-proxy-config": "^1.1.2", + "registry-js": "^1.16.1", "rxjs": "^7.8.2", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", @@ -4068,9 +4068,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.53", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.53.tgz", - "integrity": "sha512-6KCe/YsqF0SciXm8qg/qVuDXGwQqJgRaqrT6YhZUjqs3mclG9G6Gdwu9YEi8t/NYobNWKw0E+aCXW2TFxJgr7A==", + "version": "0.1.55", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.55.tgz", + "integrity": "sha512-KRy3fTCNGvAQxA4amTODXPuubxrYlqKsyJOXPaIn+YDACwJa7shrOryHg6xrib6uHAHT2fEkcTMk9TT4MRPxQA==", "license": "Apache-2.0", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", @@ -4204,9 +4204,9 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.2", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.2.tgz", - "integrity": "sha512-3ibfK2CTj7dlFFdgTIE1DdEyDpy+P3hdP/Fmlx76T9GGSYiGHqwunDSi59L1P61Kj46WADBrQ52mLUQ6FR8Rzg==", + "version": "4.36.4", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.4.tgz", + "integrity": "sha512-vGW4wlNindpr2Ep9x3iuKbrZTXe5KrE8vWpg15DjkN3qK42KMuMEQ67Pqtfgl5EseNYC1ukZm4HIQIMmt+vevA==", "hasInstallScript": true, "license": "Apache License 2.0", "dependencies": { @@ -20292,12 +20292,6 @@ "undici": "^6.16.1" } }, - "node_modules/mac-system-proxy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mac-system-proxy/-/mac-system-proxy-1.0.4.tgz", - "integrity": "sha512-IAkNLxXZrYuM99A2OhPrvUoAxohsxQciJh2D2xnD+R6vypn/AVyOYLsbZsMVCS/fEbLIe67nQ8krEAfqP12BVg==", - "license": "Apache-2.0" - }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -21387,16 +21381,6 @@ "node": ">=0.10.0" } }, - "node_modules/os-proxy-config": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/os-proxy-config/-/os-proxy-config-1.1.2.tgz", - "integrity": "sha512-sV7htE8y6NQORU0oKOUGTwQYe1gSFK3a3Z1i4h6YaqdrA9C0JIsUPQAqEkO8ejjYbRrQ+jsnks5qjtisr7042Q==", - "license": "Apache-2.0", - "dependencies": { - "mac-system-proxy": "^1.0.0", - "windows-system-proxy": "^1.0.0" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -28090,15 +28074,6 @@ "node": ">=4" } }, - "node_modules/windows-system-proxy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/windows-system-proxy/-/windows-system-proxy-1.0.0.tgz", - "integrity": "sha512-qd1WfyX9gjAqI36RHt95di2+FBr74DhvELd1EASgklCGScjwReHnWnXfUyabp/CJWl/IdnkUzG0Ub6Cv2R4KJQ==", - "license": "Apache-2.0", - "dependencies": { - "registry-js": "^1.15.1" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -28633,7 +28608,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13" }, "devDependencies": { @@ -28675,7 +28650,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28686,7 +28661,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28695,7 +28670,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.72", + "version": "0.0.73", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" @@ -28708,7 +28683,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28848,7 +28823,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28913,7 +28888,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28930,7 +28905,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28991,7 +28966,7 @@ "version": "0.0.16", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -29013,7 +28988,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29044,7 +29019,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29058,7 +29033,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29069,7 +29044,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index aadfe48b08..9d6c925b40 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 92960545fb..f59edb5549 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 2dd24848b8..bfc8ebd7e5 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 8497df84be..1b2f1011df 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## [0.0.73](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.72...lsp-codewhisperer/v0.0.73) (2025-08-11) + + +### Features + +* **amazonq:** read tool ui revamp ([c65428b](https://github.com/aws/language-servers/commit/c65428bab2cf5e47badf1e3a9453babcf881e60c)) + + +### Bug Fixes + +* **amazonq:** add fallback classpath generation ([#2077](https://github.com/aws/language-servers/issues/2077)) ([3a6ef14](https://github.com/aws/language-servers/commit/3a6ef14e78fa2e75b837bba6524751d65038f416)) +* **amazonq:** emit failed status for amazonq_invokeLLM ([#2071](https://github.com/aws/language-servers/issues/2071)) ([ee52a41](https://github.com/aws/language-servers/commit/ee52a41bc869b275fff708d7955b59f43b93bbd4)) +* **amazonq:** fix fallout of [#2051](https://github.com/aws/language-servers/issues/2051) ([#2057](https://github.com/aws/language-servers/issues/2057)) ([565066b](https://github.com/aws/language-servers/commit/565066bb61adda60333c9646db958d4208bcc8af)) +* **amazonq:** leverage lcs to find the chars added and removed ([#2092](https://github.com/aws/language-servers/issues/2092)) ([40379a8](https://github.com/aws/language-servers/commit/40379a887f8d42cc184239ca3175b4e673cc5286)) +* **amazonq:** skips continuous monitoring when WCS sees workspace as idle ([#2066](https://github.com/aws/language-servers/issues/2066)) ([9cb959d](https://github.com/aws/language-servers/commit/9cb959d4cc450d0907f8bf5265ba01d2aa68bcd0)) +* creating a new sesion for Edits trigger with next token ([#2094](https://github.com/aws/language-servers/issues/2094)) ([1da8730](https://github.com/aws/language-servers/commit/1da8730b6ed6ad53b6561368bf722e56d59596a4)) +* remove edit cache logic ([#2079](https://github.com/aws/language-servers/issues/2079)) ([9bc5b9c](https://github.com/aws/language-servers/commit/9bc5b9c1d77e5fee6f518f7f5016d3a0043a5a77)) +* sessionManager misused because there are 2 types of manager now ([#2090](https://github.com/aws/language-servers/issues/2090)) ([8db059a](https://github.com/aws/language-servers/commit/8db059ab83d94fd7c3ba3eb265044add31c80aea)) +* update client name to support Sagemaker AI origin for agentic chat ([#2093](https://github.com/aws/language-servers/issues/2093)) ([a746fe8](https://github.com/aws/language-servers/commit/a746fe845d5e09563b475f01ce44059dca9fd10f)) + ## [0.0.72](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.71...lsp-codewhisperer/v0.0.72) (2025-08-06) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 09490a4f3f..fdd34884b1 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.72", + "version": "0.0.73", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 48e9e2adec..6c8af7a272 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -67,6 +67,7 @@ import { McpManager } from './tools/mcp/mcpManager' import { AgenticChatResultStream } from './agenticChatResultStream' import { AgenticChatError } from './errors' import * as sharedUtils from '../../shared/utils' +import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' describe('AgenticChatController', () => { let mcpInstanceStub: sinon.SinonStub @@ -475,6 +476,15 @@ describe('AgenticChatController', () => { assert.strictEqual(typeof session.conversationId, 'string') }) + it('invokes IdleWorkspaceManager recordActivityTimestamp', async () => { + const recordActivityTimestampStub = sinon.stub(IdleWorkspaceManager, 'recordActivityTimestamp') + + await chatController.onChatPrompt({ tabId: mockTabId, prompt: { prompt: 'Hello' } }, mockCancellationToken) + + sinon.assert.calledOnce(recordActivityTimestampStub) + recordActivityTimestampStub.restore() + }) + it('includes chat history from the database in the request input', async () => { // Mock chat history const mockHistory = [ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 60bba5885a..72217fae07 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -230,6 +230,7 @@ import { ActiveUserTracker } from '../../shared/activeUserTracker' import { UserContext } from '../../client/token/codewhispererbearertokenclient' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' +import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' type ChatHandlers = Omit< LspHandlers, @@ -722,6 +723,8 @@ export class AgenticChatController implements ChatHandlers { // Phase 1: Initial Setup - This happens only once params.prompt.prompt = sanitizeInput(params.prompt.prompt || '') + IdleWorkspaceManager.recordActivityTimestamp() + const maybeDefaultResponse = !params.prompt.command && getDefaultChatResponse(params.prompt.prompt) if (maybeDefaultResponse) { return maybeDefaultResponse @@ -3285,6 +3288,9 @@ export class AgenticChatController implements ChatHandlers { const metric = new Metric({ cwsprChatConversationType: 'Chat', }) + + IdleWorkspaceManager.recordActivityTimestamp() + const triggerContext = await this.#getInlineChatTriggerContext(params) let response: ChatCommandOutput diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts index 04c7dc5ab1..0513443a35 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts @@ -137,10 +137,20 @@ export class CodePercentageTracker { } } + addTotalTokensForEdits(languageId: string, count: number): void { + const languageBucket = this.getLanguageBucket(languageId) + if (count >= INSERT_CUTOFF_THRESHOLD) { + languageBucket.totalTokens += count + } + } + countAcceptedTokens(languageId: string, tokens: string): void { + this.countAcceptedTokensUsingCount(languageId, tokens.length) + } + + countAcceptedTokensUsingCount(languageId: string, count: number): void { const languageBucket = this.getLanguageBucket(languageId) - const tokenCount = tokens.length - languageBucket.acceptedTokens += tokenCount + languageBucket.acceptedTokens += count } countInvocation(languageId: string): void { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 1636c17b84..29390248f7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -61,6 +61,7 @@ import { INVALID_TOKEN } from '../../shared/constants' import { AmazonQError } from '../../shared/amazonQServiceManager/errors' import * as path from 'path' import { CONTEXT_CHARACTERS_LIMIT } from './constants' +import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' const updateConfiguration = async ( features: TestFeatures, @@ -770,6 +771,22 @@ describe('CodeWhisperer Server', () => { assert.rejects(promise, ResponseError) }) + it('invokes IdleWorkspaceManager recordActivityTimestamp', async () => { + const recordActivityTimestampStub = sinon.stub(IdleWorkspaceManager, 'recordActivityTimestamp') + + await features.doInlineCompletionWithReferences( + { + textDocument: { uri: SOME_FILE.uri }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Invoked }, + }, + CancellationToken.None + ) + + sinon.assert.calledOnce(recordActivityTimestampStub) + recordActivityTimestampStub.restore() + }) + describe('Supplemental Context', () => { it('should send supplemental context when using token authentication', async () => { const test_service = sinon.createStubInstance( diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index f2b1a2c43d..23a72e3528 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -46,7 +46,7 @@ import { UserWrittenCodeTracker } from '../../shared/userWrittenCodeTracker' import { RecentEditTracker, RecentEditTrackerDefaultConfig } from './tracker/codeEditTracker' import { CursorTracker } from './tracker/cursorTracker' import { RejectedEditTracker, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG } from './tracker/rejectedEditTracker' -import { getAddedAndDeletedChars } from './diffUtils' +import { getAddedAndDeletedLines, getCharacterDifferences } from './diffUtils' import { emitPerceivedLatencyTelemetry, emitServiceInvocationFailure, @@ -55,7 +55,9 @@ import { } from './telemetry' import { DocumentChangedListener } from './documentChangedListener' import { EditCompletionHandler } from './editCompletionHandler' -import { EMPTY_RESULT } from './constants' +import { EMPTY_RESULT, ABAP_EXTENSIONS } from './constants' +import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' +import { URI } from 'vscode-uri' const mergeSuggestionsWithRightContext = ( rightFileContext: string, @@ -141,6 +143,8 @@ export const CodewhispererServerFactory = // 2. it is not designed to handle concurrent changes to these state variables. // when one handler is at the API call stage, it has not yet update the session state // but another request can start, causing the state to be incorrect. + IdleWorkspaceManager.recordActivityTimestamp() + if (isOnInlineCompletionHandlerInProgress) { logging.log(`Skip concurrent inline completion`) return EMPTY_RESULT @@ -158,7 +162,7 @@ export const CodewhispererServerFactory = if (cursorTracker) { cursorTracker.trackPosition(params.textDocument.uri, params.position) } - const textDocument = await workspace.getTextDocument(params.textDocument.uri) + const textDocument = await getTextDocument(params.textDocument.uri, workspace, logging) const codeWhispererService = amazonQServiceManager.getCodewhispererService() if (params.partialResultToken && currentSession) { @@ -498,7 +502,6 @@ export const CodewhispererServerFactory = partialResultToken: suggestionResponse.responseContext.nextToken, } } else { - session.hasEditsPending = suggestionResponse.responseContext.nextToken ? true : false return { items: suggestionResponse.suggestions .map(suggestion => { @@ -619,36 +622,29 @@ export const CodewhispererServerFactory = ) const isAccepted = acceptedItemId ? true : false const acceptedSuggestion = session.suggestions.find(s => s.itemId === acceptedItemId) - let addedCharactersForEditSuggestion = '' - let deletedCharactersForEditSuggestion = '' - if (acceptedSuggestion !== undefined) { - if (acceptedSuggestion) { - codePercentageTracker.countSuccess(session.language) - if (session.suggestionType === SuggestionType.EDIT && acceptedSuggestion.content) { - // [acceptedSuggestion.insertText] will be undefined for NEP suggestion. Use [acceptedSuggestion.content] instead. - // Since [acceptedSuggestion.content] is in the form of a diff, transform the content into addedCharacters and deletedCharacters. - const addedAndDeletedChars = getAddedAndDeletedChars(acceptedSuggestion.content) - if (addedAndDeletedChars) { - addedCharactersForEditSuggestion = addedAndDeletedChars.addedCharacters - deletedCharactersForEditSuggestion = addedAndDeletedChars.deletedCharacters - - codePercentageTracker.countAcceptedTokens( - session.language, - addedCharactersForEditSuggestion - ) - codePercentageTracker.countTotalTokens( - session.language, - addedCharactersForEditSuggestion, - true - ) - enqueueCodeDiffEntry(session, acceptedSuggestion, addedCharactersForEditSuggestion) - } - } else if (acceptedSuggestion.insertText) { - codePercentageTracker.countAcceptedTokens(session.language, acceptedSuggestion.insertText) - codePercentageTracker.countTotalTokens(session.language, acceptedSuggestion.insertText, true) + let addedLengthForEdits = 0 + let deletedLengthForEdits = 0 + if (acceptedSuggestion) { + codePercentageTracker.countSuccess(session.language) + if (session.suggestionType === SuggestionType.EDIT && acceptedSuggestion.content) { + // [acceptedSuggestion.insertText] will be undefined for NEP suggestion. Use [acceptedSuggestion.content] instead. + // Since [acceptedSuggestion.content] is in the form of a diff, transform the content into addedCharacters and deletedCharacters. + const { addedLines, deletedLines } = getAddedAndDeletedLines(acceptedSuggestion.content) + const charDiffResult = getCharacterDifferences(addedLines, deletedLines) + addedLengthForEdits = charDiffResult.charactersAdded + deletedLengthForEdits = charDiffResult.charactersRemoved + + codePercentageTracker.countAcceptedTokensUsingCount( + session.language, + charDiffResult.charactersAdded + ) + codePercentageTracker.addTotalTokensForEdits(session.language, charDiffResult.charactersAdded) + enqueueCodeDiffEntry(session, acceptedSuggestion, addedLines.join('\n')) + } else if (acceptedSuggestion.insertText) { + codePercentageTracker.countAcceptedTokens(session.language, acceptedSuggestion.insertText) + codePercentageTracker.countTotalTokens(session.language, acceptedSuggestion.insertText, true) - enqueueCodeDiffEntry(session, acceptedSuggestion) - } + enqueueCodeDiffEntry(session, acceptedSuggestion) } } @@ -687,21 +683,15 @@ export const CodewhispererServerFactory = if (firstCompletionDisplayLatency) emitPerceivedLatencyTelemetry(telemetry, session) // Always emit user trigger decision at session close - // Close session unless Edit suggestion was accepted with more pending - const shouldKeepSessionOpen = - session.suggestionType === SuggestionType.EDIT && isAccepted && session.hasEditsPending - - if (!shouldKeepSessionOpen) { - completionSessionManager.closeSession(session) - } - const streakLength = editsEnabled ? completionSessionManager.getAndUpdateStreakLength(isAccepted) : 0 + sessionManager.closeSession(session) + const streakLength = editsEnabled ? sessionManager.getAndUpdateStreakLength(isAccepted) : 0 await emitUserTriggerDecisionTelemetry( telemetry, telemetryService, session, timeSinceLastUserModification, - addedCharactersForEditSuggestion.length, - deletedCharactersForEditSuggestion.length, + addedLengthForEdits, + deletedLengthForEdits, addedDiagnostics, removedDiagnostics, streakLength, @@ -722,10 +712,9 @@ export const CodewhispererServerFactory = userWrittenCodeTracker.customizationArn = customizationArn } logging.debug(`CodePercentageTracker customizationArn updated to ${customizationArn}`) - /* - The flag enableTelemetryEventsToDestination is set to true temporarily. It's value will be determined through destination - configuration post all events migration to STE. It'll be replaced by qConfig['enableTelemetryEventsToDestination'] === true - */ + + // The flag enableTelemetryEventsToDestination is set to true temporarily. It's value will be determined through destination + // configuration post all events migration to STE. It'll be replaced by qConfig['enableTelemetryEventsToDestination'] === true // const enableTelemetryEventsToDestination = true // telemetryService.updateEnableTelemetryEventsToDestination(enableTelemetryEventsToDestination) telemetryService.updateOptOutPreference(optOutTelemetryPreference) @@ -902,3 +891,27 @@ export const CodewhispererServerFactory = export const CodeWhispererServerIAM = CodewhispererServerFactory(getOrThrowBaseIAMServiceManager) export const CodeWhispererServerToken = CodewhispererServerFactory(getOrThrowBaseTokenServiceManager) + +const getLanguageIdFromUri = (uri: string, logging?: any): string => { + try { + const extension = uri.split('.').pop()?.toLowerCase() + return ABAP_EXTENSIONS.has(extension || '') ? 'abap' : '' + } catch (err) { + logging?.log(`Error parsing URI to determine language: ${uri}: ${err}`) + return '' + } +} + +const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { + let textDocument = await workspace.getTextDocument(uri) + if (!textDocument) { + try { + const content = await workspace.fs.readFile(URI.parse(uri).fsPath) + const languageId = getLanguageIdFromUri(uri) + textDocument = TextDocument.create(uri, languageId, 0, content) + } catch (err) { + logging.log(`Unable to load from ${uri}: ${err}`) + } + } + return textDocument +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts index 49a33b35de..c5810924b6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts @@ -4,3 +4,28 @@ export const CONTEXT_CHARACTERS_LIMIT = 10240 export const EMPTY_RESULT = { sessionId: '', items: [] } export const EDIT_DEBOUNCE_INTERVAL_MS = 500 export const EDIT_STALE_RETRY_COUNT = 3 +// ABAP ADT extensions commonly used with Eclipse +export const ABAP_EXTENSIONS = new Set([ + 'asprog', + 'aclass', + 'asinc', + 'aint', + 'assrvds', + 'asbdef', + 'asddls', + 'astablds', + 'astabldt', + 'amdp', + 'apack', + 'asrv', + 'aobj', + 'aexit', + 'abdef', + 'acinc', + 'asfugr', + 'apfugr', + 'asfunc', + 'asfinc', + 'apfunc', + 'apfinc', +]) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts index 66cbeb3f23..0899dd5e46 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts @@ -213,6 +213,18 @@ export function applyUnifiedDiff(docText: string, unifiedDiff: string): string { } } +export function getAddedAndDeletedLines(unifiedDiff: string): { addedLines: string[]; deletedLines: string[] } { + const lines = unifiedDiff.split('\n') + const addedLines = lines.filter(line => line.startsWith('+') && !line.startsWith('+++')).map(line => line.slice(1)) + const deletedLines = lines + .filter(line => line.startsWith('-') && !line.startsWith('---')) + .map(line => line.slice(1)) + return { + addedLines, + deletedLines, + } +} + // src https://github.com/aws/aws-toolkit-vscode/blob/3921457b0a2094b831beea0d66cc2cbd2a833890/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts#L147 export function getAddedAndDeletedChars(unifiedDiff: string): { addedCharacters: string @@ -254,3 +266,58 @@ export function getAddedAndDeletedChars(unifiedDiff: string): { deletedCharacters, } } + +/** + * Calculate character differences between added and deleted text blocks using LCS + */ +export interface CharDiffResult { + charactersAdded: number + charactersRemoved: number +} + +/** + * Find longest common subsequence length between two strings + */ +function lcsLength(str1: string, str2: string): number[][] { + const m = str1.length + const n = str2.length + const dp = Array(m + 1) + .fill(null) + .map(() => Array(n + 1).fill(0)) + + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (str1[i - 1] === str2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1 + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + } + } + } + + return dp +} + +/** + * Calculate character differences between added and deleted blocks + */ +export function getCharacterDifferences(addedLines: string[], deletedLines: string[]): CharDiffResult { + const addedText = addedLines.join('\n') + const deletedText = deletedLines.join('\n') + + if (addedText.length === 0) { + return { charactersAdded: 0, charactersRemoved: deletedText.length } + } + + if (deletedText.length === 0) { + return { charactersAdded: addedText.length, charactersRemoved: 0 } + } + + const lcsTable = lcsLength(deletedText, addedText) + const lcsLen = lcsTable[deletedText.length][addedText.length] + + return { + charactersAdded: addedText.length - lcsLen, + charactersRemoved: deletedText.length - lcsLen, + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 5b3e7519f4..3c72e368f4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -120,16 +120,35 @@ export class EditCompletionHandler { } if (params.partialResultToken && currentSession) { + // Close ACTIVE session. We shouldn't record Discard trigger decision for trigger with nextToken. + if (currentSession && currentSession.state === 'ACTIVE') { + this.sessionManager.discardSession(currentSession) + } + + const newSession = this.sessionManager.createSession({ + document: textDocument, + startPosition: params.position, + triggerType: 'AutoTrigger', + language: currentSession.language, + requestContext: currentSession.requestContext, + autoTriggerType: undefined, + triggerCharacter: '', + classifierResult: undefined, + classifierThreshold: undefined, + credentialStartUrl: currentSession.credentialStartUrl, + supplementalMetadata: currentSession.supplementalMetadata, + customizationArn: currentSession.customizationArn, + }) // subsequent paginated requests for current session try { const suggestionResponse = await this.codeWhispererService.generateSuggestions({ - ...currentSession.requestContext, + ...newSession.requestContext, nextToken: `${params.partialResultToken}`, }) return await this.processSuggestionResponse( suggestionResponse, - currentSession, - false, + newSession, + true, params.context.selectedCompletionInfo?.range ) } catch (error) { @@ -256,16 +275,6 @@ export class EditCompletionHandler { // Close ACTIVE session and record Discard trigger decision immediately if (currentSession && currentSession.state === 'ACTIVE') { - if (this.editsEnabled && currentSession.suggestionType === SuggestionType.EDIT) { - const mergedSuggestions = mergeEditSuggestionsWithFileContext(currentSession, textDocument, fileContext) - - if (mergedSuggestions.length > 0) { - return { - items: mergedSuggestions, - sessionId: currentSession.id, - } - } - } // Emit user trigger decision at session close time for active session this.sessionManager.discardSession(currentSession) const streakLength = this.editsEnabled ? this.sessionManager.getAndUpdateStreakLength(false) : 0 diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index 8ac71737cf..cb873a2920 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -80,7 +80,6 @@ export class CodeWhispererSession { includeImportsWithSuggestions?: boolean codewhispererSuggestionImportCount: number = 0 suggestionType?: string - hasEditsPending?: boolean = false // Track the most recent itemId for paginated Edit suggestions constructor(data: SessionData) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts index b990ccfceb..d53d141a2b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts @@ -147,13 +147,7 @@ export const emitUserTriggerDecisionTelemetry = async ( streakLength ) - // Mark telemetry as complete unless Edit suggestion was accepted with more pending - const hasPendingEditTelemetry = - session.suggestionType === SuggestionType.EDIT && session.acceptedSuggestionId && session.hasEditsPending - - if (!hasPendingEditTelemetry) { - session.reportedUserDecision = true - } + session.reportedUserDecision = true } export const emitAggregatedUserTriggerDecisionTelemetry = ( diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.test.ts new file mode 100644 index 0000000000..a5d81526c9 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.test.ts @@ -0,0 +1,75 @@ +import { IdleWorkspaceManager } from './IdleWorkspaceManager' +import { WorkspaceFolderManager } from './workspaceFolderManager' +import sinon, { stubInterface, StubbedInstance } from 'ts-sinon' + +describe('IdleWorkspaceManager', () => { + let clock: sinon.SinonFakeTimers + let mockWorkspaceFolderManager: StubbedInstance + + beforeEach(() => { + clock = sinon.useFakeTimers() + mockWorkspaceFolderManager = stubInterface() + sinon.stub(WorkspaceFolderManager, 'getInstance').returns(mockWorkspaceFolderManager) + sinon.stub(console, 'error') + }) + + afterEach(() => { + clock.restore() + sinon.restore() + }) + + describe('isSessionIdle', () => { + it('should return false when session is not idle', () => { + IdleWorkspaceManager.recordActivityTimestamp() + + const result = IdleWorkspaceManager.isSessionIdle() + + expect(result).toBe(false) + }) + + it('should return true when session exceeds idle threshold', () => { + IdleWorkspaceManager.recordActivityTimestamp() + clock.tick(31 * 60 * 1000) // 31 minutes + + const result = IdleWorkspaceManager.isSessionIdle() + + expect(result).toBe(true) + }) + }) + + describe('recordActivityTimestamp', () => { + it('should update activity timestamp', async () => { + IdleWorkspaceManager.recordActivityTimestamp() + + expect(IdleWorkspaceManager.isSessionIdle()).toBe(false) + }) + + it('should not trigger workspace check when session was not idle', async () => { + mockWorkspaceFolderManager.isContinuousMonitoringStopped.returns(false) + + IdleWorkspaceManager.recordActivityTimestamp() + + sinon.assert.notCalled(mockWorkspaceFolderManager.checkRemoteWorkspaceStatusAndReact) + }) + + it('should trigger workspace check when session was idle and monitoring is active', async () => { + // Make session idle first + clock.tick(31 * 60 * 1000) + mockWorkspaceFolderManager.isContinuousMonitoringStopped.returns(false) + mockWorkspaceFolderManager.checkRemoteWorkspaceStatusAndReact.resolves() + + IdleWorkspaceManager.recordActivityTimestamp() + + sinon.assert.calledOnce(mockWorkspaceFolderManager.checkRemoteWorkspaceStatusAndReact) + }) + + it('should not trigger workspace check when session was idle but monitoring is stopped', async () => { + clock.tick(31 * 60 * 1000) + mockWorkspaceFolderManager.isContinuousMonitoringStopped.returns(true) + + IdleWorkspaceManager.recordActivityTimestamp() + + sinon.assert.notCalled(mockWorkspaceFolderManager.checkRemoteWorkspaceStatusAndReact) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts new file mode 100644 index 0000000000..5a8359ccac --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts @@ -0,0 +1,38 @@ +import { WorkspaceFolderManager } from './workspaceFolderManager' + +export class IdleWorkspaceManager { + private static readonly idleThreshold = 30 * 60 * 1000 // 30 minutes + private static lastActivityTimestamp = 0 // treat session as idle as the start + + private constructor() {} + + /** + * Records activity timestamp and triggers workspace status check if session was idle. + * + * When transitioning from idle to active, proactively checks remote workspace status + * (if continuous monitoring is enabled) without blocking the current operation. + */ + public static recordActivityTimestamp(): void { + try { + const wasSessionIdle = IdleWorkspaceManager.isSessionIdle() + IdleWorkspaceManager.lastActivityTimestamp = Date.now() + + const workspaceFolderManager = WorkspaceFolderManager.getInstance() + if (workspaceFolderManager && wasSessionIdle && !workspaceFolderManager.isContinuousMonitoringStopped()) { + // Proactively check the remote workspace status instead of waiting for the next scheduled check + // Fire and forget - don't await to avoid blocking + workspaceFolderManager.checkRemoteWorkspaceStatusAndReact().catch(err => { + // ignore errors + }) + } + } catch (err) { + // ignore errors + } + } + + public static isSessionIdle(): boolean { + const currentTime = Date.now() + const timeSinceLastActivity = currentTime - IdleWorkspaceManager.lastActivityTimestamp + return timeSinceLastActivity > IdleWorkspaceManager.idleThreshold + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/artifactManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/artifactManager.ts index 9518f9629a..dfedb0c913 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/artifactManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/artifactManager.ts @@ -694,6 +694,21 @@ export class ArtifactManager { additionalFiles.push(...updatedFiles) } + // Fallback methods to generate a .classpath at workspace folder root + if (projectRoots.length == 0) { + const javaManager = new JavaProjectAnalyzer(workspacePath) + const structure = await javaManager.analyze() + const generator = new EclipseConfigGenerator(workspaceFolder, this.logging) + const classpathFiles = await generator.generateDotClasspath(structure) + for (const classpathFile of classpathFiles) { + additionalFiles.push(classpathFile) + } + const projectFiles = await generator.generateDotProject(path.basename(workspacePath), structure) + for (const projectFile of projectFiles) { + additionalFiles.push(projectFile) + } + } + return [...files, ...additionalFiles] } diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/dependency/dependencyDiscoverer.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/dependency/dependencyDiscoverer.ts index 8a4a9755cb..ed387ca2ca 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/dependency/dependencyDiscoverer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/dependency/dependencyDiscoverer.ts @@ -191,7 +191,8 @@ export class DependencyDiscoverer { } } - public resetFromDisposal(): void { + public disposeAndReset(): void { + this.dispose() this.sharedState.isDisposed = false this.sharedState.dependencyUploadedSizeSum = 0 } diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts index 09336ffb2f..c536c1087d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts @@ -221,7 +221,6 @@ export const WorkspaceContextServer = (): Server => features => { isLoggedInUsingBearerToken(credentialsProvider) && abTestingEnabled && !workspaceFolderManager.getOptOutStatus() && - !workspaceFolderManager.getServiceQuotaExceededStatus() && workspaceIdentifier ) } @@ -303,17 +302,15 @@ export const WorkspaceContextServer = (): Server => features => { await evaluateABTesting() isWorkflowInitialized = true - workspaceFolderManager.resetAdminOptOutAndServiceQuotaStatus() + workspaceFolderManager.resetAdminOptOutStatus() if (!isUserEligibleForWorkspaceContext()) { return } fileUploadJobManager.startFileUploadJobConsumer() dependencyEventBundler.startDependencyEventBundler() - await Promise.all([ - workspaceFolderManager.initializeWorkspaceStatusMonitor(), - workspaceFolderManager.processNewWorkspaceFolders(workspaceFolders), - ]) + + workspaceFolderManager.initializeWorkspaceStatusMonitor() logging.log(`Workspace context workflow initialized`) } else if (!isLoggedIn) { if (isWorkflowInitialized) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts index 0b4ec53f25..7ab596a930 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts @@ -6,8 +6,8 @@ import { DependencyDiscoverer } from './dependency/dependencyDiscoverer' import { WorkspaceFolder } from 'vscode-languageserver-protocol' import { ArtifactManager } from './artifactManager' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' -import { CreateWorkspaceResponse } from '../../client/token/codewhispererbearertokenclient' -import { AWSError } from 'aws-sdk' +import { ListWorkspaceMetadataResponse } from '../../client/token/codewhispererbearertokenclient' +import { IdleWorkspaceManager } from './IdleWorkspaceManager' describe('WorkspaceFolderManager', () => { let mockServiceManager: StubbedInstance @@ -33,8 +33,8 @@ describe('WorkspaceFolderManager', () => { sinon.restore() }) - describe('getServiceQuotaExceededStatus', () => { - it('should return true when service quota is exceeded', async () => { + describe('checkRemoteWorkspaceStatusAndReact', () => { + it('should check and react when IDE session is not idle', async () => { // Setup const workspaceFolders: WorkspaceFolder[] = [ { @@ -43,17 +43,20 @@ describe('WorkspaceFolderManager', () => { }, ] - // Mock the createWorkspace method to throw a ServiceQuotaExceededException - const mockError: AWSError = { - name: 'ServiceQuotaExceededException', - message: 'You have too many active running workspaces.', - code: 'ServiceQuotaExceededException', - time: new Date(), - retryable: false, - statusCode: 400, + // Mock IdleSessionManager to return false (not idle) + sinon.stub(IdleWorkspaceManager, 'isSessionIdle').returns(false) + + // Mock successful response + const mockResponse: ListWorkspaceMetadataResponse = { + workspaces: [ + { + workspaceId: 'test-workspace-id', + workspaceStatus: 'CREATED', + }, + ], } - mockCodeWhispererService.createWorkspace.rejects(mockError) + mockCodeWhispererService.listWorkspaceMetadata.resolves(mockResponse as any) // Create the WorkspaceFolderManager instance using the static createInstance method workspaceFolderManager = WorkspaceFolderManager.createInstance( @@ -66,23 +69,24 @@ describe('WorkspaceFolderManager', () => { 'test-workspace-identifier' ) - // Spy on clearAllWorkspaceResources and related methods - const clearAllWorkspaceResourcesSpy = sinon.stub( + // Spy on resetWebSocketClient + const resetWebSocketClientSpy = sinon.stub(workspaceFolderManager as any, 'resetWebSocketClient') + + // Spy on handleWorkspaceCreatedState + const handleWorkspaceCreatedStateSpy = sinon.stub( workspaceFolderManager as any, - 'clearAllWorkspaceResources' + 'handleWorkspaceCreatedState' ) - // Act - trigger the createNewWorkspace method which sets isServiceQuotaExceeded - await (workspaceFolderManager as any).createNewWorkspace() + // Act - trigger the checkRemoteWorkspaceStatusAndReact method + await workspaceFolderManager.checkRemoteWorkspaceStatusAndReact() - // Assert - expect(workspaceFolderManager.getServiceQuotaExceededStatus()).toBe(true) - - // Verify that clearAllWorkspaceResources was called - sinon.assert.calledOnce(clearAllWorkspaceResourcesSpy) + // Verify that resetWebSocketClient was called once + sinon.assert.notCalled(resetWebSocketClientSpy) + sinon.assert.calledOnce(handleWorkspaceCreatedStateSpy) }) - it('should return false when service quota is not exceeded', async () => { + it('should skip checking and reacting when IDE session is idle', async () => { // Setup const workspaceFolders: WorkspaceFolder[] = [ { @@ -91,15 +95,20 @@ describe('WorkspaceFolderManager', () => { }, ] + // Mock IdleSessionManager to return true (idle) + sinon.stub(IdleWorkspaceManager, 'isSessionIdle').returns(true) + // Mock successful response - const mockResponse: CreateWorkspaceResponse = { - workspace: { - workspaceId: 'test-workspace-id', - workspaceStatus: 'RUNNING', - }, + const mockResponse: ListWorkspaceMetadataResponse = { + workspaces: [ + { + workspaceId: 'test-workspace-id', + workspaceStatus: 'CREATED', + }, + ], } - mockCodeWhispererService.createWorkspace.resolves(mockResponse as any) + mockCodeWhispererService.listWorkspaceMetadata.resolves(mockResponse as any) // Create the WorkspaceFolderManager instance using the static createInstance method workspaceFolderManager = WorkspaceFolderManager.createInstance( @@ -112,20 +121,18 @@ describe('WorkspaceFolderManager', () => { 'test-workspace-identifier' ) - // Spy on clearAllWorkspaceResources - const clearAllWorkspaceResourcesSpy = sinon.stub( - workspaceFolderManager as any, - 'clearAllWorkspaceResources' - ) + // Spy on resetWebSocketClient + const resetWebSocketClientSpy = sinon.stub(workspaceFolderManager as any, 'resetWebSocketClient') - // Act - trigger the createNewWorkspace method - await (workspaceFolderManager as any).createNewWorkspace() + // Act - trigger the checkRemoteWorkspaceStatusAndReact method + await workspaceFolderManager.checkRemoteWorkspaceStatusAndReact() - // Assert - expect(workspaceFolderManager.getServiceQuotaExceededStatus()).toBe(false) - - // Verify that clearAllWorkspaceResources was not called - sinon.assert.notCalled(clearAllWorkspaceResourcesSpy) + // Verify that resetWebSocketClient was called once + sinon.assert.calledOnce(resetWebSocketClientSpy) + sinon.assert.calledWith( + mockLogging.log, + sinon.match(/Session is idle, skipping remote workspace status check/) + ) }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts index 00048cd62f..99fc9c4628 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts @@ -20,6 +20,7 @@ import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/A import { URI } from 'vscode-uri' import path = require('path') import { isAwsError } from '../../shared/utils' +import { IdleWorkspaceManager } from './IdleWorkspaceManager' interface WorkspaceState { remoteWorkspaceState: WorkspaceStatus @@ -54,8 +55,8 @@ export class WorkspaceFolderManager { private optOutMonitorInterval: NodeJS.Timeout | undefined private messageQueueConsumerInterval: NodeJS.Timeout | undefined private isOptedOut: boolean = false - // Tracks if the user has reached their maximum allowed remote workspaces quota - private isServiceQuotaExceeded: boolean = false + private isCheckingRemoteWorkspaceStatus: boolean = false + private isArtifactUploadedToRemoteWorkspace: boolean = false static createInstance( serviceManager: AmazonQTokenServiceManager, @@ -138,13 +139,8 @@ export class WorkspaceFolderManager { return this.isOptedOut } - getServiceQuotaExceededStatus(): boolean { - return this.isServiceQuotaExceeded - } - - resetAdminOptOutAndServiceQuotaStatus(): void { + resetAdminOptOutStatus(): void { this.isOptedOut = false - this.isServiceQuotaExceeded = false } getWorkspaceState(): WorkspaceState { @@ -324,14 +320,13 @@ export class WorkspaceFolderManager { this.workspaceState.webSocketClient = webSocketClient } - async initializeWorkspaceStatusMonitor() { + initializeWorkspaceStatusMonitor() { this.logging.log(`Initializing workspace status check for workspace [${this.workspaceIdentifier}]`) // Reset workspace ID to force operations to wait for new remote workspace information this.resetRemoteWorkspaceId() - this.artifactManager.resetFromDisposal() - this.dependencyDiscoverer.resetFromDisposal() + this.isArtifactUploadedToRemoteWorkspace = false // Set up message queue consumer if (this.messageQueueConsumerInterval === undefined) { @@ -350,12 +345,8 @@ export class WorkspaceFolderManager { }, this.MESSAGE_PUBLISH_INTERVAL) } - // Perform a one-time checkRemoteWorkspaceStatusAndReact first - // Pass skipUploads as true since it would be handled by processNewWorkspaceFolders - await this.checkRemoteWorkspaceStatusAndReact(true) - // Set up continuous monitoring which periodically invokes checkRemoteWorkspaceStatusAndReact - if (!this.isOptedOut && !this.isServiceQuotaExceeded && this.continuousMonitorInterval === undefined) { + if (!this.isOptedOut && this.continuousMonitorInterval === undefined) { this.logging.log(`Starting continuous monitor for workspace [${this.workspaceIdentifier}]`) this.continuousMonitorInterval = setInterval(async () => { try { @@ -427,61 +418,92 @@ export class WorkspaceFolderManager { }) } - private async checkRemoteWorkspaceStatusAndReact(skipUploads: boolean = false) { - if (this.workspaceFolders.length === 0) { - this.logging.log(`No workspace folders added, skipping workspace status check`) + public async checkRemoteWorkspaceStatusAndReact() { + if (this.isCheckingRemoteWorkspaceStatus) { + // Skip checking remote workspace if a previous check is still in progress return } + this.isCheckingRemoteWorkspaceStatus = true + try { + if (IdleWorkspaceManager.isSessionIdle()) { + this.resetWebSocketClient() + this.logging.log('Session is idle, skipping remote workspace status check') + return + } - this.logging.log(`Checking remote workspace status for workspace [${this.workspaceIdentifier}]`) - const { metadata, optOut, error } = await this.listWorkspaceMetadata(this.workspaceIdentifier) + if (this.workspaceFolders.length === 0) { + this.logging.log(`No workspace folders added, skipping workspace status check`) + return + } - if (optOut) { - this.logging.log('User opted out, clearing all resources and starting opt-out monitor') - this.isOptedOut = true - this.clearAllWorkspaceResources() - this.startOptOutMonitor() - return - } + this.logging.log(`Checking remote workspace status for workspace [${this.workspaceIdentifier}]`) + const { metadata, optOut, error } = await this.listWorkspaceMetadata(this.workspaceIdentifier) - if (error) { - // Do not do anything if we received an exception but not caused by optOut - return - } + if (optOut) { + this.logging.log('User opted out, clearing all resources and starting opt-out monitor') + this.isOptedOut = true + this.clearAllWorkspaceResources() + this.startOptOutMonitor() + return + } - if (!metadata) { - // Workspace no longer exists, Recreate it. - this.resetRemoteWorkspaceId() // workspaceId would change if remote record is gone - await this.handleWorkspaceCreatedState(skipUploads) - return - } + if (error) { + // Do not do anything if we received an exception but not caused by optOut + return + } - this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus - if (this.workspaceState.workspaceId === undefined) { - this.setRemoteWorkspaceId(metadata.workspaceId) - } + if (!metadata) { + // Workspace no longer exists, Recreate it. + this.resetRemoteWorkspaceId() // workspaceId would change if remote record is gone + await this.handleWorkspaceCreatedState() + return + } - switch (metadata.workspaceStatus) { - case 'READY': - // Check if connection exists - const client = this.workspaceState.webSocketClient - if (!client || !client.isConnected()) { - this.logging.log( - `Workspace is ready but no connection exists or connection lost. Re-establishing connection...` - ) - await this.establishConnection(metadata) - } - break - case 'PENDING': - // Schedule an initial connection when pending - await this.waitForInitialConnection() - break - case 'CREATED': - // Workspace has no environment, Recreate it. - await this.handleWorkspaceCreatedState(skipUploads) - break - default: - this.logging.warn(`Unknown workspace status: ${metadata.workspaceStatus}`) + this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus + if (this.workspaceState.workspaceId === undefined) { + this.setRemoteWorkspaceId(metadata.workspaceId) + } + + switch (metadata.workspaceStatus) { + case 'READY': + // Check if connection exists + const client = this.workspaceState.webSocketClient + if (!client || !client.isConnected()) { + this.logging.log( + `Workspace is ready but no connection exists or connection lost. Re-establishing connection...` + ) + let uploadArtifactsPromise: Promise | undefined + if (!this.isArtifactUploadedToRemoteWorkspace) { + uploadArtifactsPromise = this.uploadAllArtifactsToRemoteWorkspace() + } + await this.establishConnection(metadata) + if (uploadArtifactsPromise) { + await uploadArtifactsPromise + } + } + break + case 'PENDING': + // Schedule an initial connection when pending + let uploadArtifactsPromise: Promise | undefined + if (!this.isArtifactUploadedToRemoteWorkspace) { + uploadArtifactsPromise = this.uploadAllArtifactsToRemoteWorkspace() + } + await this.waitForInitialConnection() + if (uploadArtifactsPromise) { + await uploadArtifactsPromise + } + break + case 'CREATED': + // Workspace has no environment, Recreate it. + await this.handleWorkspaceCreatedState() + break + default: + this.logging.warn(`Unknown workspace status: ${metadata.workspaceStatus}`) + } + } catch (error) { + this.logging.error(`Error checking remote workspace status: ${error}`) + } finally { + this.isCheckingRemoteWorkspaceStatus = false } } @@ -515,9 +537,7 @@ export class WorkspaceFolderManager { ) clearInterval(intervalId) this.optOutMonitorInterval = undefined - this.initializeWorkspaceStatusMonitor().catch(error => { - this.logging.error(`Error while initializing workspace status monitoring: ${error}`) - }) + this.initializeWorkspaceStatusMonitor() this.processNewWorkspaceFolders(this.workspaceFolders).catch(error => { this.logging.error(`Error while processing workspace folders: ${error}`) }) @@ -530,25 +550,18 @@ export class WorkspaceFolderManager { } } - private async handleWorkspaceCreatedState(skipUploads: boolean = false): Promise { + private async handleWorkspaceCreatedState(): Promise { this.logging.log(`No READY / PENDING remote workspace found, creating a new one`) // If remote state is CREATED, call create API to create a new workspace - if (this.workspaceState.webSocketClient) { - this.workspaceState.webSocketClient.destroyClient() - this.workspaceState.webSocketClient = undefined - } + this.resetWebSocketClient() const initialResult = await this.createNewWorkspace() // If creation succeeds, establish connection if (initialResult.response) { this.logging.log(`Workspace [${this.workspaceIdentifier}] created successfully, establishing connection`) + const uploadArtifactsPromise = this.uploadAllArtifactsToRemoteWorkspace() await this.waitForInitialConnection() - if (!skipUploads) { - await this.syncSourceCodesToS3(this.workspaceFolders) - this.dependencyDiscoverer.reSyncDependenciesToS3(this.workspaceFolders).catch(e => { - this.logging.warn(`Error during re-syncing dependencies: ${e}`) - }) - } + await uploadArtifactsPromise return } @@ -570,13 +583,27 @@ export class WorkspaceFolderManager { } this.logging.log(`Retry succeeded for workspace creation, establishing connection`) + const uploadArtifactsPromise = this.uploadAllArtifactsToRemoteWorkspace() await this.waitForInitialConnection() - if (!skipUploads) { - await this.syncSourceCodesToS3(this.workspaceFolders) - this.dependencyDiscoverer.reSyncDependenciesToS3(this.workspaceFolders).catch(e => { - this.logging.warn(`Error during re-syncing dependencies: ${e}`) - }) - } + await uploadArtifactsPromise + } + + private async uploadAllArtifactsToRemoteWorkspace() { + // initialize source codes + this.artifactManager.resetFromDisposal() + await this.syncSourceCodesToS3(this.workspaceFolders) + + // initialize dependencies + this.dependencyDiscoverer.disposeAndReset() + this.dependencyDiscoverer.searchDependencies(this.workspaceFolders).catch(e => { + this.logging.warn(`Error during dependency discovery: ${e}`) + }) + + this.isArtifactUploadedToRemoteWorkspace = true + } + + public isContinuousMonitoringStopped(): boolean { + return this.continuousMonitorInterval === undefined } private stopContinuousMonitoring() { @@ -602,15 +629,15 @@ export class WorkspaceFolderManager { } } - private async createNewWorkspace() { - const createWorkspaceResult = await this.createWorkspace(this.workspaceIdentifier) - - this.isServiceQuotaExceeded = createWorkspaceResult.isServiceQuotaExceeded - if (this.isServiceQuotaExceeded) { - // Stop continuous monitor and all actions - this.clearAllWorkspaceResources() + private resetWebSocketClient() { + if (this.workspaceState.webSocketClient) { + this.workspaceState.webSocketClient.destroyClient() + this.workspaceState.webSocketClient = undefined } + } + private async createNewWorkspace() { + const createWorkspaceResult = await this.createWorkspace(this.workspaceIdentifier) const workspaceDetails = createWorkspaceResult.response if (!workspaceDetails) { this.logging.warn(`Failed to create remote workspace for [${this.workspaceIdentifier}]`) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 32233e1cf8..a162ff44e6 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -439,7 +439,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { this.logging.info( `GenerateCompletion request: "endpoint": ${this.codeWhispererEndpoint}, - "predictionType": ${request.predictionTypes?.toString() ?? ''}, + "predictionType": ${request.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, "filename": ${request.fileContext.filename}, "language": ${request.fileContext.programmingLanguage.languageName}, "supplementalContextCount": ${request.supplementalContexts?.length ?? 0}, diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts index e83d04bbb3..85cd8817a7 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts @@ -134,26 +134,36 @@ describe('getClientName', () => { }) describe('getOriginFromClientInfo', () => { - it('returns MD_IDE for SMUS-IDE client name', () => { + it('returns MD_IDE for client names starting with SMUS-IDE prefix', () => { const result = getOriginFromClientInfo('AmazonQ-For-SMUS-IDE-1.0.0') assert.strictEqual(result, 'MD_IDE') }) - it('returns MD_IDE for SMUS-CE client name', () => { + it('returns MD_IDE for client names starting with SMUS-CE prefix', () => { const result = getOriginFromClientInfo('AmazonQ-For-SMUS-CE-1.0.0') assert.strictEqual(result, 'MD_IDE') }) - it('returns MD_IDE for client names starting with SMUS-IDE prefix', () => { + it('returns MD_IDE for client names starting with SMAI-CE prefix', () => { + const result = getOriginFromClientInfo('AmazonQ-For-SMAI-CE-1.0.0') + assert.strictEqual(result, 'MD_IDE') + }) + + it('returns MD_IDE for SMUS-IDE client name', () => { const result = getOriginFromClientInfo('AmazonQ-For-SMUS-IDE') assert.strictEqual(result, 'MD_IDE') }) - it('returns MD_IDE for client names starting with SMUS-CE prefix', () => { + it('returns MD_IDE for SMUS-CE client name', () => { const result = getOriginFromClientInfo('AmazonQ-For-SMUS-CE') assert.strictEqual(result, 'MD_IDE') }) + it('returns MD_IDE for SMAI-CE client name', () => { + const result = getOriginFromClientInfo('AmazonQ-For-SMAI-CE') + assert.strictEqual(result, 'MD_IDE') + }) + it('returns IDE for non-SMUS client name', () => { const result = getOriginFromClientInfo('VSCode-Extension') assert.strictEqual(result, 'IDE') diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index e178de4a51..a7a95d8801 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -381,7 +381,12 @@ export function getClientName(lspParams: InitializeParams | undefined): string | } export function getOriginFromClientInfo(clientName: string | undefined): Origin { - if (clientName?.startsWith('AmazonQ-For-SMUS-IDE') || clientName?.startsWith('AmazonQ-For-SMUS-CE')) { + // TODO: Update with a new origin for SMAI case, as a short-term solution Sagemaker AI CE is using same origin as that of Sagemaker Unified Studio's IDE and CE + if ( + clientName?.startsWith('AmazonQ-For-SMUS-IDE') || + clientName?.startsWith('AmazonQ-For-SMUS-CE') || + clientName?.startsWith('AmazonQ-For-SMAI-CE') + ) { return 'MD_IDE' } return 'IDE' diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index 929bee5583..e8cb3b2c8a 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index df4d04e39a..298f3820f0 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index 6cc3037232..a9e3cf9d4c 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index 620b3ba16b..9ff685cfdc 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index e971b6af08..caa7801b5f 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 2231bd884a..58fd5e591d 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 529b59ad6b..573170a3a9 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index e24f1d0ff7..827509803e 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.121", + "@aws/language-server-runtimes": "^0.2.123", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From 18e04156c8137451158fc255c977aa2e503380a9 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Mon, 11 Aug 2025 14:24:37 -0700 Subject: [PATCH 5/6] feat(amazonq): add back auto-approve (#2099) --- chat-client/src/client/tabs/tabFactory.ts | 2 +- .../agenticChat/agenticChatController.ts | 43 ++++- .../agenticChat/constants/constants.ts | 8 + .../agenticChat/tools/executeBash.ts | 31 ++-- .../agenticChat/tools/grepSearch.ts | 4 +- .../tools/mcp/mcpEventHandler.test.ts | 1 + .../agenticChat/tools/mcp/mcpEventHandler.ts | 148 +++++++++++------- .../agenticChat/tools/mcp/mcpManager.ts | 6 +- .../agenticChat/tools/mcp/mcpUtils.ts | 3 +- .../agenticChat/tools/toolShared.ts | 8 +- 10 files changed, 169 insertions(+), 85 deletions(-) diff --git a/chat-client/src/client/tabs/tabFactory.ts b/chat-client/src/client/tabs/tabFactory.ts index 3a6012471a..6340add2d8 100644 --- a/chat-client/src/client/tabs/tabFactory.ts +++ b/chat-client/src/client/tabs/tabFactory.ts @@ -202,7 +202,7 @@ Select code & ask me to explain, debug or optimize it, or type \`/\` for quick a tabBarButtons.push({ id: McpServerTabButtonId, icon: MynahIcons.TOOLS, - description: 'Configure MCP servers', + description: 'Configure MCP servers and Built-in tools', }) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index a082782d08..65c8c4d88c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -190,6 +190,9 @@ import { DEFAULT_WINDOW_REJECT_SHORTCUT, DEFAULT_MACOS_STOP_SHORTCUT, DEFAULT_WINDOW_STOP_SHORTCUT, + OUT_OF_WORKSPACE_WARNING_MSG, + CREDENTIAL_FILE_WARNING_MSG, + BINARY_FILE_WARNING_MSG, } from './constants/constants' import { AgenticChatError, @@ -1791,9 +1794,9 @@ export class AgenticChatController implements ChatHandlers { const tool = new Tool(this.#features) // For MCP tools, get the permission from McpManager - // const permission = McpManager.instance.getToolPerm('Built-in', toolUse.name) + const permission = McpManager.instance.getToolPerm('Built-in', toolUse.name) // If permission is 'alwaysAllow', we don't need to ask for acceptance - // const builtInPermission = permission !== 'alwaysAllow' + const builtInPermission = permission !== 'alwaysAllow' // Get the approved paths from the session const approvedPaths = session.approvedPaths @@ -1804,14 +1807,33 @@ export class AgenticChatController implements ChatHandlers { approvedPaths ) + const isExecuteBash = toolUse.name === EXECUTE_BASH + + // check if tool execution's path is out of workspace + const isOutOfWorkSpace = warning === OUT_OF_WORKSPACE_WARNING_MSG + // check if tool involved secured files + const isSecuredFilesInvoled = + warning === BINARY_FILE_WARNING_MSG || warning === CREDENTIAL_FILE_WARNING_MSG + // Honor built-in permission if available, otherwise use tool's requiresAcceptance - // const requiresAcceptance = builtInPermission || toolRequiresAcceptance + let toolRequiresAcceptance = + (builtInPermission || isOutOfWorkSpace || isSecuredFilesInvoled) ?? requiresAcceptance + + // if the command is read-only and in-workspace --> flip back to no approval needed + if ( + isExecuteBash && + commandCategory === CommandCategory.ReadOnly && + !isOutOfWorkSpace && + !requiresAcceptance + ) { + toolRequiresAcceptance = false + } - if (requiresAcceptance || toolUse.name === EXECUTE_BASH) { + if (toolRequiresAcceptance || isExecuteBash) { // for executeBash, we till send the confirmation message without action buttons const confirmationResult = this.#processToolConfirmation( toolUse, - requiresAcceptance, + toolRequiresAcceptance, warning, commandCategory, toolUse.name, @@ -1819,7 +1841,7 @@ export class AgenticChatController implements ChatHandlers { tabId ) cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult) - const isExecuteBash = toolUse.name === EXECUTE_BASH + if (isExecuteBash) { this.#telemetryController.emitInteractWithAgenticChat( 'GeneratedCommand', @@ -1830,7 +1852,7 @@ export class AgenticChatController implements ChatHandlers { this.#abTestingAllocation?.userVariation ) } - if (requiresAcceptance) { + if (toolRequiresAcceptance) { await this.waitForToolApproval( toolUse, chatResultStream, @@ -2880,7 +2902,7 @@ export class AgenticChatController implements ChatHandlers { body = builtInPermission ? `I need permission to read files.\n${formattedPaths.join('\n')}` : `I need permission to read files outside the workspace.\n${formattedPaths.join('\n')}` - } else { + } else if (toolName === 'listDirectory') { const readFilePath = (toolUse.input as unknown as ListDirectoryParams).path // Validate the path using our synchronous utility @@ -2890,6 +2912,11 @@ export class AgenticChatController implements ChatHandlers { body = builtInPermission ? `I need permission to list directories.\n\`${readFilePath}\`` : `I need permission to list directories outside the workspace.\n\`${readFilePath}\`` + } else { + const readFilePath = (toolUse.input as unknown as ListDirectoryParams).path + body = builtInPermission + ? `I need permission to search files.\n\`${readFilePath}\`` + : `I need permission to search files outside the workspace.\n\`${readFilePath}\`` } break } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index 09fbb20436..66a0a00221 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -88,3 +88,11 @@ export const DEFAULT_LINUX_STOP_SHORTCUT = 'Meta + ⇧ + ⌫' export const DEFAULT_MACOS_REJECT_SHORTCUT = '⇧ ⌘ R' export const DEFAULT_WINDOW_REJECT_SHORTCUT = 'Ctrl + ⇧ + R' export const DEFAULT_LINUX_REJECT_SHORTCUT = 'Meta + ⇧ + R' + +// Warning Message Constants +export const DESTRUCTIVE_COMMAND_WARNING_MSG = 'WARNING: Potentially destructive command detected:\n\n' +export const MUTATE_COMMAND_WARNING_MSG = 'Mutation command:\n\n' +export const OUT_OF_WORKSPACE_WARNING_MSG = 'Execution out of workspace scope:\n\n' +export const CREDENTIAL_FILE_WARNING_MSG = + 'WARNING: Command involves credential files that require secure permissions:\n\n' +export const BINARY_FILE_WARNING_MSG = 'WARNING: Command involves binary files that require secure permissions:\n\n' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/executeBash.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/executeBash.ts index 74662c4e37..b2af7827e4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/executeBash.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/executeBash.ts @@ -15,6 +15,15 @@ import { existsSync, statSync } from 'fs' import { parseBaseCommands } from '../utils/commandParser' import { BashCommandEvent, ChatTelemetryEventName } from '../../../shared/telemetry/types' +// Warning message +import { + BINARY_FILE_WARNING_MSG, + CREDENTIAL_FILE_WARNING_MSG, + DESTRUCTIVE_COMMAND_WARNING_MSG, + MUTATE_COMMAND_WARNING_MSG, + OUT_OF_WORKSPACE_WARNING_MSG, +} from '../constants/constants' + export enum CommandCategory { ReadOnly, Mutate, @@ -89,12 +98,6 @@ export const commandCategories = new Map([ ]) export const maxToolResponseSize: number = 1024 * 1024 // 1MB export const lineCount: number = 1024 -export const destructiveCommandWarningMessage = 'WARNING: Potentially destructive command detected:\n\n' -export const mutateCommandWarningMessage = 'Mutation command:\n\n' -export const outOfWorkspaceWarningmessage = 'Execution out of workspace scope:\n\n' -export const credentialFileWarningMessage = - 'WARNING: Command involves credential files that require secure permissions:\n\n' -export const binaryFileWarningMessage = 'WARNING: Command involves binary files that require secure permissions:\n\n' /** * Parameters for executing a command on the system shell. @@ -222,7 +225,7 @@ export class ExecuteBash { // Treat tilde paths as absolute paths (they will be expanded by the shell) return { requiresAcceptance: true, - warning: destructiveCommandWarningMessage, + warning: DESTRUCTIVE_COMMAND_WARNING_MSG, commandCategory: CommandCategory.Destructive, } } else if (!isAbsolute(arg) && params.cwd) { @@ -245,7 +248,7 @@ export class ExecuteBash { this.logging.info(`Detected credential file in command: ${fullPath}`) return { requiresAcceptance: true, - warning: credentialFileWarningMessage, + warning: CREDENTIAL_FILE_WARNING_MSG, commandCategory: CommandCategory.Mutate, } } @@ -255,7 +258,7 @@ export class ExecuteBash { this.logging.info(`Detected binary file in command: ${fullPath}`) return { requiresAcceptance: true, - warning: binaryFileWarningMessage, + warning: BINARY_FILE_WARNING_MSG, commandCategory: CommandCategory.Mutate, } } @@ -272,7 +275,7 @@ export class ExecuteBash { if (!isInWorkspace) { return { requiresAcceptance: true, - warning: outOfWorkspaceWarningmessage, + warning: OUT_OF_WORKSPACE_WARNING_MSG, commandCategory: highestCommandCategory, } } @@ -296,13 +299,13 @@ export class ExecuteBash { case CommandCategory.Destructive: return { requiresAcceptance: true, - warning: destructiveCommandWarningMessage, + warning: DESTRUCTIVE_COMMAND_WARNING_MSG, commandCategory: CommandCategory.Destructive, } case CommandCategory.Mutate: return { requiresAcceptance: true, - warning: mutateCommandWarningMessage, + warning: MUTATE_COMMAND_WARNING_MSG, commandCategory: CommandCategory.Mutate, } case CommandCategory.ReadOnly: @@ -324,7 +327,7 @@ export class ExecuteBash { if (!workspaceFolders || workspaceFolders.length === 0) { return { requiresAcceptance: true, - warning: outOfWorkspaceWarningmessage, + warning: OUT_OF_WORKSPACE_WARNING_MSG, commandCategory: highestCommandCategory, } } @@ -341,7 +344,7 @@ export class ExecuteBash { if (!isInWorkspace) { return { requiresAcceptance: true, - warning: outOfWorkspaceWarningmessage, + warning: OUT_OF_WORKSPACE_WARNING_MSG, commandCategory: highestCommandCategory, } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/grepSearch.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/grepSearch.ts index 9ae48ccae3..f1d52e01ee 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/grepSearch.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/grepSearch.ts @@ -7,6 +7,7 @@ import { ChildProcess, ChildProcessOptions } from '@aws/lsp-core/out/util/proces import path = require('path') import { dirname } from 'path' import { pathToFileURL } from 'url' +import { OUT_OF_WORKSPACE_WARNING_MSG } from '../constants/constants' export interface GrepSearchParams { path?: string @@ -81,7 +82,8 @@ export class GrepSearch { public async requiresAcceptance(params: GrepSearchParams): Promise { const path = this.getSearchDirectory(params.path) - return { requiresAcceptance: !workspaceUtils.isInWorkspace(getWorkspaceFolderPaths(this.workspace), path) } + const isInWorkspace = workspaceUtils.isInWorkspace(getWorkspaceFolderPaths(this.workspace), path) + return { requiresAcceptance: !isInWorkspace, warning: !isInWorkspace ? OUT_OF_WORKSPACE_WARNING_MSG : '' } } public async invoke(params: GrepSearchParams, token?: CancellationToken): Promise { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts index 01984a310e..e17ba22788 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts @@ -49,6 +49,7 @@ describe('McpEventHandler error handling', () => { }, agent: { getTools: sinon.stub().returns([]), + getBuiltInToolNames: sinon.stub().returns([]), }, lsp: {}, telemetry: { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index e58d848608..2d57630cbf 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -34,7 +34,7 @@ import { URI } from 'vscode-uri' interface PermissionOption { label: string value: string - description: string + description?: string } export class McpEventHandler { @@ -129,38 +129,42 @@ export class McpEventHandler { // Transform server configs into DetailedListItem objects const activeItems: DetailedListItem[] = [] const disabledItems: DetailedListItem[] = [] - const builtInItems: DetailedListItem[] = [] // Get built-in tools programmatically const allTools = this.#features.agent.getTools({ format: 'bedrock' }) - const mcpToolNames = new Set(mcpManager.getAllTools().map(tool => tool.toolName)) + const builtInToolNames = new Set(this.#features.agent.getBuiltInToolNames()) const builtInTools = allTools - .filter(tool => !mcpToolNames.has(tool.toolSpecification.name)) + .filter(tool => { + return builtInToolNames.has(tool.toolSpecification.name) && tool.toolSpecification.name !== 'fsReplace' + }) .map(tool => ({ name: tool.toolSpecification.name, - description: tool.toolSpecification.description || `${tool.toolSpecification.name} tool`, + description: + this.#getBuiltInToolDescription(tool.toolSpecification.name) || + tool.toolSpecification.description || + `${tool.toolSpecification.name} tool`, })) // Add built-in tools as a server in the active items - // activeItems.push({ - // title: 'Built-in', - // description: `${builtInTools.length} tools`, - // children: [ - // { - // groupName: 'serverInformation', - // children: [ - // { - // title: 'status', - // description: 'ENABLED', - // }, - // { - // title: 'toolcount', - // description: `${builtInTools.length}`, - // }, - // ], - // }, - // ], - // }) + activeItems.push({ + title: 'Built-in', + description: `${builtInTools.length} tools`, + children: [ + { + groupName: 'serverInformation', + children: [ + { + title: 'status', + description: 'ENABLED', + }, + { + title: 'toolcount', + description: `${builtInTools.length}`, + }, + ], + }, + ], + }) Array.from(mcpManagerServerConfigs.entries()).forEach(([serverName, config]) => { const toolsWithPermissions = mcpManager.getAllToolsWithPermissions(serverName) @@ -224,7 +228,7 @@ export class McpEventHandler { // Return the result in the expected format const header = { - title: 'MCP Servers', + title: 'MCP Servers and Built-in Tools', description: "Add MCP servers to extend Q's capabilities.", // only show error on list mcp server page if unable to read mcp.json file status: configLoadErrors @@ -288,7 +292,7 @@ export class McpEventHandler { return { id, header: { - title: 'MCP Servers', + title: 'MCP Servers and Built-in Tools', status: {}, description: `Add MCP servers to extend Q's capabilities.`, actions: [], @@ -810,17 +814,23 @@ export class McpEventHandler { if (serverName === 'Built-in') { // Handle Built-in server specially const allTools = this.#features.agent.getTools({ format: 'bedrock' }) - const mcpToolNames = new Set(McpManager.instance.getAllTools().map(tool => tool.toolName)) + const builtInToolNames = new Set(this.#features.agent.getBuiltInToolNames()) + // combine fsWrite and fsReplace into fsWrite const builtInTools = allTools - .filter(tool => !mcpToolNames.has(tool.toolSpecification.name)) + .filter(tool => { + return ( + builtInToolNames.has(tool.toolSpecification.name) && tool.toolSpecification.name !== 'fsReplace' + ) + }) .map(tool => { - // Set default permission based on tool name - const permission = 'alwaysAllow' - + const permission = McpManager.instance.getToolPerm(serverName, tool.toolSpecification.name) return { tool: { toolName: tool.toolSpecification.name, - description: tool.toolSpecification.description || `${tool.toolSpecification.name} tool`, + description: + this.#getBuiltInToolDescription(tool.toolSpecification.name) || + tool.toolSpecification.description || + `${tool.toolSpecification.name} tool`, }, permission, } @@ -833,6 +843,7 @@ export class McpEventHandler { header: { title: serverName, status: serverStatusError || {}, + description: 'TOOLS', actions: [], }, list: [], @@ -1047,9 +1058,9 @@ export class McpEventHandler { // For Built-in server, use a special function that doesn't include the 'Deny' option let permissionOptions = this.#buildPermissionOptions() - // if (serverName === 'Built-in') { - // permissionOptions = this.#buildBuiltInPermissionOptions() - // } + if (serverName === 'Built-in') { + permissionOptions = this.#buildBuiltInPermissionOptions() + } filterOptions.push({ type: 'select', @@ -1057,6 +1068,9 @@ export class McpEventHandler { title: toolName, description: item.tool.description, options: permissionOptions, + ...(toolName === 'fsWrite' + ? { disabled: true, selectTooltip: 'Permission for this tool is not configurable yet' } + : {}), ...{ value: item.permission, boldTitle: true, mandatory: true, hideMandatoryIcon: true }, }) }) @@ -1120,33 +1134,57 @@ export class McpEventHandler { /** * Builds permission options for Built-in tools (no 'Disable' option) */ - // #buildBuiltInPermissionOptions(currentPermission: string) { - // const permissionOptions: PermissionOption[] = [] - - // if (currentPermission !== 'alwaysAllow') { - // permissionOptions.push({ - // label: 'Always run', - // value: 'alwaysAllow', - // }) - // } - - // if (currentPermission !== 'ask') { - // permissionOptions.push({ - // label: 'Ask to run', - // value: 'ask', - // }) - // } - - // return permissionOptions - // } + #buildBuiltInPermissionOptions() { + const permissionOptions: PermissionOption[] = [] + + permissionOptions.push({ + label: 'Ask', + value: 'ask', + description: 'Ask for your approval each time this tool is run', + }) + + permissionOptions.push({ + label: 'Always Allow', + value: 'alwaysAllow', + description: 'Always allow this tool to run without asking for approval', + }) + + return permissionOptions + } + + #getBuiltInToolDescription(toolName: string) { + switch (toolName) { + case 'fsRead': + return 'Read the content of files.' + case 'listDirectory': + return 'List the structure of a directory and its subdirectories.' + case 'fileSearch': + return 'Search for files and directories using fuzzy name matching.' + case 'executeBash': + return 'Run shell or powershell commands.\n\nNote: read-only commands are auto-run' + case 'fsWrite': + case 'fsReplace': + return 'Create or edit files.' + case 'qCodeReview': + return 'Review tool analyzes code for security vulnerabilities, quality issues, and best practices across multiple programming languages.' + default: + return '' + } + } /** * Handles MCP permission change events to update the pending permission config without applying changes */ async #handleMcpPermissionChange(params: McpServerClickParams) { const serverName = params.title - const updatedPermissionConfig = params.optionsValues + // combine fsWrite and fsReplace into fsWrite + if (serverName === 'Built-in' && params.optionsValues?.fsWrite) { + // add fsReplace along + params.optionsValues.fsReplace = params.optionsValues.fsWrite + } + + const updatedPermissionConfig = params.optionsValues if (!serverName || !updatedPermissionConfig) { return { id: params.id } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 04f827ff2c..47ce750a63 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -493,7 +493,7 @@ export class McpManager { */ public getToolPerm(server: string, tool: string): McpPermissionType { // For built-in tools, check directly without prefix - if (server === 'builtIn') { + if (server === 'Built-in') { return this.agentConfig.allowedTools.includes(tool) ? McpPermissionType.alwaysAllow : McpPermissionType.ask } @@ -937,7 +937,7 @@ export class McpManager { // Process each tool permission for (const [toolName, permission] of Object.entries(perm.toolPerms || {})) { - const toolId = `${serverPrefix}/${toolName}` + const toolId = (unsanitizedServerName !== 'Built-in' ? `${serverPrefix}/` : '') + `${toolName}` if (permission === McpPermissionType.deny) { // For deny: if server is enabled as a whole, we need to switch to individual tools @@ -1077,7 +1077,7 @@ export class McpManager { */ public requiresApproval(server: string, tool: string): boolean { // For built-in tools, check directly without prefix - if (server === 'builtIn') { + if (server === 'Built-in') { return !this.agentConfig.allowedTools.includes(tool) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 45ab34170c..0b45e9031c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -10,6 +10,7 @@ import path = require('path') import { QClientCapabilities } from '../../../configuration/qConfigurationServer' import crypto = require('crypto') import { Features } from '@aws/language-server-runtimes/server-interface/server' +import { EXECUTE_BASH } from '../../constants/toolConstants' /** * Load, validate, and parse MCP server configurations from JSON files. @@ -696,7 +697,7 @@ export function convertPersonaToAgent( // Add default allowed tools const writeToolNames = new Set(featureAgent.getBuiltInWriteToolNames()) - const defaultAllowedTools = featureAgent.getBuiltInToolNames().filter(toolName => !writeToolNames.has(toolName)) + const defaultAllowedTools = featureAgent.getBuiltInToolNames().filter(toolName => toolName !== EXECUTE_BASH) for (const toolName of defaultAllowedTools) { if (!agent.allowedTools.includes(toolName)) { agent.allowedTools.push(toolName) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolShared.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolShared.ts index 0303b7fc81..0314bdd754 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolShared.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolShared.ts @@ -3,6 +3,7 @@ import { workspaceUtils } from '@aws/lsp-core' import { getWorkspaceFolderPaths } from '@aws/lsp-core/out/util/workspaceUtils' import * as path from 'path' import { CommandCategory } from './executeBash' +import { OUT_OF_WORKSPACE_WARNING_MSG } from '../constants/constants' interface Output { kind: Kind @@ -127,10 +128,13 @@ export async function requiresPathAcceptance( if (logging) { logging.debug('No workspace folders found when checking file acceptance') } - return { requiresAcceptance: true } + return { requiresAcceptance: true, warning: OUT_OF_WORKSPACE_WARNING_MSG } } const isInWorkspace = workspaceUtils.isInWorkspace(workspaceFolders, path) - return { requiresAcceptance: !isInWorkspace } + return { + requiresAcceptance: !isInWorkspace, + warning: !isInWorkspace ? OUT_OF_WORKSPACE_WARNING_MSG : undefined, + } } catch (error) { if (logging) { logging.error(`Error checking file acceptance: ${error}`) From 8f0a4bb5c45e81881a01b6f77ae1850ea1057edd Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Sat, 8 Nov 2025 18:27:33 -0800 Subject: [PATCH 6/6] feat(amazonq): add in-context permission update for built-in tools (#2062) * fix(amazonq): add warning to executeBash regardless perm;fix optionValue in perm fill with all tools * fix: retain built-in tool permissions; bump up mynah-ui version * fix(chat-client): add warning to shell chat card even auto-accept * feat(amazonq): add permission for built-in tools metric to AgenticChatWithToolUse * feat(amazonq): add telemtry when built-in tool permission update * feat: add tool permission update in chat item card * feat: add hyperlink in description of in-context permission card * feat(chat-client): fix in-context dropdown * fix(chat-client): add missing type to render the dropdown * fix(amazonq): rename dropdown to quickSettings to be more semantic * feat(chat-client): add quickSettings to mcp approval chat card; clean up * feat(amazonq): re-name auto-run-command to trust-command for pairty with Kiro * chore: refactor logic * fix(chat-client): fix description hyperlink in permission quickSettings; clean up * refactor: clean up code * fix(chat-client): update text to align with mock * feat(chat-client): add in-context permission update to Mcp tools * feat(amazonq): add auto-approve back * fix: agentPath in processPermissionUpdates is undefined for builtInTools * fix(amazonq): remove in-context for mcp --- .../agenticChat/agenticChatController.ts | 91 ++++++++++++------- .../agenticChat/tools/mcp/mcpEventHandler.ts | 40 ++++++-- .../agenticChat/tools/mcp/mcpManager.ts | 2 +- .../agenticChat/tools/mcp/mcpUtils.ts | 26 ++++-- .../chat/telemetry/chatTelemetryController.ts | 8 +- 5 files changed, 116 insertions(+), 51 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 65c8c4d88c..c7b7cde3ba 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -166,7 +166,7 @@ import { CancellationError, workspaceUtils } from '@aws/lsp-core' import { FsRead, FsReadParams } from './tools/fsRead' import { ListDirectory, ListDirectoryParams } from './tools/listDirectory' import { FsWrite, FsWriteParams } from './tools/fsWrite' -import { ExecuteBash, ExecuteBashParams } from './tools/executeBash' +import { commandCategories, ExecuteBash, ExecuteBashParams } from './tools/executeBash' import { ExplanatoryParams, InvokeOutput, ToolApprovalException } from './tools/toolShared' import { validatePathBasic, validatePathExists, validatePaths as validatePathsSync } from './utils/pathValidation' import { GrepSearch, SanitizedRipgrepOutput } from './tools/grepSearch' @@ -233,7 +233,7 @@ import { getLatestAvailableModel } from './utils/agenticChatControllerHelper' import { ActiveUserTracker } from '../../shared/activeUserTracker' import { UserContext } from '../../client/token/codewhispererbearertokenclient' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' -import { McpPermissionType } from './tools/mcp/mcpTypes' +import { McpPermissionType, MCPServerPermission } from './tools/mcp/mcpTypes' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' @@ -407,24 +407,23 @@ export class AgenticChatController implements ChatHandlers { if (params.buttonId === BUTTON_TRUST_COMMAND) { // get result from metadata const toolName = params.metadata!['toolName'] - const newPermission = params.metadata!['permission'] + const new_permission = params.metadata!['permission'] const serverName = params.metadata!['serverName'] - const currentPermission = McpManager.instance.getToolPerm(serverName, toolName) + const current_permission = McpManager.instance.getToolPerm(serverName, toolName) // only trigger update if curren != previous - if (currentPermission !== newPermission) { + if (current_permission !== new_permission) { // generate perm object const perm = await this.#mcpEventHandler.generateEmptyBuiltInToolPermission() // load updated permission - perm.toolPerms[toolName] = newPermission as McpPermissionType + perm.toolPerms[toolName] = new_permission as McpPermissionType // update permission try { await McpManager.instance.updateServerPermission(serverName, perm) // if the new permission is asks --> only update permission, dont continue - // this only happen on a completed card - if (newPermission === 'ask') { + if (new_permission === 'ask') { return { success: true, } @@ -449,7 +448,6 @@ export class AgenticChatController implements ChatHandlers { params.messageId.endsWith(SUFFIX_PERMISSION) ? params.messageId.replace(SUFFIX_PERMISSION, '') : params.messageId - const handler = session.data.getDeferredToolExecution(messageId) if (!handler?.reject || !handler.resolve) { if (params.buttonId === BUTTON_TRUST_COMMAND) { @@ -1460,6 +1458,18 @@ export class AgenticChatController implements ChatHandlers { metric.setDimension('requestIds', metric.metric.requestIds) const toolNames = this.#toolUseLatencies.map(item => item.toolName) const toolUseIds = this.#toolUseLatencies.map(item => item.toolUseId) + + const builtInToolNames = new Set(this.#features.agent.getBuiltInToolNames()) + const permission: string[] = [] + + for (const toolName of toolNames) { + if (builtInToolNames.has(toolName)) { + permission.push(McpManager.instance.getToolPerm('Built-in', toolName)) + } else { + // TODO: determine mcp-server of the current tool to get permission + } + } + this.#telemetryController.emitAgencticLoop_InvokeLLM( response.$metadata.requestId!, conversationId, @@ -1475,7 +1485,8 @@ export class AgenticChatController implements ChatHandlers { this.#timeBetweenChunks, session.pairProgrammingMode, this.#abTestingAllocation?.experimentName, - this.#abTestingAllocation?.userVariation + this.#abTestingAllocation?.userVariation, + permission ) } else { // Send an error card to UI? @@ -1708,6 +1719,7 @@ export class AgenticChatController implements ChatHandlers { promptBlockId: number, session: ChatSessionService, toolName: string, + commandCategory?: CommandCategory, tabId?: string ) { const deferred = this.#createDeferred() @@ -1716,7 +1728,7 @@ export class AgenticChatController implements ChatHandlers { await deferred.promise // Note: we want to overwrite the button block because it already exists in the stream. await resultStream.overwriteResultBlock( - this.#getUpdateToolConfirmResult(toolUse, true, toolName, tabId), + this.#getUpdateToolConfirmResult(toolUse, true, toolName, undefined, commandCategory, tabId), promptBlockId ) } @@ -1772,6 +1784,10 @@ export class AgenticChatController implements ChatHandlers { }) } } + + // for later use + let finalCommandCategory: CommandCategory | undefined + switch (toolUse.name) { case FS_READ: case LIST_DIRECTORY: @@ -1807,6 +1823,8 @@ export class AgenticChatController implements ChatHandlers { approvedPaths ) + finalCommandCategory = commandCategory + const isExecuteBash = toolUse.name === EXECUTE_BASH // check if tool execution's path is out of workspace @@ -1837,7 +1855,7 @@ export class AgenticChatController implements ChatHandlers { warning, commandCategory, toolUse.name, - undefined, + builtInPermission, tabId ) cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult) @@ -1859,6 +1877,7 @@ export class AgenticChatController implements ChatHandlers { cachedButtonBlockId, session, toolUse.name, + commandCategory, tabId ) } @@ -1913,7 +1932,7 @@ export class AgenticChatController implements ChatHandlers { requiresAcceptance, warning, undefined, - toolName, // Pass the original tool name here + toolName, // Pass the original tool name here, undefined, tabId ) @@ -1924,6 +1943,7 @@ export class AgenticChatController implements ChatHandlers { cachedButtonBlockId, session, toolName, + undefined, tabId ) } @@ -1976,7 +1996,7 @@ export class AgenticChatController implements ChatHandlers { session.addApprovedPath(inputPath) } - const ws = this.#getWritableStream(chatResultStream, toolUse) + const ws = this.#getWritableStream(chatResultStream, toolUse, finalCommandCategory) const result = await this.#features.agent.runTool(toolUse.name, toolUse.input, token, ws) let toolResultContent: ToolResultContentBlock @@ -2394,7 +2414,11 @@ export class AgenticChatController implements ChatHandlers { }) } - #getWritableStream(chatResultStream: AgenticChatResultStream, toolUse: ToolUse): WritableStream | undefined { + #getWritableStream( + chatResultStream: AgenticChatResultStream, + toolUse: ToolUse, + commandCategory?: CommandCategory + ): WritableStream | undefined { if (toolUse.name === CodeReview.toolName) { return this.#getToolOverWritableStream(chatResultStream, toolUse) } @@ -2413,7 +2437,14 @@ export class AgenticChatController implements ChatHandlers { const completedHeader: ChatMessage['header'] = { body: 'shell', - status: { status: 'success', icon: 'ok', text: 'Completed' }, + status: { + status: 'success', + icon: 'ok', + text: 'Completed', + ...(toolUse.name === EXECUTE_BASH + ? { description: this.#getCommandCategoryDescription(commandCategory ?? CommandCategory.ReadOnly) } + : {}), + }, buttons: [], } @@ -2465,10 +2496,11 @@ export class AgenticChatController implements ChatHandlers { isAccept: boolean, originalToolName: string, toolType?: string, + commandCategory?: CommandCategory, tabId?: string ): ChatResult { const toolName = originalToolName ?? (toolType || toolUse.name) - + const quickSettings = this.#buildQuickSettings(toolUse, toolName!, toolType, tabId) // Handle bash commands with special formatting if (toolName === EXECUTE_BASH) { return { @@ -2488,6 +2520,7 @@ export class AgenticChatController implements ChatHandlers { }), buttons: isAccept ? [this.#renderStopShellCommandButton()] : [], }, + quickSettings, } } @@ -2775,13 +2808,8 @@ export class AgenticChatController implements ChatHandlers { const quickSettings = this.#buildQuickSettings(toolUse, toolName!, toolType, tabId) // Configure tool-specific UI elements switch (toolName) { - case EXECUTE_BASH: { + case 'executeBash': { const commandString = (toolUse.input as unknown as ExecuteBashParams).command - // get feature flag - const shortcut = - this.#features.lsp.getClientInitializeParams()?.initializationOptions?.aws?.awsClientCapabilities?.q - ?.shortcut - const runKey = this.#getKeyBinding('aws.amazonq.runCmdExecution') const rejectKey = this.#getKeyBinding('aws.amazonq.rejectCmdExecution') @@ -2817,16 +2845,12 @@ export class AgenticChatController implements ChatHandlers { : undefined header = { - status: requiresAcceptance - ? { - icon: statusIcon, - status: statusType, - position: 'left', - description: this.#getCommandCategoryDescription( - commandCategory ?? CommandCategory.ReadOnly - ), - } - : {}, + status: { + icon: statusIcon, + status: statusType, + position: 'left', + description: this.#getCommandCategoryDescription(commandCategory ?? CommandCategory.ReadOnly), + }, body: 'shell', buttons, } @@ -2944,6 +2968,7 @@ export class AgenticChatController implements ChatHandlers { messageId: this.#getMessageIdForToolUse(toolType, toolUse), header, body: warning ? (toolName === EXECUTE_BASH ? '' : '\n\n') + body : body, + quickSettings, } } else { return { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index 2d57630cbf..49911a9df0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -34,7 +34,7 @@ import { URI } from 'vscode-uri' interface PermissionOption { label: string value: string - description?: string + description: string } export class McpEventHandler { @@ -1165,7 +1165,7 @@ export class McpEventHandler { case 'fsWrite': case 'fsReplace': return 'Create or edit files.' - case 'qCodeReview': + case 'codeReview': return 'Review tool analyzes code for security vulnerabilities, quality issues, and best practices across multiple programming languages.' default: return '' @@ -1178,12 +1178,6 @@ export class McpEventHandler { async #handleMcpPermissionChange(params: McpServerClickParams) { const serverName = params.title - // combine fsWrite and fsReplace into fsWrite - if (serverName === 'Built-in' && params.optionsValues?.fsWrite) { - // add fsReplace along - params.optionsValues.fsReplace = params.optionsValues.fsWrite - } - const updatedPermissionConfig = params.optionsValues if (!serverName || !updatedPermissionConfig) { return { id: params.id } @@ -1258,6 +1252,33 @@ export class McpEventHandler { transportType: transportType, languageServerVersion: this.#features.runtime.serverInfo.version, }) + } else { + // it's mean built-in tool, but do another extra check to confirm + if (serverName === 'Built-in') { + let toolName: string[] = [] + let perm: string[] = [] + + for (const [key, val] of Object.entries(permission.toolPerms)) { + toolName.push(key) + perm.push(val) + } + + this.#telemetryController?.emitMCPServerInitializeEvent({ + source: 'updatePermission', + command: 'Built-in', + enabled: true, + numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length, + scope: + permission.__configPath__ === + getGlobalAgentConfigPath(this.#features.workspace.fs.getUserHomeDir()) + ? 'global' + : 'workspace', + transportType: '', + languageServerVersion: this.#features.runtime.serverInfo.version, + toolName: toolName, + permission: perm, + }) + } } // Clear the pending permission config after applying @@ -1398,10 +1419,11 @@ export class McpEventHandler { * Processes permission updates from the UI */ async #processPermissionUpdates(serverName: string, updatedPermissionConfig: any, agentPath: string | undefined) { + const builtInToolAgentPath = await this.#getAgentPath() const perm: MCPServerPermission = { enabled: true, toolPerms: {}, - __configPath__: agentPath, + __configPath__: serverName === 'Built-in' ? builtInToolAgentPath : agentPath, } // Process each tool permission setting diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 47ce750a63..acf2290887 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -456,7 +456,7 @@ export class McpManager { */ public isToolDisabled(server: string, tool: string): boolean { // built-in tools cannot be disabled - if (server === 'builtIn') { + if (server === 'Built-in') { return false } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 0b45e9031c..fdf03b7740 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -628,7 +628,8 @@ export function enabledMCP(params: InitializeParams | undefined): boolean { export function convertPersonaToAgent( persona: PersonaConfig, mcpServers: Record, - featureAgent: Agent + featureAgent: Agent, + existingAgentConfig: AgentConfig | undefined ): AgentConfig { const agent: AgentConfig = { name: 'default-agent', @@ -695,12 +696,22 @@ export function convertPersonaToAgent( } } - // Add default allowed tools - const writeToolNames = new Set(featureAgent.getBuiltInWriteToolNames()) + // handle permission of built-in tools + // check if agent config exists const defaultAllowedTools = featureAgent.getBuiltInToolNames().filter(toolName => toolName !== EXECUTE_BASH) - for (const toolName of defaultAllowedTools) { - if (!agent.allowedTools.includes(toolName)) { - agent.allowedTools.push(toolName) + if (!existingAgentConfig) { + // not yet created --> add all defaults tools + for (const toolName of defaultAllowedTools) { + if (!agent.allowedTools.includes(toolName)) { + agent.allowedTools.push(toolName) + } + } + } else { + // only consider tools that are not in existingAgentConfig + for (const toolName of defaultAllowedTools) { + if (!agent.allowedTools.includes(toolName) && !existingAgentConfig.tools.includes(toolName)) { + agent.allowedTools.push(toolName) + } } } @@ -909,7 +920,8 @@ async function migrateConfigToAgent( } // Convert to agent config - const newAgentConfig = convertPersonaToAgent(personaConfig, serverConfigs, agent) + logging.info('Migrating started') + const newAgentConfig = convertPersonaToAgent(personaConfig, serverConfigs, agent, existingAgentConfig) newAgentConfig.includedFiles = ['AmazonQ.md', 'README.md', '.amazonq/rules/**/*.md'] newAgentConfig.resources = [] // Initialize with empty array diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 8e9cb92624..69813e8bd4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -195,7 +195,8 @@ export class ChatTelemetryController { cwsprChatTimeBetweenChunks?: number[], agenticCodingMode?: boolean, experimentName?: string, - userVariation?: string + userVariation?: string, + permission?: string[] ) { this.#telemetry.emitMetric({ name: ChatTelemetryEventName.AgencticLoop_InvokeLLM, @@ -216,6 +217,7 @@ export class ChatTelemetryController { modelId, experimentName: experimentName, userVariation: userVariation, + permission: permission?.join(',') ?? '', }, }) } @@ -385,6 +387,8 @@ export class ChatTelemetryController { source?: string transportType?: string languageServerVersion?: string + toolName?: string[] + permission?: string[] }) { this.#telemetry.emitMetric({ name: ChatTelemetryEventName.MCPServerInit, @@ -399,6 +403,8 @@ export class ChatTelemetryController { scope: data?.scope, source: data?.source, transportType: data?.transportType, + toolName: data?.toolName?.join(',') ?? '', + permission: data?.permission?.join(',') ?? '', }, }) }