Skip to content

Commit 36a6784

Browse files
authored
chore(chat): Report response telemetry VSCODE-603 (#845)
1 parent 13367ed commit 36a6784

File tree

3 files changed

+220
-39
lines changed

3 files changed

+220
-39
lines changed

src/participant/participant.ts

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,21 @@ export default class ParticipantController {
190190
modelInput: ModelInput;
191191
stream: vscode.ChatResponseStream;
192192
token: vscode.CancellationToken;
193-
}): Promise<void> {
193+
}): Promise<{ outputLength: number }> {
194194
const chatResponse = await this._getChatResponse({
195195
modelInput,
196196
token,
197197
});
198+
199+
let length = 0;
198200
for await (const fragment of chatResponse.text) {
199201
stream.markdown(fragment);
202+
length += fragment.length;
200203
}
204+
205+
return {
206+
outputLength: length,
207+
};
201208
}
202209

203210
_streamCodeBlockActions({
@@ -236,22 +243,34 @@ export default class ParticipantController {
236243
modelInput: ModelInput;
237244
stream: vscode.ChatResponseStream;
238245
token: vscode.CancellationToken;
239-
}): Promise<void> {
246+
}): Promise<{
247+
outputLength: number;
248+
hasCodeBlock: boolean;
249+
}> {
240250
const chatResponse = await this._getChatResponse({
241251
modelInput,
242252
token,
243253
});
244254

255+
let outputLength = 0;
256+
let hasCodeBlock = false;
245257
await processStreamWithIdentifiers({
246258
processStreamFragment: (fragment: string) => {
247259
stream.markdown(fragment);
260+
outputLength += fragment.length;
248261
},
249262
onStreamIdentifier: (content: string) => {
250263
this._streamCodeBlockActions({ runnableContent: content, stream });
264+
hasCodeBlock = true;
251265
},
252266
inputIterable: chatResponse.text,
253267
identifier: codeBlockIdentifier,
254268
});
269+
270+
return {
271+
outputLength,
272+
hasCodeBlock,
273+
};
255274
}
256275

257276
// This will stream all of the response content and create a string from it.
@@ -287,10 +306,19 @@ export default class ParticipantController {
287306
connectionNames: this._getConnectionNames(),
288307
});
289308

290-
await this.streamChatResponseContentWithCodeActions({
291-
modelInput,
292-
token,
293-
stream,
309+
const { hasCodeBlock, outputLength } =
310+
await this.streamChatResponseContentWithCodeActions({
311+
modelInput,
312+
token,
313+
stream,
314+
});
315+
316+
this._telemetryService.trackCopilotParticipantResponse({
317+
command: 'generic',
318+
has_cta: false,
319+
found_namespace: false,
320+
has_runnable_content: hasCodeBlock,
321+
output_length: outputLength,
294322
});
295323

296324
return genericRequestChatResult(context.history);
@@ -995,6 +1023,7 @@ export default class ParticipantController {
9951023
context,
9961024
token,
9971025
});
1026+
9981027
if (!databaseName || !collectionName) {
9991028
return await this._askForNamespace({
10001029
command: '/schema',
@@ -1056,7 +1085,7 @@ export default class ParticipantController {
10561085
connectionNames: this._getConnectionNames(),
10571086
...(sampleDocuments ? { sampleDocuments } : {}),
10581087
});
1059-
await this.streamChatResponse({
1088+
const response = await this.streamChatResponse({
10601089
modelInput,
10611090
stream,
10621091
token,
@@ -1072,6 +1101,14 @@ export default class ParticipantController {
10721101
],
10731102
});
10741103

1104+
this._telemetryService.trackCopilotParticipantResponse({
1105+
command: 'schema',
1106+
has_cta: true,
1107+
found_namespace: true,
1108+
has_runnable_content: false,
1109+
output_length: response.outputLength,
1110+
});
1111+
10751112
return schemaRequestChatResult(context.history);
10761113
}
10771114

@@ -1160,10 +1197,19 @@ export default class ParticipantController {
11601197
...(sampleDocuments ? { sampleDocuments } : {}),
11611198
});
11621199

1163-
await this.streamChatResponseContentWithCodeActions({
1164-
modelInput,
1165-
stream,
1166-
token,
1200+
const { hasCodeBlock, outputLength } =
1201+
await this.streamChatResponseContentWithCodeActions({
1202+
modelInput,
1203+
stream,
1204+
token,
1205+
});
1206+
1207+
this._telemetryService.trackCopilotParticipantResponse({
1208+
command: 'query',
1209+
has_cta: false,
1210+
found_namespace: true,
1211+
has_runnable_content: hasCodeBlock,
1212+
output_length: outputLength,
11671213
});
11681214

11691215
return queryRequestChatResult(context.history);
@@ -1239,11 +1285,12 @@ export default class ParticipantController {
12391285
connectionNames: this._getConnectionNames(),
12401286
});
12411287

1242-
await this.streamChatResponseContentWithCodeActions({
1243-
modelInput,
1244-
stream,
1245-
token,
1246-
});
1288+
const { hasCodeBlock, outputLength } =
1289+
await this.streamChatResponseContentWithCodeActions({
1290+
modelInput,
1291+
stream,
1292+
token,
1293+
});
12471294

12481295
this._streamResponseReference({
12491296
reference: {
@@ -1252,6 +1299,14 @@ export default class ParticipantController {
12521299
},
12531300
stream,
12541301
});
1302+
1303+
this._telemetryService.trackCopilotParticipantResponse({
1304+
command: 'docs/copilot',
1305+
has_cta: true,
1306+
found_namespace: false,
1307+
has_runnable_content: hasCodeBlock,
1308+
output_length: outputLength,
1309+
});
12551310
}
12561311

12571312
_streamResponseReference({
@@ -1307,6 +1362,14 @@ export default class ParticipantController {
13071362
if (docsResult.responseContent) {
13081363
stream.markdown(docsResult.responseContent);
13091364
}
1365+
1366+
this._telemetryService.trackCopilotParticipantResponse({
1367+
command: 'docs/chatbot',
1368+
has_cta: !!docsResult.responseReferences,
1369+
found_namespace: false,
1370+
has_runnable_content: false,
1371+
output_length: docsResult.responseContent?.length ?? 0,
1372+
});
13101373
} catch (error) {
13111374
// If the docs chatbot API is not available, fall back to Copilot’s LLM and include
13121375
// the MongoDB documentation link for users to go to our documentation site directly.

src/telemetry/telemetryService.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ export type ParticipantPromptProperties = {
119119
internal_purpose: InternalPromptPurpose;
120120
};
121121

122+
export type ParticipantResponseProperties = {
123+
command: string;
124+
has_cta: boolean;
125+
has_runnable_content: boolean;
126+
found_namespace: boolean;
127+
output_length: number;
128+
};
129+
122130
export function chatResultFeedbackKindToTelemetryValue(
123131
kind: vscode.ChatResultFeedbackKind
124132
): TelemetryFeedbackKind {
@@ -148,7 +156,9 @@ type TelemetryEventProperties =
148156
| SavedConnectionsLoadedProperties
149157
| SurveyActionProperties
150158
| ParticipantFeedbackProperties
151-
| ParticipantResponseFailedProperties;
159+
| ParticipantResponseFailedProperties
160+
| ParticipantPromptProperties
161+
| ParticipantResponseProperties;
152162

153163
export enum TelemetryEventTypes {
154164
PLAYGROUND_CODE_EXECUTED = 'Playground Code Executed',
@@ -172,6 +182,7 @@ export enum TelemetryEventTypes {
172182
PARTICIPANT_WELCOME_SHOWN = 'Participant Welcome Shown',
173183
PARTICIPANT_RESPONSE_FAILED = 'Participant Response Failed',
174184
PARTICIPANT_PROMPT_SUBMITTED = 'Participant Prompt Submitted',
185+
PARTICIPANT_RESPONSE_GENERATED = 'Participant Response Generated',
175186
}
176187

177188
export enum ParticipantErrorTypes {
@@ -438,4 +449,8 @@ export default class TelemetryService {
438449
trackCopilotParticipantPrompt(stats: ParticipantPromptProperties): void {
439450
this.track(TelemetryEventTypes.PARTICIPANT_PROMPT_SUBMITTED, stats);
440451
}
452+
453+
trackCopilotParticipantResponse(props: ParticipantResponseProperties): void {
454+
this.track(TelemetryEventTypes.PARTICIPANT_RESPONSE_GENERATED, props);
455+
}
441456
}

0 commit comments

Comments
 (0)