@vscode/chat-lib 0.4.1-9 → 0.5.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/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/completions-core/vscode-node/lib/src/networking.d.ts.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.js +6 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.js.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/model.d.ts +4 -0
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/model.d.ts.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/model.js +4 -0
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/model.js.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/connectionState.d.ts.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/connectionState.js +1 -0
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/connectionState.js.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/network.d.ts.map +1 -1
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/network.js +1 -0
- package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/snippy/network.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 +71 -11
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.d.ts.map +1 -1
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.js +6 -3
- package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.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 +373 -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/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 +2 -0
- package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts.map +1 -1
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js +24 -3
- package/dist/src/_internal/extension/xtab/node/xtabProvider.js.map +1 -1
- package/dist/src/_internal/platform/authentication/node/copilotTokenManager.d.ts.map +1 -1
- package/dist/src/_internal/platform/authentication/node/copilotTokenManager.js +3 -0
- package/dist/src/_internal/platform/authentication/node/copilotTokenManager.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 +18 -36
- package/dist/src/_internal/platform/configuration/common/configurationService.d.ts.map +1 -1
- package/dist/src/_internal/platform/configuration/common/configurationService.js +37 -51
- 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 +2 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js +26 -7
- 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 +1 -1
- package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts.map +1 -1
- package/dist/src/_internal/platform/endpoint/node/messagesApi.js +61 -7
- 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 +9 -1
- package/dist/src/_internal/platform/git/common/gitService.d.ts.map +1 -1
- package/dist/src/_internal/platform/git/common/gitService.js +17 -5
- package/dist/src/_internal/platform/git/common/gitService.js.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts +12 -2
- package/dist/src/_internal/platform/github/common/githubAPI.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/githubAPI.js +23 -12
- package/dist/src/_internal/platform/github/common/githubAPI.js.map +1 -1
- package/dist/src/_internal/platform/github/common/githubService.d.ts +11 -1
- package/dist/src/_internal/platform/github/common/githubService.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/githubService.js +52 -14
- package/dist/src/_internal/platform/github/common/githubService.js.map +1 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.d.ts +5 -2
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.d.ts.map +1 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.js +4 -1
- package/dist/src/_internal/platform/github/common/nullOctokitServiceImpl.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts +1 -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 +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts +3 -0
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts.map +1 -1
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js +5 -0
- package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js.map +1 -1
- package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.d.ts.map +1 -1
- package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js +1 -0
- package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/anthropic.d.ts +10 -11
- package/dist/src/_internal/platform/networking/common/anthropic.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/anthropic.js +28 -23
- package/dist/src/_internal/platform/networking/common/anthropic.js.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetcherService.d.ts +29 -0
- package/dist/src/_internal/platform/networking/common/fetcherService.d.ts.map +1 -1
- package/dist/src/_internal/platform/networking/common/fetcherService.js +29 -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 +5 -5
- package/dist/src/_internal/platform/networking/common/networking.js.map +1 -1
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts +83 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js +496 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts +89 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts.map +1 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js +269 -0
- package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.d.ts +104 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/genAiAttributes.js +124 -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 +26 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.d.ts.map +1 -0
- package/dist/src/_internal/platform/otel/common/noopOtelService.js +51 -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 +160 -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/_internal/platform/proxyModels/node/proxyModelsService.d.ts.map +1 -1
- package/dist/src/_internal/platform/proxyModels/node/proxyModelsService.js +1 -0
- package/dist/src/_internal/platform/proxyModels/node/proxyModelsService.js.map +1 -1
- package/dist/src/main.d.ts.map +1 -1
- package/dist/src/main.js +10 -0
- package/dist/src/main.js.map +1 -1
- package/dist/src/package.json +267 -91
- package/package.json +4 -3
|
@@ -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,38 @@ 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
|
+
// Extract and set structured prompt sections for the debug panel
|
|
204
|
+
if (otelInferenceSpan) {
|
|
205
|
+
const capiMessages = requestBody.messages;
|
|
206
|
+
// User request: last user-role message
|
|
207
|
+
const userMessages = capiMessages?.filter(m => m.role === 'user');
|
|
208
|
+
const lastUserMsg = userMessages?.[userMessages.length - 1];
|
|
209
|
+
if (lastUserMsg?.content) {
|
|
210
|
+
otelInferenceSpan.setAttribute(index_1.CopilotChatAttr.USER_REQUEST, lastUserMsg.content);
|
|
211
|
+
}
|
|
212
|
+
// System instructions (first system message) — raw text for debug panel sections
|
|
213
|
+
const systemMsg = capiMessages?.find(m => m.role === 'system');
|
|
214
|
+
if (systemMsg?.content) {
|
|
215
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.SYSTEM_INSTRUCTIONS, systemMsg.content);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Always capture full request content for the debug panel
|
|
219
|
+
if (otelInferenceSpan) {
|
|
220
|
+
const capiMessages = requestBody.messages;
|
|
221
|
+
if (capiMessages) {
|
|
222
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.INPUT_MESSAGES, (0, index_1.truncateForOTel)(JSON.stringify((0, index_1.toInputMessages)(capiMessages))));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
179
225
|
tokenCount = await chatEndpoint.acquireTokenizer().countMessagesTokens(messages);
|
|
180
226
|
const extensionId = source?.extensionId ?? constants_1.EXTENSION_ID;
|
|
181
227
|
this._onDidMakeChatMLRequest.fire({
|
|
@@ -189,7 +235,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
189
235
|
pendingLoggedChatRequest?.markTimeToFirstToken(timeToFirstToken);
|
|
190
236
|
switch (response.type) {
|
|
191
237
|
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);
|
|
238
|
+
const result = await this.processSuccessfulResponse(response, messages, requestBody, ourRequestId, maxResponseTokens, tokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpoint, userInitiatedRequest, transport, actualFetcher, actualBytesReceived, suspendEventSeen, resumeEventSeen);
|
|
193
239
|
// Handle FilteredRetry case with augmented messages
|
|
194
240
|
if (result.type === commonTypes_1.ChatFetchResponseType.FilteredRetry) {
|
|
195
241
|
if (opts.enableRetryOnFilter) {
|
|
@@ -237,6 +283,76 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
237
283
|
};
|
|
238
284
|
}
|
|
239
285
|
pendingLoggedChatRequest?.resolve(result, streamRecorder.deltas);
|
|
286
|
+
// Record OTel token usage metrics if available
|
|
287
|
+
if (result.type === commonTypes_1.ChatFetchResponseType.Success && result.usage) {
|
|
288
|
+
const metricAttrs = {
|
|
289
|
+
operationName: index_1.GenAiOperationName.CHAT,
|
|
290
|
+
providerName: index_1.GenAiProviderName.GITHUB,
|
|
291
|
+
requestModel: chatEndpoint.model,
|
|
292
|
+
responseModel: result.resolvedModel,
|
|
293
|
+
};
|
|
294
|
+
if (result.usage.prompt_tokens) {
|
|
295
|
+
index_1.GenAiMetrics.recordTokenUsage(this._otelService, result.usage.prompt_tokens, 'input', metricAttrs);
|
|
296
|
+
}
|
|
297
|
+
if (result.usage.completion_tokens) {
|
|
298
|
+
index_1.GenAiMetrics.recordTokenUsage(this._otelService, result.usage.completion_tokens, 'output', metricAttrs);
|
|
299
|
+
}
|
|
300
|
+
// Set token usage and response details on the chat span before ending it
|
|
301
|
+
otelInferenceSpan?.setAttributes({
|
|
302
|
+
[index_1.GenAiAttr.USAGE_INPUT_TOKENS]: result.usage.prompt_tokens ?? 0,
|
|
303
|
+
[index_1.GenAiAttr.USAGE_OUTPUT_TOKENS]: result.usage.completion_tokens ?? 0,
|
|
304
|
+
[index_1.GenAiAttr.RESPONSE_MODEL]: result.resolvedModel ?? chatEndpoint.model,
|
|
305
|
+
[index_1.GenAiAttr.RESPONSE_ID]: result.requestId,
|
|
306
|
+
[index_1.GenAiAttr.RESPONSE_FINISH_REASONS]: ['stop'],
|
|
307
|
+
...(result.usage.prompt_tokens_details?.cached_tokens
|
|
308
|
+
? { [index_1.GenAiAttr.USAGE_CACHE_READ_INPUT_TOKENS]: result.usage.prompt_tokens_details.cached_tokens }
|
|
309
|
+
: {}),
|
|
310
|
+
[index_1.CopilotChatAttr.TIME_TO_FIRST_TOKEN]: timeToFirstToken,
|
|
311
|
+
...(result.serverRequestId ? { [index_1.CopilotChatAttr.SERVER_REQUEST_ID]: result.serverRequestId } : {}),
|
|
312
|
+
...(result.usage.completion_tokens_details?.reasoning_tokens
|
|
313
|
+
? { [index_1.GenAiAttr.USAGE_REASONING_TOKENS]: result.usage.completion_tokens_details.reasoning_tokens }
|
|
314
|
+
: {}),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
// Always capture response content for the debug panel
|
|
318
|
+
if (otelInferenceSpan && result.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
319
|
+
const responseText = streamRecorder.deltas.map(d => d.text).join('');
|
|
320
|
+
const toolCalls = streamRecorder.deltas
|
|
321
|
+
.filter(d => d.copilotToolCalls?.length)
|
|
322
|
+
.flatMap(d => d.copilotToolCalls.map(tc => ({
|
|
323
|
+
type: 'tool_call', id: tc.id, name: tc.name, arguments: tc.arguments
|
|
324
|
+
})));
|
|
325
|
+
const parts = [];
|
|
326
|
+
if (responseText) {
|
|
327
|
+
parts.push({ type: 'text', content: responseText });
|
|
328
|
+
}
|
|
329
|
+
parts.push(...toolCalls);
|
|
330
|
+
if (parts.length > 0) {
|
|
331
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.OUTPUT_MESSAGES, (0, index_1.truncateForOTel)(JSON.stringify([{ role: 'assistant', parts }])));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Emit OTel inference details event BEFORE ending the span
|
|
335
|
+
// so the log record inherits the active trace context
|
|
336
|
+
(0, index_1.emitInferenceDetailsEvent)(this._otelService, {
|
|
337
|
+
model: chatEndpoint.model,
|
|
338
|
+
temperature: requestOptions?.temperature,
|
|
339
|
+
maxTokens: requestOptions?.max_tokens,
|
|
340
|
+
}, result.type === commonTypes_1.ChatFetchResponseType.Success ? {
|
|
341
|
+
id: result.requestId,
|
|
342
|
+
model: result.resolvedModel,
|
|
343
|
+
finishReasons: ['stop'],
|
|
344
|
+
inputTokens: result.usage?.prompt_tokens,
|
|
345
|
+
outputTokens: result.usage?.completion_tokens,
|
|
346
|
+
} : undefined);
|
|
347
|
+
otelInferenceSpan?.end();
|
|
348
|
+
otelInferenceSpan = undefined;
|
|
349
|
+
// Record OTel time-to-first-token metric
|
|
350
|
+
if (timeToFirstToken > 0) {
|
|
351
|
+
index_1.GenAiMetrics.recordTimeToFirstToken(this._otelService, chatEndpoint.model, timeToFirstToken / 1000);
|
|
352
|
+
}
|
|
353
|
+
if (useWebSocket && result.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
354
|
+
this._consecutiveWebSocketRetryFallbacks = 0;
|
|
355
|
+
}
|
|
240
356
|
return result;
|
|
241
357
|
}
|
|
242
358
|
case fetch_2.FetchResponseKind.Canceled:
|
|
@@ -245,6 +361,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
245
361
|
requestId: ourRequestId,
|
|
246
362
|
model: chatEndpoint.model,
|
|
247
363
|
apiType: chatEndpoint.apiType,
|
|
364
|
+
transport,
|
|
248
365
|
associatedRequestId: telemetryProperties.associatedRequestId,
|
|
249
366
|
retryAfterError: telemetryProperties.retryAfterError,
|
|
250
367
|
retryAfterErrorGitHubRequestId: telemetryProperties.retryAfterErrorGitHubRequestId,
|
|
@@ -268,6 +385,13 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
268
385
|
issuedTime: baseTelemetry.issuedTime,
|
|
269
386
|
});
|
|
270
387
|
pendingLoggedChatRequest?.resolveWithCancelation();
|
|
388
|
+
// Set canceled status on OTel span
|
|
389
|
+
otelInferenceSpan?.setAttributes({
|
|
390
|
+
[index_1.GenAiAttr.RESPONSE_FINISH_REASONS]: ['cancelled'],
|
|
391
|
+
[index_1.CopilotChatAttr.CANCELED]: true,
|
|
392
|
+
});
|
|
393
|
+
otelInferenceSpan?.end();
|
|
394
|
+
otelInferenceSpan = undefined;
|
|
271
395
|
return this.processCanceledResponse(response, ourRequestId, streamRecorder, telemetryProperties);
|
|
272
396
|
case fetch_2.FetchResponseKind.Failed: {
|
|
273
397
|
const processed = this.processFailedResponse(response, ourRequestId);
|
|
@@ -276,7 +400,9 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
276
400
|
const statusCodesToRetry = retryServerErrorStatusCodes
|
|
277
401
|
.split(',')
|
|
278
402
|
.map(s => parseInt(s.trim(), 10));
|
|
279
|
-
|
|
403
|
+
const retryAfterServerError = enableRetryOnError && actualStatusCode !== undefined && statusCodesToRetry.includes(actualStatusCode);
|
|
404
|
+
const retryWithoutWebSocket = enableRetryOnError && useWebSocket;
|
|
405
|
+
if (retryAfterServerError || retryWithoutWebSocket) {
|
|
280
406
|
const { retryResult } = await this._retryAfterError({
|
|
281
407
|
opts,
|
|
282
408
|
processed,
|
|
@@ -285,6 +411,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
285
411
|
tokenCount,
|
|
286
412
|
maxResponseTokens,
|
|
287
413
|
timeToError: timeToFirstToken,
|
|
414
|
+
transport,
|
|
288
415
|
actualFetcher,
|
|
289
416
|
bytesReceived: actualBytesReceived,
|
|
290
417
|
baseTelemetry,
|
|
@@ -310,6 +437,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
310
437
|
maxResponseTokens,
|
|
311
438
|
timeToFirstToken,
|
|
312
439
|
isVisionRequest: this.filterImageMessages(messages),
|
|
440
|
+
transport,
|
|
313
441
|
fetcher: actualFetcher,
|
|
314
442
|
bytesReceived: actualBytesReceived,
|
|
315
443
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -323,6 +451,14 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
323
451
|
}
|
|
324
452
|
}
|
|
325
453
|
catch (err) {
|
|
454
|
+
// End OTel inference span on error if not already ended
|
|
455
|
+
if (otelInferenceSpan) {
|
|
456
|
+
otelInferenceSpan.setStatus(2 /* SpanStatusCode.ERROR */, err instanceof Error ? err.message : String(err));
|
|
457
|
+
otelInferenceSpan.setAttribute(index_1.StdAttr.ERROR_TYPE, err instanceof Error ? err.constructor.name : 'Error');
|
|
458
|
+
otelInferenceSpan.setAttribute(index_1.GenAiAttr.RESPONSE_FINISH_REASONS, ['error']);
|
|
459
|
+
otelInferenceSpan.recordException(err);
|
|
460
|
+
otelInferenceSpan.end();
|
|
461
|
+
}
|
|
326
462
|
const timeToError = Date.now() - baseTelemetry.issuedTime;
|
|
327
463
|
if (err.fetcherId) {
|
|
328
464
|
actualFetcher = err.fetcherId;
|
|
@@ -334,34 +470,34 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
334
470
|
resumeEventSeen = true;
|
|
335
471
|
}
|
|
336
472
|
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 };
|
|
473
|
+
const retryNetworkError = enableRetryOnError && processed.type === commonTypes_1.ChatFetchResponseType.NetworkError && this._configurationService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.RetryNetworkErrors, this._experimentationService);
|
|
474
|
+
const retryWithoutWebSocket = enableRetryOnError && useWebSocket && (processed.type === commonTypes_1.ChatFetchResponseType.NetworkError || processed.type === commonTypes_1.ChatFetchResponseType.Failed);
|
|
475
|
+
if (retryNetworkError || retryWithoutWebSocket) {
|
|
476
|
+
const { retryResult, connectivityTestError, connectivityTestErrorGitHubRequestId } = await this._retryAfterError({
|
|
477
|
+
opts,
|
|
478
|
+
processed,
|
|
479
|
+
telemetryProperties,
|
|
480
|
+
requestBody,
|
|
481
|
+
tokenCount,
|
|
482
|
+
maxResponseTokens,
|
|
483
|
+
timeToError,
|
|
484
|
+
transport,
|
|
485
|
+
actualFetcher,
|
|
486
|
+
bytesReceived: err.bytesReceived,
|
|
487
|
+
baseTelemetry,
|
|
488
|
+
streamRecorder,
|
|
489
|
+
retryReason: 'network_error',
|
|
490
|
+
debugNamePrefix: 'retry-error-',
|
|
491
|
+
pendingLoggedChatRequest,
|
|
492
|
+
token,
|
|
493
|
+
usernameToScrub,
|
|
494
|
+
suspendEventSeen,
|
|
495
|
+
resumeEventSeen,
|
|
496
|
+
});
|
|
497
|
+
if (retryResult) {
|
|
498
|
+
return retryResult;
|
|
364
499
|
}
|
|
500
|
+
telemetryProperties = { ...telemetryProperties, connectivityTestError, connectivityTestErrorGitHubRequestId };
|
|
365
501
|
}
|
|
366
502
|
if (processed.type === commonTypes_1.ChatFetchResponseType.Canceled) {
|
|
367
503
|
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendCancellationTelemetry(this._telemetryService, {
|
|
@@ -369,6 +505,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
369
505
|
requestId: ourRequestId,
|
|
370
506
|
model: chatEndpoint.model,
|
|
371
507
|
apiType: chatEndpoint.apiType,
|
|
508
|
+
transport,
|
|
372
509
|
associatedRequestId: telemetryProperties.associatedRequestId,
|
|
373
510
|
retryAfterError: telemetryProperties.retryAfterError,
|
|
374
511
|
retryAfterErrorGitHubRequestId: telemetryProperties.retryAfterErrorGitHubRequestId,
|
|
@@ -401,6 +538,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
401
538
|
maxResponseTokens,
|
|
402
539
|
timeToFirstToken: timeToError,
|
|
403
540
|
isVisionRequest: this.filterImageMessages(messages),
|
|
541
|
+
transport,
|
|
404
542
|
fetcher: actualFetcher,
|
|
405
543
|
bytesReceived: err.bytesReceived,
|
|
406
544
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -428,6 +566,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
428
566
|
const res = await this._fetcherService.fetch(url, {
|
|
429
567
|
headers,
|
|
430
568
|
useFetcher,
|
|
569
|
+
callSite: 'capi-ping',
|
|
431
570
|
});
|
|
432
571
|
if (res.status >= 200 && res.status < 300) {
|
|
433
572
|
this._logService.info(`CAPI ping successful, proceeding with chat request retry...`);
|
|
@@ -468,7 +607,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
468
607
|
return authHeaders;
|
|
469
608
|
}
|
|
470
609
|
async _retryAfterError(params) {
|
|
471
|
-
const { opts, processed, telemetryProperties, requestBody, tokenCount, maxResponseTokens, timeToError, actualFetcher, bytesReceived, baseTelemetry, streamRecorder, retryReason, debugNamePrefix, pendingLoggedChatRequest, token, usernameToScrub, suspendEventSeen, resumeEventSeen, } = params;
|
|
610
|
+
const { opts, processed, telemetryProperties, requestBody, tokenCount, maxResponseTokens, timeToError, transport, actualFetcher, bytesReceived, baseTelemetry, streamRecorder, retryReason, debugNamePrefix, pendingLoggedChatRequest, token, usernameToScrub, suspendEventSeen, resumeEventSeen, } = params;
|
|
472
611
|
// net::ERR_NETWORK_CHANGED: https://github.com/microsoft/vscode/issues/260297
|
|
473
612
|
const isNetworkChangedError = ['darwin', 'linux'].includes(process.platform) && processed.reason.indexOf('net::ERR_NETWORK_CHANGED') !== -1;
|
|
474
613
|
// When Electron's network process crashes, all requests through it fail permanently.
|
|
@@ -495,6 +634,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
495
634
|
maxResponseTokens,
|
|
496
635
|
timeToFirstToken: timeToError,
|
|
497
636
|
isVisionRequest: this.filterImageMessages(opts.messages),
|
|
637
|
+
transport,
|
|
498
638
|
fetcher: actualFetcher,
|
|
499
639
|
bytesReceived,
|
|
500
640
|
issuedTime: baseTelemetry.issuedTime,
|
|
@@ -505,6 +645,8 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
505
645
|
streamRecorder.callback('', 0, { text: '', retryReason });
|
|
506
646
|
const retryResult = await this.fetchMany({
|
|
507
647
|
...opts,
|
|
648
|
+
useWebSocket: false,
|
|
649
|
+
ignoreStatefulMarker: opts.useWebSocket || opts.ignoreStatefulMarker,
|
|
508
650
|
debugName: debugNamePrefix + opts.debugName,
|
|
509
651
|
userInitiatedRequest: false, // do not mark the retry as user initiated
|
|
510
652
|
telemetryProperties: {
|
|
@@ -518,9 +660,17 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
518
660
|
useFetcher,
|
|
519
661
|
}, token);
|
|
520
662
|
pendingLoggedChatRequest?.resolve(retryResult, streamRecorder.deltas);
|
|
663
|
+
if (opts.useWebSocket && retryResult.type === commonTypes_1.ChatFetchResponseType.Success) {
|
|
664
|
+
this._consecutiveWebSocketRetryFallbacks++;
|
|
665
|
+
this._logService.info(`[ChatWebSocketManager] WebSocket request failed with successful HTTP fallback (${this._consecutiveWebSocketRetryFallbacks} consecutive).`);
|
|
666
|
+
if (opts.conversationId && opts.turnId) {
|
|
667
|
+
// Closing here because the retry is transparent.
|
|
668
|
+
this._webSocketManager.closeConnection(opts.conversationId, opts.turnId);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
521
671
|
return { retryResult, connectivityTestError, connectivityTestErrorGitHubRequestId };
|
|
522
672
|
}
|
|
523
|
-
async _fetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
673
|
+
async _fetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
524
674
|
const isPowerSaveBlockerEnabled = this._configurationService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.ChatRequestPowerSaveBlocker, this._experimentationService);
|
|
525
675
|
const blockerHandle = isPowerSaveBlockerEnabled && location !== commonTypes_1.ChatLocation.Other ? this._powerService.acquirePowerSaveBlocker() : undefined;
|
|
526
676
|
let suspendEventSeen = false;
|
|
@@ -534,7 +684,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
534
684
|
this._logService.info(`System resumed during streaming request ${ourRequestId} (${commonTypes_1.ChatLocation.toString(location)})`);
|
|
535
685
|
});
|
|
536
686
|
try {
|
|
537
|
-
const fetchResult = await this._doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
687
|
+
const fetchResult = await this._doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
538
688
|
return { ...fetchResult, suspendEventSeen: suspendEventSeen || undefined, resumeEventSeen: resumeEventSeen || undefined };
|
|
539
689
|
}
|
|
540
690
|
catch (err) {
|
|
@@ -552,28 +702,190 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
552
702
|
blockerHandle?.dispose();
|
|
553
703
|
}
|
|
554
704
|
}
|
|
555
|
-
async _doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
705
|
+
async _doFetchAndStreamChat(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, copilotToken, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, useWebSocket, turnId, conversationId, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
556
706
|
if (cancellationToken.isCancellationRequested) {
|
|
557
707
|
return { result: { type: fetch_2.FetchResponseKind.Canceled, reason: 'before fetch request' } };
|
|
558
708
|
}
|
|
559
|
-
this
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
709
|
+
// OTel inference span for this LLM call
|
|
710
|
+
const serverAddress = typeof chatEndpointInfo.urlOrRequestMetadata === 'string'
|
|
711
|
+
? (() => { try {
|
|
712
|
+
return new URL(chatEndpointInfo.urlOrRequestMetadata).hostname;
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
return undefined;
|
|
716
|
+
} })()
|
|
717
|
+
: undefined;
|
|
718
|
+
const chatSessionId = (0, requestLogger_1.getCurrentCapturingToken)()?.chatSessionId;
|
|
719
|
+
const otelSpan = this._otelService.startSpan(`chat ${chatEndpointInfo.model}`, {
|
|
720
|
+
kind: 2 /* SpanKind.CLIENT */,
|
|
721
|
+
attributes: {
|
|
722
|
+
[index_1.GenAiAttr.OPERATION_NAME]: index_1.GenAiOperationName.CHAT,
|
|
723
|
+
[index_1.GenAiAttr.PROVIDER_NAME]: index_1.GenAiProviderName.GITHUB,
|
|
724
|
+
[index_1.GenAiAttr.REQUEST_MODEL]: chatEndpointInfo.model,
|
|
725
|
+
[index_1.GenAiAttr.CONVERSATION_ID]: telemetryProperties?.requestId ?? ourRequestId,
|
|
726
|
+
[index_1.GenAiAttr.REQUEST_MAX_TOKENS]: request.max_tokens ?? request.max_output_tokens ?? request.max_completion_tokens ?? 2048,
|
|
727
|
+
...(request.temperature !== undefined ? { [index_1.GenAiAttr.REQUEST_TEMPERATURE]: request.temperature } : {}),
|
|
728
|
+
...(request.top_p !== undefined ? { [index_1.GenAiAttr.REQUEST_TOP_P]: request.top_p } : {}),
|
|
729
|
+
[index_1.CopilotChatAttr.MAX_PROMPT_TOKENS]: chatEndpointInfo.modelMaxPromptTokens,
|
|
730
|
+
...(serverAddress ? { [index_1.StdAttr.SERVER_ADDRESS]: serverAddress } : {}),
|
|
731
|
+
...(conversationId ? { [index_1.CopilotChatAttr.SESSION_ID]: conversationId } : {}),
|
|
732
|
+
...(chatSessionId ? { [index_1.CopilotChatAttr.CHAT_SESSION_ID]: chatSessionId } : {}),
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
const otelStartTime = Date.now();
|
|
736
|
+
try {
|
|
737
|
+
this._logService.debug(`modelMaxPromptTokens ${chatEndpointInfo.modelMaxPromptTokens}`);
|
|
738
|
+
this._logService.debug(`modelMaxResponseTokens ${request.max_tokens ?? 2048}`);
|
|
739
|
+
this._logService.debug(`chat model ${chatEndpointInfo.model}`);
|
|
740
|
+
secretKey ??= copilotToken.token;
|
|
741
|
+
if (!secretKey) {
|
|
742
|
+
// If no key is set we error
|
|
743
|
+
const urlOrRequestMetadata = (0, networking_1.stringifyUrlOrRequestMetadata)(chatEndpointInfo.urlOrRequestMetadata);
|
|
744
|
+
this._logService.error(`Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
745
|
+
(0, stream_1.sendCommunicationErrorTelemetry)(this._telemetryService, `Failed to send request to ${urlOrRequestMetadata} due to missing key`);
|
|
746
|
+
return {
|
|
747
|
+
result: {
|
|
748
|
+
type: fetch_2.FetchResponseKind.Failed,
|
|
749
|
+
modelRequestId: undefined,
|
|
750
|
+
failKind: fetch_2.ChatFailKind.TokenExpiredOrInvalid,
|
|
751
|
+
reason: 'key is missing'
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
// WebSocket path: use persistent WebSocket connection for Responses API endpoints
|
|
756
|
+
if (useWebSocket && turnId && conversationId) {
|
|
757
|
+
const wsResult = await this._doFetchViaWebSocket(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, turnId, conversationId, cancellationToken, userInitiatedRequest, telemetryProperties, requestKindOptions);
|
|
758
|
+
return { ...wsResult, otelSpan };
|
|
759
|
+
}
|
|
760
|
+
const httpResult = await this._doFetchViaHttp(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions);
|
|
761
|
+
return { ...httpResult, otelSpan };
|
|
762
|
+
}
|
|
763
|
+
catch (err) {
|
|
764
|
+
otelSpan.setStatus(2 /* SpanStatusCode.ERROR */, err instanceof Error ? err.message : String(err));
|
|
765
|
+
otelSpan.setAttribute(index_1.StdAttr.ERROR_TYPE, err instanceof Error ? err.constructor.name : 'Error');
|
|
766
|
+
otelSpan.recordException(err);
|
|
767
|
+
throw err;
|
|
768
|
+
}
|
|
769
|
+
finally {
|
|
770
|
+
const durationSec = (Date.now() - otelStartTime) / 1000;
|
|
771
|
+
index_1.GenAiMetrics.recordOperationDuration(this._otelService, durationSec, {
|
|
772
|
+
operationName: index_1.GenAiOperationName.CHAT,
|
|
773
|
+
providerName: index_1.GenAiProviderName.GITHUB,
|
|
774
|
+
requestModel: chatEndpointInfo.model,
|
|
775
|
+
});
|
|
776
|
+
// Span is NOT ended here — caller (fetchMany) will set token attributes and end it
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Sends a chat request via a persistent WebSocket connection instead of HTTP POST.
|
|
781
|
+
* Events are the same Responses API streaming events, processed by OpenAIResponsesProcessor.
|
|
782
|
+
*/
|
|
783
|
+
async _doFetchViaWebSocket(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, turnId, conversationId, cancellationToken, userInitiatedRequest, telemetryProperties, requestKindOptions) {
|
|
784
|
+
const intent = locationToIntent(location);
|
|
785
|
+
const agentInteractionType = requestKindOptions?.kind === 'subagent' ?
|
|
786
|
+
'conversation-subagent' :
|
|
787
|
+
requestKindOptions?.kind === 'background' ?
|
|
788
|
+
'conversation-background' :
|
|
789
|
+
intent === 'conversation-agent' ? intent : undefined;
|
|
790
|
+
const additionalHeaders = {
|
|
791
|
+
'Authorization': `Bearer ${secretKey}`,
|
|
792
|
+
'X-Request-Id': ourRequestId,
|
|
793
|
+
'OpenAI-Intent': intent,
|
|
794
|
+
'X-GitHub-Api-Version': '2025-05-01',
|
|
795
|
+
'X-Interaction-Id': this._interactionService.interactionId,
|
|
796
|
+
'X-Initiator': userInitiatedRequest ? 'user' : 'agent',
|
|
797
|
+
...(chatEndpointInfo.getExtraHeaders ? chatEndpointInfo.getExtraHeaders(location) : {}),
|
|
798
|
+
};
|
|
799
|
+
if (agentInteractionType) {
|
|
800
|
+
additionalHeaders['X-Interaction-Type'] = agentInteractionType;
|
|
801
|
+
additionalHeaders['X-Agent-Task-Id'] = ourRequestId;
|
|
802
|
+
}
|
|
803
|
+
if (request.messages?.some((m) => Array.isArray(m.content) ? m.content.some(c => 'image_url' in c) : false) && chatEndpointInfo.supportsVision) {
|
|
804
|
+
additionalHeaders['Copilot-Vision-Request'] = 'true';
|
|
576
805
|
}
|
|
806
|
+
const connection = await this._webSocketManager.getOrCreateConnection(conversationId, turnId, additionalHeaders);
|
|
807
|
+
// Generate unique ID to link input and output messages
|
|
808
|
+
const modelCallId = (0, uuid_1.generateUuid)();
|
|
809
|
+
const telemetryData = telemetryData_1.TelemetryData.createAndMarkAsIssued({
|
|
810
|
+
endpoint: 'completions',
|
|
811
|
+
engineName: 'chat',
|
|
812
|
+
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
813
|
+
transport: 'websocket',
|
|
814
|
+
...{ ...telemetryProperties, modelCallId },
|
|
815
|
+
}, {
|
|
816
|
+
maxTokenWindow: chatEndpointInfo.modelMaxPromptTokens
|
|
817
|
+
});
|
|
818
|
+
const modelRequestId = (0, fetch_1.getRequestId)(connection.responseHeaders);
|
|
819
|
+
telemetryData.extendWithRequestId(modelRequestId);
|
|
820
|
+
for (const [key, value] of Object.entries(request)) {
|
|
821
|
+
if (key === 'messages' || key === 'input') {
|
|
822
|
+
continue;
|
|
823
|
+
} // Skip messages (PII)
|
|
824
|
+
telemetryData.properties[`request.option.${key}`] = JSON.stringify(value) ?? 'undefined';
|
|
825
|
+
}
|
|
826
|
+
telemetryData.properties['headerRequestId'] = ourRequestId;
|
|
827
|
+
this._telemetryService.sendGHTelemetryEvent('request.sent', telemetryData.properties, telemetryData.measurements);
|
|
828
|
+
const requestStart = Date.now();
|
|
829
|
+
const handle = connection.sendRequest(request, cancellationToken);
|
|
830
|
+
const extendedBaseTelemetryData = baseTelemetryData.extendedBy({ modelCallId });
|
|
831
|
+
const processor = this._instantiationService.createInstance(responsesApi_1.OpenAIResponsesProcessor, extendedBaseTelemetryData, modelRequestId.headerRequestId, modelRequestId.gitHubRequestId);
|
|
832
|
+
const chatCompletions = new async_1.AsyncIterableObject(async (emitter) => {
|
|
833
|
+
try {
|
|
834
|
+
await new Promise((resolve, reject) => {
|
|
835
|
+
handle.onEvent(event => {
|
|
836
|
+
const completion = processor.push(event, finishedCb);
|
|
837
|
+
if (completion) {
|
|
838
|
+
(0, responsesApi_1.sendCompletionOutputTelemetry)(this._telemetryService, this._logService, completion, extendedBaseTelemetryData);
|
|
839
|
+
emitter.emitOne(completion);
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
handle.onError(error => {
|
|
843
|
+
error.gitHubRequestId = modelRequestId.gitHubRequestId;
|
|
844
|
+
if ((0, errors_2.isCancellationError)(error)) {
|
|
845
|
+
reject(error);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const warningTelemetry = telemetryData.extendedBy({ error: error.message });
|
|
849
|
+
this._telemetryService.sendGHTelemetryEvent('request.shownWarning', warningTelemetry.properties, warningTelemetry.measurements);
|
|
850
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
851
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
852
|
+
telemetryData.properties.error = error.message;
|
|
853
|
+
this._logService.debug(`request.error: [websocket], took ${totalTimeMs} ms`);
|
|
854
|
+
this._telemetryService.sendGHTelemetryEvent('request.error', telemetryData.properties, telemetryData.measurements);
|
|
855
|
+
reject(error);
|
|
856
|
+
});
|
|
857
|
+
handle.onComplete(() => {
|
|
858
|
+
const totalTimeMs = Date.now() - requestStart;
|
|
859
|
+
telemetryData.measurements.totalTimeMs = totalTimeMs;
|
|
860
|
+
this._logService.debug(`request.response: [websocket], took ${totalTimeMs} ms`);
|
|
861
|
+
this._telemetryService.sendGHTelemetryEvent('request.response', telemetryData.properties, telemetryData.measurements);
|
|
862
|
+
resolve();
|
|
863
|
+
});
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
finally {
|
|
867
|
+
let messagesToLog = request.messages;
|
|
868
|
+
if ((!messagesToLog || messagesToLog.length === 0) && request.input) {
|
|
869
|
+
try {
|
|
870
|
+
const rawMessages = (0, responsesApi_1.responseApiInputToRawMessagesForLogging)(request);
|
|
871
|
+
messagesToLog = (0, openai_1.rawMessageToCAPI)(rawMessages);
|
|
872
|
+
}
|
|
873
|
+
catch (e) {
|
|
874
|
+
this._logService.error(`Failed to convert Response API input to messages for telemetry:`, e);
|
|
875
|
+
messagesToLog = [];
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
(0, chatStream_1.sendEngineMessagesTelemetry)(this._telemetryService, messagesToLog ?? [], telemetryData, false, this._logService);
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
return {
|
|
882
|
+
result: {
|
|
883
|
+
type: fetch_2.FetchResponseKind.Success,
|
|
884
|
+
chatCompletions,
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
async _doFetchViaHttp(chatEndpointInfo, request, baseTelemetryData, finishedCb, secretKey, location, ourRequestId, nChoices, cancellationToken, userInitiatedRequest, telemetryProperties, useFetcher, canRetryOnce, requestKindOptions) {
|
|
577
889
|
// Generate unique ID to link input and output messages
|
|
578
890
|
const modelCallId = (0, uuid_1.generateUuid)();
|
|
579
891
|
const response = await this._fetchWithInstrumentation(chatEndpointInfo, ourRequestId, request, secretKey, location, cancellationToken, userInitiatedRequest, { ...telemetryProperties, modelCallId }, useFetcher, canRetryOnce, requestKindOptions);
|
|
@@ -660,6 +972,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
660
972
|
endpoint: 'completions',
|
|
661
973
|
engineName: 'chat',
|
|
662
974
|
uiKind: commonTypes_1.ChatLocation.toString(location),
|
|
975
|
+
transport: 'http',
|
|
663
976
|
...telemetryProperties // This includes the modelCallId from fetchAndStreamChat
|
|
664
977
|
}, {
|
|
665
978
|
maxTokenWindow: chatEndpoint.modelMaxPromptTokens
|
|
@@ -946,7 +1259,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
946
1259
|
reason: `Request Failed: ${response.status} ${text}`
|
|
947
1260
|
};
|
|
948
1261
|
}
|
|
949
|
-
async processSuccessfulResponse(response, messages, requestBody, requestId, maxResponseTokens, promptTokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpointInfo, userInitiatedRequest, fetcher, bytesReceived, suspendEventSeen, resumeEventSeen) {
|
|
1262
|
+
async processSuccessfulResponse(response, messages, requestBody, requestId, maxResponseTokens, promptTokenCount, timeToFirstToken, streamRecorder, baseTelemetry, chatEndpointInfo, userInitiatedRequest, transport, fetcher, bytesReceived, suspendEventSeen, resumeEventSeen) {
|
|
950
1263
|
const completions = [];
|
|
951
1264
|
for await (const chatCompletion of response.chatCompletions) {
|
|
952
1265
|
chatMLFetcherTelemetry_1.ChatMLFetcherTelemetrySender.sendSuccessTelemetry(this._telemetryService, {
|
|
@@ -960,6 +1273,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
960
1273
|
timeToFirstToken,
|
|
961
1274
|
timeToFirstTokenEmitted: (baseTelemetry && streamRecorder.firstTokenEmittedTime) ? streamRecorder.firstTokenEmittedTime - baseTelemetry.issuedTime : -1,
|
|
962
1275
|
hasImageMessages: this.filterImageMessages(messages),
|
|
1276
|
+
transport,
|
|
963
1277
|
fetcher,
|
|
964
1278
|
bytesReceived,
|
|
965
1279
|
suspendEventSeen,
|
|
@@ -1225,7 +1539,7 @@ let ChatMLFetcherImpl = class ChatMLFetcherImpl extends AbstractChatMLFetcher {
|
|
|
1225
1539
|
}
|
|
1226
1540
|
};
|
|
1227
1541
|
exports.ChatMLFetcherImpl = ChatMLFetcherImpl;
|
|
1228
|
-
exports.ChatMLFetcherImpl = ChatMLFetcherImpl = __decorate([
|
|
1542
|
+
exports.ChatMLFetcherImpl = ChatMLFetcherImpl = ChatMLFetcherImpl_1 = __decorate([
|
|
1229
1543
|
__param(0, fetcherService_1.IFetcherService),
|
|
1230
1544
|
__param(1, telemetry_1.ITelemetryService),
|
|
1231
1545
|
__param(2, requestLogger_1.IRequestLogger),
|
|
@@ -1238,7 +1552,9 @@ exports.ChatMLFetcherImpl = ChatMLFetcherImpl = __decorate([
|
|
|
1238
1552
|
__param(9, configurationService_1.IConfigurationService),
|
|
1239
1553
|
__param(10, nullExperimentationService_1.IExperimentationService),
|
|
1240
1554
|
__param(11, powerService_1.IPowerService),
|
|
1241
|
-
__param(12, instantiation_1.IInstantiationService)
|
|
1555
|
+
__param(12, instantiation_1.IInstantiationService),
|
|
1556
|
+
__param(13, chatWebSocketManager_1.IChatWebSocketManager),
|
|
1557
|
+
__param(14, otelService_1.IOTelService)
|
|
1242
1558
|
], ChatMLFetcherImpl);
|
|
1243
1559
|
/**
|
|
1244
1560
|
* Validates a chat request payload to ensure it is valid
|