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

feat(participant): export to a playground VSCODE-574 #832

Merged
merged 16 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@
"dark": "images/dark/play.svg"
}
},
{
"command": "mdb.exportCodeToPlayground",
"title": "Export Code to Playground"
},
{
"command": "mdb.exportToPython",
"title": "MongoDB: Export To Python 3"
Expand Down Expand Up @@ -747,6 +751,17 @@
"when": "mdb.isPlayground == true"
}
],
"mdb.copilot": [
{
"command": "mdb.exportCodeToPlayground"
}
],
"editor/context": [
{
"submenu": "mdb.copilot",
"group": "1_main@2"
}
],
"commandPalette": [
{
"command": "mdb.selectDatabaseWithParticipant",
Expand Down Expand Up @@ -948,6 +963,10 @@
"command": "mdb.runPlayground",
"when": "false"
},
{
"command": "mdb.exportCodeToPlayground",
"when": "false"
},
{
"command": "mdb.createIndexFromTreeView",
"when": "false"
Expand Down Expand Up @@ -994,6 +1013,12 @@
}
]
},
"submenus": [
{
"id": "mdb.copilot",
"label": "MongoDB Copilot"
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
}
],
"keybindings": [
{
"command": "mdb.runSelectedPlaygroundBlocks",
Expand Down
1 change: 1 addition & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum EXTENSION_COMMANDS {
MDB_RUN_SELECTED_PLAYGROUND_BLOCKS = 'mdb.runSelectedPlaygroundBlocks',
MDB_RUN_ALL_PLAYGROUND_BLOCKS = 'mdb.runAllPlaygroundBlocks',
MDB_RUN_ALL_OR_SELECTED_PLAYGROUND_BLOCKS = 'mdb.runPlayground',
MDB_EXPORT_CODE_TO_PLAYGROUND = 'mdb.exportCodeToPlayground',

MDB_FIX_THIS_INVALID_INTERACTIVE_SYNTAX = 'mdb.fixThisInvalidInteractiveSyntax',
MDB_FIX_ALL_INVALID_INTERACTIVE_SYNTAX = 'mdb.fixAllInvalidInteractiveSyntax',
Expand Down
34 changes: 17 additions & 17 deletions src/editors/playgroundController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
// TODO: this function was copied from the compass-export-to-language module
// https://github.com/mongodb-js/compass/blob/7c4bc0789a7b66c01bb7ba63955b3b11ed40c094/packages/compass-export-to-language/src/modules/count-aggregation-stages-in-string.js
// and should be updated as well when the better solution for the problem will be found.
const countAggregationStagesInString = (str: string) => {

Check warning on line 65 in src/editors/playgroundController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (ubuntu-latest)

Missing return type on function

Check warning on line 65 in src/editors/playgroundController.ts

View workflow job for this annotation

GitHub Actions / Test and Build (macos-latest)

Missing return type on function
if (!dummySandbox) {
dummySandbox = vm.createContext(Object.create(null), {
codeGeneration: { strings: false, wasm: false },
Expand Down Expand Up @@ -492,33 +492,33 @@
}

try {
const progressResult = await vscode.window.withProgress(
return await vscode.window.withProgress(
{
location: ProgressLocation.Notification,
title: 'Running MongoDB playground...',
cancellable: true,
},
async (progress, token) => {
token.onCancellationRequested(() => {
// If a user clicked the cancel button terminate all playground scripts.
this._languageServerController.cancelAll();

return { result: undefined };
async (progress, token): Promise<ShellEvaluateResult> => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
return new Promise(async (resolve, reject) => {
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
token.onCancellationRequested(() => {
// If a user clicked the cancel button terminate all playground scripts.
this._languageServerController.cancelAll();
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
return resolve({ result: undefined });
});

try {
// Run all playground scripts.
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
const result = await this._evaluate(codeToEvaluate);
return resolve(result);
} catch (error) {
return reject(error);
}
});

// Run all playground scripts.
const result: ShellEvaluateResult = await this._evaluate(
codeToEvaluate
);

return result;
}
);

return progressResult;
} catch (error) {
log.error('Evaluating playground with cancel modal failed', error);

return { result: undefined };
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/mdbExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ export default class MDBExtensionController implements vscode.Disposable {
EXTENSION_COMMANDS.MDB_RUN_ALL_OR_SELECTED_PLAYGROUND_BLOCKS,
() => this._playgroundController.runAllOrSelectedPlaygroundBlocks()
);
this.registerCommand(EXTENSION_COMMANDS.MDB_EXPORT_CODE_TO_PLAYGROUND, () =>
this._participantController.exportCodeToPlayground()
);

this.registerCommand(
EXTENSION_COMMANDS.MDB_FIX_THIS_INVALID_INTERACTIVE_SYNTAX,
Expand Down
84 changes: 80 additions & 4 deletions src/participant/participant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import EXTENSION_COMMANDS from '../commands';
import type { StorageController } from '../storage';
import { StorageVariables } from '../storage';
import { GenericPrompt, isPromptEmpty } from './prompts/generic';
import { ExportToPlaygroundPrompt } from './prompts/exportToPlayground';
import type { ChatResult } from './constants';
import {
askToConnectChatResult,
Expand Down Expand Up @@ -42,6 +43,7 @@ import {
} from '../telemetry/telemetryService';
import { DocsChatbotAIService } from './docsChatbotAIService';
import type TelemetryService from '../telemetry/telemetryService';
import formatError from '../utils/formatError';

const log = createLogger('participant');

Expand Down Expand Up @@ -132,7 +134,7 @@ export default class ParticipantController {
return this._participant;
}

handleError(err: any, command: string): never {
handleError(err: any, command: string): void {
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
let errorCode: string | undefined;
let errorName: ParticipantErrorTypes;
// Making the chat request might fail because
Expand Down Expand Up @@ -168,9 +170,6 @@ export default class ParticipantController {
error_name: errorName,
}
);

// Re-throw other errors so they show up in the UI.
throw err;
}

/**
Expand Down Expand Up @@ -1201,6 +1200,81 @@ export default class ParticipantController {
});
}

async exportCodeToPlayground(): Promise<boolean> {
const activeTextEditor = vscode.window.activeTextEditor;
if (!activeTextEditor) {
await vscode.window.showErrorMessage('Active editor not found.');
return Promise.resolve(false);
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
}

const sortedSelections = Array.from(activeTextEditor.selections).sort(
(a, b) => a.start.compareTo(b.start)
);
const selectedText = sortedSelections
.map((selection) => activeTextEditor.document.getText(selection))
.join('\n');
const code =
selectedText || activeTextEditor.document.getText().trim() || '';
try {
const progressResult = await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: 'Exporting code to a playground...',
cancellable: true,
},
async (progress, token): Promise<string | undefined> => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
return new Promise(async (resolve, reject) => {
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
token.onCancellationRequested(() => {
void vscode.window.showInformationMessage(
'The running export to a playground operation was canceled.'
);
return reject();
});

const messages = ExportToPlaygroundPrompt.buildMessages(code);
try {
const responseContent = await this.getChatResponseContent({
messages,
token,
});
return resolve(responseContent);
} catch (error) {
return reject(error);
}
});
}
);

if (progressResult?.includes("Sorry, I can't assist with that.")) {
void vscode.window.showErrorMessage("Sorry, I can't assist with that.");
return Promise.resolve(false);
Anemy marked this conversation as resolved.
Show resolved Hide resolved
}

if (progressResult) {
const runnableContent = getRunnableContentFromString(progressResult);
if (runnableContent) {
await vscode.commands.executeCommand(
EXTENSION_COMMANDS.OPEN_PARTICIPANT_QUERY_IN_PLAYGROUND,
{
runnableContent,
}
);
}
}

return Promise.resolve(true);
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
this.handleError(error, 'exportToPlayground');
await vscode.window.showErrorMessage(
`An error occurred exporting to a playground: ${
formatError(error).message
}`
);
return Promise.resolve(false);
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
}
}

async chatHandler(
...args: [
vscode.ChatRequest,
Expand Down Expand Up @@ -1249,6 +1323,8 @@ Please see our [FAQ](https://www.mongodb.com/docs/generative-ai-faq/) for more i
}
} catch (e) {
this.handleError(e, request.command || 'generic');
// Re-throw other errors so they show up in the UI.
throw e;
}
}

Expand Down
31 changes: 31 additions & 0 deletions src/participant/prompts/exportToPlayground.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as vscode from 'vscode';

export class ExportToPlaygroundPrompt {
static getAssistantPrompt(): vscode.LanguageModelChatMessage {
const prompt = `You are a MongoDB expert.
Your task is to help the user build MongoDB queries and aggregation pipelines that perform their task.
You convert user's code written in any programming language to the MongoDB Shell syntax.
Take a user promt as an input string and translate it to the MongoDB Shell language.
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
Keep your response concise.
You should suggest queries that are performant and correct.
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
Respond with markdown, suggest code in a Markdown code block that begins with \`\`\`javascript and ends with \`\`\`.
Anemy marked this conversation as resolved.
Show resolved Hide resolved
Respond in MongoDB shell syntax using the \`\`\`javascript code block syntax.`;

// eslint-disable-next-line new-cap
return vscode.LanguageModelChatMessage.Assistant(prompt);
}

static getUserPrompt(prompt: string): vscode.LanguageModelChatMessage {
// eslint-disable-next-line new-cap
return vscode.LanguageModelChatMessage.User(prompt);
Anemy marked this conversation as resolved.
Show resolved Hide resolved
}

static buildMessages(prompt: string): vscode.LanguageModelChatMessage[] {
const messages = [
ExportToPlaygroundPrompt.getAssistantPrompt(),
ExportToPlaygroundPrompt.getUserPrompt(prompt),
];

return messages;
alenakhineika marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading
Loading