Skip to content

Commit 2e542ae

Browse files
authored
fix: emit telemetry event to RTS when failed or cancelled (#1384)
1 parent 1260dce commit 2e542ae

File tree

6 files changed

+38
-34
lines changed

6 files changed

+38
-34
lines changed

server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,10 @@
829829
"max": 20,
830830
"min": 0
831831
},
832+
"AgenticChatEventStatus": {
833+
"type": "string",
834+
"enum": ["SUCCEEDED", "CANCELLED", "FAILED"]
835+
},
832836
"AppStudioState": {
833837
"type": "structure",
834838
"required": ["namespace", "propertyName", "propertyContext"],
@@ -1010,6 +1014,9 @@
10101014
},
10111015
"hasProjectLevelContext": {
10121016
"shape": "Boolean"
1017+
},
1018+
"result": {
1019+
"shape": "AgenticChatEventStatus"
10131020
}
10141021
}
10151022
},

server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ declare namespace CodeWhispererBearerTokenClient {
246246
export type AdditionalContentEntryInnerContextString = string;
247247
export type AdditionalContentEntryNameString = string;
248248
export type AdditionalContentList = AdditionalContentEntry[];
249+
export type AgenticChatEventStatus = "SUCCEEDED"|"CANCELLED"|"FAILED"|string;
249250
export interface AppStudioState {
250251
/**
251252
* The namespace of the context. Examples: 'ui.Button', 'ui.Table.DataSource', 'ui.Table.RowActions.Button', 'logic.invokeAWS', 'logic.JavaScript'
@@ -323,6 +324,7 @@ declare namespace CodeWhispererBearerTokenClient {
323324
responseLength?: Integer;
324325
numberOfCodeBlocks?: Integer;
325326
hasProjectLevelContext?: Boolean;
327+
result?: AgenticChatEventStatus;
326328
}
327329
export type ChatHistory = ChatMessage[];
328330
export interface ChatInteractWithMessageEvent {

server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ export class AgenticChatController implements ChatHandlers {
427427
session.pairProgrammingMode,
428428
session.getConversationType()
429429
)
430+
await this.#telemetryController.emitAddMessageMetric(params.tabId, metric.metric, 'Cancelled')
431+
430432
session.abortRequest()
431433
void this.#invalidateAllShellCommands(params.tabId, session)
432434
session.rejectAllDeferredToolExecutions(new CancellationError('user'))
@@ -491,7 +493,6 @@ export class AgenticChatController implements ChatHandlers {
491493
},
492494
params.partialResultToken
493495
)
494-
495496
if (this.isUserAction(err, token)) {
496497
/**
497498
* when the session is aborted it generates an error.
@@ -505,7 +506,14 @@ export class AgenticChatController implements ChatHandlers {
505506
buttons: [],
506507
}
507508
}
508-
return this.#handleRequestError(err, errorMessageId, params.tabId, metric, session.pairProgrammingMode)
509+
return this.#handleRequestError(
510+
session.conversationId,
511+
err,
512+
errorMessageId,
513+
params.tabId,
514+
metric,
515+
session.pairProgrammingMode
516+
)
509517
}
510518
}
511519

@@ -1862,7 +1870,7 @@ export class AgenticChatController implements ChatHandlers {
18621870
cwsprChatFocusFileContextLength: triggerContext.text?.length,
18631871
})
18641872
}
1865-
await this.#telemetryController.emitAddMessageMetric(params.tabId, metric.metric)
1873+
await this.#telemetryController.emitAddMessageMetric(params.tabId, metric.metric, 'Succeeded')
18661874

18671875
this.#telemetryController.updateTriggerInfo(params.tabId, {
18681876
lastMessageTrigger: {
@@ -1882,18 +1890,23 @@ export class AgenticChatController implements ChatHandlers {
18821890
/**
18831891
* Handles errors that occur during the request
18841892
*/
1885-
#handleRequestError(
1893+
async #handleRequestError(
1894+
conversationId: string | undefined,
18861895
err: any,
18871896
errorMessageId: string,
18881897
tabId: string,
18891898
metric: Metric<CombinedConversationEvent>,
18901899
agenticCodingMode: boolean
1891-
): ChatResult | ResponseError<ChatResult> {
1900+
): Promise<ChatResult | ResponseError<ChatResult>> {
18921901
const errorMessage = getErrorMessage(err)
18931902
const requestID = getRequestID(err) ?? ''
18941903
metric.setDimension('cwsprChatResponseCode', getHttpStatusCode(err) ?? 0)
18951904
metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version)
18961905

1906+
metric.metric.requestIds = [requestID]
1907+
metric.metric.cwsprChatMessageId = errorMessageId
1908+
metric.metric.cwsprChatConversationId = conversationId
1909+
await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed')
18971910
// use custom error message for unactionable errors (user-dependent errors like PromptCharacterLimit)
18981911
if (err.code && err.code in unactionableErrorCodes) {
18991912
const customErrMessage = unactionableErrorCodes[err.code as keyof typeof unactionableErrorCodes]

server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { AcceptedSuggestionEntry, CodeDiffTracker } from '../../inline-completio
2323
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
2424
import { getEndPositionForAcceptedSuggestion, getTelemetryReasonDesc } from '../../../shared/utils'
2525
import { CodewhispererLanguage } from '../../../shared/languageDetection'
26+
import { AgenticChatEventStatus } from '../../../client/token/codewhispererbearertokenclient'
2627

2728
export const CONVERSATION_ID_METRIC_KEY = 'cwsprChatConversationId'
2829

@@ -239,7 +240,7 @@ export class ChatTelemetryController {
239240
})
240241
}
241242

242-
public emitAddMessageMetric(tabId: string, metric: Partial<CombinedConversationEvent>) {
243+
public emitAddMessageMetric(tabId: string, metric: Partial<CombinedConversationEvent>, result?: string) {
243244
const conversationId = this.getConversationId(tabId)
244245
// Store the customization value associated with the message
245246
if (metric.cwsprChatMessageId && metric.codewhispererCustomizationArn) {
@@ -264,6 +265,7 @@ export class ChatTelemetryController {
264265
responseLength: metric.cwsprChatResponseLength,
265266
numberOfCodeBlocks: metric.cwsprChatResponseCodeSnippetCount,
266267
agenticCodingMode: metric.enabled,
268+
result: result,
267269
},
268270
{
269271
chatTriggerInteraction: metric.cwsprChatTriggerInteraction,

server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ describe('TelemetryService', () => {
799799
responseLength: 3000,
800800
numberOfCodeBlocks: 0,
801801
hasProjectLevelContext: false,
802+
result: 'SUCCEEDED',
802803
},
803804
},
804805
}
@@ -883,28 +884,6 @@ describe('TelemetryService', () => {
883884
})
884885
})
885886

886-
it('should not send ChatAddMessage when conversationId is undefined', () => {
887-
telemetryService.emitChatAddMessage(
888-
{
889-
messageId: 'message123',
890-
customizationArn: 'cust-123',
891-
},
892-
{}
893-
)
894-
sinon.assert.notCalled(codeWhisperServiceStub.sendTelemetryEvent)
895-
})
896-
897-
it('should not send ChatAddMessage when messageId is undefined', () => {
898-
telemetryService.emitChatAddMessage(
899-
{
900-
conversationId: 'conv123',
901-
customizationArn: 'cust-123',
902-
},
903-
{}
904-
)
905-
sinon.assert.notCalled(codeWhisperServiceStub.sendTelemetryEvent)
906-
})
907-
908887
it('should not send ChatAddMessage when credentialsType is IAM', () => {
909888
codeWhisperServiceStub.getCredentialsType.returns('iam')
910889
telemetryService = new TelemetryService(serviceManagerStub, mockCredentialsProvider, telemetry, logging)

server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
ChatAddMessageEvent,
2020
UserIntent,
2121
InlineChatEvent,
22+
AgenticChatEventStatus,
2223
} from '../../client/token/codewhispererbearertokenclient'
2324
import { getCompletionType, getSsoConnectionType, isAwsError } from '../utils'
2425
import {
@@ -474,6 +475,7 @@ export class TelemetryService {
474475
numberOfCodeBlocks?: number
475476
hasProjectLevelContext?: number
476477
agenticCodingMode?: boolean
478+
result?: string
477479
},
478480
additionalParams: Partial<{
479481
chatTriggerInteraction: string
@@ -498,9 +500,6 @@ export class TelemetryService {
498500
requestIds?: string[]
499501
}>
500502
) {
501-
if (!params.conversationId || !params.messageId) {
502-
return
503-
}
504503
const timeBetweenChunks = params.timeBetweenChunks?.slice(0, 100)
505504
// truncate requestIds if longer than 875 so it does not go over field limit
506505
const truncatedRequestIds = additionalParams.requestIds?.slice(0, 875)
@@ -541,7 +540,7 @@ export class TelemetryService {
541540
cwsprChatFocusFileContextLength: additionalParams.cwsprChatFocusFileContextLength,
542541
cwsprChatCodeContextCount: additionalParams.cwsprChatCodeContextCount,
543542
cwsprChatCodeContextLength: additionalParams.cwsprChatCodeContextLength,
544-
result: 'Succeeded',
543+
result: params.result ?? 'Succeeded',
545544
enabled: params.agenticCodingMode,
546545
languageServerVersion: additionalParams.languageServerVersion,
547546
requestIds: truncatedRequestIds,
@@ -550,8 +549,9 @@ export class TelemetryService {
550549
}
551550

552551
const event: ChatAddMessageEvent = {
553-
conversationId: params.conversationId,
554-
messageId: params.messageId,
552+
// Fields conversationId and messageId are required, but failed or cancelled events may not have those values, then just set them as dummy value
553+
conversationId: params.conversationId ?? 'DummyConversationId',
554+
messageId: params.messageId ?? 'DummyMessageId',
555555
userIntent: params.userIntent,
556556
hasCodeSnippet: params.hasCodeSnippet,
557557
activeEditorTotalCharacters: params.activeEditorTotalCharacters,
@@ -562,6 +562,7 @@ export class TelemetryService {
562562
responseLength: params.responseLength,
563563
numberOfCodeBlocks: params.numberOfCodeBlocks,
564564
hasProjectLevelContext: false,
565+
result: params.result?.toUpperCase() ?? 'SUCCEEDED',
565566
}
566567
if (params.customizationArn) {
567568
event.customizationArn = params.customizationArn

0 commit comments

Comments
 (0)