Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion packages/amazonq/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
}
// This contains every lsp agnostic things (auth, security scan, code scan)
await activateCodeWhisperer(extContext as ExtContext)
if (Experiments.instance.get('amazonqLSP', false)) {
if (Experiments.instance.get('amazonqLSP', true)) {
await activateAmazonqLsp(context)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/amazonq/src/extensionNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async function activateAmazonQNode(context: vscode.ExtensionContext) {
extensionContext: context,
}

if (!Experiments.instance.get('amazonqChatLSP', false)) {
if (!Experiments.instance.get('amazonqChatLSP', true)) {
const appInitContext = DefaultAmazonQAppInitContext.instance
const provider = new AmazonQChatViewProvider(
context,
Expand Down
4 changes: 2 additions & 2 deletions packages/amazonq/src/lsp/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import vscode from 'vscode'
import { startLanguageServer } from './client'
import { AmazonQLspInstaller } from './lspInstaller'
import { lspSetupStage, ToolkitError } from 'aws-core-vscode/shared'
import { lspSetupStage, ToolkitError, messages } from 'aws-core-vscode/shared'

export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
try {
Expand All @@ -16,6 +16,6 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
})
} catch (err) {
const e = err as ToolkitError
void vscode.window.showInformationMessage(`Unable to launch amazonq language server: ${e.message}`)
void messages.showViewLogsMessage(`Failed to launch Amazon Q language server: ${e.message}`)
}
}
9 changes: 5 additions & 4 deletions packages/amazonq/src/lsp/chat/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ export function registerLanguageServerEventListener(languageClient: LanguageClie

const chatOptions = languageClient.initializeResult?.awsServerCapabilities?.chatOptions

// Enable the history/export feature flags
chatOptions.history = true
chatOptions.export = true
// overide the quick action commands provided by flare server initialization, which doesn't provide the group header
if (chatOptions?.quickActions?.quickActionsCommandGroups?.[0]) {
chatOptions.quickActions.quickActionsCommandGroups[0].groupName = 'Quick Actions'
}

provider.onDidResolveWebview(() => {
void provider.webview?.postMessage({
Expand Down Expand Up @@ -137,7 +138,7 @@ export function registerMessageListeners(
break
}
case DISCLAIMER_ACKNOWLEDGED: {
void AmazonQPromptSettings.instance.disablePrompt('amazonQChatDisclaimer')
void AmazonQPromptSettings.instance.update('amazonQChatDisclaimer', true)
break
}
case chatRequestType.method: {
Expand Down
20 changes: 3 additions & 17 deletions packages/amazonq/src/lsp/chat/webviewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
) {
this.webview = webviewView.webview

const lspDir = Uri.parse(LanguageServerResolver.defaultDir)
const lspDir = Uri.parse(LanguageServerResolver.defaultDir())
const dist = Uri.joinPath(globals.context.extensionUri, 'dist')
webviewView.webview.options = {
enableScripts: true,
Expand Down Expand Up @@ -68,7 +68,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
const isSM = isSageMaker('SMAI')
const isSMUS = isSageMaker('SMUS')
const disabledCommands = isSM ? `['/dev', '/transform', '/test', '/review', '/doc']` : '[]'
const disclaimerAcknowledged = AmazonQPromptSettings.instance.isPromptEnabled('amazonQChatDisclaimer')
const disclaimerAcknowledged = !AmazonQPromptSettings.instance.isPromptEnabled('amazonQChatDisclaimer')
const welcomeCount = globals.globalState.tryGet('aws.amazonq.welcomeChatShowCount', Number, 0)

// only show profile card when the two conditions
Expand Down Expand Up @@ -116,21 +116,7 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
const init = () => {
const vscodeApi = acquireVsCodeApi()
const hybridChatConnector = new HybridChatAdapter(${(await AuthUtil.instance.getChatAuthState()).amazonQ === 'connected'},${featureConfigData},${welcomeCount},${disclaimerAcknowledged},${regionProfileString},${disabledCommands},${isSMUS},${isSM},vscodeApi.postMessage)
const commands = [hybridChatConnector.initialQuickActions[0], {
groupName: 'Quick Actions',
commands: [
{
command: '/help',
icon: 'help',
description: 'Learn more about Amazon Q',
},
{
command: '/clear',
icon: 'trash',
description: 'Clear this session',
},
],
}]
const commands = [hybridChatConnector.initialQuickActions[0]]
amazonQChat.createChat(vscodeApi, {disclaimerAcknowledged: ${disclaimerAcknowledged}, quickActionCommands: commands}, hybridChatConnector);
}
</script>
Expand Down
32 changes: 23 additions & 9 deletions packages/amazonq/src/lsp/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ import { InlineCompletionManager } from '../app/inline/completion'
import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth'
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
import { ConnectionMetadata } from '@aws/language-server-runtimes/protocol'
import { Settings, oidcClientName, createServerOptions, globals, Experiments, Commands } from 'aws-core-vscode/shared'
import {
Settings,
oidcClientName,
createServerOptions,
globals,
Experiments,
Commands,
validateNodeExe,
getLogger,
} from 'aws-core-vscode/shared'
import { activate } from './chat/activation'
import { AmazonQResourcePaths } from './lspInstaller'

const localize = nls.loadMessageBundle()
const logger = getLogger('amazonqLsp.lspClient')

export async function startLanguageServer(
extensionContext: vscode.ExtensionContext,
Expand All @@ -25,24 +35,27 @@ export async function startLanguageServer(

const serverModule = resourcePaths.lsp

const argv = [
'--nolazy',
'--preserve-symlinks',
'--stdio',
'--pre-init-encryption',
'--set-credentials-encryption-key',
]
const serverOptions = createServerOptions({
encryptionKey,
executable: resourcePaths.node,
serverModule,
execArgv: [
'--nolazy',
'--preserve-symlinks',
'--stdio',
'--pre-init-encryption',
'--set-credentials-encryption-key',
],
execArgv: argv,
})

const documentSelector = [{ scheme: 'file', language: '*' }]

const clientId = 'amazonq'
const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`)

await validateNodeExe(resourcePaths.node, resourcePaths.lsp, argv, logger)

// Options to control the language client
const clientOptions: LanguageClientOptions = {
// Register the server for json documents
Expand All @@ -61,6 +74,7 @@ export async function startLanguageServer(
awsClientCapabilities: {
window: {
notifications: true,
showSaveFileDialog: true,
},
},
},
Expand Down Expand Up @@ -117,7 +131,7 @@ export async function startLanguageServer(
)
}

if (Experiments.instance.get('amazonqChatLSP', false)) {
if (Experiments.instance.get('amazonqChatLSP', true)) {
await activate(client, encryptionKey, resourcePaths.ui)
}

Expand Down
4 changes: 2 additions & 2 deletions packages/amazonq/src/lsp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export interface ExtendedAmazonQLSPConfig extends LspConfig {
}

export const defaultAmazonQLspConfig: ExtendedAmazonQLSPConfig = {
manifestUrl: 'https://aws-toolkit-language-servers.amazonaws.com/codewhisperer/0/manifest.json',
supportedVersions: '^3.1.1',
manifestUrl: 'https://d3akiidp1wvqyg.cloudfront.net/qAgenticChatServer/0/manifest.json', // TODO swap this back
supportedVersions: '*', // TODO swap this back
id: 'AmazonQ', // used across IDEs for identifying global storage/local disk locations. Do not change.
suppressPromptPrefix: 'amazonQ',
path: undefined,
Expand Down
20 changes: 18 additions & 2 deletions packages/amazonq/test/unit/amazonq/lsp/lspClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*/
import * as sinon from 'sinon'
import assert from 'assert'
import { globals } from 'aws-core-vscode/shared'
import { LspClient } from 'aws-core-vscode/amazonq'
import { globals, getNodeExecutableName } from 'aws-core-vscode/shared'
import { LspClient, lspClient as lspClientModule } from 'aws-core-vscode/amazonq'

describe('Amazon Q LSP client', function () {
let lspClient: LspClient
Expand Down Expand Up @@ -50,6 +50,22 @@ describe('Amazon Q LSP client', function () {
assert.ok(!encryptedSample.includes('hello'))
})

it('validates node executable + lsp bundle', async () => {
await assert.rejects(async () => {
await lspClientModule.activate(globals.context, {
// Mimic the `LspResolution<ResourcePaths>` type.
node: 'node.bogus.exe',
lsp: 'fake/lsp.js',
})
}, /.*failed to run basic .*node.*exitcode.*node\.bogus\.exe.*/)
await assert.rejects(async () => {
await lspClientModule.activate(globals.context, {
node: getNodeExecutableName(),
lsp: 'fake/lsp.js',
})
}, /.*failed to run .*exitcode.*node.*lsp\.js/)
})

afterEach(() => {
sinon.restore()
})
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/amazonq/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
} from './onboardingPage/walkthrough'
export { LspController } from './lsp/lspController'
export { LspClient } from './lsp/lspClient'
export * as lspClient from './lsp/lspClient'
export { api } from './extApi'
export { AmazonQChatViewProvider } from './webview/webView'
export { amazonQHelpUrl } from '../shared/constants'
Expand Down
Loading