Skip to content

feat: extended protocol for conversation-based agents experience support #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
64 changes: 32 additions & 32 deletions runtimes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ The server runtime implementation acts as a proxy for LSP methods, which means i
| onInlineCompletion | Yes | Provide list of inline completion suggestions from the Server |
| onExecuteCommand | Yes | Executes a custom command provided by the Server. Servers are advised to document custom commands they support in the package README. |

##### LSP Workspace

| Description | Method | Params | Method type | Response Type |
| ------------------------------------ | --------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| Request to select workspace item (folder, file) with the selected items returned | `aws/selectWorkspaceItem` | `SelectWorkspaceItemParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) Server to Client | `SelectWorkspaceItemResult` |
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand what this means. Does this return the file contents? Show it on screen?

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 returns URI to selected folder/file back to LSP server. I do not think we need to return any contents as LSP server has access to contents if needed. The purpose of this method is to give customer possibility to select.

| Sent notification to open file differences for the new file content. Supports new, updated or removed files. | `aws/openFileDiff` | `OpenFileDiffParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Server to Client | n/a |

##### LSP Extensions

| Method Name | Method | Params | Method Type | Response Type | Notes |
Expand Down Expand Up @@ -159,21 +166,24 @@ The runtime supports chat by default

| Description | Method | Params | Method type | Response Type |
| ------------------------------------ | --------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| Send chat prompt | `aws/chat/sendChatPrompt` | `ChatParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) | `ChatResult` |
| End conversation | `aws/chat/endChat` | `EndChatParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) | `EndChatResult` |
| Send chat quick action | `aws/chat/sendChatQuickAction` | `QuickActionParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) | `ChatResult` |
| Send chat UI ready event | `aws/chat/ready` | n/a | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send chat vote event | `aws/chat/vote` | `VoteParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send chat feedback event | `aws/chat/feedback` | `FeedbackParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send tab add event | `aws/chat/tabAdd` | `TabAddParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send active tab change event | `aws/chat/tabChange` | `TabChangeParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send tab remove event | `aws/chat/tabRemove` | `TabRemoveParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send insert to cursor position event | `aws/chat/insertToCursorPosition` | `InsertToCursorPositionParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send copy code to clipboard event | `aws/chat/copyCodeToClipboard` | `CopyCodeToClipboardParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send link click event | `aws/chat/linkClick` | `LinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send info link click event | `aws/chat/infoLinkClick` | `InfoLinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send source link click event | `aws/chat/sourceLinkClick` | `SourceLinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send followup chat item click event | `aws/chat/followUpClick` | `FollowUpClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) | n/a |
| Send chat prompt. Supports streaming chat message content to client. Response is optional - this event can be used to only trigger chat prompt request and then `aws/chat/sendChatUpdate` can be used to send chat updates asyncronously. | `aws/chat/sendChatPrompt` | `ChatParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) Client to Server | `ChatResult` |
| End conversation | `aws/chat/endChat` | `EndChatParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) Client to Server | `EndChatResult` |
| Send chat quick action. Response is optional - this event can be used to only trigger chat quick action request and then `aws/chat/sendChatUpdate` can be used to send chat updates asyncronously. | `aws/chat/sendChatQuickAction` | `QuickActionParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) Client to Server | `ChatResult` |
| Send chat UI ready event | `aws/chat/ready` | n/a | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send chat vote event | `aws/chat/vote` | `VoteParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send chat feedback event | `aws/chat/feedback` | `FeedbackParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send tab add event | `aws/chat/tabAdd` | `TabAddParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send active tab change event | `aws/chat/tabChange` | `TabChangeParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send tab remove event | `aws/chat/tabRemove` | `TabRemoveParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send insert to cursor position event | `aws/chat/insertToCursorPosition` | `InsertToCursorPositionParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send copy code to clipboard event | `aws/chat/copyCodeToClipboard` | `CopyCodeToClipboardParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send link click event | `aws/chat/linkClick` | `LinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send info link click event | `aws/chat/infoLinkClick` | `InfoLinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send source link click event | `aws/chat/sourceLinkClick` | `SourceLinkClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send followup chat item click event | `aws/chat/followUpClick` | `FollowUpClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |
| Send request to open existing tab, if `tabId` is passed or create and open new tab, if `tabId` is not passed. For the new tab, it's also possible to set tab state and content. | `aws/chat/openTab` | `OpenTabParams` | [Request](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage) Server to Client | `OpenTabResult` |
| Send chat messages and tab state update to specific tab. Depending on new vs existing`messageId` within `ChatMessage` message, the massgage will be added or updated. | `aws/chat/sendChatUpdate` | `ChatUpdateParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Server to Client | n/a |
| Send file or file action click event. | `aws/chat/fileClick` | `FileClickParams` | [Notification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage) Client to Server | n/a |

```ts
export interface ChatPrompt {
Expand All @@ -182,25 +192,15 @@ export interface ChatPrompt {
command?: string
}

export interface ChatParams {
tabId: string
prompt: ChatPrompt
partialResultToken?: ProgressToken
interface PartialResultParams {
partialResultToken?: number | string
}

export interface ChatResult {
body?: string
messageId?: string
canBeVoted?: boolean // requires messageId to be filled to show vote thumbs
relatedContent?: {
title?: string
content: SourceLink[]
}
followUp?: {
text?: string
options?: ChatItemAction[]
}
codeReference?: ReferenceTrackerInformation[]
export interface ChatParams extends PartialResultParams {
tabId: string
prompt: ChatPrompt
cursorState?: CursorState[]
textDocument?: TextDocumentIdentifier
}
```

Expand Down
10 changes: 10 additions & 0 deletions runtimes/protocol/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ import {
OPEN_TAB_REQUEST_METHOD,
OpenTabParams,
OpenTabResult,
CHAT_UPDATE_NOTIFICATION_METHOD,
FILE_CLICK_NOTIFICATION_METHOD,
ChatUpdateParams,
FileClickParams,
} from './lsp'

export const chatRequestType = new AutoParameterStructuresProtocolRequestType<
Expand Down Expand Up @@ -81,3 +85,9 @@ export const followUpClickNotificationType = new ProtocolNotificationType<Follow
export const openTabRequestType = new ProtocolRequestType<OpenTabParams, OpenTabResult, never, void, void>(
OPEN_TAB_REQUEST_METHOD
)
export const chatUpdateNotificationType = new ProtocolNotificationType<ChatUpdateParams, void>(
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 update existing chat messages in the current tab or add new ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add and update - depends on messageId provided.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok! No deletion.

CHAT_UPDATE_NOTIFICATION_METHOD
)
export const fileClickNotificationType = new ProtocolNotificationType<FileClickParams, void>(
FILE_CLICK_NOTIFICATION_METHOD
)
1 change: 1 addition & 0 deletions runtimes/protocol/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './lsp'
export * from './notification'
export * from './telemetry'
export * from './configuration'
export * from './workspace'
21 changes: 21 additions & 0 deletions runtimes/protocol/workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
OPEN_FILE_DIFF_NOTIFICATION_METHOD,
OpenFileDiffParams,
ProtocolNotificationType,
ProtocolRequestType,
SELECT_WORKSPACE_ITEM_REQUEST_METHOD,
SelectWorkspaceItemParams,
SelectWorkspaceItemResult,
} from './lsp'

export const selectWorkspaceItemRequestType = new ProtocolRequestType<
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The intent and protocol is different. We need to get selected items back in server.

Copy link
Contributor

Choose a reason for hiding this comment

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

FYI: I think we usually run into issues when we use ProtocolRequestType and therefore usually use the AutoParameterStructuresProtocolRequestType

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What kind of issues?

Copy link
Contributor

Choose a reason for hiding this comment

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

When would the client send this? What is the use case?

SelectWorkspaceItemParams,
SelectWorkspaceItemResult,
never,
void,
void
>(SELECT_WORKSPACE_ITEM_REQUEST_METHOD)

export const openFileDiffNotificationType = new ProtocolNotificationType<OpenFileDiffParams, void>(
OPEN_FILE_DIFF_NOTIFICATION_METHOD
)
8 changes: 8 additions & 0 deletions runtimes/runtimes/base-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ import {
ShowMessageRequest,
ShowDocumentRequest,
openTabRequestType,
openFileDiffNotificationType,
selectWorkspaceItemRequestType,
chatUpdateNotificationType,
fileClickNotificationType,
} from '../protocol'
import { createConnection } from 'vscode-languageserver/browser'
import {
Expand Down Expand Up @@ -135,6 +139,8 @@ export const baseRuntime = (connections: { reader: MessageReader; writer: Messag
onSourceLinkClick: handler => lspConnection.onNotification(sourceLinkClickNotificationType.method, handler),
onFollowUpClicked: handler => lspConnection.onNotification(followUpClickNotificationType.method, handler),
openTab: params => lspConnection.sendRequest(openTabRequestType.method, params),
sendChatUpdate: params => lspConnection.sendNotification(chatUpdateNotificationType.method, params),
onFileClicked: handler => lspConnection.onNotification(fileClickNotificationType.method, handler),
}

const identityManagement: IdentityManagement = {
Expand Down Expand Up @@ -195,6 +201,8 @@ export const baseRuntime = (connections: { reader: MessageReader; writer: Messag
onDidDeleteFiles: params => lspConnection.workspace.onDidDeleteFiles(params),
onDidRenameFiles: params => lspConnection.workspace.onDidRenameFiles(params),
onUpdateConfiguration: lspServer.setUpdateConfigurationHandler,
selectWorkspaceItem: params => lspConnection.sendRequest(selectWorkspaceItemRequestType.method, params),
openFileDiff: params => lspConnection.sendNotification(openFileDiffNotificationType.method, params),
},
window: {
showMessage: params => lspConnection.sendNotification(ShowMessageNotification.method, params),
Expand Down
12 changes: 12 additions & 0 deletions runtimes/runtimes/chat/baseChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import {
OpenTabParams,
OpenTabResult,
openTabRequestType,
ChatUpdateParams,
chatUpdateNotificationType,
FileClickParams,
fileClickNotificationType,
} from '../../protocol'
import { Chat } from '../../server-interface'

Expand Down Expand Up @@ -93,4 +97,12 @@ export class BaseChat implements Chat {
public openTab(params: OpenTabParams): Promise<OpenTabResult> {
return this.connection.sendRequest(openTabRequestType.method, params)
}

public sendChatUpdate(params: ChatUpdateParams) {
this.connection.sendNotification(chatUpdateNotificationType.method, params)
}

public onFileClicked(handler: NotificationHandler<FileClickParams>) {
this.connection.onNotification(fileClickNotificationType.method, handler)
}
}
5 changes: 5 additions & 0 deletions runtimes/runtimes/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
CancellationToken,
GetSsoTokenParams,
didChangeDependencyPathsNotificationType,
openFileDiffNotificationType,
selectWorkspaceItemRequestType,
} from '../protocol'
import { ProposedFeatures, createConnection } from 'vscode-languageserver/node'
import {
Expand Down Expand Up @@ -321,6 +323,9 @@ export const standalone = (props: RuntimeProps) => {
onDidDeleteFiles: params => lspConnection.workspace.onDidDeleteFiles(params),
onDidRenameFiles: params => lspConnection.workspace.onDidRenameFiles(params),
onUpdateConfiguration: lspServer.setUpdateConfigurationHandler,
selectWorkspaceItem: params =>
lspConnection.sendRequest(selectWorkspaceItemRequestType.method, params),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Do we have to specify selectWorkspaceItemRequestType.method? I remember if we just passed selectWorkspaceItemRequestType it also worked and I remember when you pass the .method which is a string, you lose some benefits that come with typescript

Same applies to openFileDiff

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've seen different versions used throughout the codebase. If you know what it impacts exactly, I can change.

openFileDiff: params => lspConnection.sendNotification(openFileDiffNotificationType.method, params),
},
window: {
showMessage: params => lspConnection.sendNotification(ShowMessageNotification.method, params),
Expand Down
4 changes: 4 additions & 0 deletions runtimes/server-interface/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
TabRemoveParams,
OpenTabParams,
OpenTabResult,
ChatUpdateParams,
FileClickParams,
} from '../protocol'

/**
Expand All @@ -40,4 +42,6 @@ export type Chat = {
onInfoLinkClick: (handler: NotificationHandler<InfoLinkClickParams>) => void
onSourceLinkClick: (handler: NotificationHandler<SourceLinkClickParams>) => void
onFollowUpClicked: (handler: NotificationHandler<FollowUpClickParams>) => void
sendChatUpdate: (params: ChatUpdateParams) => void
onFileClicked: (handler: NotificationHandler<FileClickParams>) => void
}
7 changes: 7 additions & 0 deletions runtimes/server-interface/lsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ import {
DidChangeDependencyPathsParams,
UpdateConfigurationParams,
InlineCompletionWithReferencesParams,
OpenFileDiffParams,
SelectWorkspaceItemParams,
SelectWorkspaceItemResult,
} from '../protocol'

// Re-export whole surface of LSP protocol used in Runtimes.
Expand Down Expand Up @@ -136,6 +139,10 @@ export type Lsp = {
onDidDeleteFiles: (handler: NotificationHandler<DeleteFilesParams>) => void
onDidRenameFiles: (handler: NotificationHandler<RenameFilesParams>) => void
onUpdateConfiguration: (handler: RequestHandler<UpdateConfigurationParams, void, void>) => void
selectWorkspaceItem: (
handler: RequestHandler<SelectWorkspaceItemParams, SelectWorkspaceItemResult | undefined | null, void>
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we allow for undefined or null as a result?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Customer could click cancel in the dialog popup, something needs to be returned in this case.

Copy link
Contributor

Choose a reason for hiding this comment

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

What operations trigger this dialog popup? Is there another (existing or new) request that this relates to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Followup action called "Choose another folder in your workspace". This is needed to request customer select a folder for context.

) => void
openFileDiff: (params: OpenFileDiffParams) => void
}
window: {
showMessage: (params: ShowMessageParams) => Promise<void>
Expand Down
Loading