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
38 changes: 13 additions & 25 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 131 additions & 13 deletions packages/amazonq/src/lsp/chat/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
COPY_TO_CLIPBOARD,
AuthFollowUpType,
DISCLAIMER_ACKNOWLEDGED,
UiMessageResultParams,
} from '@aws/chat-client-ui-types'
import {
ChatResult,
Expand All @@ -21,30 +22,41 @@ import {
QuickActionResult,
QuickActionParams,
insertToCursorPositionNotificationType,
ErrorCodes,
ResponseError,
openTabRequestType,
getSerializedChatRequestType,
listConversationsRequestType,
conversationClickRequestType,
ShowSaveFileDialogRequestType,
ShowSaveFileDialogParams,
LSPErrorCodes,
tabBarActionRequestType,
} from '@aws/language-server-runtimes/protocol'
import { v4 as uuidv4 } from 'uuid'
import * as vscode from 'vscode'
import { Disposable, LanguageClient, Position, State, TextDocumentIdentifier } from 'vscode-languageclient'
import { Disposable, LanguageClient, Position, TextDocumentIdentifier } from 'vscode-languageclient'
import * as jose from 'jose'
import { AmazonQChatViewProvider } from './webviewProvider'
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
import { AmazonQPromptSettings, messages } from 'aws-core-vscode/shared'

export function registerLanguageServerEventListener(languageClient: LanguageClient, provider: AmazonQChatViewProvider) {
languageClient.onDidChangeState(({ oldState, newState }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this never got called because at this point in the code the language server is already activated

if (oldState === State.Starting && newState === State.Running) {
languageClient.info(
'Language client received initializeResult from server:',
JSON.stringify(languageClient.initializeResult)
)
languageClient.info(
'Language client received initializeResult from server:',
JSON.stringify(languageClient.initializeResult)
)

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

void provider.webview?.postMessage({
command: CHAT_OPTIONS,
params: chatOptions,
})
}
// Enable the history feature flag
chatOptions.history = true

provider.onDidResolveWebview(() => {
void provider.webview?.postMessage({
command: CHAT_OPTIONS,
params: chatOptions,
})
})

languageClient.onTelemetry((e) => {
Expand All @@ -60,6 +72,7 @@ export function registerMessageListeners(
provider.webview?.onDidReceiveMessage(async (message) => {
languageClient.info(`[VSCode Client] Received ${JSON.stringify(message)} from chat`)

const webview = provider.webview
switch (message.command) {
case COPY_TO_CLIPBOARD:
languageClient.info('[VSCode Client] Copy to clipboard event received')
Expand Down Expand Up @@ -172,6 +185,15 @@ export function registerMessageListeners(
)
break
}
case listConversationsRequestType.method:
await handleRequest(languageClient, message.params, webview, listConversationsRequestType.method)
break
case conversationClickRequestType.method:
await handleRequest(languageClient, message.params, webview, conversationClickRequestType.method)
break
case tabBarActionRequestType.method:
await handleRequest(languageClient, message.params, webview, tabBarActionRequestType.method)
break
case followUpClickNotificationType.method:
if (!isValidAuthFollowUpType(message.params.followUp.type)) {
languageClient.sendNotification(followUpClickNotificationType.method, message.params)
Expand All @@ -184,6 +206,89 @@ export function registerMessageListeners(
break
}
}, undefined)

const registerHandlerWithResponseRouter = (command: string) => {
const handler = async (params: any, _: any) => {
const mapErrorType = (type: string | undefined): number => {
switch (type) {
case 'InvalidRequest':
return ErrorCodes.InvalidRequest
case 'InternalError':
return ErrorCodes.InternalError
case 'UnknownError':
default:
return ErrorCodes.UnknownErrorCode
}
}
const requestId = uuidv4()

void provider.webview?.postMessage({
requestId: requestId,
command: command,
params: params,
})
const responsePromise = new Promise<UiMessageResultParams | undefined>((resolve, reject) => {
const timeout = setTimeout(() => {
disposable?.dispose()
reject(new Error('Request timed out'))
}, 30000)

const disposable = provider.webview?.onDidReceiveMessage((message: any) => {
if (message.requestId === requestId) {
clearTimeout(timeout)
disposable?.dispose()
resolve(message.params)
}
})
})

const result = await responsePromise

if (result?.success) {
return result.result
} else {
return new ResponseError(
mapErrorType(result?.error.type),
result?.error.message ?? 'No response from client'
)
}
}

languageClient.onRequest(command, handler)
}

registerHandlerWithResponseRouter(openTabRequestType.method)
registerHandlerWithResponseRouter(getSerializedChatRequestType.method)

languageClient.onRequest(ShowSaveFileDialogRequestType.method, async (params: ShowSaveFileDialogParams) => {
const filters: Record<string, string[]> = {}
const formatMappings = [
{ format: 'markdown', key: 'Markdown', extensions: ['md'] },
{ format: 'html', key: 'HTML', extensions: ['html'] },
]

for (const format of params.supportedFormats ?? []) {
const mapping = formatMappings.find((m) => m.format === format)
if (mapping) {
filters[mapping.key] = mapping.extensions
}
}

const saveAtUri = params.defaultUri ? vscode.Uri.parse(params.defaultUri) : vscode.Uri.file('export-chat.md')
const targetUri = await vscode.window.showSaveDialog({
filters,
defaultUri: saveAtUri,
title: 'Export',
})

if (!targetUri) {
return new ResponseError(LSPErrorCodes.RequestFailed, 'Export failed')
}

return {
targetUri: targetUri.toString(),
}
})
}

function isServerEvent(command: string) {
Expand Down Expand Up @@ -258,3 +363,16 @@ async function handleCompleteResult<T>(
})
disposable.dispose()
}

async function handleRequest(
languageClient: LanguageClient,
params: any,
webview: vscode.Webview | undefined,
requestMethod: string
) {
const result = await languageClient.sendRequest(requestMethod, params)
void webview?.postMessage({
command: requestMethod,
params: result,
})
}
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,8 @@
"devDependencies": {
"@aws-sdk/types": "^3.13.1",
"@aws/chat-client-ui-types": "^0.1.12",
"@aws/language-server-runtimes": "^0.2.49",
"@aws/language-server-runtimes-types": "^0.1.10",
"@aws/language-server-runtimes": "^0.2.58",
"@aws/language-server-runtimes-types": "^0.1.13",
"@cspotcode/source-map-support": "^0.8.1",
"@sinonjs/fake-timers": "^10.0.2",
"@types/adm-zip": "^0.4.34",
Expand Down
Loading