Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/editSurvivalTracking/common/editSurvivalReporter.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type vscode from 'vscode';
7
import { IGitService } from '../../../platform/git/common/gitService';
8
import { resolveWorkspaceOTelMetadata, type WorkspaceOTelMetadata } from '../../../platform/otel/common/workspaceOTelMetadata';
9
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
10
import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';
11
import { TimeoutTimer } from '../../../util/vs/base/common/async';
12
import { DisposableStore } from '../../../util/vs/base/common/lifecycle';
13
import { StringEdit } from '../../../util/vs/editor/common/core/edits/stringEdit';
14
import { stringEditFromTextContentChange } from '../../editing/common/edit';
15
import { ArcTracker } from './arcTracker';
16
import { EditSurvivalTracker } from './editSurvivalTracker';
17
18
export interface EditSurvivalResult {
19
readonly telemetryService: ITelemetryService;
20
readonly fourGram: number;
21
readonly noRevert: number;
22
readonly timeDelayMs: number;
23
readonly didBranchChange: boolean;
24
readonly currentFileContent?: string;
25
readonly workspace?: WorkspaceOTelMetadata;
26
27
/**
28
* Set includeArc to get this!
29
* See ArcTracker.
30
*/
31
readonly arc?: number;
32
33
/**
34
* Text states for each edit region
35
*/
36
readonly textBeforeAiEdits?: string[];
37
readonly textAfterAiEdits?: string[];
38
readonly textAfterUserEdits?: string[];
39
}
40
41
export class EditSurvivalReporter {
42
private readonly _store = new DisposableStore();
43
private readonly _editSurvivalTracker = new EditSurvivalTracker(this._documentTextBeforeMarkedEdits, this._markedEdits);
44
private readonly _arcTracker = this._options.includeArc === true ? new ArcTracker(this._documentTextBeforeMarkedEdits, this._markedEdits) : undefined;
45
private readonly _initialBranchName: string | undefined;
46
47
/**
48
* ```
49
* _documentTextBeforeMarkedEdits
50
* ----markedEdits---->
51
* ----editsOnTop---->
52
* _document.getText()
53
* ----onDidChangeTextDocument edits---->
54
* [30sec] -> telemetry event of survival rate of markedEdits
55
* [2min] -> ...
56
* [5min] -> ...
57
* [10min] -> ...
58
* ```
59
*/
60
constructor(
61
private readonly _document: vscode.TextDocument,
62
private readonly _documentTextBeforeMarkedEdits: string,
63
private readonly _markedEdits: StringEdit,
64
editsOnTop: StringEdit,
65
private readonly _options: { includeArc?: boolean },
66
private readonly _sendTelemetryEvent: (res: EditSurvivalResult) => void,
67
@IWorkspaceService workspaceService: IWorkspaceService,
68
@IGitService private readonly _gitService: IGitService,
69
@ITelemetryService private readonly _telemetryService: ITelemetryService
70
) {
71
this._store.add(workspaceService.onDidChangeTextDocument(e => {
72
if (e.document !== this._document) {
73
return;
74
}
75
const edits = stringEditFromTextContentChange(e.contentChanges);
76
this._editSurvivalTracker.handleEdits(edits);
77
this._arcTracker?.handleEdits(edits);
78
}));
79
80
this._editSurvivalTracker.handleEdits(editsOnTop);
81
this._arcTracker?.handleEdits(editsOnTop);
82
83
this._initialBranchName = this._gitService.activeRepository.get()?.headBranchName;
84
85
// This aligns with github inline completions
86
this._reportAfter(0);
87
this._reportAfter(5 * 1000);
88
this._reportAfter(30 * 1000);
89
this._reportAfter(120 * 1000);
90
this._reportAfter(300 * 1000);
91
this._reportAfter(600 * 1000);
92
// track up to 15min to allow for slower edit responses from legacy SD endpoint
93
this._reportAfter(900 * 1000, () => {
94
this._store.dispose();
95
});
96
}
97
98
private _getCurrentBranchName() {
99
return this._gitService.activeRepository.get()?.headBranchName;
100
}
101
102
private _reportAfter(timeoutMs: number, cb?: () => void) {
103
const timer = new TimeoutTimer(() => {
104
this._report(timeoutMs);
105
timer.dispose();
106
if (cb) {
107
cb();
108
}
109
}, timeoutMs);
110
this._store.add(timer);
111
}
112
113
private _report(timeMs: number): void {
114
const survivalRate = this._editSurvivalTracker.computeTrackedEditsSurvivalScore();
115
116
const currentBranch = this._getCurrentBranchName();
117
const didBranchChange = currentBranch !== this._initialBranchName;
118
const workspace = resolveWorkspaceOTelMetadata(this._gitService, this._document.uri);
119
this._sendTelemetryEvent({
120
telemetryService: this._telemetryService,
121
fourGram: survivalRate.fourGram,
122
noRevert: survivalRate.noRevert,
123
timeDelayMs: timeMs,
124
didBranchChange,
125
currentFileContent: this._document.getText(),
126
workspace,
127
arc: this._arcTracker?.getAcceptedRestrainedCharactersCount(),
128
textBeforeAiEdits: survivalRate.textBeforeAiEdits,
129
textAfterAiEdits: survivalRate.textAfterAiEdits,
130
textAfterUserEdits: survivalRate.textAfterUserEdits,
131
});
132
}
133
134
public cancel(): void {
135
this._store.dispose();
136
}
137
}
138
139