|
1 | 1 | import * as vscode from 'vscode';
|
2 |
| -import type { ChatResult, ParticipantResponseType } from '../constants'; |
| 2 | +import type { ChatResult } from '../constants'; |
3 | 3 | import type {
|
4 | 4 | InternalPromptPurpose,
|
5 | 5 | ParticipantPromptProperties,
|
6 | 6 | } from '../../telemetry/telemetryService';
|
7 |
| -import { ParticipantErrorTypes } from '../participantErrorTypes'; |
| 7 | +import { PromptHistory } from './promptHistory'; |
8 | 8 |
|
9 | 9 | export interface PromptArgsBase {
|
10 | 10 | request: {
|
@@ -53,6 +53,26 @@ export function getContentLength(
|
53 | 53 | return 0;
|
54 | 54 | }
|
55 | 55 |
|
| 56 | +export function getContent(message: vscode.LanguageModelChatMessage): string { |
| 57 | + const content = message.content as any; |
| 58 | + if (typeof content === 'string') { |
| 59 | + return content; |
| 60 | + } |
| 61 | + |
| 62 | + if (Array.isArray(content)) { |
| 63 | + return content.reduce((agg: string, element) => { |
| 64 | + const value = element?.value ?? element?.content?.value; |
| 65 | + if (typeof value === 'string') { |
| 66 | + return agg + value; |
| 67 | + } |
| 68 | + |
| 69 | + return agg; |
| 70 | + }, ''); |
| 71 | + } |
| 72 | + |
| 73 | + return ''; |
| 74 | +} |
| 75 | + |
56 | 76 | export function isContentEmpty(
|
57 | 77 | message: vscode.LanguageModelChatMessage
|
58 | 78 | ): boolean {
|
@@ -88,7 +108,10 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
|
88 | 108 | }
|
89 | 109 |
|
90 | 110 | async buildMessages(args: TArgs): Promise<ModelInput> {
|
91 |
| - let historyMessages = this.getHistoryMessages(args); |
| 111 | + let historyMessages = PromptHistory.getFilteredHistory({ |
| 112 | + history: args.context?.history, |
| 113 | + ...args, |
| 114 | + }); |
92 | 115 | // If the current user's prompt is a connection name, and the last
|
93 | 116 | // message was to connect. We want to use the last
|
94 | 117 | // message they sent before the connection name as their prompt.
|
@@ -157,115 +180,4 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
|
157 | 180 | internal_purpose: this.internalPurposeForTelemetry,
|
158 | 181 | };
|
159 | 182 | }
|
160 |
| - |
161 |
| - // When passing the history to the model we only want contextual messages |
162 |
| - // to be passed. This function parses through the history and returns |
163 |
| - // the messages that are valuable to keep. |
164 |
| - // eslint-disable-next-line complexity |
165 |
| - protected getHistoryMessages({ |
166 |
| - connectionNames, |
167 |
| - context, |
168 |
| - databaseName, |
169 |
| - collectionName, |
170 |
| - }: { |
171 |
| - connectionNames?: string[]; // Used to scrape the connecting messages from the history. |
172 |
| - context?: vscode.ChatContext; |
173 |
| - databaseName?: string; |
174 |
| - collectionName?: string; |
175 |
| - }): vscode.LanguageModelChatMessage[] { |
176 |
| - const messages: vscode.LanguageModelChatMessage[] = []; |
177 |
| - |
178 |
| - if (!context) { |
179 |
| - return []; |
180 |
| - } |
181 |
| - |
182 |
| - let previousItem: |
183 |
| - | vscode.ChatRequestTurn |
184 |
| - | vscode.ChatResponseTurn |
185 |
| - | undefined = undefined; |
186 |
| - |
187 |
| - const namespaceIsKnown = |
188 |
| - databaseName !== undefined && collectionName !== undefined; |
189 |
| - for (const historyItem of context.history) { |
190 |
| - if (historyItem instanceof vscode.ChatRequestTurn) { |
191 |
| - if ( |
192 |
| - historyItem.prompt?.trim().length === 0 || |
193 |
| - connectionNames?.includes(historyItem.prompt) |
194 |
| - ) { |
195 |
| - // When the message is empty or a connection name then we skip it. |
196 |
| - // It's probably going to be the response to the connect step. |
197 |
| - previousItem = historyItem; |
198 |
| - continue; |
199 |
| - } |
200 |
| - |
201 |
| - if (previousItem instanceof vscode.ChatResponseTurn) { |
202 |
| - const responseIntent = (previousItem.result as ChatResult).metadata |
203 |
| - ?.intent; |
204 |
| - |
205 |
| - // If the namespace is already known, skip responses to prompts asking for it. |
206 |
| - if (responseIntent === 'askForNamespace' && namespaceIsKnown) { |
207 |
| - previousItem = historyItem; |
208 |
| - continue; |
209 |
| - } |
210 |
| - } |
211 |
| - |
212 |
| - // eslint-disable-next-line new-cap |
213 |
| - messages.push(vscode.LanguageModelChatMessage.User(historyItem.prompt)); |
214 |
| - } |
215 |
| - |
216 |
| - if (historyItem instanceof vscode.ChatResponseTurn) { |
217 |
| - if ( |
218 |
| - historyItem.result.errorDetails?.message === |
219 |
| - ParticipantErrorTypes.FILTERED |
220 |
| - ) { |
221 |
| - // If the response led to a filtered error, we do not want the |
222 |
| - // error-causing message to be sent again so we remove it. |
223 |
| - messages.pop(); |
224 |
| - continue; |
225 |
| - } |
226 |
| - |
227 |
| - let message = ''; |
228 |
| - |
229 |
| - // Skip a response to an empty user prompt message or connect message. |
230 |
| - const responseTypesToSkip: ParticipantResponseType[] = [ |
231 |
| - 'emptyRequest', |
232 |
| - 'askToConnect', |
233 |
| - ]; |
234 |
| - |
235 |
| - const responseType = (historyItem.result as ChatResult)?.metadata |
236 |
| - ?.intent; |
237 |
| - if (responseTypesToSkip.includes(responseType)) { |
238 |
| - previousItem = historyItem; |
239 |
| - continue; |
240 |
| - } |
241 |
| - |
242 |
| - // If the namespace is already known, skip including prompts asking for it. |
243 |
| - if (responseType === 'askForNamespace' && namespaceIsKnown) { |
244 |
| - previousItem = historyItem; |
245 |
| - continue; |
246 |
| - } |
247 |
| - |
248 |
| - for (const fragment of historyItem.response) { |
249 |
| - if (fragment instanceof vscode.ChatResponseMarkdownPart) { |
250 |
| - message += fragment.value.value; |
251 |
| - |
252 |
| - if ( |
253 |
| - (historyItem.result as ChatResult)?.metadata?.intent === |
254 |
| - 'askForNamespace' |
255 |
| - ) { |
256 |
| - // When the message is the assistant asking for part of a namespace, |
257 |
| - // we only want to include the question asked, not the user's |
258 |
| - // database and collection names in the history item. |
259 |
| - break; |
260 |
| - } |
261 |
| - } |
262 |
| - } |
263 |
| - // eslint-disable-next-line new-cap |
264 |
| - messages.push(vscode.LanguageModelChatMessage.Assistant(message)); |
265 |
| - } |
266 |
| - previousItem = historyItem; |
267 |
| - } |
268 |
| - |
269 |
| - return messages; |
270 |
| - } |
271 | 183 | }
|
0 commit comments