Skip to content

Commit 78c67b1

Browse files
authored
fix: should keep reporting UTDE telemetry if there are still pending Edits suggestions (aws#2051)
1 parent a8725b4 commit 78c67b1

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,7 @@ export const CodewhispererServerFactory =
681681
partialResultToken: suggestionResponse.responseContext.nextToken,
682682
}
683683
} else {
684+
session.hasEditsPending = suggestionResponse.responseContext.nextToken ? true : false
684685
return {
685686
items: suggestionResponse.suggestions
686687
.map(suggestion => {
@@ -867,7 +868,13 @@ export const CodewhispererServerFactory =
867868
if (firstCompletionDisplayLatency) emitPerceivedLatencyTelemetry(telemetry, session)
868869

869870
// Always emit user trigger decision at session close
870-
sessionManager.closeSession(session)
871+
// Close session unless Edit suggestion was accepted with more pending
872+
const shouldKeepSessionOpen =
873+
session.suggestionType === SuggestionType.EDIT && isAccepted && session.hasEditsPending
874+
875+
if (!shouldKeepSessionOpen) {
876+
sessionManager.closeSession(session)
877+
}
871878
const streakLength = editsEnabled ? sessionManager.getAndUpdateStreakLength(isAccepted) : 0
872879
await emitUserTriggerDecisionTelemetry(
873880
telemetry,

server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import {
66
} from '@aws/language-server-runtimes/server-interface'
77
import { v4 as uuidv4 } from 'uuid'
88
import { CodewhispererAutomatedTriggerType, CodewhispererTriggerType } from '../auto-trigger/autoTrigger'
9-
import { GenerateSuggestionsRequest, ResponseContext, Suggestion } from '../../../shared/codeWhispererService'
9+
import {
10+
GenerateSuggestionsRequest,
11+
ResponseContext,
12+
Suggestion,
13+
SuggestionType,
14+
} from '../../../shared/codeWhispererService'
1015
import { CodewhispererLanguage } from '../../../shared/languageDetection'
1116
import { CodeWhispererSupplementalContext } from '../../../shared/models/model'
1217
import { Logging } from '@aws/language-server-runtimes/server-interface'
@@ -75,6 +80,9 @@ export class CodeWhispererSession {
7580
includeImportsWithSuggestions?: boolean
7681
codewhispererSuggestionImportCount: number = 0
7782
suggestionType?: string
83+
hasEditsPending?: boolean = false
84+
// Track the most recent itemId for paginated Edit suggestions
85+
recentItemId?: string
7886

7987
constructor(data: SessionData) {
8088
this.id = this.generateSessionId()
@@ -153,7 +161,11 @@ export class CodeWhispererSession {
153161
typeaheadLength?: number
154162
) {
155163
// Skip if session results were already recorded for session of session is closed
156-
if (this.state === 'CLOSED' || this.state === 'DISCARD' || this.completionSessionResult) {
164+
if (
165+
this.state === 'CLOSED' ||
166+
this.state === 'DISCARD' ||
167+
(this.completionSessionResult && this.suggestionType === SuggestionType.COMPLETION)
168+
) {
157169
return
158170
}
159171

@@ -195,6 +207,8 @@ export class CodeWhispererSession {
195207
// No recommendation was accepted, but user have seen this suggestion
196208
this.setSuggestionState(itemId, 'Reject')
197209
}
210+
211+
this.recentItemId = itemId
198212
}
199213

200214
this.firstCompletionDisplayLatency = firstCompletionDisplayLatency
@@ -240,6 +254,24 @@ export class CodeWhispererSession {
240254
}
241255
return isEmpty ? 'Empty' : 'Discard'
242256
}
257+
258+
/**
259+
* Determines trigger decision based on the most recent user action.
260+
* Uses the last processed itemId to determine the overall session decision.
261+
*/
262+
getLatestUserTriggerDecision(): UserTriggerDecision | undefined {
263+
// Force Discard trigger decision when session was explicitly discarded by server
264+
if (this.state === 'DISCARD') {
265+
return 'Discard'
266+
}
267+
268+
if (!this.recentItemId) return
269+
270+
const state = this.getSuggestionState(this.recentItemId)
271+
if (state === 'Accept') return 'Accept'
272+
if (state === 'Reject') return 'Reject'
273+
return state === 'Empty' ? 'Empty' : 'Discard'
274+
}
243275
}
244276

245277
export class SessionManager {

server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CodeWhispererSession } from './session/sessionManager'
44
import { CodeWhispererPerceivedLatencyEvent, CodeWhispererServiceInvocationEvent } from '../../shared/telemetry/types'
55
import { getCompletionType, isAwsError } from '../../shared/utils'
66
import { TelemetryService } from '../../shared/telemetry/telemetryService'
7+
import { SuggestionType } from '../../shared/codeWhispererService'
78

89
export const emitServiceInvocationTelemetry = (
910
telemetry: Telemetry,
@@ -121,8 +122,15 @@ export const emitUserTriggerDecisionTelemetry = async (
121122
return
122123
}
123124

125+
// Edits show one suggestion sequentially (with pagination), so use latest itemId state;
126+
// Completions show multiple suggestions together, so aggregate all states
127+
const userTriggerDecision =
128+
session.suggestionType === SuggestionType.EDIT
129+
? session.getLatestUserTriggerDecision()
130+
: session.getAggregatedUserTriggerDecision()
131+
124132
// Can not emit previous trigger decision if it's not available on the session
125-
if (!session.getAggregatedUserTriggerDecision()) {
133+
if (!userTriggerDecision) {
126134
return
127135
}
128136

@@ -137,7 +145,13 @@ export const emitUserTriggerDecisionTelemetry = async (
137145
streakLength
138146
)
139147

140-
session.reportedUserDecision = true
148+
// Mark telemetry as complete unless Edit suggestion was accepted with more pending
149+
const hasPendingEditTelemetry =
150+
session.suggestionType === SuggestionType.EDIT && session.acceptedSuggestionId && session.hasEditsPending
151+
152+
if (!hasPendingEditTelemetry) {
153+
session.reportedUserDecision = true
154+
}
141155
}
142156

143157
export const emitAggregatedUserTriggerDecisionTelemetry = (

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,13 @@ export class TelemetryService {
117117

118118
private getSuggestionState(session: CodeWhispererSession): SuggestionState {
119119
let suggestionState: SuggestionState
120-
switch (session.getAggregatedUserTriggerDecision()) {
120+
// Edits show one suggestion sequentially (with pagination), so use latest itemId state;
121+
// Completions show multiple suggestions together, so aggregate all states
122+
const userTriggerDecision =
123+
session.suggestionType === SuggestionType.EDIT
124+
? session.getLatestUserTriggerDecision()
125+
: session.getAggregatedUserTriggerDecision()
126+
switch (userTriggerDecision) {
121127
case 'Accept':
122128
suggestionState = 'ACCEPT'
123129
break

0 commit comments

Comments
 (0)