Skip to content

Commit 288617f

Browse files
committed
update
1 parent ad0e018 commit 288617f

File tree

12 files changed

+156
-131
lines changed

12 files changed

+156
-131
lines changed

packages/amazonq/src/inlineChat/controller/inlineChatController.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { computeDecorations } from '../decorations/computeDecorations'
1313
import { CodelensProvider } from '../codeLenses/codeLenseProvider'
1414
import { PromptMessage, ReferenceLogController } from 'aws-core-vscode/codewhispererChat'
1515
import { CodeWhispererSettings } from 'aws-core-vscode/codewhisperer'
16-
import { QCodeGenTracker } from 'aws-core-vscode/codewhisperer'
16+
import { UserWrittenCodeTracker } from 'aws-core-vscode/codewhisperer'
1717
import {
1818
codicon,
1919
getIcon,
@@ -69,7 +69,6 @@ export class InlineChatController {
6969
},
7070
this.task
7171
)
72-
QCodeGenTracker.instance.onInlineChatAcceptance()
7372
}
7473
const deletions = task.diff.filter((diff) => diff.type === 'deletion')
7574
await editor.edit(
@@ -86,6 +85,7 @@ export class InlineChatController {
8685
await this.updateTaskAndLenses(task)
8786
this.referenceLogController.addReferenceLog(task.codeReferences, task.replacement ? task.replacement : '')
8887
await this.reset()
88+
UserWrittenCodeTracker.instance.onQFinishesEdits()
8989
}
9090

9191
public async rejectAllChanges(task = this.task, userInvoked: boolean): Promise<void> {
@@ -199,7 +199,8 @@ export class InlineChatController {
199199
getLogger().info('inlineQuickPick query is empty')
200200
return
201201
}
202-
202+
UserWrittenCodeTracker.instance.onQStartsMakingEdits()
203+
UserWrittenCodeTracker.instance.onQFeatureInvoked()
203204
this.userQuery = query
204205
await textDocumentUtil.addEofNewline(editor)
205206
this.task = await this.createTask(query, editor.document, editor.selection)

packages/core/src/amazonq/commons/controllers/contentController.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getSelectionFromRange,
1717
} from '../../../shared/utilities/textDocumentUtilities'
1818
import { extractFileAndCodeSelectionFromMessage, fs, getErrorMsg, ToolkitError } from '../../../shared'
19+
import { UserWrittenCodeTracker } from '../../../codewhisperer/tracker/userWrittenCodeTracker'
1920

2021
export class ContentProvider implements vscode.TextDocumentContentProvider {
2122
constructor(private uri: vscode.Uri) {}
@@ -41,6 +42,7 @@ export class EditorContentController {
4142
) {
4243
const editor = window.activeTextEditor
4344
if (editor) {
45+
UserWrittenCodeTracker.instance.onQStartsMakingEdits()
4446
const cursorStart = editor.selection.active
4547
const indentRange = new vscode.Range(new vscode.Position(cursorStart.line, 0), cursorStart)
4648
// use the user editor intent if the position to the left of cursor is just space or tab
@@ -71,6 +73,9 @@ export class EditorContentController {
7173
getLogger().error('TextEditor.edit failed: %s', (e as Error).message)
7274
}
7375
)
76+
.then(() => {
77+
UserWrittenCodeTracker.instance.onQFinishesEdits()
78+
})
7479
}
7580
}
7681

packages/core/src/codewhisperer/activation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ import { SecurityIssueTreeViewProvider } from './service/securityIssueTreeViewPr
9999
import { setContext } from '../shared/vscode/setContext'
100100
import { syncSecurityIssueWebview } from './views/securityIssue/securityIssueWebview'
101101
import { detectCommentAboveLine } from '../shared/utilities/commentUtils'
102-
import { QCodeGenTracker } from './tracker/qCodeGenTracker'
102+
import { UserWrittenCodeTracker } from './tracker/userWrittenCodeTracker'
103103

104104
let localize: nls.LocalizeFunc
105105

@@ -556,7 +556,7 @@ export async function activate(context: ExtContext): Promise<void> {
556556
}
557557

558558
CodeWhispererCodeCoverageTracker.getTracker(e.document.languageId)?.countTotalTokens(e)
559-
QCodeGenTracker.instance.onTextDocumentChange(e)
559+
UserWrittenCodeTracker.instance.onTextDocumentChange(e)
560560
/**
561561
* Handle this keystroke event only when
562562
* 1. It is not a backspace

packages/core/src/codewhisperer/client/user-service-2.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@
626626
"timestamp": { "shape": "Timestamp" },
627627
"unmodifiedAcceptedCharacterCount": { "shape": "PrimitiveInteger" },
628628
"totalNewCodeCharacterCount": { "shape": "PrimitiveInteger" },
629-
"totalNewCodeLineCount": { "shape": "PrimitiveInteger" }
629+
"totalNewCodeLineCount": { "shape": "PrimitiveInteger" },
630+
"userWrittenCodeCharacterCount": { "shape": "PrimitiveInteger" },
631+
"userWrittenCodeLineCount": { "shape": "PrimitiveInteger" }
630632
}
631633
},
632634
"CodeFixAcceptanceEvent": {

packages/core/src/codewhisperer/commands/onInlineAcceptance.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { RecommendationService } from '../service/recommendationService'
3232
import { Container } from '../service/serviceContainer'
3333
import { telemetry } from '../../shared/telemetry'
3434
import { TelemetryHelper } from '../util/telemetryHelper'
35-
import { QCodeGenTracker } from '../tracker/qCodeGenTracker'
35+
import { UserWrittenCodeTracker } from '../tracker/userWrittenCodeTracker'
3636

3737
export const acceptSuggestion = Commands.declare(
3838
'aws.amazonq.accept',
@@ -127,7 +127,7 @@ export async function onInlineAcceptance(acceptanceEntry: OnRecommendationAccept
127127
acceptanceEntry.editor.document.getText(insertedCoderange),
128128
acceptanceEntry.editor.document.fileName
129129
)
130-
QCodeGenTracker.instance.onInlineCompletionAcceptance(acceptanceEntry)
130+
UserWrittenCodeTracker.instance.onQFinishesEdits()
131131
if (acceptanceEntry.references !== undefined) {
132132
const referenceLog = ReferenceLogViewProvider.getReferenceLog(
133133
acceptanceEntry.recommendation,

packages/core/src/codewhisperer/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,4 @@ export * as CodeWhispererConstants from '../codewhisperer/models/constants'
101101
export { getSelectedCustomization } from './util/customizationUtil'
102102
export { Container } from './service/serviceContainer'
103103
export * from './util/gitUtil'
104-
export { QCodeGenTracker } from './tracker/qCodeGenTracker'
104+
export { UserWrittenCodeTracker } from './tracker/userWrittenCodeTracker'

packages/core/src/codewhisperer/service/inlineCompletionItemProvider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ReferenceInlineProvider } from './referenceInlineProvider'
1212
import { ImportAdderProvider } from './importAdderProvider'
1313
import { application } from '../util/codeWhispererApplication'
1414
import path from 'path'
15+
import { UserWrittenCodeTracker } from '../tracker/userWrittenCodeTracker'
1516

1617
export class CWInlineCompletionItemProvider implements vscode.InlineCompletionItemProvider {
1718
private activeItemIndex: number | undefined
@@ -170,6 +171,7 @@ export class CWInlineCompletionItemProvider implements vscode.InlineCompletionIt
170171
this.nextMove = 0
171172
TelemetryHelper.instance.setFirstSuggestionShowTime()
172173
session.setPerceivedLatency()
174+
UserWrittenCodeTracker.instance.onQStartsMakingEdits()
173175
this._onDidShow.fire()
174176
if (matchedCount >= 2 || this.nextToken !== '') {
175177
const result = [item]

packages/core/src/codewhisperer/service/recommendationHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import { openUrl } from '../../shared/utilities/vsCodeUtils'
4444
import { indent } from '../../shared/utilities/textUtilities'
4545
import path from 'path'
4646
import { isIamConnection } from '../../auth/connection'
47-
import { QCodeGenTracker } from '../tracker/qCodeGenTracker'
47+
import { UserWrittenCodeTracker } from '../tracker/userWrittenCodeTracker'
4848

4949
/**
5050
* This class is for getRecommendation/listRecommendation API calls and its states
@@ -317,7 +317,7 @@ export class RecommendationHandler {
317317
getLogger().debug(msg)
318318
if (invocationResult === 'Succeeded') {
319319
CodeWhispererCodeCoverageTracker.getTracker(session.language)?.incrementServiceInvocationCount()
320-
QCodeGenTracker.instance.onQFeatureInvoked()
320+
UserWrittenCodeTracker.instance.onQFeatureInvoked()
321321
} else {
322322
if (
323323
(errorMessage?.includes(invalidCustomizationMessage) && errorCode === 'AccessDeniedException') ||

packages/core/src/codewhisperer/tracker/qCodeGenTracker.ts renamed to packages/core/src/codewhisperer/tracker/userWrittenCodeTracker.ts

Lines changed: 51 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import * as vscode from 'vscode'
77
import { getLogger } from '../../shared/logger/logger'
88
import * as CodeWhispererConstants from '../models/constants'
9-
import { OnRecommendationAcceptanceEntry, vsCodeState } from '../models/model'
109
import { runtimeLanguageContext } from '../util/runtimeLanguageContext'
1110
import { TelemetryHelper } from '../util/telemetryHelper'
1211
import { AuthUtil } from '../util/authUtil'
@@ -15,22 +14,37 @@ import { codeWhispererClient as client } from '../client/codewhisperer'
1514
import { isAwsError } from '../../shared/errors'
1615

1716
/**
18-
* This singleton class is mainly used for calculating the total code written by Amazon Q and user
19-
* It is meant to replace `CodeWhispererCodeCoverageTracker`
17+
* This singleton class is mainly used for calculating the user written code
18+
* for active Amazon Q users.
19+
* It reports the user written code per 5 minutes when the user is coding and using Amazon Q features
2020
*/
21-
export class QCodeGenTracker {
22-
private _totalNewCodeCharacterCount: number
23-
private _totalNewCodeLineCount: number
21+
export class UserWrittenCodeTracker {
22+
private _userWrittenNewCodeCharacterCount: number
23+
private _userWrittenNewCodeLineCount: number
24+
private _qIsMakingEdits: boolean
2425
private _timer?: NodeJS.Timer
2526
private _qUsageCount: number
27+
private _lastQInvocationTime: number
2628

27-
static #instance: QCodeGenTracker
29+
static #instance: UserWrittenCodeTracker
2830
static copySnippetThreshold = 50
31+
static resetQIsEditingTimeoutMs = 5 * 60 * 1000
2932

3033
private constructor() {
31-
this._totalNewCodeLineCount = 0
32-
this._totalNewCodeCharacterCount = 0
34+
this._userWrittenNewCodeLineCount = 0
35+
this._userWrittenNewCodeCharacterCount = 0
3336
this._qUsageCount = 0
37+
this._qIsMakingEdits = false
38+
this._timer = undefined
39+
this._lastQInvocationTime = 0
40+
}
41+
42+
private resetTracker() {
43+
this._userWrittenNewCodeLineCount = 0
44+
this._userWrittenNewCodeCharacterCount = 0
45+
this._qUsageCount = 0
46+
this._qIsMakingEdits = false
47+
this._lastQInvocationTime = 0
3448
}
3549

3650
public static get instance() {
@@ -45,6 +59,15 @@ export class QCodeGenTracker {
4559
// for all Q features
4660
public onQFeatureInvoked() {
4761
this._qUsageCount += 1
62+
this._lastQInvocationTime = performance.now()
63+
}
64+
65+
public onQStartsMakingEdits() {
66+
this._qIsMakingEdits = true
67+
}
68+
69+
public onQFinishesEdits() {
70+
this._qIsMakingEdits = false
4871
}
4972

5073
public emitCodeContribution() {
@@ -60,8 +83,8 @@ export class QCodeGenTracker {
6083
acceptedCharacterCount: 0,
6184
totalCharacterCount: 0,
6285
timestamp: new Date(Date.now()),
63-
totalNewCodeCharacterCount: this._totalNewCodeCharacterCount,
64-
totalNewCodeLineCount: this._totalNewCodeLineCount,
86+
userWrittenCodeCharacterCount: this._userWrittenNewCodeCharacterCount,
87+
userWrittenCodeLineCount: this._userWrittenNewCodeLineCount,
6588
},
6689
},
6790
})
@@ -98,7 +121,7 @@ export class QCodeGenTracker {
98121
getLogger().debug(`Skip emiting code contribution metric. There is no active Amazon Q usage. `)
99122
return
100123
}
101-
if (this._totalNewCodeCharacterCount === 0) {
124+
if (this._userWrittenNewCodeCharacterCount === 0) {
102125
getLogger().debug(`Skip emiting code contribution metric. There is no new code added. `)
103126
return
104127
}
@@ -113,12 +136,6 @@ export class QCodeGenTracker {
113136
}, CodeWhispererConstants.defaultCheckPeriodMillis)
114137
}
115138

116-
private resetTracker() {
117-
this._totalNewCodeLineCount = 0
118-
this._totalNewCodeCharacterCount = 0
119-
this._qUsageCount = 0
120-
}
121-
122139
private closeTimer() {
123140
if (this._timer !== undefined) {
124141
clearTimeout(this._timer)
@@ -131,65 +148,32 @@ export class QCodeGenTracker {
131148
}
132149

133150
public onTextDocumentChange(e: vscode.TextDocumentChangeEvent) {
151+
// do not count code written by Q as user written code
134152
if (
135153
!runtimeLanguageContext.isLanguageSupported(e.document.languageId) ||
136-
vsCodeState.isCodeWhispererEditing ||
137-
e.contentChanges.length === 0
154+
e.contentChanges.length === 0 ||
155+
this._qIsMakingEdits
138156
) {
157+
// if the boolean of qIsMakingEdits was incorrectly set to true
158+
// due to unhandled edge cases or early terminated code paths
159+
// reset it back to false after reasonabe period of time
160+
if (this._qIsMakingEdits) {
161+
if (performance.now() - this._lastQInvocationTime > UserWrittenCodeTracker.resetQIsEditingTimeoutMs) {
162+
this._qIsMakingEdits = false
163+
}
164+
}
139165
return
140166
}
141167
const contentChange = e.contentChanges[0]
142168
// if user copies code into the editor for more than 50 characters
143-
// do not count this as total new code, this will skew the data.
144-
if (contentChange.text.length > QCodeGenTracker.copySnippetThreshold) {
169+
// do not count this as total new code, this will skew the data,
170+
// reporting highly inflated user written code
171+
if (contentChange.text.length > UserWrittenCodeTracker.copySnippetThreshold) {
145172
return
146173
}
147-
this._totalNewCodeCharacterCount += contentChange.text.length
148-
this._totalNewCodeLineCount += this.countNewLines(contentChange.text)
174+
this._userWrittenNewCodeCharacterCount += contentChange.text.length
175+
this._userWrittenNewCodeLineCount += this.countNewLines(contentChange.text)
149176
// start 5 min data reporting once valid user input is detected
150177
this.tryStartTimer()
151178
}
152-
153-
// add Q inline completion contributed code to total code written
154-
public onInlineCompletionAcceptance(acceptanceEntry: OnRecommendationAcceptanceEntry) {
155-
let typeaheadLength = 0
156-
if (acceptanceEntry.editor) {
157-
typeaheadLength = acceptanceEntry.editor.document.getText(acceptanceEntry.range).length
158-
}
159-
const documentChangeLength = acceptanceEntry.recommendation.length - typeaheadLength
160-
// if the inline completion is less than 50 characters, it will be auto captured by onTextDocumentChange
161-
// notice that the document change event of such acceptance do not include typeahead
162-
if (documentChangeLength <= QCodeGenTracker.copySnippetThreshold) {
163-
return
164-
}
165-
this._totalNewCodeCharacterCount += acceptanceEntry.recommendation.length
166-
this._totalNewCodeLineCount += this.countNewLines(acceptanceEntry.recommendation)
167-
}
168-
169-
// add Q chat insert to cursor code to total code written
170-
public onQChatInsertion(acceptedCharacterCount?: number, acceptedLineCount?: number) {
171-
if (acceptedCharacterCount && acceptedLineCount) {
172-
// if the chat inserted code is less than 50 characters, it will be auto captured by onTextDocumentChange
173-
if (acceptedCharacterCount <= QCodeGenTracker.copySnippetThreshold) {
174-
return
175-
}
176-
this._totalNewCodeCharacterCount += acceptedCharacterCount
177-
this._totalNewCodeLineCount += acceptedLineCount
178-
}
179-
}
180-
181-
// add Q inline chat acceptance to total code written
182-
public onInlineChatAcceptance() {}
183-
184-
// TODO: add Q inline chat acceptance to total code written
185-
public onTransformAcceptance() {}
186-
187-
// TODO: add Q feature dev acceptance to total code written
188-
public onFeatureDevAcceptance() {}
189-
190-
// TODO: add Q UTG acceptance to total code written
191-
public onUtgAcceptance() {}
192-
193-
// TODO: add Q UTG acceptance to total code written
194-
public onDocAcceptance() {}
195179
}

packages/core/src/codewhispererChat/clients/chat/v0/chat.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as vscode from 'vscode'
99
import { ToolkitError } from '../../../../shared/errors'
1010
import { createCodeWhispererChatStreamingClient } from '../../../../shared/clients/codewhispererChatClient'
1111
import { createQDeveloperStreamingClient } from '../../../../shared/clients/qDeveloperChatClient'
12-
import { QCodeGenTracker } from '../../../../codewhisperer/tracker/qCodeGenTracker'
12+
import { UserWrittenCodeTracker } from '../../../../codewhisperer/tracker/userWrittenCodeTracker'
1313

1414
export class ChatSession {
1515
private sessionId?: string
@@ -68,7 +68,7 @@ export class ChatSession {
6868

6969
this.sessionId = response.conversationId
7070

71-
QCodeGenTracker.instance.onQFeatureInvoked()
71+
UserWrittenCodeTracker.instance.onQFeatureInvoked()
7272

7373
return response
7474
}

0 commit comments

Comments
 (0)