@vscode/chat-lib 0.4.1-8 → 0.5.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/byok/node/openAIEndpoint.d.ts +2 -1
- package/dist/src/_internal/extension/byok/node/openAIEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/extension/byok/node/openAIEndpoint.js +6 -7
- package/dist/src/_internal/extension/byok/node/openAIEndpoint.js.map +1 -1
- package/dist/src/_internal/extension/common/constants.d.ts +0 -1
- package/dist/src/_internal/extension/common/constants.d.ts.map +1 -1
- package/dist/src/_internal/extension/common/constants.js.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/common/delay.d.ts +2 -1
- package/dist/src/_internal/extension/inlineEdits/common/delay.d.ts.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/common/delay.js +3 -0
- package/dist/src/_internal/extension/inlineEdits/common/delay.js.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.d.ts +6 -0
- package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.d.ts.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.js +9 -0
- package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.js.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts +9 -0
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js +75 -13
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts +17 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js +345 -57
- package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts +6 -3
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts.map +1 -1
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js +9 -3
- package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js.map +1 -1
- package/dist/src/_internal/extension/xtab/common/promptCrafting.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/common/promptCrafting.js +41 -4
- package/dist/src/_internal/extension/xtab/common/promptCrafting.js.map +1 -1
- package/dist/src/_internal/extension/xtab/common/tags.d.ts +1 -0
- package/dist/src/_internal/extension/xtab/common/tags.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/common/tags.js +1 -0
- package/dist/src/_internal/extension/xtab/common/tags.js.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabEndpoint.d.ts +2 -1
- package/dist/src/_internal/extension/xtab/node/xtabEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabEndpoint.js +6 -3
- package/dist/src/_internal/extension/xtab/node/xtabEndpoint.js.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.js +1 -0
- package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.js.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts +3 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js +56 -18
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js.map +1 -1
- package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts +4 -0
- package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts.map +1 -1
- package/dist/src/_internal/platform/authentication/common/copilotToken.js +6 -0
- package/dist/src/_internal/platform/authentication/common/copilotToken.js.map +1 -1
- package/dist/src/_internal/platform/chat/common/commonTypes.d.ts +2 -1
- package/dist/src/_internal/platform/chat/common/commonTypes.d.ts.map +1 -1
- package/dist/src/_internal/platform/chat/common/commonTypes.js +61 -17
- package/dist/src/_internal/platform/chat/common/commonTypes.js.map +1 -1
- package/dist/src/_internal/platform/configuration/common/configurationService.d.ts +16 -4
- package/dist/src/_internal/platform/configuration/common/configurationService.d.ts.map +1 -1
- package/dist/src/_internal/platform/configuration/common/configurationService.js +32 -6
- package/dist/src/_internal/platform/configuration/common/configurationService.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/capiClient.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/capiClient.js +1 -0
- package/dist/src/_internal/platform/endpoint/common/capiClient.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts +1 -0
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js +20 -4
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts +3 -1
- package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/endpointProvider.js +1 -0
- package/dist/src/_internal/platform/endpoint/common/endpointProvider.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.d.ts +2 -1
- package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.js +6 -3
- package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts +6 -2
- package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js +34 -12
- package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/copilotChatEndpoint.d.ts +2 -1
- package/dist/src/_internal/platform/endpoint/node/copilotChatEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/copilotChatEndpoint.js +5 -3
- package/dist/src/_internal/platform/endpoint/node/copilotChatEndpoint.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/messagesApi.js +55 -5
- package/dist/src/_internal/platform/endpoint/node/messagesApi.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.js +1 -0
- package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.js.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts +1 -0
- package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/responsesApi.js +14 -10
- package/dist/src/_internal/platform/endpoint/node/responsesApi.js.map +1 -1
- package/dist/src/_internal/platform/git/common/gitService.d.ts +4 -0
- package/dist/src/_internal/platform/git/common/gitService.d.ts.map +1 -1
- package/dist/src/_internal/platform/git/common/gitService.js.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts +1 -0
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.js +2 -0
- package/dist/src/_internal/platform/github/common/githubAPI.js.map +1 -1
- package/dist/src/_internal/platform/github/common/githubService.d.ts +10 -0
- package/dist/src/_internal/platform/github/common/githubService.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/githubService.js +38 -0
- package/dist/src/_internal/platform/github/common/githubService.js.map +1 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.d.ts +2 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.js +3 -0
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts +11 -1
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js +27 -3
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts +2 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js +2 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.js +7 -9
- package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/anthropic.d.ts +8 -1
- package/dist/src/_internal/platform/networking/common/anthropic.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/anthropic.js +20 -4
- package/dist/src/_internal/platform/networking/common/anthropic.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetcherService.d.ts +17 -0
- package/dist/src/_internal/platform/networking/common/fetcherService.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetcherService.js +27 -1
- package/dist/src/_internal/platform/networking/common/fetcherService.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/networking.d.ts +7 -0
- package/dist/src/_internal/platform/networking/common/networking.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/networking.js +4 -5
- package/dist/src/_internal/platform/networking/common/networking.js.map +1 -1
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts +76 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js +480 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts +87 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js +265 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.d.ts +85 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.js +105 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiEvents.d.ts +28 -0
- package/dist/src/_internal/platform/otel/common/genAiEvents.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiEvents.js +91 -0
- package/dist/src/_internal/platform/otel/common/genAiEvents.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiMetrics.d.ts +30 -0
- package/dist/src/_internal/platform/otel/common/genAiMetrics.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiMetrics.js +68 -0
- package/dist/src/_internal/platform/otel/common/genAiMetrics.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/index.d.ts +8 -0
- package/dist/src/_internal/platform/otel/common/index.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/index.js +35 -0
- package/dist/src/_internal/platform/otel/common/index.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/messageFormatters.d.ts +85 -0
- package/dist/src/_internal/platform/otel/common/messageFormatters.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/messageFormatters.js +122 -0
- package/dist/src/_internal/platform/otel/common/messageFormatters.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.d.ts +23 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.js +46 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/otelConfig.d.ts +35 -0
- package/dist/src/_internal/platform/otel/common/otelConfig.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/otelConfig.js +140 -0
- package/dist/src/_internal/platform/otel/common/otelConfig.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/otelService.d.ts +100 -0
- package/dist/src/_internal/platform/otel/common/otelService.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/otelService.js +10 -0
- package/dist/src/_internal/platform/otel/common/otelService.js.map +1 -0
- package/dist/src/main.d.ts.map +1 -1
- package/dist/src/main.js +9 -0
- package/dist/src/main.js.map +1 -1
- package/dist/src/package.json +227 -87
- package/package.json +3 -2
|
@@ -12,6 +12,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
12
12
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
13
13
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
14
14
|
};
|
|
15
|
+
var ChatMLFetcherImpl_1;
|
|
15
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
17
|
exports.ChatMLFetcherImpl = exports.AbstractChatMLFetcher = void 0;
|
|
17
18
|
exports.createTelemetryData = createTelemetryData;
|
|
@@ -35,8 +36,11 @@ const fetcherService_1 = require("../../../platform/networking/common/fetcherSer
|
|
|
35
36
|
const networking_1 = require("../../../platform/networking/common/networking");
|
|
36
37
|
const openai_1 = require("../../../platform/networking/common/openai");
|
|
37
38
|
const chatStream_1 = require("../../../platform/networking/node/chatStream");
|
|
39
|
+
const chatWebSocketManager_1 = require("../../../platform/networking/node/chatWebSocketManager");
|
|
38
40
|
const stream_1 = require("../../../platform/networking/node/stream");
|
|
39
41
|
const fetch_2 = require("../../../platform/openai/node/fetch");
|
|
42
|
+
const index_1 = require("../../../platform/otel/common/index");
|
|
43
|
+
const otelService_1 = require("../../../platform/otel/common/otelService");
|
|
40
44
|
const requestLogger_1 = require("../../../platform/requestLogger/node/requestLogger");
|
|
41
45
|
const nullExperimentationService_1 = require("../../../platform/telemetry/common/nullExperimentationService");
|
|
42
46
|
const telemetry_1 = require("../../../platform/telemetry/common/telemetry");
|
|
@@ -83,7 +87,9 @@ class AbstractChatMLFetcher extends lifecycle_1.Disposable {
|
|
|
83
87
|
}
|
|
84
88
|
exports.AbstractChatMLFetcher = AbstractChatMLFetcher;
|
|
85
89
|
let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
86
|
-
|
|
90
|
+
static { ChatMLFetcherImpl_1 = this; }
|
|
91
|
+
static { this._maxConsecutiveWebSocketFallbacks = 3; }
|
|
92
|
+
constructor(_fetcherService, _telemetryService, _requestLogger, _logService, _authenticationService, _interactionService, _chatQuotaService, _capiClientService, options, _configurationService, _experimentationService, _powerService, _instantiationService, _webSocketManager, _otelService) {
|
|
87
93
|
super(options);
|
|
88
94
|
this._fetcherService = _fetcherService;
|
|
89
95
|
this._telemetryService = _telemetryService;
|
|
@@ -97,23 +103,36 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
97
103
|
this._experimentationService = _experimentationService;
|
|
98
104
|
this._powerService = _powerService;
|
|
99
105
|
this._instantiationService = _instantiationService;
|
|
106
|
+
this._webSocketManager = _webSocketManager;
|
|
107
|
+
this._otelService = _otelService;
|
|
100
108
|
/**
|
|
101
109
|
* Delays (in ms) between connectivity check attempts before retrying a failed request.
|
|
102
110
|
* Configurable for testing purposes.
|
|
103
111
|
*/
|
|
104
112
|
this.connectivityCheckDelays = [1000, 10000, 10000];
|
|
113
|
+
/**
|
|
114
|
+
* Tracks consecutive WebSocket request failures where the HTTP retry succeeded.
|
|
115
|
+
* After {@link _maxConsecutiveWebSocketFallbacks} such failures, WebSocket requests are disabled entirely.
|
|
116
|
+
*/
|
|
117
|
+
this._consecutiveWebSocketRetryFallbacks = 0;
|
|
105
118
|
}
|
|
106
119
|
/**
|
|
107
120
|
* Note: the returned array of strings may be less than `n` (e.g., in case there were errors during streaming)
|
|
108
121
|
*/
|
|
109
122
|
async fetchMany(opts, token) {
|
|
110
|
-
let { debugName, endpoint: chatEndpoint, finishedCb, location, messages, requestOptions, source, telemetryProperties, userInitiatedRequest, requestKindOptions } = opts;
|
|
123
|
+
let { debugName, endpoint: chatEndpoint, finishedCb, location, messages, requestOptions, source, telemetryProperties, userInitiatedRequest, requestKindOptions, conversationId, turnId, useWebSocket, ignoreStatefulMarker } = opts;
|
|
124
|
+
if (useWebSocket && this._consecutiveWebSocketRetryFallbacks >= ChatMLFetcherImpl_1._maxConsecutiveWebSocketFallbacks) {
|
|
125
|
+
this._logService.debug(`[ChatWebSocketManager] Disabling WebSocket for request due to ${this._consecutiveWebSocketRetryFallbacks} consecutive WebSocket failures with successful HTTP fallback.`);
|
|
126
|
+
useWebSocket = false;
|
|
127
|
+
ignoreStatefulMarker = true;
|
|
128
|
+
}
|
|
111
129
|
if (!telemetryProperties) {
|
|
112
130
|
telemetryProperties = {};
|
|
113
131
|
}
|
|
114
132
|
if (!telemetryProperties.messageSource) {
|
|
115
133
|
telemetryProperties.messageSource = debugName;
|
|
116
134
|
}
|
|
135
|
+
const transport = useWebSocket ? 'websocket' : 'http';
|
|
117
136
|
// TODO @lramos15 telemetry should not drive request ids
|
|
118
137
|
const ourRequestId = telemetryProperties.requestId ?? telemetryProperties.messageId ?? (0, uuid_1.generateUuid)();
|
|
119
138
|
const maxResponseTokens = chatEndpoint.maxOutputTokens;
|
|
@@ -127,6 +146,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
127
146
|
const postOptions = this.preparePostOptions(requestOptions);
|
|
128
147
|
const requestBody = chatEndpoint.createRequestBody({
|
|
129
148
|
...opts,
|
|
149
|
+
ignoreStatefulMarker,
|
|
130
150
|
requestId: ourRequestId,
|
|
131
151
|
postOptions
|
|
132
152
|
});
|
|
@@ -141,7 +161,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
141
161
|
ourRequestId,
|
|
142
162
|
location: opts.location,
|
|
143
163
|
body: requestBody,
|
|
144
|
-
ignoreStatefulMarker
|
|
164
|
+
ignoreStatefulMarker,
|
|
145
165
|
isConversationRequest: opts.isConversationRequest,
|
|
146
166
|
customMetadata: opts.customMetadata
|
|
147
167
|
});
|
|
@@ -155,6 +175,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
155
175
|
let actualStatusCode;
|
|
156
176
|
let suspendEventSeen;
|
|
157
177
|
let resumeEventSeen;
|
|
178
|
+
let otelInferenceSpan;
|
|
158
179
|
try {
|
|
159
180
|
let response;
|
|
160
181
|
const payloadValidationResult = isValidChatPayload(opts.messages, postOptions, chatEndpoint, this._configurationService, this._experimentationService);
|
|
@@ -169,13 +190,31 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
169
190
|
else {
|
|
170
191
|
const copilotToken = await this._authenticationService.getCopilotToken();
|
|
171
192
|
usernameToScrub = copilotToken.username;
|
|
172
|
-
const fetchResult = await this._fetchAndStreamChat(chatEndpoint, requestBody, baseTelemetry, streamRecorder.callback, requestOptions.secretKey, copilotToken, opts.location, ourRequestId, postOptions.n, token, userInitiatedRequest, telemetryProperties, opts.useFetcher, canRetryOnce, requestKindOptions);
|
|
193
|
+
const fetchResult = await this._fetchAndStreamChat(chatEndpoint, requestBody, baseTelemetry, streamRecorder.callback, requestOptions.secretKey, copilotToken, opts.location, ourRequestId, postOptions.n, token, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, opts.useFetcher, canRetryOnce, requestKindOptions);
|
|
173
194
|
response = fetchResult.result;
|
|
174
195
|
actualFetcher = fetchResult.fetcher;
|
|
175
196
|
actualBytesReceived = fetchResult.bytesReceived;
|
|
176
197
|
actualStatusCode = fetchResult.statusCode;
|
|
177
198
|
suspendEventSeen = fetchResult.suspendEventSeen;
|
|
178
199
|
resumeEventSeen = fetchResult.resumeEventSeen;
|
|
200
|
+
otelInferenceSpan = fetchResult.otelSpan;
|
|
201
|
+
// Tag span with debug name so orphaned spans (title, progressMessages, etc.) are identifiable
|
|
202
|
+
otelInferenceSpan?.setAttribute(index_1.GenAiAttr.AGENT_NAME, debugName);
|
|
203
|
+
// Capture request content when enabled
|
|
204
|
+
if (this._otelService.config.captureContent && otelInferenceSpan) {
|
|
205
|
+
const capiMessages = requestBody.messages;
|
|
206
|
+
if (capiMessages) {
|
|
207
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.INPUT_MESSAGES, (0, index_1.truncateForOTel)(JSON.stringify((0, index_1.toInputMessages)(capiMessages))));
|
|
208
|
+
}
|
|
209
|
+
// Capture system instructions (first system message)
|
|
210
|
+
const systemMsg = capiMessages?.find(m => m.role === 'system');
|
|
211
|
+
if (systemMsg?.content) {
|
|
212
|
+
const sysInstructions = (0, index_1.toSystemInstructions)(systemMsg.content);
|
|
213
|
+
if (sysInstructions) {
|
|
214
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.SYSTEM_INSTRUCTIONS, (0, index_1.truncateForOTel)(JSON.stringify(sysInstructions)));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
179
218
|
tokenCount = await chatEndpoint.acquireTokenizer().countMessagesTokens(messages);
|
|
180
219
|
const extensionId = source?.extensionId ?? constants_1.EXTENSION_ID;
|
|
181
220
|
this._onDidMakeChatMLRequest.fire({
|
|
@@ -189,7 +228,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
189
228
|
pendingLoggedChatRequest?.markTimeToFirstToken(timeToFirstToken);
|
|
190
229
|
switch (response.type) {
|
|
191
230
|
case fetch_2.FetchResponseKind.Success: {
|
|
192
|
-
const result = await this.processSuccessfulResponse(response, messages, requestBody, ourRequestId, maxResponseTokens, tokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpoint, userInitiatedRequest, actualFetcher, actualBytesReceived, suspendEventSeen, resumeEventSeen);
|
|
231
|
+
const result = await this.processSuccessfulResponse(response, messages, requestBody, ourRequestId, maxResponseTokens, tokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpoint, userInitiatedRequest, transport, actualFetcher, actualBytesReceived, suspendEventSeen, resumeEventSeen);
|
|
193
232
|
// Handle FilteredRetry case with augmented messages
|
|
194
233
|
if (result.type === commonTypes_1.ChatFetchResponseType.FilteredRetry) {
|
|
195
234
|
if (opts.enableRetryOnFilter) {
|
|
@@ -237,6 +276,72 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
237
276
|
};
|
|
238
277
|
}
|
|
239
278
|
pendingLoggedChatRequest?.resolve(result, streamRecorder.deltas);
|
|
279
|
+
// Record OTel token usage metrics if available
|
|
280
|
+
if (result.type === commonTypes_1.ChatFetchResponseType.Success && result.usage) {
|
|
281
|
+
const metricAttrs = {
|
|
282
|
+
operationName: index_1.GenAiOperationName.CHAT,
|
|
283
|
+
providerName: index_1.GenAiProviderName.GITHUB,
|
|
284
|
+
requestModel: chatEndpoint.model,
|
|
285
|
+
responseModel: result.resolvedModel,
|
|
286
|
+
};
|
|
287
|
+
if (result.usage.prompt_tokens) {
|
|
288
|
+
index_1.GenAiMetrics.recordTokenUsage(this._otelService, result.usage.prompt_tokens, 'input', metricAttrs);
|
|
289
|
+
}
|
|
290
|
+
if (result.usage.completion_tokens) {
|
|
291
|
+
index_1.GenAiMetrics.recordTokenUsage(this._otelService, result.usage.completion_tokens, 'output', metricAttrs);
|
|
292
|
+
}
|
|
293
|
+
// Set token usage and response details on the chat span before ending it
|
|
294
|
+
otelInferenceSpan?.setAttributes({
|
|
295
|
+
[index_1.GenAiAttr.USAGE_INPUT_TOKENS]: result.usage.prompt_tokens ?? 0,
|
|
296
|
+
[index_1.GenAiAttr.USAGE_OUTPUT_TOKENS]: result.usage.completion_tokens ?? 0,
|
|
297
|
+
[index_1.GenAiAttr.RESPONSE_MODEL]: result.resolvedModel ?? chatEndpoint.model,
|
|
298
|
+
[index_1.GenAiAttr.RESPONSE_ID]: result.requestId,
|
|
299
|
+
[index_1.GenAiAttr.RESPONSE_FINISH_REASONS]: ['stop'],
|
|
300
|
+
...(result.usage.prompt_tokens_details?.cached_tokens
|
|
301
|
+
? { [index_1.GenAiAttr.USAGE_CACHE_READ_INPUT_TOKENS]: result.usage.prompt_tokens_details.cached_tokens }
|
|
302
|
+
: {}),
|
|
303
|
+
[index_1.CopilotChatAttr.TIME_TO_FIRST_TOKEN]: timeToFirstToken,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// Capture response content when enabled
|
|
307
|
+
if (this._otelService.config.captureContent && otelInferenceSpan && result.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
308
|
+
const responseText = streamRecorder.deltas.map(d => d.text).join('');
|
|
309
|
+
const toolCalls = streamRecorder.deltas
|
|
310
|
+
.filter(d => d.copilotToolCalls?.length)
|
|
311
|
+
.flatMap(d => d.copilotToolCalls.map(tc => ({
|
|
312
|
+
type: 'tool_call', id: tc.id, name: tc.name, arguments: tc.arguments
|
|
313
|
+
})));
|
|
314
|
+
const parts = [];
|
|
315
|
+
if (responseText) {
|
|
316
|
+
parts.push({ type: 'text', content: responseText });
|
|
317
|
+
}
|
|
318
|
+
parts.push(...toolCalls);
|
|
319
|
+
if (parts.length > 0) {
|
|
320
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.OUTPUT_MESSAGES, (0, index_1.truncateForOTel)(JSON.stringify([{ role: 'assistant', parts }])));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Emit OTel inference details event BEFORE ending the span
|
|
324
|
+
// so the log record inherits the active trace context
|
|
325
|
+
(0, index_1.emitInferenceDetailsEvent)(this._otelService, {
|
|
326
|
+
model: chatEndpoint.model,
|
|
327
|
+
temperature: requestOptions?.temperature,
|
|
328
|
+
maxTokens: requestOptions?.max_tokens,
|
|
329
|
+
}, result.type === commonTypes_1.ChatFetchResponseType.Success ? {
|
|
330
|
+
id: result.requestId,
|
|
331
|
+
model: result.resolvedModel,
|
|
332
|
+
finishReasons: ['stop'],
|
|
333
|
+
inputTokens: result.usage?.prompt_tokens,
|
|
334
|
+
outputTokens: result.usage?.completion_tokens,
|
|
335
|
+
} : undefined);
|
|
336
|
+
otelInferenceSpan?.end();
|
|
337
|
+
otelInferenceSpan = undefined;
|
|
338
|
+
// Record OTel time-to-first-token metric
|
|
339
|
+
if (timeToFirstToken > 0) {
|
|
340
|
+
index_1.GenAiMetrics.recordTimeToFirstToken(this._otelService, chatEndpoint.model, timeToFirstToken / 1000);
|
|
341
|
+
}
|
|
342
|
+
if (useWebSocket && result.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
343
|
+
this._consecutiveWebSocketRetryFallbacks = 0;
|
|
344
|
+
}
|
|
240
345
|
return result;
|
|
241
346
|
}
|
|
242
347
|
case fetch_2.FetchResponseKind.Canceled:
|
|
@@ -245,6 +350,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
245
350
|
requestId: ourRequestId,
|
|
246
351
|
model: chatEndpoint.model,
|
|
247
352
|
apiType: chatEndpoint.apiType,
|
|
353
|
+
transport,
|
|
248
354
|
associatedRequestId: telemetryProperties.associatedRequestId,
|
|
249
355
|
retryAfterError: telemetryProperties.retryAfterError,
|
|
250
356
|
retryAfterErrorGitHubRequestId: telemetryProperties.retryAfterErrorGitHubRequestId,
|
|
@@ -276,7 +382,9 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
276
382
|
const statusCodesToRetry = retryServerErrorStatusCodes
|
|
277
383
|
.split(',')
|
|
278
384
|
.map(s => parseInt(s.trim(), 10));
|
|
279
|
-
|
|
385
|
+
const retryAfterServerError = enableRetryOnError && actualStatusCode !== undefined && statusCodesToRetry.includes(actualStatusCode);
|
|
386
|
+
const retryWithoutWebSocket = enableRetryOnError && useWebSocket;
|
|
387
|
+
if (retryAfterServerError || retryWithoutWebSocket) {
|
|
280
388
|
const { retryResult } = await this._retryAfterError({
|
|
281
389
|
opts,
|
|
282
390
|
processed,
|
|
@@ -285,6 +393,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
285
393
|
tokenCount,
|
|
286
394
|
maxResponseTokens,
|
|
287
395
|
timeToError: timeToFirstToken,
|
|
396
|
+
transport,
|
|
288
397
|
actualFetcher,
|
|
289
398
|
bytesReceived: actualBytesReceived,
|
|
290
399
|
baseTelemetry,
|
|
@@ -310,6 +419,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
310
419
|
maxResponseTokens,
|
|
311
420
|
timeToFirstToken,
|
|
312
421
|
isVisionRequest: this.filterImageMessages(messages),
|
|
422
|
+
transport,
|
|
313
423
|
fetcher: actualFetcher,
|
|
314
424
|
bytesReceived: actualBytesReceived,
|
|
315
425
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -323,6 +433,8 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
323
433
|
}
|
|
324
434
|
}
|
|
325
435
|
catch (err) {
|
|
436
|
+
// End OTel inference span on error if not already ended
|
|
437
|
+
otelInferenceSpan?.end();
|
|
326
438
|
const timeToError = Date.now() - baseTelemetry.issuedTime;
|
|
327
439
|
if (err.fetcherId) {
|
|
328
440
|
actualFetcher = err.fetcherId;
|
|
@@ -334,34 +446,34 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
334
446
|
resumeEventSeen = true;
|
|
335
447
|
}
|
|
336
448
|
const processed = this.processError(err, ourRequestId, err.gitHubRequestId, usernameToScrub);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
telemetryProperties = { ...telemetryProperties, connectivityTestError, connectivityTestErrorGitHubRequestId };
|
|
449
|
+
const retryNetworkError = enableRetryOnError && processed.type === commonTypes_1.ChatFetchResponseType.NetworkError && this._configurationService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.RetryNetworkErrors, this._experimentationService);
|
|
450
|
+
const retryWithoutWebSocket = enableRetryOnError && useWebSocket && (processed.type === commonTypes_1.ChatFetchResponseType.NetworkError || processed.type === commonTypes_1.ChatFetchResponseType.Failed);
|
|
451
|
+
if (retryNetworkError || retryWithoutWebSocket) {
|
|
452
|
+
const { retryResult, connectivityTestError, connectivityTestErrorGitHubRequestId } = await this._retryAfterError({
|
|
453
|
+
opts,
|
|
454
|
+
processed,
|
|
455
|
+
telemetryProperties,
|
|
456
|
+
requestBody,
|
|
457
|
+
tokenCount,
|
|
458
|
+
maxResponseTokens,
|
|
459
|
+
timeToError,
|
|
460
|
+
transport,
|
|
461
|
+
actualFetcher,
|
|
462
|
+
bytesReceived: err.bytesReceived,
|
|
463
|
+
baseTelemetry,
|
|
464
|
+
streamRecorder,
|
|
465
|
+
retryReason: 'network_error',
|
|
466
|
+
debugNamePrefix: 'retry-error-',
|
|
467
|
+
pendingLoggedChatRequest,
|
|
468
|
+
token,
|
|
469
|
+
usernameToScrub,
|
|
470
|
+
suspendEventSeen,
|
|
471
|
+
resumeEventSeen,
|
|
472
|
+
});
|
|
473
|
+
if (retryResult) {
|
|
474
|
+
return retryResult;
|
|
364
475
|
}
|
|
476
|
+
telemetryProperties = { ...telemetryProperties, connectivityTestError, connectivityTestErrorGitHubRequestId };
|
|
365
477
|
}
|
|
366
478
|
if (processed.type === commonTypes_1.ChatFetchResponseType.Canceled) {
|
|
367
479
|
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendCancellationTelemetry(this._telemetryService, {
|
|
@@ -369,6 +481,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
369
481
|
requestId: ourRequestId,
|
|
370
482
|
model: chatEndpoint.model,
|
|
371
483
|
apiType: chatEndpoint.apiType,
|
|
484
|
+
transport,
|
|
372
485
|
associatedRequestId: telemetryProperties.associatedRequestId,
|
|
373
486
|
retryAfterError: telemetryProperties.retryAfterError,
|
|
374
487
|
retryAfterErrorGitHubRequestId: telemetryProperties.retryAfterErrorGitHubRequestId,
|
|
@@ -401,6 +514,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
401
514
|
maxResponseTokens,
|
|
402
515
|
timeToFirstToken: timeToError,
|
|
403
516
|
isVisionRequest: this.filterImageMessages(messages),
|
|
517
|
+
transport,
|
|
404
518
|
fetcher: actualFetcher,
|
|
405
519
|
bytesReceived: err.bytesReceived,
|
|
406
520
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -468,7 +582,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
468
582
|
return authHeaders;
|
|
469
583
|
}
|
|
470
584
|
async _retryAfterError(params) {
|
|
471
|
-
const { opts, processed, telemetryProperties, requestBody, tokenCount, maxResponseTokens, timeToError, actualFetcher, bytesReceived, baseTelemetry, streamRecorder, retryReason, debugNamePrefix, pendingLoggedChatRequest, token, usernameToScrub, suspendEventSeen, resumeEventSeen, } = params;
|
|
585
|
+
const { opts, processed, telemetryProperties, requestBody, tokenCount, maxResponseTokens, timeToError, transport, actualFetcher, bytesReceived, baseTelemetry, streamRecorder, retryReason, debugNamePrefix, pendingLoggedChatRequest, token, usernameToScrub, suspendEventSeen, resumeEventSeen, } = params;
|
|
472
586
|
// net::ERR_NETWORK_CHANGED: https://github.com/microsoft/vscode/issues/260297
|
|
473
587
|
const isNetworkChangedError = ['darwin', 'linux'].includes(process.platform) && processed.reason.indexOf('net::ERR_NETWORK_CHANGED') !== -1;
|
|
474
588
|
// When Electron's network process crashes, all requests through it fail permanently.
|
|
@@ -495,6 +609,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
495
609
|
maxResponseTokens,
|
|
496
610
|
timeToFirstToken: timeToError,
|
|
497
611
|
isVisionRequest: this.filterImageMessages(opts.messages),
|
|
612
|
+
transport,
|
|
498
613
|
fetcher: actualFetcher,
|
|
499
614
|
bytesReceived,
|
|
500
615
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -505,6 +620,8 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
505
620
|
streamRecorder.callback('', 0, { text: '', retryReason });
|
|
506
621
|
const retryResult = await this.fetchMany({
|
|
507
622
|
...opts,
|
|
623
|
+
useWebSocket: false,
|
|
624
|
+
ignoreStatefulMarker: opts.useWebSocket || opts.ignoreStatefulMarker,
|
|
508
625
|
debugName: debugNamePrefix + opts.debugName,
|
|
509
626
|
userInitiatedRequest: false, // do not mark the retry as user initiated
|
|
510
627
|
telemetryProperties: {
|
|
@@ -518,9 +635,17 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
518
635
|
useFetcher,
|
|
519
636
|
}, token);
|
|
520
637
|
pendingLoggedChatRequest?.resolve(retryResult, streamRecorder.deltas);
|
|
638
|
+
if (opts.useWebSocket && retryResult.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
639
|
+
this._consecutiveWebSocketRetryFallbacks++;
|
|
640
|
+
this._logService.info(`[ChatWebSocketManager] WebSocket request failed with successful HTTP fallback (${this._consecutiveWebSocketRetryFallbacks} consecutive).`);
|
|
641
|
+
if (opts.conversationId && opts.turnId) {
|
|
642
|
+
// Closing here because the retry is transparent.
|
|
643
|
+
this._webSocketManager.closeConnection(opts.conversationId, opts.turnId);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
521
646
|
return { retryResult, connectivityTestError, connectivityTestErrorGitHubRequestId };
|
|
522
647
|
}
|
|
523
|
-
async _fetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
648
|
+
async _fetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
524
649
|
const isPowerSaveBlockerEnabled = this._configurationService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.ChatRequestPowerSaveBlocker, this._experimentationService);
|
|
525
650
|
const blockerHandle = isPowerSaveBlockerEnabled && location !== commonTypes_1.ChatLocation.Other ? this._powerService.acquirePowerSaveBlocker() : undefined;
|
|
526
651
|
let suspendEventSeen = false;
|
|
@@ -534,7 +659,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
534
659
|
this._logService.info(`System resumed during streaming request ${ourRequestId} (${commonTypes_1.ChatLocation.toString(location)})`);
|
|
535
660
|
});
|
|
536
661
|
try {
|
|
537
|
-
const fetchResult = await this._doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
662
|
+
const fetchResult = await this._doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
538
663
|
return { ...fetchResult, suspendEventSeen: suspendEventSeen || undefined, resumeEventSeen: resumeEventSeen || undefined };
|
|
539
664
|
}
|
|
540
665
|
catch (err) {
|
|
@@ -552,28 +677,187 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
552
677
|
blockerHandle?.dispose();
|
|
553
678
|
}
|
|
554
679
|
}
|
|
555
|
-
async _doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
680
|
+
async _doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
556
681
|
if (cancellationToken.isCancellationRequested) {
|
|
557
682
|
return { result: { type: fetch_2.FetchResponseKind.Canceled, reason: 'before fetch request' } };
|
|
558
683
|
}
|
|
559
|
-
this
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
684
|
+
// OTel inference span for this LLM call
|
|
685
|
+
const serverAddress = typeof chatEndpointInfo.urlOrRequestMetadata === 'string'
|
|
686
|
+
? (() => { try {
|
|
687
|
+
return new URL(chatEndpointInfo.urlOrRequestMetadata).hostname;
|
|
688
|
+
}
|
|
689
|
+
catch {
|
|
690
|
+
return undefined;
|
|
691
|
+
} })()
|
|
692
|
+
: undefined;
|
|
693
|
+
const otelSpan = this._otelService.startSpan(`chat ${chatEndpointInfo.model}`, {
|
|
694
|
+
kind: 2 /* SpanKind.CLIENT */,
|
|
695
|
+
attributes: {
|
|
696
|
+
[index_1.GenAiAttr.OPERATION_NAME]: index_1.GenAiOperationName.CHAT,
|
|
697
|
+
[index_1.GenAiAttr.PROVIDER_NAME]: index_1.GenAiProviderName.GITHUB,
|
|
698
|
+
[index_1.GenAiAttr.REQUEST_MODEL]: chatEndpointInfo.model,
|
|
699
|
+
[index_1.GenAiAttr.CONVERSATION_ID]: telemetryProperties?.requestId ?? ourRequestId,
|
|
700
|
+
[index_1.GenAiAttr.REQUEST_MAX_TOKENS]: request.max_tokens ?? request.max_output_tokens ?? request.max_completion_tokens ?? 2048,
|
|
701
|
+
...(request.temperature !== undefined ? { [index_1.GenAiAttr.REQUEST_TEMPERATURE]: request.temperature } : {}),
|
|
702
|
+
...(request.top_p !== undefined ? { [index_1.GenAiAttr.REQUEST_TOP_P]: request.top_p } : {}),
|
|
703
|
+
[index_1.CopilotChatAttr.MAX_PROMPT_TOKENS]: chatEndpointInfo.modelMaxPromptTokens,
|
|
704
|
+
...(serverAddress ? { [index_1.StdAttr.SERVER_ADDRESS]: serverAddress } : {}),
|
|
705
|
+
},
|
|
706
|
+
});
|
|
707
|
+
const otelStartTime = Date.now();
|
|
708
|
+
try {
|
|
709
|
+
this._logService.debug(`modelMaxPromptTokens ${chatEndpointInfo.modelMaxPromptTokens}`);
|
|
710
|
+
this._logService.debug(`modelMaxResponseTokens ${request.max_tokens ?? 2048}`);
|
|
711
|
+
this._logService.debug(`chat model ${chatEndpointInfo.model}`);
|
|
712
|
+
secretKey ??= copilotToken.token;
|
|
713
|
+
if (!secretKey) {
|
|
714
|
+
// If no key is set we error
|
|
715
|
+
const urlOrRequestMetadata = (0, networking_1.stringifyUrlOrRequestMetadata)(chatEndpointInfo.urlOrRequestMetadata);
|
|
716
|
+
this._logService.error(`Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
717
|
+
(0, stream_1.sendCommunicationErrorTelemetry)(this._telemetryService, `Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
718
|
+
return {
|
|
719
|
+
result: {
|
|
720
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
721
|
+
modelRequestId: undefined,
|
|
722
|
+
failKind: fetch_2.ChatFailKind.TokenExpiredOrInvalid,
|
|
723
|
+
reason: 'key is missing'
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
// WebSocket path: use persistent WebSocket connection for Responses API endpoints
|
|
728
|
+
if (useWebSocket && turnId && conversationId) {
|
|
729
|
+
const wsResult = await this._doFetchViaWebSocket(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, turnId, conversationId, cancellationToken, userInitiatedRequest, telemetryProperties, requestKindOptions);
|
|
730
|
+
return { ...wsResult, otelSpan };
|
|
731
|
+
}
|
|
732
|
+
const httpResult = await this._doFetchViaHttp(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
733
|
+
return { ...httpResult, otelSpan };
|
|
576
734
|
}
|
|
735
|
+
catch (err) {
|
|
736
|
+
otelSpan.setStatus(2 /* SpanStatusCode.ERROR */, err instanceof Error ? err.message : String(err));
|
|
737
|
+
otelSpan.setAttribute(index_1.StdAttr.ERROR_TYPE, err instanceof Error ? err.constructor.name : 'Error');
|
|
738
|
+
otelSpan.recordException(err);
|
|
739
|
+
throw err;
|
|
740
|
+
}
|
|
741
|
+
finally {
|
|
742
|
+
const durationSec = (Date.now() - otelStartTime) / 1000;
|
|
743
|
+
index_1.GenAiMetrics.recordOperationDuration(this._otelService, durationSec, {
|
|
744
|
+
operationName: index_1.GenAiOperationName.CHAT,
|
|
745
|
+
providerName: index_1.GenAiProviderName.GITHUB,
|
|
746
|
+
requestModel: chatEndpointInfo.model,
|
|
747
|
+
});
|
|
748
|
+
// Span is NOT ended here — caller (fetchMany) will set token attributes and end it
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Sends a chat request via a persistent WebSocket connection instead of HTTP POST.
|
|
753
|
+
* Events are the same Responses API streaming events, processed by OpenAIResponsesProcessor.
|
|
754
|
+
*/
|
|
755
|
+
async _doFetchViaWebSocket(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, turnId, conversationId, cancellationToken, userInitiatedRequest, telemetryProperties, requestKindOptions) {
|
|
756
|
+
const intent = locationToIntent(location);
|
|
757
|
+
const agentInteractionType = requestKindOptions?.kind === 'subagent' ?
|
|
758
|
+
'conversation-subagent' :
|
|
759
|
+
requestKindOptions?.kind === 'background' ?
|
|
760
|
+
'conversation-background' :
|
|
761
|
+
intent === 'conversation-agent' ? intent : undefined;
|
|
762
|
+
const additionalHeaders = {
|
|
763
|
+
'Authorization': `Bearer ${secretKey}`,
|
|
764
|
+
'X-Request-Id': ourRequestId,
|
|
765
|
+
'OpenAI-Intent': intent,
|
|
766
|
+
'X-GitHub-Api-Version': '2025-05-01',
|
|
767
|
+
'X-Interaction-Id': this._interactionService.interactionId,
|
|
768
|
+
'X-Initiator': userInitiatedRequest ? 'user' : 'agent',
|
|
769
|
+
...(chatEndpointInfo.getExtraHeaders ? chatEndpointInfo.getExtraHeaders(location) : {}),
|
|
770
|
+
};
|
|
771
|
+
if (agentInteractionType) {
|
|
772
|
+
additionalHeaders['X-Interaction-Type'] = agentInteractionType;
|
|
773
|
+
additionalHeaders['X-Agent-Task-Id'] = ourRequestId;
|
|
774
|
+
}
|
|
775
|
+
if (request.messages?.some((m) => Array.isArray(m.content) ? m.content.some(c => 'image_url' in c) : false) && chatEndpointInfo.supportsVision) {
|
|
776
|
+
additionalHeaders['Copilot-Vision-Request'] = 'true';
|
|
777
|
+
}
|
|
778
|
+
const connection = await this._webSocketManager.getOrCreateConnection(conversationId, turnId, additionalHeaders);
|
|
779
|
+
// Generate unique ID to link input and output messages
|
|
780
|
+
const modelCallId = (0, uuid_1.generateUuid)();
|
|
781
|
+
const telemetryData = telemetryData_1.TelemetryData.createAndMarkAsIssued({
|
|
782
|
+
endpoint: 'completions',
|
|
783
|
+
engineName: 'chat',
|
|
784
|
+
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
785
|
+
transport: 'websocket',
|
|
786
|
+
...{ ...telemetryProperties, modelCallId },
|
|
787
|
+
}, {
|
|
788
|
+
maxTokenWindow: chatEndpointInfo.modelMaxPromptTokens
|
|
789
|
+
});
|
|
790
|
+
const modelRequestId = (0, fetch_1.getRequestId)(connection.responseHeaders);
|
|
791
|
+
telemetryData.extendWithRequestId(modelRequestId);
|
|
792
|
+
for (const [key, value] of Object.entries(request)) {
|
|
793
|
+
if (key === 'messages' || key === 'input') {
|
|
794
|
+
continue;
|
|
795
|
+
} // Skip messages (PII)
|
|
796
|
+
telemetryData.properties[`request.option.${key}`] = JSON.stringify(value) ?? 'undefined';
|
|
797
|
+
}
|
|
798
|
+
telemetryData.properties['headerRequestId'] = ourRequestId;
|
|
799
|
+
this._telemetryService.sendGHTelemetryEvent('request.sent', telemetryData.properties, telemetryData.measurements);
|
|
800
|
+
const requestStart = Date.now();
|
|
801
|
+
const handle = connection.sendRequest(request, cancellationToken);
|
|
802
|
+
const extendedBaseTelemetryData = baseTelemetryData.extendedBy({ modelCallId });
|
|
803
|
+
const processor = this._instantiationService.createInstance(responsesApi_1.OpenAIResponsesProcessor, extendedBaseTelemetryData, modelRequestId.headerRequestId, modelRequestId.gitHubRequestId);
|
|
804
|
+
const chatCompletions = new async_1.AsyncIterableObject(async (emitter) => {
|
|
805
|
+
try {
|
|
806
|
+
await new Promise((resolve, reject) => {
|
|
807
|
+
handle.onEvent(event => {
|
|
808
|
+
const completion = processor.push(event, finishedCb);
|
|
809
|
+
if (completion) {
|
|
810
|
+
(0, responsesApi_1.sendCompletionOutputTelemetry)(this._telemetryService, this._logService, completion, extendedBaseTelemetryData);
|
|
811
|
+
emitter.emitOne(completion);
|
|
812
|
+
}
|
|
813
|
+
});
|
|
814
|
+
handle.onError(error => {
|
|
815
|
+
error.gitHubRequestId = modelRequestId.gitHubRequestId;
|
|
816
|
+
if ((0, errors_2.isCancellationError)(error)) {
|
|
817
|
+
reject(error);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
const warningTelemetry = telemetryData.extendedBy({ error: error.message });
|
|
821
|
+
this._telemetryService.sendGHTelemetryEvent('request.shownWarning', warningTelemetry.properties, warningTelemetry.measurements);
|
|
822
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
823
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
824
|
+
telemetryData.properties.error = error.message;
|
|
825
|
+
this._logService.debug(`request.error: [websocket], took ${totalTimeMs} ms`);
|
|
826
|
+
this._telemetryService.sendGHTelemetryEvent('request.error', telemetryData.properties, telemetryData.measurements);
|
|
827
|
+
reject(error);
|
|
828
|
+
});
|
|
829
|
+
handle.onComplete(() => {
|
|
830
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
831
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
832
|
+
this._logService.debug(`request.response: [websocket], took ${totalTimeMs} ms`);
|
|
833
|
+
this._telemetryService.sendGHTelemetryEvent('request.response', telemetryData.properties, telemetryData.measurements);
|
|
834
|
+
resolve();
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
finally {
|
|
839
|
+
let messagesToLog = request.messages;
|
|
840
|
+
if ((!messagesToLog || messagesToLog.length === 0) && request.input) {
|
|
841
|
+
try {
|
|
842
|
+
const rawMessages = (0, responsesApi_1.responseApiInputToRawMessagesForLogging)(request);
|
|
843
|
+
messagesToLog = (0, openai_1.rawMessageToCAPI)(rawMessages);
|
|
844
|
+
}
|
|
845
|
+
catch (e) {
|
|
846
|
+
this._logService.error(`Failed to convert Response API input to messages for telemetry:`, e);
|
|
847
|
+
messagesToLog = [];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
(0, chatStream_1.sendEngineMessagesTelemetry)(this._telemetryService, messagesToLog ?? [], telemetryData, false, this._logService);
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
return {
|
|
854
|
+
result: {
|
|
855
|
+
type: fetch_2.FetchResponseKind.Success,
|
|
856
|
+
chatCompletions,
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
async _doFetchViaHttp(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
577
861
|
// Generate unique ID to link input and output messages
|
|
578
862
|
const modelCallId = (0, uuid_1.generateUuid)();
|
|
579
863
|
const response = await this._fetchWithInstrumentation(chatEndpointInfo, ourRequestId, request, secretKey, location, cancellationToken, userInitiatedRequest, { ...telemetryProperties, modelCallId }, useFetcher, canRetryOnce, requestKindOptions);
|
|
@@ -660,6 +944,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
660
944
|
endpoint: 'completions',
|
|
661
945
|
engineName: 'chat',
|
|
662
946
|
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
947
|
+
transport: 'http',
|
|
663
948
|
...telemetryProperties // This includes the modelCallId from fetchAndStreamChat
|
|
664
949
|
}, {
|
|
665
950
|
maxTokenWindow: chatEndpoint.modelMaxPromptTokens
|
|
@@ -946,7 +1231,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
946
1231
|
reason: `Request Failed: ${response.status} ${text}`
|
|
947
1232
|
};
|
|
948
1233
|
}
|
|
949
|
-
async processSuccessfulResponse(response, messages, requestBody, requestId, maxResponseTokens, promptTokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpointInfo, userInitiatedRequest, fetcher, bytesReceived, suspendEventSeen, resumeEventSeen) {
|
|
1234
|
+
async processSuccessfulResponse(response, messages, requestBody, requestId, maxResponseTokens, promptTokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpointInfo, userInitiatedRequest, transport, fetcher, bytesReceived, suspendEventSeen, resumeEventSeen) {
|
|
950
1235
|
const completions = [];
|
|
951
1236
|
for await (const chatCompletion of response.chatCompletions) {
|
|
952
1237
|
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendSuccessTelemetry(this._telemetryService, {
|
|
@@ -960,6 +1245,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
960
1245
|
timeToFirstToken,
|
|
961
1246
|
timeToFirstTokenEmitted: (baseTelemetry && streamRecorder.firstTokenEmittedTime) ? streamRecorder.firstTokenEmittedTime - baseTelemetry.issuedTime : -1,
|
|
962
1247
|
hasImageMessages: this.filterImageMessages(messages),
|
|
1248
|
+
transport,
|
|
963
1249
|
fetcher,
|
|
964
1250
|
bytesReceived,
|
|
965
1251
|
suspendEventSeen,
|
|
@@ -1225,7 +1511,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
1225
1511
|
}
|
|
1226
1512
|
};
|
|
1227
1513
|
exports.ChatMLFetcherImpl = ChatMLFetcherImpl;
|
|
1228
|
-
exports.ChatMLFetcherImpl = ChatMLFetcherImpl = __decorate([
|
|
1514
|
+
exports.ChatMLFetcherImpl = ChatMLFetcherImpl = ChatMLFetcherImpl_1 = __decorate([
|
|
1229
1515
|
__param(0, fetcherService_1.IFetcherService),
|
|
1230
1516
|
__param(1, telemetry_1.ITelemetryService),
|
|
1231
1517
|
__param(2, requestLogger_1.IRequestLogger),
|
|
@@ -1238,7 +1524,9 @@ exports.ChatMLFetcherImpl = ChatMLFetcherImpl = __decorate([
|
|
|
1238
1524
|
__param(9, configurationService_1.IConfigurationService),
|
|
1239
1525
|
__param(10, nullExperimentationService_1.IExperimentationService),
|
|
1240
1526
|
__param(11, powerService_1.IPowerService),
|
|
1241
|
-
__param(12, instantiation_1.IInstantiationService)
|
|
1527
|
+
__param(12, instantiation_1.IInstantiationService),
|
|
1528
|
+
__param(13, chatWebSocketManager_1.IChatWebSocketManager),
|
|
1529
|
+
__param(14, otelService_1.IOTelService)
|
|
1242
1530
|
], ChatMLFetcherImpl);
|
|
1243
1531
|
/**
|
|
1244
1532
|
* Validates a chat request payload to ensure it is valid
|