@@ -5,6 +5,7 @@ import type {
55 ParticipantPromptProperties ,
66} from '../../telemetry/telemetryService' ;
77import { PromptHistory } from './promptHistory' ;
8+ import { getCopilotModel } from '../model' ;
89import type { ParticipantCommandType } from '../participantTypes' ;
910
1011export interface PromptArgsBase {
@@ -94,34 +95,76 @@ export function isContentEmpty(
9495 return true ;
9596}
9697
97- export abstract class PromptBase < TArgs extends PromptArgsBase > {
98- protected abstract getAssistantPrompt ( args : TArgs ) : string ;
98+ export abstract class PromptBase < PromptArgs extends PromptArgsBase > {
99+ protected abstract getAssistantPrompt ( args : PromptArgs ) : string ;
99100
100101 protected get internalPurposeForTelemetry ( ) : InternalPromptPurpose {
101102 return undefined ;
102103 }
103104
104- protected getUserPrompt ( args : TArgs ) : Promise < UserPromptResponse > {
105+ protected getUserPrompt ( {
106+ request,
107+ } : PromptArgs ) : Promise < UserPromptResponse > {
105108 return Promise . resolve ( {
106- prompt : args . request . prompt ,
109+ prompt : request . prompt ,
107110 hasSampleDocs : false ,
108111 } ) ;
109112 }
110113
111- async buildMessages ( args : TArgs ) : Promise < ModelInput > {
112- let historyMessages = PromptHistory . getFilteredHistory ( {
113- history : args . context ?. history ,
114- ...args ,
114+ private async _countRemainingTokens ( {
115+ model,
116+ assistantPrompt,
117+ requestPrompt,
118+ } : {
119+ model : vscode . LanguageModelChat | undefined ;
120+ assistantPrompt : vscode . LanguageModelChatMessage ;
121+ requestPrompt : string ;
122+ } ) : Promise < number | undefined > {
123+ if ( model ) {
124+ const [ assistantPromptTokens , userPromptTokens ] = await Promise . all ( [
125+ model . countTokens ( assistantPrompt ) ,
126+ model . countTokens ( requestPrompt ) ,
127+ ] ) ;
128+ return model . maxInputTokens - ( assistantPromptTokens + userPromptTokens ) ;
129+ }
130+ return undefined ;
131+ }
132+
133+ async buildMessages ( args : PromptArgs ) : Promise < ModelInput > {
134+ const { context, request, databaseName, collectionName, connectionNames } =
135+ args ;
136+
137+ const model = await getCopilotModel ( ) ;
138+
139+ // eslint-disable-next-line new-cap
140+ const assistantPrompt = vscode . LanguageModelChatMessage . Assistant (
141+ this . getAssistantPrompt ( args )
142+ ) ;
143+
144+ const tokenLimit = await this . _countRemainingTokens ( {
145+ model,
146+ assistantPrompt,
147+ requestPrompt : request . prompt ,
148+ } ) ;
149+
150+ let historyMessages = await PromptHistory . getFilteredHistory ( {
151+ history : context ?. history ,
152+ model,
153+ tokenLimit,
154+ namespaceIsKnown :
155+ databaseName !== undefined && collectionName !== undefined ,
156+ connectionNames,
115157 } ) ;
158+
116159 // If the current user's prompt is a connection name, and the last
117160 // message was to connect. We want to use the last
118161 // message they sent before the connection name as their prompt.
119- if ( args . connectionNames ?. includes ( args . request . prompt ) ) {
120- const history = args . context ?. history ;
162+ if ( connectionNames ?. includes ( request . prompt ) ) {
163+ const history = context ?. history ;
121164 if ( ! history ) {
122165 return {
123166 messages : [ ] ,
124- stats : this . getStats ( [ ] , args , false ) ,
167+ stats : this . getStats ( [ ] , { request , context } , false ) ,
125168 } ;
126169 }
127170 const previousResponse = history [
@@ -132,13 +175,11 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
132175 // Go through the history in reverse order to find the last user message.
133176 for ( let i = history . length - 1 ; i >= 0 ; i -- ) {
134177 if ( history [ i ] instanceof vscode . ChatRequestTurn ) {
178+ request . prompt = ( history [ i ] as vscode . ChatRequestTurn ) . prompt ;
135179 // Rewrite the arguments so that the prompt is the last user message from history
136180 args = {
137181 ...args ,
138- request : {
139- ...args . request ,
140- prompt : ( history [ i ] as vscode . ChatRequestTurn ) . prompt ,
141- } ,
182+ request,
142183 } ;
143184
144185 // Remove the item from the history messages array.
@@ -150,23 +191,20 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
150191 }
151192
152193 const { prompt, hasSampleDocs } = await this . getUserPrompt ( args ) ;
153- const messages = [
154- // eslint-disable-next-line new-cap
155- vscode . LanguageModelChatMessage . Assistant ( this . getAssistantPrompt ( args ) ) ,
156- ...historyMessages ,
157- // eslint-disable-next-line new-cap
158- vscode . LanguageModelChatMessage . User ( prompt ) ,
159- ] ;
194+ // eslint-disable-next-line new-cap
195+ const userPrompt = vscode . LanguageModelChatMessage . User ( prompt ) ;
196+
197+ const messages = [ assistantPrompt , ...historyMessages , userPrompt ] ;
160198
161199 return {
162200 messages,
163- stats : this . getStats ( messages , args , hasSampleDocs ) ,
201+ stats : this . getStats ( messages , { request , context } , hasSampleDocs ) ,
164202 } ;
165203 }
166204
167205 protected getStats (
168206 messages : vscode . LanguageModelChatMessage [ ] ,
169- { request, context } : TArgs ,
207+ { request, context } : Pick < PromptArgsBase , 'request' | 'context' > ,
170208 hasSampleDocs : boolean
171209 ) : ParticipantPromptProperties {
172210 return {
0 commit comments