@@ -5,6 +5,7 @@ import type {
5
5
ParticipantPromptProperties ,
6
6
} from '../../telemetry/telemetryService' ;
7
7
import { PromptHistory } from './promptHistory' ;
8
+ import { getCopilotModel } from '../model' ;
8
9
import type { ParticipantCommandType } from '../participantTypes' ;
9
10
10
11
export interface PromptArgsBase {
@@ -94,34 +95,76 @@ export function isContentEmpty(
94
95
return true ;
95
96
}
96
97
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 ;
99
100
100
101
protected get internalPurposeForTelemetry ( ) : InternalPromptPurpose {
101
102
return undefined ;
102
103
}
103
104
104
- protected getUserPrompt ( args : TArgs ) : Promise < UserPromptResponse > {
105
+ protected getUserPrompt ( {
106
+ request,
107
+ } : PromptArgs ) : Promise < UserPromptResponse > {
105
108
return Promise . resolve ( {
106
- prompt : args . request . prompt ,
109
+ prompt : request . prompt ,
107
110
hasSampleDocs : false ,
108
111
} ) ;
109
112
}
110
113
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,
115
157
} ) ;
158
+
116
159
// If the current user's prompt is a connection name, and the last
117
160
// message was to connect. We want to use the last
118
161
// 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 ;
121
164
if ( ! history ) {
122
165
return {
123
166
messages : [ ] ,
124
- stats : this . getStats ( [ ] , args , false ) ,
167
+ stats : this . getStats ( [ ] , { request , context } , false ) ,
125
168
} ;
126
169
}
127
170
const previousResponse = history [
@@ -132,13 +175,11 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
132
175
// Go through the history in reverse order to find the last user message.
133
176
for ( let i = history . length - 1 ; i >= 0 ; i -- ) {
134
177
if ( history [ i ] instanceof vscode . ChatRequestTurn ) {
178
+ request . prompt = ( history [ i ] as vscode . ChatRequestTurn ) . prompt ;
135
179
// Rewrite the arguments so that the prompt is the last user message from history
136
180
args = {
137
181
...args ,
138
- request : {
139
- ...args . request ,
140
- prompt : ( history [ i ] as vscode . ChatRequestTurn ) . prompt ,
141
- } ,
182
+ request,
142
183
} ;
143
184
144
185
// Remove the item from the history messages array.
@@ -150,23 +191,20 @@ export abstract class PromptBase<TArgs extends PromptArgsBase> {
150
191
}
151
192
152
193
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 ] ;
160
198
161
199
return {
162
200
messages,
163
- stats : this . getStats ( messages , args , hasSampleDocs ) ,
201
+ stats : this . getStats ( messages , { request , context } , hasSampleDocs ) ,
164
202
} ;
165
203
}
166
204
167
205
protected getStats (
168
206
messages : vscode . LanguageModelChatMessage [ ] ,
169
- { request, context } : TArgs ,
207
+ { request, context } : Pick < PromptArgsBase , 'request' | 'context' > ,
170
208
hasSampleDocs : boolean
171
209
) : ParticipantPromptProperties {
172
210
return {
0 commit comments