@vscode/chat-lib 0.1.0 → 0.1.1-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js +1 -1
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts +21 -7
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js +409 -175
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts +42 -0
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts.map +1 -0
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js +171 -0
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js.map +1 -0
- package/dist/src/_internal/extension/xtab/common/tags.d.ts +13 -0
- package/dist/src/_internal/extension/xtab/common/tags.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/common/tags.js +15 -1
- package/dist/src/_internal/extension/xtab/common/tags.js.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js +6 -20
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js.map +1 -1
- package/dist/src/_internal/platform/configuration/common/configurationService.d.ts +1 -3
- package/dist/src/_internal/platform/configuration/common/configurationService.d.ts.map +1 -1
- package/dist/src/_internal/platform/configuration/common/configurationService.js +2 -4
- package/dist/src/_internal/platform/configuration/common/configurationService.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts +2 -0
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js +39 -4
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts +5 -6
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.js +6 -0
- package/dist/src/_internal/platform/github/common/githubAPI.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/observableWorkspace.d.ts +0 -1
- package/dist/src/_internal/platform/inlineEdits/common/observableWorkspace.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/observableWorkspace.js +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/observableWorkspace.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts +21 -9
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js +51 -17
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetch.d.ts +0 -1
- package/dist/src/_internal/platform/networking/common/fetch.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetch.js +0 -8
- package/dist/src/_internal/platform/networking/common/fetch.js.map +1 -1
- package/dist/src/_internal/platform/openai/node/fetch.d.ts +2 -33
- package/dist/src/_internal/platform/openai/node/fetch.d.ts.map +1 -1
- package/dist/src/_internal/platform/openai/node/fetch.js +0 -401
- package/dist/src/_internal/platform/openai/node/fetch.js.map +1 -1
- package/dist/src/package.json +46 -25
- package/package.json +1 -1
|
@@ -47,29 +47,39 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
47
47
|
};
|
|
48
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
49
|
exports.ChatMLFetcherImpl = exports.AbstractChatMLFetcher = void 0;
|
|
50
|
+
exports.createTelemetryData = createTelemetryData;
|
|
51
|
+
exports.locationToIntent = locationToIntent;
|
|
50
52
|
const prompt_tsx_1 = require("@vscode/prompt-tsx");
|
|
53
|
+
const authentication_1 = require("../../../platform/authentication/common/authentication");
|
|
51
54
|
const chatMLFetcher_1 = require("../../../platform/chat/common/chatMLFetcher");
|
|
55
|
+
const chatQuotaService_1 = require("../../../platform/chat/common/chatQuotaService");
|
|
52
56
|
const commonTypes_1 = require("../../../platform/chat/common/commonTypes");
|
|
53
57
|
const conversationOptions_1 = require("../../../platform/chat/common/conversationOptions");
|
|
54
58
|
const globalStringUtils_1 = require("../../../platform/chat/common/globalStringUtils");
|
|
59
|
+
const interactionService_1 = require("../../../platform/chat/common/interactionService");
|
|
55
60
|
const configurationService_1 = require("../../../platform/configuration/common/configurationService");
|
|
61
|
+
const capiClient_1 = require("../../../platform/endpoint/common/capiClient");
|
|
56
62
|
const autoChatEndpoint_1 = require("../../../platform/endpoint/node/autoChatEndpoint");
|
|
57
63
|
const logService_1 = require("../../../platform/log/common/logService");
|
|
64
|
+
const fetch_1 = require("../../../platform/networking/common/fetch");
|
|
58
65
|
const fetcherService_1 = require("../../../platform/networking/common/fetcherService");
|
|
66
|
+
const networking_1 = require("../../../platform/networking/common/networking");
|
|
59
67
|
const openai_1 = require("../../../platform/networking/common/openai");
|
|
60
|
-
const
|
|
68
|
+
const chatStream_1 = require("../../../platform/networking/node/chatStream");
|
|
69
|
+
const stream_1 = require("../../../platform/networking/node/stream");
|
|
70
|
+
const fetch_2 = require("../../../platform/openai/node/fetch");
|
|
61
71
|
const requestLogger_1 = require("../../../platform/requestLogger/node/requestLogger");
|
|
62
72
|
const telemetry_1 = require("../../../platform/telemetry/common/telemetry");
|
|
63
73
|
const telemetryData_1 = require("../../../platform/telemetry/common/telemetryData");
|
|
64
74
|
const anomalyDetection_1 = require("../../../util/common/anomalyDetection");
|
|
75
|
+
const crypto_1 = require("../../../util/common/crypto");
|
|
65
76
|
const errorsUtil = __importStar(require("../../../util/common/errors"));
|
|
66
77
|
const errors_1 = require("../../../util/vs/base/common/errors");
|
|
67
78
|
const event_1 = require("../../../util/vs/base/common/event");
|
|
68
79
|
const uuid_1 = require("../../../util/vs/base/common/uuid");
|
|
69
|
-
const instantiation_1 = require("../../../util/vs/platform/instantiation/common/instantiation");
|
|
70
80
|
const openAIEndpoint_1 = require("../../byok/node/openAIEndpoint");
|
|
71
81
|
const constants_1 = require("../../common/constants");
|
|
72
|
-
const
|
|
82
|
+
const chatMLFetcherTelemetry_1 = require("./chatMLFetcherTelemetry");
|
|
73
83
|
const strings_1 = require("../../../util/vs/base/common/strings");
|
|
74
84
|
class AbstractChatMLFetcher {
|
|
75
85
|
constructor(options) {
|
|
@@ -99,14 +109,16 @@ class AbstractChatMLFetcher {
|
|
|
99
109
|
}
|
|
100
110
|
exports.AbstractChatMLFetcher = AbstractChatMLFetcher;
|
|
101
111
|
let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
102
|
-
constructor(_fetcherService, _telemetryService, _requestLogger, _logService, _authenticationService,
|
|
112
|
+
constructor(_fetcherService, _telemetryService, _requestLogger, _logService, _authenticationService, _interactionService, _chatQuotaService, _capiClientService, options) {
|
|
103
113
|
super(options);
|
|
104
114
|
this._fetcherService = _fetcherService;
|
|
105
115
|
this._telemetryService = _telemetryService;
|
|
106
116
|
this._requestLogger = _requestLogger;
|
|
107
117
|
this._logService = _logService;
|
|
108
118
|
this._authenticationService = _authenticationService;
|
|
109
|
-
this.
|
|
119
|
+
this._interactionService = _interactionService;
|
|
120
|
+
this._chatQuotaService = _chatQuotaService;
|
|
121
|
+
this._capiClientService = _capiClientService;
|
|
110
122
|
}
|
|
111
123
|
/**
|
|
112
124
|
* Note: the returned array of strings may be less than `n` (e.g., in case there were errors during streaming)
|
|
@@ -130,7 +142,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
130
142
|
delete requestOptions['prediction'];
|
|
131
143
|
}
|
|
132
144
|
const postOptions = this.preparePostOptions(requestOptions);
|
|
133
|
-
const requestBody =
|
|
145
|
+
const requestBody = chatEndpoint.createRequestBody({
|
|
134
146
|
...opts,
|
|
135
147
|
requestId: ourRequestId,
|
|
136
148
|
postOptions
|
|
@@ -156,14 +168,14 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
156
168
|
const payloadValidationResult = isValidChatPayload(opts.messages, postOptions);
|
|
157
169
|
if (!payloadValidationResult.isValid) {
|
|
158
170
|
response = {
|
|
159
|
-
type:
|
|
171
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
160
172
|
modelRequestId: undefined,
|
|
161
|
-
failKind:
|
|
173
|
+
failKind: fetch_2.ChatFailKind.ValidationFailed,
|
|
162
174
|
reason: payloadValidationResult.reason,
|
|
163
175
|
};
|
|
164
176
|
}
|
|
165
177
|
else {
|
|
166
|
-
response = await this.
|
|
178
|
+
response = await this._fetchAndStreamChat(chatEndpoint, requestBody, baseTelemetry, streamRecorder.callback, requestOptions.secretKey, opts.location, ourRequestId, postOptions.n, token, userInitiatedRequest, telemetryProperties, opts.useFetcher);
|
|
167
179
|
tokenCount = await chatEndpoint.acquireTokenizer().countMessagesTokens(messages);
|
|
168
180
|
const extensionId = source?.extensionId ?? constants_1.EXTENSION_ID;
|
|
169
181
|
this._onDidMakeChatMLRequest.fire({
|
|
@@ -176,7 +188,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
176
188
|
const timeToFirstToken = Date.now() - baseTelemetry.issuedTime;
|
|
177
189
|
pendingLoggedChatRequest?.markTimeToFirstToken(timeToFirstToken);
|
|
178
190
|
switch (response.type) {
|
|
179
|
-
case
|
|
191
|
+
case fetch_2.FetchResponseKind.Success: {
|
|
180
192
|
const result = await this.processSuccessfulResponse(response, messages, requestBody, ourRequestId, maxResponseTokens, tokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpoint, userInitiatedRequest);
|
|
181
193
|
// Handle FilteredRetry case with augmented messages
|
|
182
194
|
if (result.type === commonTypes_1.ChatFetchResponseType.FilteredRetry) {
|
|
@@ -226,8 +238,8 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
226
238
|
pendingLoggedChatRequest?.resolve(result, streamRecorder.deltas);
|
|
227
239
|
return result;
|
|
228
240
|
}
|
|
229
|
-
case
|
|
230
|
-
this.
|
|
241
|
+
case fetch_2.FetchResponseKind.Canceled:
|
|
242
|
+
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendCancellationTelemetry(this._telemetryService, {
|
|
231
243
|
source: telemetryProperties.messageSource ?? 'unknown',
|
|
232
244
|
requestId: ourRequestId,
|
|
233
245
|
model: chatEndpoint.model,
|
|
@@ -248,9 +260,9 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
248
260
|
});
|
|
249
261
|
pendingLoggedChatRequest?.resolveWithCancelation();
|
|
250
262
|
return this.processCanceledResponse(response, ourRequestId);
|
|
251
|
-
case
|
|
263
|
+
case fetch_2.FetchResponseKind.Failed: {
|
|
252
264
|
const processed = this.processFailedResponse(response, ourRequestId);
|
|
253
|
-
this.
|
|
265
|
+
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendResponseErrorTelemetry(this._telemetryService, processed, telemetryProperties, ourRequestId, chatEndpoint, requestBody, tokenCount, maxResponseTokens, timeToFirstToken, this.filterImageMessages(messages));
|
|
254
266
|
pendingLoggedChatRequest?.resolve(processed);
|
|
255
267
|
return processed;
|
|
256
268
|
}
|
|
@@ -284,7 +296,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
284
296
|
}
|
|
285
297
|
}
|
|
286
298
|
if (processed.type === commonTypes_1.ChatFetchResponseType.Canceled) {
|
|
287
|
-
this.
|
|
299
|
+
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendCancellationTelemetry(this._telemetryService, {
|
|
288
300
|
source: telemetryProperties.messageSource ?? 'unknown',
|
|
289
301
|
requestId: ourRequestId,
|
|
290
302
|
model: chatEndpoint.model,
|
|
@@ -302,170 +314,357 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
302
314
|
});
|
|
303
315
|
}
|
|
304
316
|
else {
|
|
305
|
-
this.
|
|
317
|
+
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendResponseErrorTelemetry(this._telemetryService, processed, telemetryProperties, ourRequestId, chatEndpoint, requestBody, tokenCount, maxResponseTokens, timeToError, this.filterImageMessages(messages));
|
|
306
318
|
}
|
|
307
319
|
pendingLoggedChatRequest?.resolve(processed);
|
|
308
320
|
return processed;
|
|
309
321
|
}
|
|
310
322
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
323
|
+
async _fetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher) {
|
|
324
|
+
if (cancellationToken.isCancellationRequested) {
|
|
325
|
+
return { type: fetch_2.FetchResponseKind.Canceled, reason: 'before fetch request' };
|
|
326
|
+
}
|
|
327
|
+
this._logService.debug(`modelMaxPromptTokens ${chatEndpointInfo.modelMaxPromptTokens}`);
|
|
328
|
+
this._logService.debug(`modelMaxResponseTokens ${request.max_tokens ?? 2048}`);
|
|
329
|
+
this._logService.debug(`chat model ${chatEndpointInfo.model}`);
|
|
330
|
+
secretKey ??= (await this._authenticationService.getCopilotToken()).token;
|
|
331
|
+
if (!secretKey) {
|
|
332
|
+
// If no key is set we error
|
|
333
|
+
const urlOrRequestMetadata = (0, networking_1.stringifyUrlOrRequestMetadata)(chatEndpointInfo.urlOrRequestMetadata);
|
|
334
|
+
this._logService.error(`Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
335
|
+
(0, stream_1.sendCommunicationErrorTelemetry)(this._telemetryService, `Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
336
|
+
return {
|
|
337
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
338
|
+
modelRequestId: undefined,
|
|
339
|
+
failKind: fetch_2.ChatFailKind.TokenExpiredOrInvalid,
|
|
340
|
+
reason: 'key is missing'
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
// Generate unique ID to link input and output messages
|
|
344
|
+
const modelCallId = (0, uuid_1.generateUuid)();
|
|
345
|
+
const response = await this._fetchWithInstrumentation(chatEndpointInfo, ourRequestId, request, secretKey, location, cancellationToken, userInitiatedRequest, { ...telemetryProperties, modelCallId }, useFetcher);
|
|
346
|
+
if (cancellationToken.isCancellationRequested) {
|
|
347
|
+
const body = await response.body();
|
|
348
|
+
try {
|
|
349
|
+
// Destroy the stream so that the server is hopefully notified we don't want any more data
|
|
350
|
+
// and can cancel/forget about the request itself.
|
|
351
|
+
body.destroy();
|
|
332
352
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
353
|
+
catch (e) {
|
|
354
|
+
this._logService.error(e, `Error destroying stream`);
|
|
355
|
+
this._telemetryService.sendGHTelemetryException(e, 'Error destroying stream');
|
|
356
|
+
}
|
|
357
|
+
return { type: fetch_2.FetchResponseKind.Canceled, reason: 'after fetch request' };
|
|
358
|
+
}
|
|
359
|
+
if (response.status === 200 && this._authenticationService.copilotToken?.isFreeUser && this._authenticationService.copilotToken?.isChatQuotaExceeded) {
|
|
360
|
+
this._authenticationService.resetCopilotToken();
|
|
361
|
+
}
|
|
362
|
+
if (response.status !== 200) {
|
|
363
|
+
const telemetryData = createTelemetryData(chatEndpointInfo, location, ourRequestId);
|
|
364
|
+
this._logService.info('Request ID for failed request: ' + ourRequestId);
|
|
365
|
+
return this._handleError(telemetryData, response, ourRequestId);
|
|
366
|
+
}
|
|
367
|
+
// Extend baseTelemetryData with modelCallId for output messages
|
|
368
|
+
const extendedBaseTelemetryData = baseTelemetryData.extendedBy({ modelCallId });
|
|
369
|
+
const chatCompletions = await chatEndpointInfo.processResponseFromChatEndpoint(this._telemetryService, this._logService, response, nChoices ?? /* OpenAI's default */ 1, finishedCb, extendedBaseTelemetryData, cancellationToken);
|
|
370
|
+
// CAPI will return us a Copilot Edits Session Header which is our token to using the speculative decoding endpoint
|
|
371
|
+
// We should store this in the auth service for easy use later
|
|
372
|
+
if (response.headers.get('Copilot-Edits-Session')) {
|
|
373
|
+
this._authenticationService.speculativeDecodingEndpointToken = response.headers.get('Copilot-Edits-Session') ?? undefined;
|
|
374
|
+
}
|
|
375
|
+
this._chatQuotaService.processQuotaHeaders(response.headers);
|
|
376
|
+
return {
|
|
377
|
+
type: fetch_2.FetchResponseKind.Success,
|
|
378
|
+
chatCompletions,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
async _fetchWithInstrumentation(chatEndpoint, ourRequestId, request, secretKey, location, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher) {
|
|
382
|
+
// If request contains an image, we include this header.
|
|
383
|
+
const additionalHeaders = {
|
|
384
|
+
'X-Interaction-Id': this._interactionService.interactionId,
|
|
385
|
+
'X-Initiator': userInitiatedRequest ? 'user' : 'agent', // Agent = a system request / not the primary user query.
|
|
386
|
+
};
|
|
387
|
+
if (request.messages?.some((m) => Array.isArray(m.content) ? m.content.some(c => 'image_url' in c) : false) && chatEndpoint.supportsVision) {
|
|
388
|
+
additionalHeaders['Copilot-Vision-Request'] = 'true';
|
|
389
|
+
}
|
|
390
|
+
const telemetryData = telemetryData_1.TelemetryData.createAndMarkAsIssued({
|
|
391
|
+
endpoint: 'completions',
|
|
392
|
+
engineName: 'chat',
|
|
393
|
+
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
394
|
+
...telemetryProperties // This includes the modelCallId from fetchAndStreamChat
|
|
340
395
|
}, {
|
|
341
|
-
|
|
342
|
-
promptTokenCount,
|
|
343
|
-
tokenCountMax,
|
|
344
|
-
timeToFirstToken,
|
|
345
|
-
timeToFirstTokenEmitted,
|
|
346
|
-
timeToCancelled,
|
|
347
|
-
isVisionRequest,
|
|
348
|
-
isBYOK,
|
|
349
|
-
isAuto
|
|
396
|
+
maxTokenWindow: chatEndpoint.modelMaxPromptTokens
|
|
350
397
|
});
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
"timeToFirstToken": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Time to first token", "isMeasurement": true },
|
|
370
|
-
"timeToFirstTokenEmitted": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Time to first token emitted (visible text)", "isMeasurement": true },
|
|
371
|
-
"isVisionRequest": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Whether the request was for a vision model", "isMeasurement": true },
|
|
372
|
-
"isBYOK": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Whether the request was for a BYOK model", "isMeasurement": true },
|
|
373
|
-
"isAuto": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Whether the request was for an Auto model", "isMeasurement": true },
|
|
374
|
-
"retryAfterErrorCategory": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "If the response failed and this is a retry attempt, this contains the error category." },
|
|
375
|
-
"retryAfterFilterCategory": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "If the response was filtered and this is a retry attempt, this contains the original filtered content category." }
|
|
398
|
+
for (const [key, value] of Object.entries(request)) {
|
|
399
|
+
if (key === 'messages' || key === 'input') {
|
|
400
|
+
continue;
|
|
401
|
+
} // Skip messages (PII)
|
|
402
|
+
telemetryData.properties[`request.option.${key}`] = JSON.stringify(value) ?? 'undefined';
|
|
403
|
+
}
|
|
404
|
+
// The request ID we are passed in is sent in the request to the proxy, and included in our pre-request telemetry.
|
|
405
|
+
// We hope (but do not rely on) that the model will use the same ID in the response, allowing us to correlate
|
|
406
|
+
// the request and response.
|
|
407
|
+
telemetryData.properties['headerRequestId'] = ourRequestId;
|
|
408
|
+
this._telemetryService.sendGHTelemetryEvent('request.sent', telemetryData.properties, telemetryData.measurements);
|
|
409
|
+
const requestStart = Date.now();
|
|
410
|
+
const intent = locationToIntent(location);
|
|
411
|
+
// Wrap the Promise with success/error callbacks so we can log/measure it
|
|
412
|
+
return (0, networking_1.postRequest)(this._fetcherService, this._telemetryService, this._capiClientService, chatEndpoint, secretKey, await (0, crypto_1.createRequestHMAC)(process.env.HMAC_SECRET), intent, ourRequestId, request, additionalHeaders, cancellationToken, useFetcher).then(response => {
|
|
413
|
+
const apim = response.headers.get('apim-request-id');
|
|
414
|
+
if (apim) {
|
|
415
|
+
this._logService.debug(`APIM request id: ${apim}`);
|
|
376
416
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
417
|
+
const ghRequestId = response.headers.get('x-github-request-id');
|
|
418
|
+
if (ghRequestId) {
|
|
419
|
+
this._logService.debug(`GH request id: ${ghRequestId}`);
|
|
420
|
+
}
|
|
421
|
+
// This ID is hopefully the one the same as ourRequestId, but it is not guaranteed.
|
|
422
|
+
// If they are different then we will override the original one we set in telemetryData above.
|
|
423
|
+
const modelRequestId = (0, fetch_1.getRequestId)(response, undefined);
|
|
424
|
+
telemetryData.extendWithRequestId(modelRequestId);
|
|
425
|
+
// TODO: Add response length (requires parsing)
|
|
426
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
427
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
428
|
+
this._logService.debug(`request.response: [${(0, networking_1.stringifyUrlOrRequestMetadata)(chatEndpoint.urlOrRequestMetadata)}], took ${totalTimeMs} ms`);
|
|
429
|
+
this._telemetryService.sendGHTelemetryEvent('request.response', telemetryData.properties, telemetryData.measurements);
|
|
430
|
+
return response;
|
|
431
|
+
})
|
|
432
|
+
.catch(error => {
|
|
433
|
+
if (this._fetcherService.isAbortError(error)) {
|
|
434
|
+
// If we cancelled a network request, we don't want to log a `request.error`
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
const warningTelemetry = telemetryData.extendedBy({ error: 'Network exception' });
|
|
438
|
+
this._telemetryService.sendGHTelemetryEvent('request.shownWarning', warningTelemetry.properties, warningTelemetry.measurements);
|
|
439
|
+
telemetryData.properties.code = String(error.code ?? '');
|
|
440
|
+
telemetryData.properties.errno = String(error.errno ?? '');
|
|
441
|
+
telemetryData.properties.message = String(error.message ?? '');
|
|
442
|
+
telemetryData.properties.type = String(error.type ?? '');
|
|
443
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
444
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
445
|
+
this._logService.debug(`request.response: [${(0, networking_1.stringifyUrlOrRequestMetadata)(chatEndpoint.urlOrRequestMetadata)}] took ${totalTimeMs} ms`);
|
|
446
|
+
this._telemetryService.sendGHTelemetryEvent('request.error', telemetryData.properties, telemetryData.measurements);
|
|
447
|
+
throw error;
|
|
448
|
+
})
|
|
449
|
+
.finally(() => {
|
|
450
|
+
(0, chatStream_1.sendEngineMessagesTelemetry)(this._telemetryService, request.messages ?? [], telemetryData, false, this._logService);
|
|
398
451
|
});
|
|
399
452
|
}
|
|
453
|
+
async _handleError(telemetryData, response, requestId) {
|
|
454
|
+
const modelRequestIdObj = (0, fetch_1.getRequestId)(response, undefined);
|
|
455
|
+
requestId = modelRequestIdObj.headerRequestId || requestId;
|
|
456
|
+
modelRequestIdObj.headerRequestId = requestId;
|
|
457
|
+
telemetryData.properties.error = `Response status was ${response.status}`;
|
|
458
|
+
telemetryData.properties.status = String(response.status);
|
|
459
|
+
this._telemetryService.sendGHTelemetryEvent('request.shownWarning', telemetryData.properties, telemetryData.measurements);
|
|
460
|
+
const text = await response.text();
|
|
461
|
+
let jsonData;
|
|
462
|
+
try {
|
|
463
|
+
jsonData = JSON.parse(text);
|
|
464
|
+
jsonData = jsonData?.error ?? jsonData; // Extract nested error object if it exists
|
|
465
|
+
}
|
|
466
|
+
catch {
|
|
467
|
+
// JSON parsing failed, it's not json content.
|
|
468
|
+
}
|
|
469
|
+
if (400 <= response.status && response.status < 500) {
|
|
470
|
+
if (response.status === 400 && text.includes('off_topic')) {
|
|
471
|
+
return {
|
|
472
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
473
|
+
modelRequestId: modelRequestIdObj,
|
|
474
|
+
failKind: fetch_2.ChatFailKind.OffTopic,
|
|
475
|
+
reason: 'filtered as off_topic by intent classifier: message was not programming related',
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
if (response.status === 401 && text.includes('authorize_url') && jsonData?.authorize_url) {
|
|
479
|
+
return {
|
|
480
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
481
|
+
modelRequestId: modelRequestIdObj,
|
|
482
|
+
failKind: fetch_2.ChatFailKind.AgentUnauthorized,
|
|
483
|
+
reason: response.statusText || response.statusText,
|
|
484
|
+
data: jsonData
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
if (response.status === 400 && jsonData?.code === 'previous_response_not_found') {
|
|
488
|
+
return {
|
|
489
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
490
|
+
modelRequestId: modelRequestIdObj,
|
|
491
|
+
failKind: fetch_2.ChatFailKind.InvalidPreviousResponseId,
|
|
492
|
+
reason: jsonData.message || 'Invalid previous response ID',
|
|
493
|
+
data: jsonData,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
if (response.status === 401 || response.status === 403) {
|
|
497
|
+
// Token has expired or invalid, fetch a new one on next request
|
|
498
|
+
// TODO(drifkin): these actions should probably happen in vsc specific code
|
|
499
|
+
this._authenticationService.resetCopilotToken(response.status);
|
|
500
|
+
return {
|
|
501
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
502
|
+
modelRequestId: modelRequestIdObj,
|
|
503
|
+
failKind: fetch_2.ChatFailKind.TokenExpiredOrInvalid,
|
|
504
|
+
reason: jsonData?.message || `token expired or invalid: ${response.status}`,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
if (response.status === 402) {
|
|
508
|
+
// When we receive a 402, we have exceed a quota
|
|
509
|
+
// This is stored on the token so let's refresh it
|
|
510
|
+
this._authenticationService.resetCopilotToken(response.status);
|
|
511
|
+
const retryAfter = response.headers.get('retry-after');
|
|
512
|
+
const convertToDate = (retryAfterString) => {
|
|
513
|
+
if (!retryAfterString) {
|
|
514
|
+
return undefined;
|
|
515
|
+
}
|
|
516
|
+
// Try treating it as a date
|
|
517
|
+
const retryAfterDate = new Date(retryAfterString);
|
|
518
|
+
if (!isNaN(retryAfterDate.getDate())) {
|
|
519
|
+
return retryAfterDate;
|
|
520
|
+
}
|
|
521
|
+
// It is not a date, try treating it as a duration from the current date
|
|
522
|
+
const retryAfterDuration = parseInt(retryAfterString, 10);
|
|
523
|
+
if (isNaN(retryAfterDuration)) {
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
526
|
+
return new Date(Date.now() + retryAfterDuration * 1000);
|
|
527
|
+
};
|
|
528
|
+
const retryAfterDate = convertToDate(retryAfter);
|
|
529
|
+
return {
|
|
530
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
531
|
+
modelRequestId: modelRequestIdObj,
|
|
532
|
+
failKind: fetch_2.ChatFailKind.QuotaExceeded,
|
|
533
|
+
reason: jsonData?.message ?? 'Free tier quota exceeded',
|
|
534
|
+
data: {
|
|
535
|
+
capiError: jsonData,
|
|
536
|
+
retryAfter: retryAfterDate
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if (response.status === 404) {
|
|
541
|
+
let errorReason;
|
|
542
|
+
// Check if response body is valid JSON
|
|
543
|
+
if (!jsonData) {
|
|
544
|
+
errorReason = text;
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
errorReason = JSON.stringify(jsonData);
|
|
548
|
+
}
|
|
549
|
+
return {
|
|
550
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
551
|
+
modelRequestId: modelRequestIdObj,
|
|
552
|
+
failKind: fetch_2.ChatFailKind.NotFound,
|
|
553
|
+
reason: errorReason
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (response.status === 422) {
|
|
557
|
+
return {
|
|
558
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
559
|
+
modelRequestId: modelRequestIdObj,
|
|
560
|
+
failKind: fetch_2.ChatFailKind.ContentFilter,
|
|
561
|
+
reason: 'Filtered by Responsible AI Service'
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
if (response.status === 424) {
|
|
565
|
+
return {
|
|
566
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
567
|
+
modelRequestId: modelRequestIdObj,
|
|
568
|
+
failKind: fetch_2.ChatFailKind.AgentFailedDependency,
|
|
569
|
+
reason: text
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
if (response.status === 429) {
|
|
573
|
+
let rateLimitReason = text;
|
|
574
|
+
rateLimitReason = jsonData?.message ?? jsonData?.code;
|
|
575
|
+
if (text.includes('extension_blocked') && jsonData?.code === 'extension_blocked' && jsonData?.type === 'rate_limit_error') {
|
|
576
|
+
return {
|
|
577
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
578
|
+
modelRequestId: modelRequestIdObj,
|
|
579
|
+
failKind: fetch_2.ChatFailKind.ExtensionBlocked,
|
|
580
|
+
reason: 'Extension blocked',
|
|
581
|
+
data: {
|
|
582
|
+
...jsonData?.message,
|
|
583
|
+
retryAfter: response.headers.get('retry-after'),
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
// HTTP 429 Too Many Requests
|
|
588
|
+
return {
|
|
589
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
590
|
+
modelRequestId: modelRequestIdObj,
|
|
591
|
+
failKind: fetch_2.ChatFailKind.RateLimited,
|
|
592
|
+
reason: rateLimitReason,
|
|
593
|
+
data: {
|
|
594
|
+
retryAfter: response.headers.get('retry-after'),
|
|
595
|
+
rateLimitKey: response.headers.get('x-ratelimit-exceeded'),
|
|
596
|
+
capiError: jsonData
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
if (response.status === 466) {
|
|
601
|
+
this._logService.info(text);
|
|
602
|
+
return {
|
|
603
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
604
|
+
modelRequestId: modelRequestIdObj,
|
|
605
|
+
failKind: fetch_2.ChatFailKind.ClientNotSupported,
|
|
606
|
+
reason: `client not supported: ${text}`
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
if (response.status === 499) {
|
|
610
|
+
this._logService.info('Cancelled by server');
|
|
611
|
+
return {
|
|
612
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
613
|
+
modelRequestId: modelRequestIdObj,
|
|
614
|
+
failKind: fetch_2.ChatFailKind.ServerCanceled,
|
|
615
|
+
reason: 'canceled by server'
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
else if (500 <= response.status && response.status < 600) {
|
|
620
|
+
if (response.status === 503) {
|
|
621
|
+
return {
|
|
622
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
623
|
+
modelRequestId: modelRequestIdObj,
|
|
624
|
+
failKind: fetch_2.ChatFailKind.RateLimited,
|
|
625
|
+
reason: 'Upstream provider rate limit hit',
|
|
626
|
+
data: {
|
|
627
|
+
retryAfter: null,
|
|
628
|
+
rateLimitKey: null,
|
|
629
|
+
capiError: { code: 'upstream_provider_rate_limit', message: text }
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
const reasonNoText = `Server error: ${response.status}`;
|
|
634
|
+
const reason = `${reasonNoText} ${text}`;
|
|
635
|
+
this._logService.error(reason);
|
|
636
|
+
// HTTP 5xx Server Error
|
|
637
|
+
return {
|
|
638
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
639
|
+
modelRequestId: modelRequestIdObj,
|
|
640
|
+
failKind: fetch_2.ChatFailKind.ServerError,
|
|
641
|
+
reason: reasonNoText,
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
this._logService.error(`Request Failed: ${response.status} ${text}`);
|
|
645
|
+
(0, stream_1.sendCommunicationErrorTelemetry)(this._telemetryService, 'Unhandled status from server: ' + response.status, text);
|
|
646
|
+
return {
|
|
647
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
648
|
+
modelRequestId: modelRequestIdObj,
|
|
649
|
+
failKind: fetch_2.ChatFailKind.Unknown,
|
|
650
|
+
reason: `Request Failed: ${response.status} ${text}`
|
|
651
|
+
};
|
|
652
|
+
}
|
|
400
653
|
async processSuccessfulResponse(response, messages, requestBody, requestId, maxResponseTokens, promptTokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpointInfo, userInitiatedRequest) {
|
|
401
654
|
const completions = [];
|
|
402
655
|
for await (const chatCompletion of response.chatCompletions) {
|
|
403
|
-
|
|
404
|
-
"response.success" : {
|
|
405
|
-
"owner": "digitarald",
|
|
406
|
-
"comment": "Report quality details for a successful service response.",
|
|
407
|
-
"reason": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Reason for why a response finished" },
|
|
408
|
-
"filterReason": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Reason for why a response was filtered" },
|
|
409
|
-
"source": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Source of the initial request" },
|
|
410
|
-
"initiatorType": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Whether the request was initiated by a user or an agent" },
|
|
411
|
-
"model": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Model selection for the response" },
|
|
412
|
-
"modelInvoked": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Actual model invoked for the response" },
|
|
413
|
-
"apiType": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "API type for the response- chat completions or responses" },
|
|
414
|
-
"requestId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Id of the current turn request" },
|
|
415
|
-
"associatedRequestId": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Another request ID that this request is associated with (eg, the originating request of a summarization request)." },
|
|
416
|
-
"reasoningEffort": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Reasoning effort level" },
|
|
417
|
-
"reasoningSummary": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Reasoning summary level" },
|
|
418
|
-
"totalTokenMax": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Maximum total token window", "isMeasurement": true },
|
|
419
|
-
"clientPromptTokenCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Number of prompt tokens, locally counted", "isMeasurement": true },
|
|
420
|
-
"promptTokenCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Number of prompt tokens, server side counted", "isMeasurement": true },
|
|
421
|
-
"promptCacheTokenCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Number of prompt tokens hitting cache as reported by server", "isMeasurement": true },
|
|
422
|
-
"tokenCountMax": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Maximum generated tokens", "isMeasurement": true },
|
|
423
|
-
"tokenCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Number of generated tokens", "isMeasurement": true },
|
|
424
|
-
"reasoningTokens": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Number of reasoning tokens", "isMeasurement": true },
|
|
425
|
-
"acceptedPredictionTokens": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Number of tokens in the prediction that appeared in the completion", "isMeasurement": true },
|
|
426
|
-
"rejectedPredictionTokens": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Number of tokens in the prediction that appeared in the completion", "isMeasurement": true },
|
|
427
|
-
"completionTokens": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Number of tokens in the output", "isMeasurement": true },
|
|
428
|
-
"timeToFirstToken": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Time to first token", "isMeasurement": true },
|
|
429
|
-
"timeToFirstTokenEmitted": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Time to first token emitted (visible text)", "isMeasurement": true },
|
|
430
|
-
"timeToComplete": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Time to complete the request", "isMeasurement": true },
|
|
431
|
-
"isVisionRequest": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "comment": "Whether the request was for a vision model", "isMeasurement": true },
|
|
432
|
-
"isBYOK": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Whether the request was for a BYOK model", "isMeasurement": true },
|
|
433
|
-
"isAuto": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "Whether the request was for an Auto model", "isMeasurement": true },
|
|
434
|
-
"retryAfterErrorCategory": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "If the response failed and this is a retry attempt, this contains the error category." },
|
|
435
|
-
"retryAfterFilterCategory": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "If the response was filtered and this is a retry attempt, this contains the original filtered content category." }
|
|
436
|
-
}
|
|
437
|
-
*/
|
|
438
|
-
this._telemetryService.sendTelemetryEvent('response.success', { github: true, microsoft: true }, {
|
|
439
|
-
reason: chatCompletion.finishReason,
|
|
440
|
-
filterReason: chatCompletion.filterReason,
|
|
441
|
-
source: baseTelemetry?.properties.messageSource ?? 'unknown',
|
|
442
|
-
initiatorType: userInitiatedRequest ? 'user' : 'agent',
|
|
443
|
-
model: chatEndpointInfo?.model,
|
|
444
|
-
modelInvoked: chatCompletion.model,
|
|
445
|
-
apiType: chatEndpointInfo?.apiType,
|
|
656
|
+
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendSuccessTelemetry(this._telemetryService, {
|
|
446
657
|
requestId,
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
tokenCountMax: maxResponseTokens,
|
|
455
|
-
promptTokenCount: chatCompletion.usage?.prompt_tokens,
|
|
456
|
-
promptCacheTokenCount: chatCompletion.usage?.prompt_tokens_details?.cached_tokens,
|
|
457
|
-
clientPromptTokenCount: promptTokenCount,
|
|
458
|
-
tokenCount: chatCompletion.usage?.total_tokens,
|
|
459
|
-
reasoningTokens: chatCompletion.usage?.completion_tokens_details?.reasoning_tokens,
|
|
460
|
-
acceptedPredictionTokens: chatCompletion.usage?.completion_tokens_details?.accepted_prediction_tokens,
|
|
461
|
-
rejectedPredictionTokens: chatCompletion.usage?.completion_tokens_details?.rejected_prediction_tokens,
|
|
462
|
-
completionTokens: chatCompletion.usage?.completion_tokens,
|
|
658
|
+
chatCompletion,
|
|
659
|
+
baseTelemetry,
|
|
660
|
+
userInitiatedRequest,
|
|
661
|
+
chatEndpointInfo,
|
|
662
|
+
requestBody,
|
|
663
|
+
maxResponseTokens,
|
|
664
|
+
promptTokenCount,
|
|
463
665
|
timeToFirstToken,
|
|
464
666
|
timeToFirstTokenEmitted: (baseTelemetry && streamRecorder.firstTokenEmittedTime) ? streamRecorder.firstTokenEmittedTime - baseTelemetry.issuedTime : -1,
|
|
465
|
-
|
|
466
|
-
isVisionRequest: this.filterImageMessages(messages) ? 1 : -1,
|
|
467
|
-
isBYOK: (0, openAIEndpoint_1.isBYOKModel)(chatEndpointInfo),
|
|
468
|
-
isAuto: (0, autoChatEndpoint_1.isAutoModel)(chatEndpointInfo)
|
|
667
|
+
hasImageMessages: this.filterImageMessages(messages),
|
|
469
668
|
});
|
|
470
669
|
if (!this.isRepetitive(chatCompletion, baseTelemetry?.properties)) {
|
|
471
670
|
completions.push(chatCompletion);
|
|
@@ -564,38 +763,38 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
564
763
|
processFailedResponse(response, requestId) {
|
|
565
764
|
const serverRequestId = response.modelRequestId?.gitHubRequestId;
|
|
566
765
|
const reason = response.reason;
|
|
567
|
-
if (response.failKind ===
|
|
766
|
+
if (response.failKind === fetch_2.ChatFailKind.RateLimited) {
|
|
568
767
|
return { type: commonTypes_1.ChatFetchResponseType.RateLimited, reason, requestId, serverRequestId, retryAfter: response.data?.retryAfter, rateLimitKey: (response.data?.rateLimitKey || ''), capiError: response.data?.capiError };
|
|
569
768
|
}
|
|
570
|
-
if (response.failKind ===
|
|
769
|
+
if (response.failKind === fetch_2.ChatFailKind.QuotaExceeded) {
|
|
571
770
|
return { type: commonTypes_1.ChatFetchResponseType.QuotaExceeded, reason, requestId, serverRequestId, retryAfter: response.data?.retryAfter, capiError: response.data?.capiError };
|
|
572
771
|
}
|
|
573
|
-
if (response.failKind ===
|
|
772
|
+
if (response.failKind === fetch_2.ChatFailKind.OffTopic) {
|
|
574
773
|
return { type: commonTypes_1.ChatFetchResponseType.OffTopic, reason, requestId, serverRequestId };
|
|
575
774
|
}
|
|
576
|
-
if (response.failKind ===
|
|
775
|
+
if (response.failKind === fetch_2.ChatFailKind.TokenExpiredOrInvalid || response.failKind === fetch_2.ChatFailKind.ClientNotSupported || reason.includes('Bad request: ')) {
|
|
577
776
|
return { type: commonTypes_1.ChatFetchResponseType.BadRequest, reason, requestId, serverRequestId };
|
|
578
777
|
}
|
|
579
|
-
if (response.failKind ===
|
|
778
|
+
if (response.failKind === fetch_2.ChatFailKind.ServerError) {
|
|
580
779
|
return { type: commonTypes_1.ChatFetchResponseType.Failed, reason, requestId, serverRequestId };
|
|
581
780
|
}
|
|
582
|
-
if (response.failKind ===
|
|
781
|
+
if (response.failKind === fetch_2.ChatFailKind.ContentFilter) {
|
|
583
782
|
return { type: commonTypes_1.ChatFetchResponseType.PromptFiltered, reason, category: openai_1.FilterReason.Prompt, requestId, serverRequestId };
|
|
584
783
|
}
|
|
585
|
-
if (response.failKind ===
|
|
784
|
+
if (response.failKind === fetch_2.ChatFailKind.AgentUnauthorized) {
|
|
586
785
|
return { type: commonTypes_1.ChatFetchResponseType.AgentUnauthorized, reason, authorizationUrl: response.data.authorize_url, requestId, serverRequestId };
|
|
587
786
|
}
|
|
588
|
-
if (response.failKind ===
|
|
787
|
+
if (response.failKind === fetch_2.ChatFailKind.AgentFailedDependency) {
|
|
589
788
|
return { type: commonTypes_1.ChatFetchResponseType.AgentFailedDependency, reason, requestId, serverRequestId };
|
|
590
789
|
}
|
|
591
|
-
if (response.failKind ===
|
|
790
|
+
if (response.failKind === fetch_2.ChatFailKind.ExtensionBlocked) {
|
|
592
791
|
const retryAfter = typeof response.data?.retryAfter === 'number' ? response.data.retryAfter : 300;
|
|
593
792
|
return { type: commonTypes_1.ChatFetchResponseType.ExtensionBlocked, reason, requestId, retryAfter, learnMoreLink: response.data?.learnMoreLink ?? '', serverRequestId };
|
|
594
793
|
}
|
|
595
|
-
if (response.failKind ===
|
|
794
|
+
if (response.failKind === fetch_2.ChatFailKind.NotFound) {
|
|
596
795
|
return { type: commonTypes_1.ChatFetchResponseType.NotFound, reason, requestId, serverRequestId };
|
|
597
796
|
}
|
|
598
|
-
if (response.failKind ===
|
|
797
|
+
if (response.failKind === fetch_2.ChatFailKind.InvalidPreviousResponseId) {
|
|
599
798
|
return { type: commonTypes_1.ChatFetchResponseType.InvalidStatefulMarker, reason, requestId, serverRequestId };
|
|
600
799
|
}
|
|
601
800
|
return { type: commonTypes_1.ChatFetchResponseType.Failed, reason, requestId, serverRequestId };
|
|
@@ -677,8 +876,10 @@ exports.ChatMLFetcherImpl = ChatMLFetcherImpl = __decorate([
|
|
|
677
876
|
__param(2, requestLogger_1.IRequestLogger),
|
|
678
877
|
__param(3, logService_1.ILogService),
|
|
679
878
|
__param(4, authentication_1.IAuthenticationService),
|
|
680
|
-
__param(5,
|
|
681
|
-
__param(6,
|
|
879
|
+
__param(5, interactionService_1.IInteractionService),
|
|
880
|
+
__param(6, chatQuotaService_1.IChatQuotaService),
|
|
881
|
+
__param(7, capiClient_1.ICAPIClientService),
|
|
882
|
+
__param(8, conversationOptions_1.IConversationOptions)
|
|
682
883
|
], ChatMLFetcherImpl);
|
|
683
884
|
/**
|
|
684
885
|
* Validates a chat request payload to ensure it is valid
|
|
@@ -705,4 +906,37 @@ function isValidChatPayload(messages, postOptions) {
|
|
|
705
906
|
function asUnexpected(reason) {
|
|
706
907
|
return `Prompt failed validation with the reason: ${reason}. Please file an issue.`;
|
|
707
908
|
}
|
|
909
|
+
function createTelemetryData(chatEndpointInfo, location, headerRequestId) {
|
|
910
|
+
return telemetryData_1.TelemetryData.createAndMarkAsIssued({
|
|
911
|
+
endpoint: 'completions',
|
|
912
|
+
engineName: 'chat',
|
|
913
|
+
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
914
|
+
headerRequestId
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* WARNING: The value that is returned from this function drives the disablement of RAI for full-file rewrite requests
|
|
919
|
+
* in Copilot Edits, Copilot Chat, Agent Mode, and Inline Chat.
|
|
920
|
+
* If your chat location generates full-file rewrite requests and you are unsure if changing something here will cause problems, please talk to @roblourens
|
|
921
|
+
*/
|
|
922
|
+
function locationToIntent(location) {
|
|
923
|
+
switch (location) {
|
|
924
|
+
case commonTypes_1.ChatLocation.Panel:
|
|
925
|
+
return 'conversation-panel';
|
|
926
|
+
case commonTypes_1.ChatLocation.Editor:
|
|
927
|
+
return 'conversation-inline';
|
|
928
|
+
case commonTypes_1.ChatLocation.EditingSession:
|
|
929
|
+
return 'conversation-edits';
|
|
930
|
+
case commonTypes_1.ChatLocation.Notebook:
|
|
931
|
+
return 'conversation-notebook';
|
|
932
|
+
case commonTypes_1.ChatLocation.Terminal:
|
|
933
|
+
return 'conversation-terminal';
|
|
934
|
+
case commonTypes_1.ChatLocation.Other:
|
|
935
|
+
return 'conversation-other';
|
|
936
|
+
case commonTypes_1.ChatLocation.Agent:
|
|
937
|
+
return 'conversation-agent';
|
|
938
|
+
case commonTypes_1.ChatLocation.ResponsesProxy:
|
|
939
|
+
return 'responses-proxy';
|
|
940
|
+
}
|
|
941
|
+
}
|
|
708
942
|
//# sourceMappingURL=chatMLFetcher.js.map
|