Skip to content

Commit 118aee0

Browse files
authored
feat(participant): route generic prompt by intent and update generic prompt VSCODE-572 (#830)
1 parent 08fac17 commit 118aee0

File tree

8 files changed

+456
-39
lines changed

8 files changed

+456
-39
lines changed

src/participant/participant.ts

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
} from '../telemetry/telemetryService';
3939
import { DocsChatbotAIService } from './docsChatbotAIService';
4040
import type TelemetryService from '../telemetry/telemetryService';
41+
import { IntentPrompt, type PromptIntent } from './prompts/intent';
4142

4243
const log = createLogger('participant');
4344

@@ -214,8 +215,7 @@ export default class ParticipantController {
214215
}
215216
}
216217

217-
// @MongoDB what is mongodb?
218-
async handleGenericRequest(
218+
async _handleRoutedGenericRequest(
219219
request: vscode.ChatRequest,
220220
context: vscode.ChatContext,
221221
stream: vscode.ChatResponseStream,
@@ -241,6 +241,93 @@ export default class ParticipantController {
241241
return genericRequestChatResult(context.history);
242242
}
243243

244+
async _routeRequestToHandler({
245+
context,
246+
promptIntent,
247+
request,
248+
stream,
249+
token,
250+
}: {
251+
context: vscode.ChatContext;
252+
promptIntent: Omit<PromptIntent, 'Default'>;
253+
request: vscode.ChatRequest;
254+
stream: vscode.ChatResponseStream;
255+
token: vscode.CancellationToken;
256+
}): Promise<ChatResult> {
257+
switch (promptIntent) {
258+
case 'Query':
259+
return this.handleQueryRequest(request, context, stream, token);
260+
case 'Docs':
261+
return this.handleDocsRequest(request, context, stream, token);
262+
case 'Schema':
263+
return this.handleSchemaRequest(request, context, stream, token);
264+
case 'Code':
265+
return this.handleQueryRequest(request, context, stream, token);
266+
default:
267+
return this._handleRoutedGenericRequest(
268+
request,
269+
context,
270+
stream,
271+
token
272+
);
273+
}
274+
}
275+
276+
async _getIntentFromChatRequest({
277+
context,
278+
request,
279+
token,
280+
}: {
281+
context: vscode.ChatContext;
282+
request: vscode.ChatRequest;
283+
token: vscode.CancellationToken;
284+
}): Promise<PromptIntent> {
285+
const messages = await Prompts.intent.buildMessages({
286+
connectionNames: this._getConnectionNames(),
287+
request,
288+
context,
289+
});
290+
291+
const responseContent = await this.getChatResponseContent({
292+
messages,
293+
token,
294+
});
295+
296+
return IntentPrompt.getIntentFromModelResponse(responseContent);
297+
}
298+
299+
async handleGenericRequest(
300+
request: vscode.ChatRequest,
301+
context: vscode.ChatContext,
302+
stream: vscode.ChatResponseStream,
303+
token: vscode.CancellationToken
304+
): Promise<ChatResult> {
305+
// We "prompt chain" to handle the generic requests.
306+
// First we ask the model to parse for intent.
307+
// If there is an intent, we can route it to one of the handlers (/commands).
308+
// When there is no intention or it's generic we handle it with a generic handler.
309+
const promptIntent = await this._getIntentFromChatRequest({
310+
context,
311+
request,
312+
token,
313+
});
314+
315+
if (token.isCancellationRequested) {
316+
return this._handleCancelledRequest({
317+
context,
318+
stream,
319+
});
320+
}
321+
322+
return this._routeRequestToHandler({
323+
context,
324+
promptIntent,
325+
request,
326+
stream,
327+
token,
328+
});
329+
}
330+
244331
async connectWithParticipant({
245332
id,
246333
command,

src/participant/prompts/generic.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import * as vscode from 'vscode';
2+
23
import type { PromptArgsBase } from './promptBase';
34
import { PromptBase } from './promptBase';
45

56
export class GenericPrompt extends PromptBase<PromptArgsBase> {
67
protected getAssistantPrompt(): string {
78
return `You are a MongoDB expert.
8-
Your task is to help the user craft MongoDB queries and aggregation pipelines that perform their task.
9-
Keep your response concise.
10-
You should suggest queries that are performant and correct.
11-
Respond with markdown, suggest code in a Markdown code block that begins with \`\`\`javascript and ends with \`\`\`.
12-
You can imagine the schema, collection, and database name.
13-
Respond in MongoDB shell syntax using the \`\`\`javascript code block syntax.`;
9+
Your task is to help the user with MongoDB related questions.
10+
When applicable, you may suggest MongoDB code, queries, and aggregation pipelines that perform their task.
11+
Rules:
12+
1. Keep your response concise.
13+
2. You should suggest code that is performant and correct.
14+
3. Respond with markdown.
15+
4. When relevant, provide code in a Markdown code block that begins with \`\`\`javascript and ends with \`\`\`.
16+
5. Use MongoDB shell syntax for code unless the user requests a specific language.
17+
6. If you require additional information to provide a response, ask the user for it.
18+
7. When specifying a database, use the MongoDB syntax use('databaseName').`;
1419
}
1520

1621
public getEmptyRequestResponse(): string {
17-
// TODO(VSCODE-572): Generic empty response handler
1822
return vscode.l10n.t(
1923
'Ask anything about MongoDB, from writing queries to questions about your cluster.'
2024
);

src/participant/prompts/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { GenericPrompt } from './generic';
21
import type * as vscode from 'vscode';
2+
3+
import { GenericPrompt } from './generic';
4+
import { IntentPrompt } from './intent';
35
import { NamespacePrompt } from './namespace';
46
import { QueryPrompt } from './query';
57
import { SchemaPrompt } from './schema';
68

79
export class Prompts {
810
public static generic = new GenericPrompt();
11+
public static intent = new IntentPrompt();
912
public static namespace = new NamespacePrompt();
1013
public static query = new QueryPrompt();
1114
public static schema = new SchemaPrompt();

src/participant/prompts/intent.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { PromptArgsBase } from './promptBase';
2+
import { PromptBase } from './promptBase';
3+
4+
export type PromptIntent = 'Query' | 'Schema' | 'Docs' | 'Default';
5+
6+
export class IntentPrompt extends PromptBase<PromptArgsBase> {
7+
protected getAssistantPrompt(): string {
8+
return `You are a MongoDB expert.
9+
Your task is to help guide a conversation with a user to the correct handler.
10+
You will be provided a conversation and your task is to determine the intent of the user.
11+
The intent handlers are:
12+
- Query
13+
- Schema
14+
- Docs
15+
- Default
16+
Rules:
17+
1. Respond only with the intent handler.
18+
2. Use the "Query" intent handler when the user is asking for code that relates to a specific collection.
19+
3. Use the "Docs" intent handler when the user is asking a question that involves MongoDB documentation.
20+
4. Use the "Schema" intent handler when the user is asking for the schema or shape of documents of a specific collection.
21+
5. Use the "Default" intent handler when a user is asking for code that does NOT relate to a specific collection.
22+
6. Use the "Default" intent handler for everything that may not be handled by another handler.
23+
7. If you are uncertain of the intent, use the "Default" intent handler.
24+
25+
Example:
26+
User: How do I create an index in my pineapples collection?
27+
Response:
28+
Query
29+
30+
Example:
31+
User:
32+
What is $vectorSearch?
33+
Response:
34+
Docs`;
35+
}
36+
37+
static getIntentFromModelResponse(response: string): PromptIntent {
38+
response = response.trim();
39+
switch (response) {
40+
case 'Query':
41+
return 'Query';
42+
case 'Schema':
43+
return 'Schema';
44+
case 'Docs':
45+
return 'Docs';
46+
default:
47+
return 'Default';
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)