From a808a9092696c85fef12e9d5d508a1ca4c9465a1 Mon Sep 17 00:00:00 2001 From: Josh Pinkney Date: Sat, 19 Apr 2025 11:40:46 -0400 Subject: [PATCH 1/4] save --- aws-toolkit-vscode.code-workspace | 3 ++ packages/amazonq/.vscode/launch.json | 6 ++-- packages/amazonq/src/lsp/chat/activation.ts | 28 +++++++++++++------ packages/amazonq/src/lsp/client.ts | 25 +++++++++++++++-- .../codewhisperer/util/customizationUtil.ts | 3 ++ packages/core/src/shared/index.ts | 2 +- 6 files changed, 53 insertions(+), 14 deletions(-) diff --git a/aws-toolkit-vscode.code-workspace b/aws-toolkit-vscode.code-workspace index f03aafae2fe..479f9e8fd66 100644 --- a/aws-toolkit-vscode.code-workspace +++ b/aws-toolkit-vscode.code-workspace @@ -12,6 +12,9 @@ { "path": "packages/amazonq", }, + { + "path": "../language-servers", + }, ], "settings": { "typescript.tsdk": "node_modules/typescript/lib", diff --git a/packages/amazonq/.vscode/launch.json b/packages/amazonq/.vscode/launch.json index d6ed103c42e..e151c1d5bd4 100644 --- a/packages/amazonq/.vscode/launch.json +++ b/packages/amazonq/.vscode/launch.json @@ -13,9 +13,9 @@ "args": ["--extensionDevelopmentPath=${workspaceFolder}"], "env": { "SSMDOCUMENT_LANGUAGESERVER_PORT": "6010", - "WEBPACK_DEVELOPER_SERVER": "http://localhost:8080" - // "__AMAZONQLSP_PATH": "${workspaceFolder}/../../../language-servers/app/aws-lsp-codewhisperer-runtimes/out/agent-standalone.js", - // "__AMAZONQLSP_UI": "${workspaceFolder}/../../../language-servers/chat-client/build/amazonq-ui.js" + "WEBPACK_DEVELOPER_SERVER": "http://localhost:8080", + "__AMAZONQLSP_PATH": "${workspaceFolder}/../../../language-servers/app/aws-lsp-codewhisperer-runtimes/out/agent-standalone.js", + "__AMAZONQLSP_UI": "${workspaceFolder}/../../../language-servers/chat-client/build/amazonq-ui.js" }, "envFile": "${workspaceFolder}/.local.env", "outFiles": ["${workspaceFolder}/dist/**/*.js", "${workspaceFolder}/../core/dist/**/*.js"], diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index a4b251ce834..8dae10bb1af 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -8,17 +8,19 @@ import { LanguageClient } from 'vscode-languageclient' import { AmazonQChatViewProvider } from './webviewProvider' import { registerCommands } from './commands' import { registerLanguageServerEventListener, registerMessageListeners } from './messages' -import { getLogger, globals } from 'aws-core-vscode/shared' +import { Commands, getLogger, globals, undefinedIfEmpty } from 'aws-core-vscode/shared' import { activate as registerLegacyChatListeners } from '../../app/chat/activation' import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq' -import { AuthUtil } from 'aws-core-vscode/codewhisperer' +import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' import { updateConfigurationRequestType } from '@aws/language-server-runtimes/protocol' export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) { const disposables = globals.context.subscriptions // Make sure we've sent an auth profile to the language server before even initializing the UI - await updateProfile(languageClient) + await updateConfiguration(languageClient, { + profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, + }) const provider = new AmazonQChatViewProvider(mynahUIPath) @@ -60,18 +62,28 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu disposables.push( AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => { - void updateProfile(languageClient) + void updateConfiguration(languageClient, { + profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, + }) await provider.refreshWebview() + }), + Commands.register('aws.amazonq.updateCustomizations', () => { + void updateConfiguration(languageClient, { + customization: undefinedIfEmpty(getSelectedCustomization().arn), + }) }) ) } -async function updateProfile(client: LanguageClient) { +async function updateConfiguration( + client: LanguageClient, + settings: { + [key: string]: string | undefined + } +) { // update the profile on the language server await client.sendRequest(updateConfigurationRequestType.method, { section: 'aws.q', - settings: { - profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, - }, + settings, }) } diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 42b621be550..28a2eb19099 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -9,7 +9,6 @@ import * as crypto from 'crypto' import { LanguageClient, LanguageClientOptions, RequestType } from 'vscode-languageclient' import { InlineCompletionManager } from '../app/inline/completion' import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth' -import { AuthUtil } from 'aws-core-vscode/codewhisperer' import { ConnectionMetadata, CreateFilesParams, @@ -22,6 +21,7 @@ import { updateConfigurationRequestType, WorkspaceFolder, } from '@aws/language-server-runtimes/protocol' +import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' import { Settings, oidcClientName, @@ -32,6 +32,8 @@ import { oneSecond, validateNodeExe, getLogger, + undefinedIfEmpty, + getOptOutPreference, } from 'aws-core-vscode/shared' import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' @@ -74,17 +76,36 @@ export async function startLanguageServer( documentSelector, middleware: { workspace: { + /** + * Convert VSCode settings format to be compatible with flare's configs + */ configuration: async (params, token, next) => { const config = await next(params, token) if (params.items[0].section === 'aws.q') { + const customization = undefinedIfEmpty(getSelectedCustomization().arn) return [ { + customization, + optOutTelemetryPreference: getOptOutPreference(), projectContext: { - enableLocalIndexing: true, + // TODO uncomment this when local indexing is in agent chat server manifest + enableLocalIndexing: false, }, }, ] } + if (params.items[0].section === 'aws.codeWhisperer') { + return [ + { + includeSuggestionsWithCodeReferences: vscode.workspace + .getConfiguration() + .get('amazonQ.showCodeWithReferences'), + shareCodeWhispererContentWithAWS: vscode.workspace + .getConfiguration() + .get('amazonQ.shareContentWithAWS'), + }, + ] + } return config }, }, diff --git a/packages/core/src/codewhisperer/util/customizationUtil.ts b/packages/core/src/codewhisperer/util/customizationUtil.ts index 7898b7a17ba..d2bcc8ce703 100644 --- a/packages/core/src/codewhisperer/util/customizationUtil.ts +++ b/packages/core/src/codewhisperer/util/customizationUtil.ts @@ -147,6 +147,9 @@ export const setSelectedCustomization = async (customization: Customization, isO } vsCodeState.isFreeTierLimitReached = false await Commands.tryExecute('aws.amazonq.refreshStatusBar') + + // hack: triggers amazon q to send the customizations back to flare + await Commands.tryExecute('aws.amazonq.updateCustomizations') } export const getPersistedCustomizations = (): Customization[] => { diff --git a/packages/core/src/shared/index.ts b/packages/core/src/shared/index.ts index c538d268240..4cda5285f69 100644 --- a/packages/core/src/shared/index.ts +++ b/packages/core/src/shared/index.ts @@ -27,7 +27,7 @@ export { Prompter } from './ui/prompter' export { VirtualFileSystem } from './virtualFilesystem' export { VirtualMemoryFile } from './virtualMemoryFile' export { AmazonqCreateUpload, Metric } from './telemetry/telemetry' -export { getClientId, getOperatingSystem } from './telemetry/util' +export { getClientId, getOperatingSystem, getOptOutPreference } from './telemetry/util' export { extensionVersion } from './vscode/env' export { cast } from './utilities/typeConstructors' export * as workspaceUtils from './utilities/workspaceUtils' From 0dc9542a856b9969883083d459c983a117572552 Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Sat, 19 Apr 2025 19:28:40 -0400 Subject: [PATCH 2/4] Fix optout telemetry setting being sent to flare Just needed to fix the value to match that of the one in configurationUtils.ts Signed-off-by: nkomonen-amazon --- packages/amazonq/src/lsp/client.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 28a2eb19099..6d1e65c295b 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -83,10 +83,15 @@ export async function startLanguageServer( const config = await next(params, token) if (params.items[0].section === 'aws.q') { const customization = undefinedIfEmpty(getSelectedCustomization().arn) + /** + * IMPORTANT: This object is parsed by the following code in the language server, **so + * it must match that expected shape**. + * https://github.com/aws/language-servers/blob/1d2ca018f2248106690438b860d40a7ee67ac728/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/configurationUtils.ts#L114 + */ return [ { customization, - optOutTelemetryPreference: getOptOutPreference(), + optOutTelemetry: getOptOutPreference() === 'OPTOUT', projectContext: { // TODO uncomment this when local indexing is in agent chat server manifest enableLocalIndexing: false, From 05abaf060ce00f8739d8431bc7e7727bdb68b0e8 Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Sun, 20 Apr 2025 00:44:07 -0400 Subject: [PATCH 3/4] fix customizations change not being synced to lsp Problem: A message was already set up in a previous commit to send the lsp a message when the Q customization model was changed, but it didn't work as expected. Solution: There are different lsp messages sent to indicate a change in user settings. For auth Q profile it is one type of Request, and for the customization selection, it uses a different lsp notification. Each type of message has its own handler in the language server, so if we send the message using the wrong message type, it will not be handled correctly since the correct handler is somewhere else. The notable handling functions were: - getAmazonQRelatedWorkspaceConfigs(), where it is part of the handler for `didChangeConfiguration()` - setupConfigurationListeners(), where it is part of the handler for `onUpdateConfiguration()` Signed-off-by: nkomonen-amazon --- packages/amazonq/src/lsp/chat/activation.ts | 52 +++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index 8dae10bb1af..3592c66fed4 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -12,13 +12,17 @@ import { Commands, getLogger, globals, undefinedIfEmpty } from 'aws-core-vscode/ import { activate as registerLegacyChatListeners } from '../../app/chat/activation' import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq' import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' -import { updateConfigurationRequestType } from '@aws/language-server-runtimes/protocol' +import { + DidChangeConfigurationNotification, + updateConfigurationRequestType, +} from '@aws/language-server-runtimes/protocol' export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) { const disposables = globals.context.subscriptions // Make sure we've sent an auth profile to the language server before even initializing the UI - await updateConfiguration(languageClient, { + await pushConfigUpdate(languageClient, { + type: 'profile', profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, }) @@ -62,28 +66,48 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu disposables.push( AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => { - void updateConfiguration(languageClient, { + void pushConfigUpdate(languageClient, { + type: 'profile', profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, }) await provider.refreshWebview() }), Commands.register('aws.amazonq.updateCustomizations', () => { - void updateConfiguration(languageClient, { + void pushConfigUpdate(languageClient, { + type: 'customization', customization: undefinedIfEmpty(getSelectedCustomization().arn), }) }) ) } -async function updateConfiguration( - client: LanguageClient, - settings: { - [key: string]: string | undefined +/** + * Push a config value to the language server, effectively updating it with the + * latest configuration from the client. + * + * The issue is we need to push certain configs to different places, since there are + * different handlers for specific configs. So this determines the correct place to + * push the given config. + */ +async function pushConfigUpdate(client: LanguageClient, config: QConfigs) { + if (config.type === 'profile') { + await client.sendRequest(updateConfigurationRequestType.method, { + section: 'aws.q', + settings: { profileArn: config.profileArn }, + }) + } else if (config.type === 'customization') { + client.sendNotification(DidChangeConfigurationNotification.type.method, { + section: 'aws.q', + settings: { customization: config.customization }, + }) } -) { - // update the profile on the language server - await client.sendRequest(updateConfigurationRequestType.method, { - section: 'aws.q', - settings, - }) } +type ProfileConfig = { + type: 'profile' + profileArn: string | undefined +} +type CustomizationConfig = { + type: 'customization' + customization: string | undefined +} +type QConfigs = ProfileConfig | CustomizationConfig From f303e56e7b63d15959d94fa8fe3607e3822bdbac Mon Sep 17 00:00:00 2001 From: nkomonen-amazon Date: Sun, 20 Apr 2025 14:20:33 -0400 Subject: [PATCH 4/4] Fix comments: - Remove some unrelated development related code - Enable local indexing Signed-off-by: nkomonen-amazon --- aws-toolkit-vscode.code-workspace | 3 --- packages/amazonq/.vscode/launch.json | 7 ++++--- packages/amazonq/src/lsp/client.ts | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/aws-toolkit-vscode.code-workspace b/aws-toolkit-vscode.code-workspace index 479f9e8fd66..f03aafae2fe 100644 --- a/aws-toolkit-vscode.code-workspace +++ b/aws-toolkit-vscode.code-workspace @@ -12,9 +12,6 @@ { "path": "packages/amazonq", }, - { - "path": "../language-servers", - }, ], "settings": { "typescript.tsdk": "node_modules/typescript/lib", diff --git a/packages/amazonq/.vscode/launch.json b/packages/amazonq/.vscode/launch.json index e151c1d5bd4..b00c5071ce5 100644 --- a/packages/amazonq/.vscode/launch.json +++ b/packages/amazonq/.vscode/launch.json @@ -13,9 +13,10 @@ "args": ["--extensionDevelopmentPath=${workspaceFolder}"], "env": { "SSMDOCUMENT_LANGUAGESERVER_PORT": "6010", - "WEBPACK_DEVELOPER_SERVER": "http://localhost:8080", - "__AMAZONQLSP_PATH": "${workspaceFolder}/../../../language-servers/app/aws-lsp-codewhisperer-runtimes/out/agent-standalone.js", - "__AMAZONQLSP_UI": "${workspaceFolder}/../../../language-servers/chat-client/build/amazonq-ui.js" + "WEBPACK_DEVELOPER_SERVER": "http://localhost:8080" + // Below allows for overrides used during development + // "__AMAZONQLSP_PATH": "${workspaceFolder}/../../../language-servers/app/aws-lsp-codewhisperer-runtimes/out/agent-standalone.js", + // "__AMAZONQLSP_UI": "${workspaceFolder}/../../../language-servers/chat-client/build/amazonq-ui.js" }, "envFile": "${workspaceFolder}/.local.env", "outFiles": ["${workspaceFolder}/dist/**/*.js", "${workspaceFolder}/../core/dist/**/*.js"], diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 6d1e65c295b..b3205d009d6 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -93,8 +93,7 @@ export async function startLanguageServer( customization, optOutTelemetry: getOptOutPreference() === 'OPTOUT', projectContext: { - // TODO uncomment this when local indexing is in agent chat server manifest - enableLocalIndexing: false, + enableLocalIndexing: true, }, }, ]