From d85b6550871679acecaa0aec4493a61d1523291c Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 18 Nov 2024 14:34:05 +0100 Subject: [PATCH 1/3] add empty prompt scenario and improve the prompt --- src/participant/participant.ts | 50 ++++++----- src/participant/prompts/schema.ts | 14 ++- .../suite/participant/participant.test.ts | 89 ++++++++++--------- 3 files changed, 85 insertions(+), 68 deletions(-) diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 5fe25c130..4ff1a4c8e 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -1187,17 +1187,6 @@ export default class ParticipantController { }); } - if ( - Prompts.isPromptEmpty(request) && - this._doesLastMessageAskForNamespace(context.history) - ) { - return this.handleEmptyNamespaceMessage({ - command: '/schema', - context, - stream, - }); - } - const namespace = await this._getNamespaceFromChat({ request, context, @@ -1221,6 +1210,19 @@ export default class ParticipantController { }); } + if (Prompts.isPromptEmpty(request)) { + if (this._doesLastMessageAskForNamespace(context.history)) { + return this.handleEmptyNamespaceMessage({ + command: '/schema', + context, + stream, + }); + } + + stream.markdown(Prompts.schema.emptyRequestResponse); + return emptyRequestChatResult(context.history); + } + if (token.isCancellationRequested) { return this._handleCancelledRequest({ context, @@ -1314,19 +1316,6 @@ export default class ParticipantController { }); } - if (Prompts.isPromptEmpty(request)) { - if (this._doesLastMessageAskForNamespace(context.history)) { - return this.handleEmptyNamespaceMessage({ - command: '/query', - context, - stream, - }); - } - - stream.markdown(Prompts.query.emptyRequestResponse); - return emptyRequestChatResult(context.history); - } - // We "prompt chain" to handle the query requests. // First we ask the model to parse for the database and collection name. // If they exist, we can then use them in our final completion. @@ -1361,6 +1350,19 @@ export default class ParticipantController { }); } + if (Prompts.isPromptEmpty(request)) { + if (this._doesLastMessageAskForNamespace(context.history)) { + return this.handleEmptyNamespaceMessage({ + command: '/query', + context, + stream, + }); + } + + stream.markdown(Prompts.query.emptyRequestResponse); + return emptyRequestChatResult(context.history); + } + let schema: string | undefined; let sampleDocuments: Document[] | undefined; try { diff --git a/src/participant/prompts/schema.ts b/src/participant/prompts/schema.ts index 362d1cf8e..f77ac62e8 100644 --- a/src/participant/prompts/schema.ts +++ b/src/participant/prompts/schema.ts @@ -1,5 +1,6 @@ import type { UserPromptResponse } from './promptBase'; import { PromptBase, type PromptArgsBase } from './promptBase'; +import * as vscode from 'vscode'; export const DOCUMENTS_TO_SAMPLE_FOR_SCHEMA_PROMPT = 100; @@ -21,9 +22,10 @@ export class SchemaPrompt extends PromptBase { return `You are a senior engineer who describes the schema of documents in a MongoDB database. The schema is generated from a sample of documents in the user's collection. You must follow these rules. -Rule 1: Try to be as concise as possible. -Rule 2: Pay attention to the JSON schema. -Rule 3: Mention the amount of documents sampled in your response. +Rule 1: Your answer should always describe the schema of documents in the collection. +Rule 2: Try to be as concise as possible. +Rule 3: Pay attention to the JSON schema. +Rule 4: Mention the amount of documents sampled in your response. Amount of documents sampled: ${amountOfDocumentsSampled}.`; } @@ -44,4 +46,10 @@ ${schema}`, hasSampleDocs: false, }); } + + get emptyRequestResponse(): string { + return vscode.l10n.t( + 'Please specify a question when using this command. Usage: @MongoDB /schema what is the schema for the sample_mflix.users collection?' + ); + } } diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index f6c05bbec..d8645f854 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -661,6 +661,30 @@ suite('Participant Controller Test Suite', function () { }); }); + test('returns a special response with an empty prompt', async function () { + // Put the namespace in metadata as otherwise the user is meant to + // be prompted for a namespace with an empty prompt + sinon.replace( + testParticipantController._chatMetadataStore, + 'getChatMetadata', + () => ({ + databaseName: 'dbOne', + collectionName: 'collectionOne', + }) + ); + + await invokeChatHandler({ + prompt: '', + command: 'query', + references: [], + }); + + expect(chatStreamStub.markdown.calledOnce).is.true; + expect(chatStreamStub.markdown.getCall(0).firstArg).equals( + Prompts.query.emptyRequestResponse + ); + }); + test('generates a query', async function () { const chatRequestMock = { prompt: 'find all docs by a name example', @@ -1335,47 +1359,6 @@ suite('Participant Controller Test Suite', function () { 'Which database would you like to use? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n' ); }); - - test('with history, and a blank prompt, it sets a message so it does not cause model error (VSCODE-626)', async function () { - const chatRequestMock = { - prompt: '', - command: 'schema', - references: [], - }; - chatContextStub = { - history: [ - createChatRequestTurn( - '/query', - 'how do I make a find request vs favorite_fruits.pineapple?' - ), - createChatResponseTurn('/query', { - response: [ - { - value: { value: 'some code' } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'query', - chatId: 'abc', - }, - }, - }), - ], - }; - await invokeChatHandler(chatRequestMock); - - expect(sendRequestStub.calledOnce).to.be.true; - - const messages = sendRequestStub.firstCall - .args[0] as vscode.LanguageModelChatMessage[]; - expect(getMessageContent(messages[0])).to.include( - 'Parse all user messages to find a database name and a collection name.' - ); - expect(getMessageContent(messages[3])).to.include( - 'see previous messages' - ); - }); }); suite( @@ -1387,6 +1370,30 @@ suite('Participant Controller Test Suite', function () { }); }); + test('returns a special response with an empty prompt', async function () { + // Put the namespace in metadata as otherwise the user is meant to + // be prompted for a namespace with an empty prompt + sinon.replace( + testParticipantController._chatMetadataStore, + 'getChatMetadata', + () => ({ + databaseName: 'dbOne', + collectionName: 'collectionOne', + }) + ); + + await invokeChatHandler({ + prompt: '', + command: 'schema', + references: [], + }); + + expect(chatStreamStub.markdown.calledOnce).is.true; + expect(chatStreamStub.markdown.getCall(0).firstArg).equals( + Prompts.schema.emptyRequestResponse + ); + }); + test('shows a button to view the json output', async function () { const chatRequestMock = { prompt: 'what is my schema', From 4e07c77854593662b8c7ac2399de1f7d4b64cc45 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 18 Nov 2024 15:12:56 +0100 Subject: [PATCH 2/3] remove empty prompt namespace asking --- src/participant/participant.ts | 52 +++++++++---------- .../suite/participant/participant.test.ts | 37 ------------- 2 files changed, 26 insertions(+), 63 deletions(-) diff --git a/src/participant/participant.ts b/src/participant/participant.ts index 4ff1a4c8e..e43154660 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -1187,6 +1187,19 @@ export default class ParticipantController { }); } + if (Prompts.isPromptEmpty(request)) { + if (this._doesLastMessageAskForNamespace(context.history)) { + return this.handleEmptyNamespaceMessage({ + command: '/schema', + context, + stream, + }); + } + + stream.markdown(Prompts.schema.emptyRequestResponse); + return emptyRequestChatResult(context.history); + } + const namespace = await this._getNamespaceFromChat({ request, context, @@ -1210,19 +1223,6 @@ export default class ParticipantController { }); } - if (Prompts.isPromptEmpty(request)) { - if (this._doesLastMessageAskForNamespace(context.history)) { - return this.handleEmptyNamespaceMessage({ - command: '/schema', - context, - stream, - }); - } - - stream.markdown(Prompts.schema.emptyRequestResponse); - return emptyRequestChatResult(context.history); - } - if (token.isCancellationRequested) { return this._handleCancelledRequest({ context, @@ -1316,6 +1316,19 @@ export default class ParticipantController { }); } + if (Prompts.isPromptEmpty(request)) { + if (this._doesLastMessageAskForNamespace(context.history)) { + return this.handleEmptyNamespaceMessage({ + command: '/query', + context, + stream, + }); + } + + stream.markdown(Prompts.query.emptyRequestResponse); + return emptyRequestChatResult(context.history); + } + // We "prompt chain" to handle the query requests. // First we ask the model to parse for the database and collection name. // If they exist, we can then use them in our final completion. @@ -1350,19 +1363,6 @@ export default class ParticipantController { }); } - if (Prompts.isPromptEmpty(request)) { - if (this._doesLastMessageAskForNamespace(context.history)) { - return this.handleEmptyNamespaceMessage({ - command: '/query', - context, - stream, - }); - } - - stream.markdown(Prompts.query.emptyRequestResponse); - return emptyRequestChatResult(context.history); - } - let schema: string | undefined; let sampleDocuments: Document[] | undefined; try { diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index d8645f854..c342c1662 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -662,17 +662,6 @@ suite('Participant Controller Test Suite', function () { }); test('returns a special response with an empty prompt', async function () { - // Put the namespace in metadata as otherwise the user is meant to - // be prompted for a namespace with an empty prompt - sinon.replace( - testParticipantController._chatMetadataStore, - 'getChatMetadata', - () => ({ - databaseName: 'dbOne', - collectionName: 'collectionOne', - }) - ); - await invokeChatHandler({ prompt: '', command: 'query', @@ -1324,21 +1313,6 @@ suite('Participant Controller Test Suite', function () { }); }); - test('without a prompt it asks for the database name without pinging ai', async function () { - const chatRequestMock = { - prompt: '', - command: 'schema', - references: [], - }; - await invokeChatHandler(chatRequestMock); - - expect(sendRequestStub.called).to.be.false; - const askForDBMessage = chatStreamStub.markdown.getCall(0).args[0]; - expect(askForDBMessage).to.include( - 'Which database would you like to use? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n' - ); - }); - test('with a prompt it asks the ai for the namespace', async function () { const chatRequestMock = { prompt: 'pineapple', @@ -1371,17 +1345,6 @@ suite('Participant Controller Test Suite', function () { }); test('returns a special response with an empty prompt', async function () { - // Put the namespace in metadata as otherwise the user is meant to - // be prompted for a namespace with an empty prompt - sinon.replace( - testParticipantController._chatMetadataStore, - 'getChatMetadata', - () => ({ - databaseName: 'dbOne', - collectionName: 'collectionOne', - }) - ); - await invokeChatHandler({ prompt: '', command: 'schema', From 4081feb9bbc17ea11e65da9184cd42328f052e68 Mon Sep 17 00:00:00 2001 From: gagik Date: Wed, 20 Nov 2024 11:10:49 +0100 Subject: [PATCH 3/3] Remove empty prompt and just use rule --- src/participant/participant.ts | 20 +- src/participant/prompts/schema.ts | 7 - .../suite/participant/participant.test.ts | 351 +++++++++++------- .../suite/participant/participantHelpers.ts | 28 +- 4 files changed, 240 insertions(+), 166 deletions(-) diff --git a/src/participant/participant.ts b/src/participant/participant.ts index e43154660..5fe25c130 100644 --- a/src/participant/participant.ts +++ b/src/participant/participant.ts @@ -1187,17 +1187,15 @@ export default class ParticipantController { }); } - if (Prompts.isPromptEmpty(request)) { - if (this._doesLastMessageAskForNamespace(context.history)) { - return this.handleEmptyNamespaceMessage({ - command: '/schema', - context, - stream, - }); - } - - stream.markdown(Prompts.schema.emptyRequestResponse); - return emptyRequestChatResult(context.history); + if ( + Prompts.isPromptEmpty(request) && + this._doesLastMessageAskForNamespace(context.history) + ) { + return this.handleEmptyNamespaceMessage({ + command: '/schema', + context, + stream, + }); } const namespace = await this._getNamespaceFromChat({ diff --git a/src/participant/prompts/schema.ts b/src/participant/prompts/schema.ts index f77ac62e8..a2025748e 100644 --- a/src/participant/prompts/schema.ts +++ b/src/participant/prompts/schema.ts @@ -1,6 +1,5 @@ import type { UserPromptResponse } from './promptBase'; import { PromptBase, type PromptArgsBase } from './promptBase'; -import * as vscode from 'vscode'; export const DOCUMENTS_TO_SAMPLE_FOR_SCHEMA_PROMPT = 100; @@ -46,10 +45,4 @@ ${schema}`, hasSampleDocs: false, }); } - - get emptyRequestResponse(): string { - return vscode.l10n.t( - 'Please specify a question when using this command. Usage: @MongoDB /schema what is the schema for the sample_mflix.users collection?' - ); - } } diff --git a/src/test/suite/participant/participant.test.ts b/src/test/suite/participant/participant.test.ts index c342c1662..67bcd5f7a 100644 --- a/src/test/suite/participant/participant.test.ts +++ b/src/test/suite/participant/participant.test.ts @@ -661,19 +661,6 @@ suite('Participant Controller Test Suite', function () { }); }); - test('returns a special response with an empty prompt', async function () { - await invokeChatHandler({ - prompt: '', - command: 'query', - references: [], - }); - - expect(chatStreamStub.markdown.calledOnce).is.true; - expect(chatStreamStub.markdown.getCall(0).firstArg).equals( - Prompts.query.emptyRequestResponse - ); - }); - test('generates a query', async function () { const chatRequestMock = { prompt: 'find all docs by a name example', @@ -1094,22 +1081,18 @@ suite('Participant Controller Test Suite', function () { '/query', 'find all docs by a name example' ), - createChatResponseTurn('/query', { - response: [ - { - value: { - value: - 'Which database would you like this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', - chatId: firstChatId, + createChatResponseTurn( + '/query', + 'Which database would you like this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', + { + result: { + metadata: { + intent: 'askForNamespace', + chatId: firstChatId, + }, }, - }, - }), + } + ), ], }; @@ -1164,40 +1147,32 @@ suite('Participant Controller Test Suite', function () { '/query', 'find all docs by a name example' ), - createChatResponseTurn('/query', { - response: [ - { - value: { - value: - 'Which database would you like to this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', + createChatResponseTurn( + '/query', + 'Which database would you like to this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', + { + result: { + metadata: { + intent: 'askForNamespace', + }, }, - }, - }), + } + ), createChatRequestTurn('/query', 'dbOne'), - createChatResponseTurn('/query', { - response: [ - { - value: { - value: - 'Which collection would you like to query within dbOne? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', - databaseName: 'dbOne', - collectionName: 'collOne', - chatId: firstChatId, + createChatResponseTurn( + '/query', + 'Which collection would you like to query within dbOne? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', + { + result: { + metadata: { + intent: 'askForNamespace', + databaseName: 'dbOne', + collectionName: 'collOne', + chatId: firstChatId, + }, }, - }, - }), + } + ), ], }; await invokeChatHandler(chatRequestMock); @@ -1237,22 +1212,18 @@ suite('Participant Controller Test Suite', function () { '/query', 'find all docs by a name example' ), - createChatResponseTurn('/query', { - response: [ - { - value: { - value: - 'Which database would you like this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', - chatId: 'pineapple', + createChatResponseTurn( + '/query', + 'Which database would you like this query to run against? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n', + { + result: { + metadata: { + intent: 'askForNamespace', + chatId: 'pineapple', + }, }, - }, - }), + } + ), ], }; const chatResult = await invokeChatHandler(chatRequestMock); @@ -1313,6 +1284,21 @@ suite('Participant Controller Test Suite', function () { }); }); + test('without a prompt it asks for the database name without pinging ai', async function () { + const chatRequestMock = { + prompt: '', + command: 'schema', + references: [], + }; + await invokeChatHandler(chatRequestMock); + + expect(sendRequestStub.called).to.be.false; + const askForDBMessage = chatStreamStub.markdown.getCall(0).args[0]; + expect(askForDBMessage).to.include( + 'Which database would you like to use? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n' + ); + }); + test('with a prompt it asks the ai for the namespace', async function () { const chatRequestMock = { prompt: 'pineapple', @@ -1333,6 +1319,42 @@ suite('Participant Controller Test Suite', function () { 'Which database would you like to use? Select one by either clicking on an item in the list or typing the name manually in the chat.\n\n' ); }); + + test('with history, and a blank prompt, it sets a message so it does not cause model error (VSCODE-626)', async function () { + const chatRequestMock = { + prompt: '', + command: 'schema', + references: [], + }; + chatContextStub = { + history: [ + createChatRequestTurn( + '/query', + 'how do I make a find request vs favorite_fruits.pineapple?' + ), + createChatResponseTurn('/query', 'some code', { + result: { + metadata: { + intent: 'query', + chatId: 'abc', + }, + }, + }), + ], + }; + await invokeChatHandler(chatRequestMock); + + expect(sendRequestStub.calledOnce).to.be.true; + + const messages = sendRequestStub.firstCall + .args[0] as vscode.LanguageModelChatMessage[]; + expect(getMessageContent(messages[0])).to.include( + 'Parse all user messages to find a database name and a collection name.' + ); + expect(getMessageContent(messages[3])).to.include( + 'see previous messages' + ); + }); }); suite( @@ -1344,19 +1366,6 @@ suite('Participant Controller Test Suite', function () { }); }); - test('returns a special response with an empty prompt', async function () { - await invokeChatHandler({ - prompt: '', - command: 'schema', - references: [], - }); - - expect(chatStreamStub.markdown.calledOnce).is.true; - expect(chatStreamStub.markdown.getCall(0).firstArg).equals( - Prompts.schema.emptyRequestResponse - ); - }); - test('shows a button to view the json output', async function () { const chatRequestMock = { prompt: 'what is my schema', @@ -1507,7 +1516,7 @@ Schema: let fetchStub: sinon.SinonStub; beforeEach(function () { - sendRequestStub.onCall(0).resolves({ + sendRequestStub.resolves({ text: ['connection info'], }); }); @@ -1516,6 +1525,88 @@ Schema: global.fetch = initialFetch; }); + suite('includes the history of previous requests', function () { + let addMessageStub: sinon.SinonStub; + beforeEach(function () { + addMessageStub = sinon.stub( + testParticipantController._docsChatbotAIService, + 'addMessage' + ); + }); + + test('since the beginning', async function () { + chatContextStub = { + history: [ + createChatRequestTurn('/query', 'query request'), + createChatResponseTurn('/query', 'query response'), + createChatRequestTurn('/query', 'query request 2'), + createChatResponseTurn('/query', 'query response 2'), + createChatRequestTurn('/schema', 'schema request'), + createChatResponseTurn('/schema', 'schema response'), + ], + }; + + const chatRequestMock = { + prompt: 'docs request', + command: 'docs', + references: [], + }; + + await invokeChatHandler(chatRequestMock); + + expect(addMessageStub.calledOnce).is.true; + expect(addMessageStub.getCall(0).firstArg.message).equal( + [ + 'query request 2', + 'query response 2', + 'schema request', + 'schema response', + 'docs request', + ].join('\n\n') + ); + }); + + test('since the last docs request or response', async function () { + chatContextStub = { + history: [ + createChatRequestTurn('/query', 'query request'), + createChatResponseTurn('/query', 'query response'), + createChatRequestTurn('/docs', 'first docs request'), + createChatResponseTurn('/docs', 'first docs response'), + createChatRequestTurn('/schema', 'schema request'), + createChatResponseTurn('/schema', 'schema response'), + ], + }; + + const chatRequestMock = { + prompt: 'docs request', + command: 'docs', + references: [], + }; + + await invokeChatHandler(chatRequestMock); + + expect(addMessageStub.calledOnce).is.true; + expect(addMessageStub.getCall(0).firstArg.message).equals( + ['schema request', 'schema response', 'docs request'].join('\n\n') + ); + + chatContextStub = { + history: [ + createChatRequestTurn('/query', 'query request'), + createChatResponseTurn('/query', 'query response'), + createChatRequestTurn('/docs', 'first docs request'), + ], + }; + + await invokeChatHandler(chatRequestMock); + + expect(addMessageStub.getCall(1).firstArg.message).equals( + 'docs request' + ); + }); + }); + test('shows a message and docs link on empty prompt', async function () { fetchStub = sinon.stub().resolves(); global.fetch = fetchStub; @@ -2124,42 +2215,32 @@ Schema: chatContextStub = { history: [ createChatRequestTurn('/query', userMessages[0]), - createChatResponseTurn('/query', { - participant: CHAT_PARTICIPANT_ID, - response: [ - { - value: { - value: - 'Which database would you like to query within this database?', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', + createChatResponseTurn( + '/query', + 'Which database would you like to query within this database?', + { + result: { + metadata: { + intent: 'askForNamespace', + }, }, - }, - }), + } + ), createChatRequestTurn('/query', 'dbOne'), - createChatResponseTurn('/query', { - participant: CHAT_PARTICIPANT_ID, - response: [ - { - value: { - value: - 'Which collection would you like to query within dbOne?', - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askForNamespace', - databaseName: 'dbOne', - collectionName: undefined, - chatId: testChatId, + createChatResponseTurn( + '/query', + 'Which collection would you like to query within dbOne?', + { + result: { + metadata: { + intent: 'askForNamespace', + databaseName: 'dbOne', + collectionName: undefined, + chatId: testChatId, + }, }, - }, - }), + } + ), createChatRequestTurn('/query', 'collectionOne'), createChatRequestTurn('/query', userMessages[1]), ], @@ -2238,12 +2319,9 @@ Schema: chatContextStub = { history: [ createChatRequestTurn('/query', expectedPrompt), - createChatResponseTurn('/query', { - participant: CHAT_PARTICIPANT_ID, - response: [ - { - value: { - value: `Looks like you aren't currently connected, first let's get you connected to the cluster we'd like to create this query to run against. + createChatResponseTurn( + '/query', + `Looks like you aren't currently connected, first let's get you connected to the cluster we'd like to create this query to run against. ${createMarkdownLink({ commandId: EXTENSION_COMMANDS.CONNECT_WITH_PARTICIPANT, @@ -2255,16 +2333,15 @@ Schema: name: 'atlas', data: {}, })}`, - } as vscode.MarkdownString, - }, - ], - result: { - metadata: { - intent: 'askToConnect', - chatId: 'abc', + { + result: { + metadata: { + intent: 'askToConnect', + chatId: 'abc', + }, }, - }, - }), + } + ), ], }; @@ -2316,7 +2393,7 @@ Schema: 'give me the count of all people in the prod database' ), createChatRequestTurn('/query', 'some disallowed message'), - createChatResponseTurn('/query', { + createChatResponseTurn('/query', undefined, { result: { errorDetails: { message: ParticipantErrorTypes.FILTERED, diff --git a/src/test/suite/participant/participantHelpers.ts b/src/test/suite/participant/participantHelpers.ts index b66d810d4..77448c3d9 100644 --- a/src/test/suite/participant/participantHelpers.ts +++ b/src/test/suite/participant/participantHelpers.ts @@ -8,10 +8,7 @@ export function createChatRequestTurn( options: { participant?: vscode.ChatRequestTurn['participant']; references?: vscode.ChatRequestTurn['references']; - } = { - participant: CHAT_PARTICIPANT_ID, - references: [], - } + } = {} ): vscode.ChatRequestTurn { const { participant = CHAT_PARTICIPANT_ID, references = [] } = options; @@ -25,18 +22,27 @@ export function createChatRequestTurn( export function createChatResponseTurn( command: ParticipantCommand, + /** Helper shortcut for response text, use options.response for a more manual setup */ + responseText?: string, options: { - response?: vscode.ChatResponseTurn['response']; + response?: vscode.ChatResponseTurn['response'] | undefined; result?: vscode.ChatResponseTurn['result']; participant?: string; - } = { - response: [], - result: {}, - participant: CHAT_PARTICIPANT_ID, - } + } = {} ): vscode.ChatRequestTurn { const { - response = [], + response = responseText + ? [ + Object.assign( + Object.create(vscode.ChatResponseMarkdownPart.prototype), + { + value: { + value: responseText, + }, + } + ), + ] + : [], result = {}, participant = CHAT_PARTICIPANT_ID, } = options;