3
3
* SPDX-License-Identifier: Apache-2.0
4
4
*/
5
5
import * as telemetry from '../../shared/telemetry/telemetry'
6
- import * as vscode from 'vscode'
7
6
import { runtimeLanguageContext } from './runtimeLanguageContext'
8
7
import { RecommendationsList } from '../client/codewhisperer'
9
- import { isCloud9 } from '../../shared/extensionUtilities'
10
8
import { LicenseUtil } from './licenseUtil'
11
9
12
10
export class TelemetryHelper {
13
- /**
14
- * to record each recommendation is prefix matched or not with
15
- * left context before 'editor.action.triggerSuggest'
16
- */
17
- public isPrefixMatched : boolean [ ]
18
-
19
11
/**
20
12
* Trigger type for getting CodeWhisperer recommendation
21
13
*/
@@ -34,7 +26,6 @@ export class TelemetryHelper {
34
26
public cursorOffset : number
35
27
36
28
constructor ( ) {
37
- this . isPrefixMatched = [ ]
38
29
this . triggerType = 'OnDemand'
39
30
this . CodeWhispererAutomatedtriggerType = 'KeyStrokeCount'
40
31
this . completionType = 'Line'
@@ -47,49 +38,24 @@ export class TelemetryHelper {
47
38
return ( this . #instance ??= new this ( ) )
48
39
}
49
40
50
- /**
51
- * VScode IntelliSense has native matching for recommendation.
52
- * This is only to check if the recommendation match the updated left context when
53
- * user keeps typing before getting CodeWhisperer response back.
54
- * @param recommendations the recommendations of current invocation
55
- * @param startPos the invocation position of current invocation
56
- * @param newCodeWhispererRequest if newCodeWhispererRequest, then we need to reset the invocationContext.isPrefixMatched, which is used as
57
- * part of user decision telemetry (see models.ts for more details)
58
- * @param editor the current VSCode editor
59
- *
60
- * @returns
61
- */
62
- public updatePrefixMatchArray (
63
- recommendations : RecommendationsList ,
64
- startPos : vscode . Position ,
65
- newCodeWhispererRequest : boolean ,
66
- editor : vscode . TextEditor | undefined
41
+ public recordUserDecisionTelemetryForEmptyList (
42
+ requestId : string ,
43
+ sessionId : string ,
44
+ paginationIndex : number ,
45
+ languageId : string
67
46
) {
68
- if ( ! editor || ! newCodeWhispererRequest ) {
69
- return
70
- }
71
- // Only works for cloud9, as it works for completion items
72
- if ( isCloud9 ( ) && startPos . line !== editor . selection . active . line ) {
73
- return
74
- }
75
-
76
- let typedPrefix = ''
77
- if ( newCodeWhispererRequest ) {
78
- this . isPrefixMatched = [ ]
79
- }
80
-
81
- typedPrefix = editor . document . getText ( new vscode . Range ( startPos , editor . selection . active ) )
82
-
83
- recommendations . forEach ( recommendation => {
84
- if ( recommendation . content . startsWith ( typedPrefix ) ) {
85
- if ( newCodeWhispererRequest ) {
86
- this . isPrefixMatched . push ( true )
87
- }
88
- } else {
89
- if ( newCodeWhispererRequest ) {
90
- this . isPrefixMatched . push ( false )
91
- }
92
- }
47
+ const languageContext = runtimeLanguageContext . getLanguageContext ( languageId )
48
+ telemetry . recordCodewhispererUserDecision ( {
49
+ codewhispererRequestId : requestId ,
50
+ codewhispererSessionId : sessionId ? sessionId : undefined ,
51
+ codewhispererPaginationProgress : paginationIndex ,
52
+ codewhispererTriggerType : this . triggerType ,
53
+ codewhispererSuggestionIndex : - 1 ,
54
+ codewhispererSuggestionState : 'Empty' ,
55
+ codewhispererSuggestionReferences : undefined ,
56
+ codewhispererSuggestionReferenceCount : 0 ,
57
+ codewhispererCompletionType : this . completionType ,
58
+ codewhispererLanguage : languageContext . language ,
93
59
} )
94
60
}
95
61
@@ -99,10 +65,11 @@ export class TelemetryHelper {
99
65
* @param acceptIndex the index of the accepted suggestion in the corresponding list of CodeWhisperer response.
100
66
* If this function is not called on acceptance, then acceptIndex == -1
101
67
* @param languageId the language ID of the current document in current active editor
102
- * @param filtered whether this user decision is to filter the recommendation due to license
68
+ * @param paginationIndex the index of pagination calls
69
+ * @param recommendationSuggestionState the key-value mapping from index to suggestion state
103
70
*/
104
71
105
- public async recordUserDecisionTelemetry (
72
+ public recordUserDecisionTelemetry (
106
73
requestId : string ,
107
74
sessionId : string ,
108
75
recommendations : RecommendationsList ,
@@ -114,28 +81,21 @@ export class TelemetryHelper {
114
81
const languageContext = runtimeLanguageContext . getLanguageContext ( languageId )
115
82
// emit user decision telemetry
116
83
recommendations . forEach ( ( _elem , i ) => {
117
- let unseen = true
118
- let filtered = false
119
- if ( recommendationSuggestionState !== undefined ) {
120
- if ( recommendationSuggestionState . get ( i ) === 'Filtered' ) {
121
- filtered = true
122
- }
123
- if ( recommendationSuggestionState . get ( i ) === 'Showed' ) {
124
- unseen = false
125
- }
126
- }
127
84
let uniqueSuggestionReferences : string | undefined = undefined
128
85
const uniqueLicenseSet = LicenseUtil . getUniqueLicenseNames ( _elem . references )
129
86
if ( uniqueLicenseSet . size > 0 ) {
130
87
uniqueSuggestionReferences = JSON . stringify ( Array . from ( uniqueLicenseSet ) )
131
88
}
89
+ if ( _elem . content . length === 0 ) {
90
+ recommendationSuggestionState ?. set ( i , 'Empty' )
91
+ }
132
92
telemetry . recordCodewhispererUserDecision ( {
133
93
codewhispererRequestId : requestId ,
134
94
codewhispererSessionId : sessionId ? sessionId : undefined ,
135
95
codewhispererPaginationProgress : paginationIndex ,
136
96
codewhispererTriggerType : this . triggerType ,
137
97
codewhispererSuggestionIndex : i ,
138
- codewhispererSuggestionState : this . getSuggestionState ( i , acceptIndex , filtered , unseen ) ,
98
+ codewhispererSuggestionState : this . getSuggestionState ( i , acceptIndex , recommendationSuggestionState ) ,
139
99
codewhispererSuggestionReferences : uniqueSuggestionReferences ,
140
100
codewhispererSuggestionReferenceCount : _elem . references ? _elem . references . length : 0 ,
141
101
codewhispererCompletionType : this . completionType ,
@@ -147,22 +107,17 @@ export class TelemetryHelper {
147
107
public getSuggestionState (
148
108
i : number ,
149
109
acceptIndex : number ,
150
- filtered : boolean = false ,
151
- unseen : boolean = false
110
+ recommendationSuggestionState ?: Map < number , string >
152
111
) : telemetry . CodewhispererSuggestionState {
153
- if ( filtered ) return 'Filter'
154
- if ( unseen ) return 'Unseen'
155
- if ( acceptIndex == - 1 ) {
156
- return this . isPrefixMatched [ i ] ? 'Reject' : 'Discard'
112
+ const state = recommendationSuggestionState ?. get ( i )
113
+ if ( state && [ 'Empty' , 'Filter' , 'Discard' ] . includes ( state ) ) {
114
+ return state as telemetry . CodewhispererSuggestionState
115
+ } else if ( recommendationSuggestionState !== undefined && recommendationSuggestionState . get ( i ) !== 'Showed' ) {
116
+ return 'Unseen'
157
117
}
158
- if ( ! this . isPrefixMatched [ i ] ) {
159
- return 'Discard'
160
- } else {
161
- if ( i == acceptIndex ) {
162
- return 'Accept'
163
- } else {
164
- return 'Ignore'
165
- }
118
+ if ( acceptIndex === - 1 ) {
119
+ return 'Reject'
166
120
}
121
+ return i === acceptIndex ? 'Accept' : 'Ignore'
167
122
}
168
123
}
0 commit comments