Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions packages/amazonq/src/lsp/chat/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu
type: 'customization',
customization: undefinedIfEmpty(getSelectedCustomization().arn),
})
}),
globals.logOutputChannel.onDidChangeLogLevel((logLevel) => {
getLogger('amazonqLsp').info(`Local log level changed to ${logLevel}, notifying LSP`)
void pushConfigUpdate(languageClient, {
type: 'logLevel',
})
})
)
}
Expand All @@ -98,16 +104,24 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu
* 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 },
})
switch (config.type) {
case 'profile':
await client.sendRequest(updateConfigurationRequestType.method, {
section: 'aws.q',
settings: { profileArn: config.profileArn },
})
break
case 'customization':
client.sendNotification(DidChangeConfigurationNotification.type.method, {
section: 'aws.q',
settings: { customization: config.customization },
})
break
case 'logLevel':
client.sendNotification(DidChangeConfigurationNotification.type.method, {
section: 'aws.logLevel',
})
break
}
}
type ProfileConfig = {
Expand All @@ -118,4 +132,7 @@ type CustomizationConfig = {
type: 'customization'
customization: string | undefined
}
type QConfigs = ProfileConfig | CustomizationConfig
type LogLevelConfig = {
type: 'logLevel'
}
type QConfigs = ProfileConfig | CustomizationConfig | LogLevelConfig
81 changes: 46 additions & 35 deletions packages/amazonq/src/lsp/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from 'aws-core-vscode/shared'
import { activate } from './chat/activation'
import { AmazonQResourcePaths } from './lspInstaller'
import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config'

const localize = nls.loadMessageBundle()
const logger = getLogger('amazonqLsp.lspClient')
Expand Down Expand Up @@ -80,42 +81,11 @@ export async function startLanguageServer(
*/
configuration: async (params, token, next) => {
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,
optOutTelemetry: getOptOutPreference() === 'OPTOUT',
projectContext: {
// TODO: we might need another setting to control the actual indexing
enableLocalIndexing: true,
enableGpuAcceleration: CodeWhispererSettings.instance.isLocalIndexGPUEnabled(),
indexWorkerThreads: CodeWhispererSettings.instance.getIndexWorkerThreads(),
localIndexing: {
ignoreFilePatterns: CodeWhispererSettings.instance.getIndexIgnoreFilePatterns(),
maxFileSizeMB: CodeWhispererSettings.instance.getMaxIndexFileSize(),
maxIndexSizeMB: CodeWhispererSettings.instance.getMaxIndexSize(),
indexCacheDirPath: CodeWhispererSettings.instance.getIndexCacheDirPath(),
},
},
},
]
const section = params.items[0].section
if (!isValidConfigSection(section)) {
return config
}
if (params.items[0].section === 'aws.codeWhisperer') {
return [
{
includeSuggestionsWithCodeReferences:
CodeWhispererSettings.instance.isSuggestionsWithCodeReferencesEnabled(),
shareCodeWhispererContentWithAWS: !CodeWhispererSettings.instance.isOptoutEnabled(),
},
]
}
return config
return getConfigSection(section)
},
},
},
Expand All @@ -139,6 +109,7 @@ export async function startLanguageServer(
showSaveFileDialog: true,
},
},
logLevel: toAmazonQLSPLogLevel(globals.logOutputChannel.logLevel),
},
credentials: {
providesBearerToken: true,
Expand Down Expand Up @@ -296,3 +267,43 @@ function onServerRestartHandler(client: LanguageClient, auth: AmazonQLspAuth) {
await auth.refreshConnection(true)
})
}

function getConfigSection(section: ConfigSection) {
getLogger('amazonqLsp').debug('Fetching config section %s for language server', section)
switch (section) {
case 'aws.q':
/**
* 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: undefinedIfEmpty(getSelectedCustomization().arn),
optOutTelemetry: getOptOutPreference() === 'OPTOUT',
projectContext: {
// TODO: we might need another setting to control the actual indexing
enableLocalIndexing: true,
enableGpuAcceleration: CodeWhispererSettings.instance.isLocalIndexGPUEnabled(),
indexWorkerThreads: CodeWhispererSettings.instance.getIndexWorkerThreads(),
localIndexing: {
ignoreFilePatterns: CodeWhispererSettings.instance.getIndexIgnoreFilePatterns(),
maxFileSizeMB: CodeWhispererSettings.instance.getMaxIndexFileSize(),
maxIndexSizeMB: CodeWhispererSettings.instance.getMaxIndexSize(),
indexCacheDirPath: CodeWhispererSettings.instance.getIndexCacheDirPath(),
},
},
},
]
case 'aws.codeWhisperer':
return [
{
includeSuggestionsWithCodeReferences:
CodeWhispererSettings.instance.isSuggestionsWithCodeReferencesEnabled(),
shareCodeWhispererContentWithAWS: !CodeWhispererSettings.instance.isOptoutEnabled(),
},
]
case 'aws.logLevel':
Copy link
Contributor

@justinmk3 justinmk3 Apr 28, 2025

Choose a reason for hiding this comment

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

is this setting being added?

edit: oh, this is something sent to Q LSP, I think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not being added for us no. This is the section used to detect logging level changes for this notification based on their implementation here.

return [toAmazonQLSPLogLevel(globals.logOutputChannel.logLevel)]
}
}
26 changes: 25 additions & 1 deletion packages/amazonq/src/lsp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,34 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import * as vscode from 'vscode'
import { DevSettings, getServiceEnvVarConfig } from 'aws-core-vscode/shared'
import { LspConfig } from 'aws-core-vscode/amazonq'

export interface ExtendedAmazonQLSPConfig extends LspConfig {
ui?: string
}

// Taken from language server runtimes since they are not exported:
// https://github.com/aws/language-server-runtimes/blob/eae85672c345d8adaf4c8cbd741260b8a59750c4/runtimes/runtimes/util/loggingUtil.ts#L4-L10
const validLspLogLevels = ['error', 'warn', 'info', 'log', 'debug'] as const
export type LspLogLevel = (typeof validLspLogLevels)[number]
export const lspLogLevelMapping: Map<vscode.LogLevel, LspLogLevel> = new Map([
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be exported?

Suggested change
export const lspLogLevelMapping: Map<vscode.LogLevel, LspLogLevel> = new Map([
const lspLogLevelMapping: Map<vscode.LogLevel, LspLogLevel> = new Map([

[vscode.LogLevel.Error, 'error'],
[vscode.LogLevel.Warning, 'warn'],
[vscode.LogLevel.Info, 'info'],
[vscode.LogLevel.Debug, 'log'],
[vscode.LogLevel.Trace, 'debug'],
[vscode.LogLevel.Off, 'error'], // TODO: once the language server supports a no-log setting, we can map to that.
])

const configSections = ['aws.q', 'aws.codeWhisperer', 'aws.logLevel'] as const
export type ConfigSection = (typeof configSections)[number]

export function isValidConfigSection(section: unknown): section is ConfigSection {
return typeof section === 'string' && configSections.includes(section as ConfigSection)
}

export const defaultAmazonQLspConfig: ExtendedAmazonQLSPConfig = {
manifestUrl: 'https://d3akiidp1wvqyg.cloudfront.net/qAgenticChatServer/0/manifest.json', // TODO swap this back
supportedVersions: '*', // TODO swap this back
Expand All @@ -26,3 +46,7 @@ export function getAmazonQLspConfig(): ExtendedAmazonQLSPConfig {
...getServiceEnvVarConfig('amazonqLsp', Object.keys(defaultAmazonQLspConfig)),
}
}

export function toAmazonQLSPLogLevel(logLevel: vscode.LogLevel): LspLogLevel {
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets explain why briefly: "Maps the VS Code log level to an equivalent Amazon Q language server log level, since they are not 1:1"

return lspLogLevelMapping.get(logLevel) ?? 'info'
}
4 changes: 2 additions & 2 deletions packages/core/src/shared/extensionGlobals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { ExtensionContext, OutputChannel } from 'vscode'
import { ExtensionContext, LogOutputChannel, OutputChannel } from 'vscode'
import { LoginManager } from '../auth/deprecated/loginManager'
import { AwsResourceManager } from '../dynamicResources/awsResourceManager'
import { AWSClientBuilder } from './awsClientBuilder'
Expand Down Expand Up @@ -191,7 +191,7 @@ export interface ToolkitGlobals {
/**
* Log messages. Use `outputChannel` for application messages.
*/
logOutputChannel: OutputChannel
logOutputChannel: LogOutputChannel
Copy link
Contributor Author

Choose a reason for hiding this comment

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

LogOutputChannel extends OutputChannel and includes the ability to add listeners.

loginManager: LoginManager
awsContextCommands: AwsContextCommands
awsContext: AwsContext
Expand Down
5 changes: 0 additions & 5 deletions packages/core/src/shared/logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ const logLevels = new Map<LogLevel, number>([
export type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug'

export function fromVscodeLogLevel(logLevel: vscode.LogLevel): LogLevel {
if (!vscode.LogLevel) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

minimum version has been bumped since this was written

// vscode version <= 1.73
return 'info'
}

switch (logLevel) {
case vscode.LogLevel.Trace:
case vscode.LogLevel.Debug:
Expand Down
Loading