Skip to content
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

chore(participant): refactor chat participant state VSCODE-583 #810

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
4 changes: 2 additions & 2 deletions src/connectionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}

// Exported for testing.
export function getNotifyDeviceFlowForConnectionAttempt(

Check warning on line 80 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 80 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
connectionOptions: ConnectionOptions
) {
const isOIDCConnectionAttempt = isOIDCAuth(
Expand All @@ -91,7 +91,7 @@
| undefined;

if (isOIDCConnectionAttempt) {
notifyDeviceFlow = ({

Check warning on line 94 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 94 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
verificationUrl,
userCode,
}: {
Expand Down Expand Up @@ -381,7 +381,7 @@
...cloneDeep(connectionOptions.oidc),
openBrowser: browserAuthCommand
? { command: browserAuthCommand }
: async ({ signal, url }) => {

Check warning on line 384 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 384 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
try {
await openLink(url);
} catch (err) {
Expand Down Expand Up @@ -469,7 +469,7 @@
}

// Used to re-authenticate with OIDC.
async _reauthenticationHandler() {

Check warning on line 472 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 472 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
const removeConfirmationResponse =
await vscode.window.showInformationMessage(
'You need to re-authenticate to the database in order to continue.',
Expand All @@ -482,7 +482,7 @@
}
}

private async onConnectSuccess({

Check warning on line 485 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 485 in src/connectionController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
connectionInfo,
dataService,
}: {
Expand Down Expand Up @@ -1054,15 +1054,15 @@
);

if (!selectedQuickPickItem) {
return true;
return false;
}

if (selectedQuickPickItem.data.type === NewConnectionType.NEW_CONNECTION) {
return this.connectWithURI();
}

if (!selectedQuickPickItem.data.connectionId) {
return true;
return false;
}

const { successfullyConnected } = await this.connectWithConnectionId(
Expand Down
36 changes: 24 additions & 12 deletions src/mdbExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import WebviewController from './views/webviewController';
import { createIdFactory, generateId } from './utils/objectIdHelper';
import { ConnectionStorage } from './storage/connectionStorage';
import type StreamProcessorTreeItem from './explorer/streamProcessorTreeItem';
import type { RunParticipantQueryCommandArgs } from './participant/participant';
import ParticipantController from './participant/participant';

// This class is the top-level controller for our extension.
Expand Down Expand Up @@ -291,36 +292,47 @@ export default class MDBExtensionController implements vscode.Disposable {
// ------ CHAT PARTICIPANT ------ //
this.registerParticipantCommand(
EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND,
() => {
({ runnableContent }: RunParticipantQueryCommandArgs) => {
return this._playgroundController.createPlaygroundFromParticipantQuery({
text:
this._participantController._chatResult?.metadata
?.responseContent || '',
text: runnableContent,
});
}
);
this.registerParticipantCommand(
EXTENSION_COMMANDS.RUN_PARTICIPANT_QUERY,
() => {
({ runnableContent }: RunParticipantQueryCommandArgs) => {
return this._playgroundController.evaluateParticipantQuery(
this._participantController._chatResult?.metadata?.responseContent ||
''
runnableContent
);
}
);
this.registerCommand(
EXTENSION_COMMANDS.CONNECT_WITH_PARTICIPANT,
(id: string) => this._participantController.connectWithParticipant(id)
(id?: string) =>
this._participantController.connectWithParticipant(
id ? decodeURIComponent(id) : id
)
);
this.registerCommand(
EXTENSION_COMMANDS.SELECT_DATABASE_WITH_PARTICIPANT,
(name: string) =>
this._participantController.selectDatabaseWithParticipant(name)
(_data: string) => {
const data = JSON.parse(decodeURIComponent(_data));
return this._participantController.selectDatabaseWithParticipant({
chatId: data.chatId,
databaseName: data.databaseName,
});
}
);
this.registerCommand(
EXTENSION_COMMANDS.SELECT_COLLECTION_WITH_PARTICIPANT,
(name: string) =>
this._participantController.selectCollectionWithParticipant(name)
(_data: string) => {
const data = JSON.parse(decodeURIComponent(_data));
return this._participantController.selectCollectionWithParticipant({
chatId: data.chatId,
databaseName: data.databaseName,
collectionName: data.collectionName,
});
}
);
};

Expand Down
36 changes: 36 additions & 0 deletions src/participant/chatMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as vscode from 'vscode';
import { v4 as uuidv4 } from 'uuid';

export type ChatMetadata = {
databaseName?: string;
collectionName?: string;
};

export class ChatMetadataStore {
_chats: { [chatId: string]: ChatMetadata } = {};

constructor() {}

setChatMetadata(chatId: string, metadata: ChatMetadata): void {
this._chats[chatId] = metadata;
}

getChatMetadata(chatId: string): ChatMetadata | undefined {
return this._chats[chatId];
}

static getChatIdFromHistoryOrNewChatId(
history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>
): string {
for (const historyItem of history) {
if (
historyItem instanceof vscode.ChatResponseTurn &&
historyItem.result?.metadata?.chatId
) {
return historyItem.result.metadata.chatId;
}
}

return uuidv4();
}
}
61 changes: 61 additions & 0 deletions src/participant/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,63 @@
import type * as vscode from 'vscode';
import { ChatMetadataStore } from './chatMetadata';

export const CHAT_PARTICIPANT_ID = 'mongodb.participant';
export const CHAT_PARTICIPANT_MODEL = 'gpt-4o';

export class NamespaceRequestChatResult implements vscode.ChatResult {
readonly metadata: {
chatId: string;
intent: 'askForNamespace';
databaseName?: string | undefined;
collectionName?: string | undefined;
};

constructor({
databaseName,
collectionName,
history,
}: {
history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>;
databaseName: string | undefined;
collectionName: string | undefined;
}) {
this.metadata = {
chatId: ChatMetadataStore.getChatIdFromHistoryOrNewChatId(history),
intent: 'askForNamespace',
databaseName,
collectionName,
};
}
}

export class EmptyRequestChatResult implements vscode.ChatResult {
readonly metadata: {
chatId: string;
intent: 'emptyRequest';
};

constructor(
history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>
) {
this.metadata = {
chatId: ChatMetadataStore.getChatIdFromHistoryOrNewChatId(history),
intent: 'emptyRequest',
};
}
}

export class AskToConnectChatResult implements vscode.ChatResult {
readonly metadata: {
chatId: string;
intent: 'askToConnect';
};

constructor(
history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>
) {
this.metadata = {
chatId: ChatMetadataStore.getChatIdFromHistoryOrNewChatId(history),
intent: 'askToConnect',
};
}
}
32 changes: 32 additions & 0 deletions src/participant/markdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as vscode from 'vscode';

export function createMarkdownLink({
commandId,
data,
name,
}: {
commandId: string;
data?:
| {
[field: string]: any;
}
| string;
name: string;
}): vscode.MarkdownString {
const encodedData = data
? encodeURIComponent(
`["${
typeof data === 'string'
? data
: encodeURIComponent(JSON.stringify(data))
}"]`
)
: undefined;
const commandQueryString = data ? `?${encodedData}` : '';
const connName = new vscode.MarkdownString(
`- <a href="command:${commandId}${commandQueryString}">${name}</a>\n`
);
connName.supportHtml = true;
connName.isTrusted = { enabledCommands: [commandId] };
return connName;
}
Loading
Loading