@codingame/monaco-vscode-telemetry-service-override 36.2.7 → 37.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/index.js +2 -1
  2. package/package.json +2 -2
  3. package/vscode/src/vs/base/common/editArcTracker.d.ts +29 -0
  4. package/vscode/src/vs/base/common/editArcTracker.js +291 -0
  5. package/vscode/src/vs/platform/agentHost/common/diffComputeService.d.ts +19 -0
  6. package/vscode/src/vs/platform/agentHost/common/fileEditAttribution.d.ts +107 -0
  7. package/vscode/src/vs/platform/agentHost/common/fileEditAttribution.js +59 -0
  8. package/vscode/src/vs/platform/agentHost/common/fileEditAttribution.service.d.ts +12 -0
  9. package/vscode/src/vs/platform/telemetry/browser/errorTelemetry.js +5 -5
  10. package/vscode/src/vs/platform/telemetry/common/1dsAppender.d.ts +2 -0
  11. package/vscode/src/vs/platform/telemetry/common/1dsAppender.js +12 -10
  12. package/vscode/src/vs/platform/telemetry/common/editArcTelemetry.d.ts +141 -0
  13. package/vscode/src/vs/platform/telemetry/common/editArcTelemetry.js +5 -0
  14. package/vscode/src/vs/platform/telemetry/common/editTelemetry.d.ts +49 -0
  15. package/vscode/src/vs/platform/telemetry/common/editTelemetry.js +10 -0
  16. package/vscode/src/vs/platform/telemetry/common/telemetryLogAppender.d.ts +5 -2
  17. package/vscode/src/vs/platform/telemetry/common/telemetryLogAppender.js +4 -3
  18. package/vscode/src/vs/platform/telemetry/common/telemetryService.d.ts +14 -4
  19. package/vscode/src/vs/platform/telemetry/common/telemetryService.js +50 -34
  20. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/editStats/aiStatsChart.js +1 -1
  21. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/editStats/aiStatsStatusBar.js +8 -8
  22. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/editTelemetry.contribution.js +12 -7
  23. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/editTelemetryContribution.js +2 -1
  24. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/helpers/documentWithAnnotatedEdits.d.ts +7 -1
  25. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/helpers/documentWithAnnotatedEdits.js +15 -2
  26. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/settingIds.d.ts +1 -1
  27. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/settingIds.js +1 -2
  28. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/agentHostEditMarkerService.d.ts +83 -0
  29. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/agentHostEditMarkerService.js +690 -0
  30. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/arcTelemetryReporter.d.ts +2 -2
  31. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/arcTelemetrySender.d.ts +3 -3
  32. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/arcTelemetrySender.js +3 -0
  33. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/editSourceTrackingFeature.js +11 -4
  34. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/editSourceTrackingImpl.d.ts +15 -4
  35. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/editSourceTrackingImpl.js +185 -83
  36. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/editTracker.d.ts +21 -5
  37. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/editTracker.js +128 -12
  38. package/vscode/src/vs/workbench/contrib/editTelemetry/browser/telemetry/scmAdapter.d.ts +7 -2
  39. package/vscode/src/vs/workbench/contrib/editTelemetry/common/arcTracker.d.ts +3 -11
  40. package/vscode/src/vs/workbench/contrib/editTelemetry/common/arcTracker.js +17 -47
  41. package/vscode/src/vs/workbench/contrib/telemetry/browser/telemetry.contribution.js +13 -2
  42. package/vscode/src/vs/workbench/services/policies/browser/policyTelemetry.contribution.d.ts +14 -0
  43. package/vscode/src/vs/workbench/services/policies/browser/policyTelemetry.contribution.js +134 -0
  44. package/vscode/src/vs/workbench/services/telemetry/browser/telemetryService.d.ts +1 -1
  45. package/vscode/src/vs/workbench/services/dataChannel/browser/dataChannelService.d.ts +0 -10
  46. package/vscode/src/vs/workbench/services/dataChannel/browser/dataChannelService.js +0 -30
@@ -0,0 +1,690 @@
1
+
2
+ import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
3
+ import { raceTimeout } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
4
+ import { Emitter, Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
5
+ import { Disposable, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
6
+ import { Schemas } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
7
+ import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
8
+ import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
9
+ import { ActionType } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/common/actions';
10
+ import '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/sessionState';
11
+ import { IAgentHostConnectionsService } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/agentHostConnectionsService.service';
12
+ import { toAgentHostUri } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/agentHostUri';
13
+ import { buildPrepareEditAttributionResource, buildCommitEditAttributionResource, buildCancelEditAttributionResource, getFileEditAttributionMarker, createFileEditContentDigest } from '../../../../../platform/agentHost/common/fileEditAttribution.js';
14
+ import { IUriIdentityService } from '@codingame/monaco-vscode-api/vscode/vs/platform/uriIdentity/common/uriIdentity.service';
15
+ import { EditSources } from '@codingame/monaco-vscode-api/vscode/vs/editor/common/textModelEditSource';
16
+ import { ToolResultContentType } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/channels-chat/state';
17
+
18
+ const MARKER_TTL = 5 * 60 * 1000;
19
+ const ROUTE_TTL = 10 * 60 * 60 * 1000;
20
+ const MAX_MARKERS_PER_RESOURCE = 128;
21
+ const MAX_OBSERVATIONS_PER_RESOURCE = 128;
22
+ const MAX_ROUTES = 1_000;
23
+ const MAX_COVERAGE_GAP_ACKNOWLEDGEMENTS = 1_000;
24
+ const COORDINATION_TIMEOUT = 15_000;
25
+ class AgentHostEditAttributionUnknownOutcomeError extends Error {
26
+ constructor(cause) {
27
+ super("The Agent Host edit attribution outcome is unknown", {
28
+ cause
29
+ });
30
+ }
31
+ }
32
+ class AgentHostEditAttributionDeferredError extends Error {
33
+ constructor(cause) {
34
+ super("The Agent Host edit attribution was deferred", {
35
+ cause
36
+ });
37
+ }
38
+ }
39
+ let AgentHostEditMarkerService = class AgentHostEditMarkerService extends Disposable {
40
+ constructor(_connectionsService, _uriIdentityService) {
41
+ super();
42
+ this._connectionsService = _connectionsService;
43
+ this._uriIdentityService = _uriIdentityService;
44
+ this._markers = ( new Map());
45
+ this._observations = ( new Map());
46
+ this._routes = ( new Map());
47
+ this._coverageGaps = ( new Map());
48
+ this._acknowledgedCoverageGapIds = ( new Map());
49
+ this._pendingCoverageGapAcknowledgements = ( new Map());
50
+ this._onDidSuppress = this._register(( new Emitter()));
51
+ this._onDidResolve = this._register(( new Emitter()));
52
+ this._onDidInvalidate = this._register(( new Emitter()));
53
+ this._onDidReceiveMarker = this._register(( new Emitter()));
54
+ this._connectionListeners = this._register(( new DisposableStore()));
55
+ this._updateConnectionListeners();
56
+ this._register(
57
+ this._connectionsService.onDidChangeConnections(() => this._updateConnectionListeners())
58
+ );
59
+ }
60
+ createCorrelation(resource) {
61
+ const resourceKey = this._key(resource);
62
+ let currentRegistration;
63
+ let clearRegistrationScheduled = false;
64
+ return {
65
+ onDidSuppress: this._onDidSuppress.event,
66
+ onDidResolve: this._onDidResolve.event,
67
+ onDidInvalidate: this._onDidInvalidate.event,
68
+ register: (before, after) => {
69
+ if (currentRegistration?.before === before && currentRegistration.after === after) {
70
+ this._retainObservation(resourceKey, currentRegistration.id);
71
+ return currentRegistration.id;
72
+ }
73
+ const id = this._registerObservation(resourceKey, before, after);
74
+ currentRegistration = {
75
+ before,
76
+ after,
77
+ id
78
+ };
79
+ if (!clearRegistrationScheduled) {
80
+ clearRegistrationScheduled = true;
81
+ queueMicrotask(() => {
82
+ currentRegistration = undefined;
83
+ clearRegistrationScheduled = false;
84
+ });
85
+ }
86
+ return id;
87
+ },
88
+ isSuppressed: id => this._getObservation(resourceKey, id)?.resolution !== undefined,
89
+ getResolution: id => this._getObservation(resourceKey, id)?.resolution,
90
+ waitForResolution: (ids, timeoutMs) => this._waitForResolution(resourceKey, ids, timeoutMs),
91
+ release: id => this._releaseObservation(resourceKey, id)
92
+ };
93
+ }
94
+ takeCoverageGap(resource, throughSequence = Number.MAX_SAFE_INTEGER) {
95
+ const resourceKey = this._key(resource);
96
+ this._prune(resourceKey);
97
+ const state = this._coverageGaps.get(resourceKey);
98
+ if (!state) {
99
+ return undefined;
100
+ }
101
+ const included = state.entries.filter(entry => entry.sequence <= throughSequence);
102
+ const remaining = state.entries.filter(entry => entry.sequence > throughSequence);
103
+ const editCount = included.reduce((sum, entry) => sum + entry.editCount, 0);
104
+ const insertedCount = included.reduce((sum, entry) => sum + entry.insertedCount, 0);
105
+ if (remaining.length > 0) {
106
+ this._coverageGaps.set(resourceKey, {
107
+ entries: remaining,
108
+ timestamp: state.timestamp
109
+ });
110
+ } else {
111
+ this._coverageGaps.delete(resourceKey);
112
+ }
113
+ return editCount > 0 || insertedCount > 0 ? {
114
+ editCount,
115
+ insertedCount
116
+ } : undefined;
117
+ }
118
+ async prepareFlush(resource, trigger, statsUuid, isDirty, languageId = "plaintext") {
119
+ const resourceKey = this._key(resource);
120
+ this._prune(resourceKey);
121
+ const route = this._routes.get(resourceKey);
122
+ if (!route) {
123
+ return undefined;
124
+ }
125
+ const flushToken = generateUuid();
126
+ try {
127
+ const result = await this._resourceRead(route.connection, buildPrepareEditAttributionResource({
128
+ resource: route.resource,
129
+ trigger,
130
+ statsUuid,
131
+ isDirty,
132
+ flushToken,
133
+ languageId
134
+ }));
135
+ const prepared = JSON.parse(result.data);
136
+ if (prepared && (prepared.flushToken !== flushToken || !Number.isSafeInteger(prepared.agentModifiedCount) || prepared.agentModifiedCount < 0 || (prepared.lastSequence !== undefined && (!Number.isSafeInteger(prepared.lastSequence) || prepared.lastSequence < 0)) || (prepared.coverageGapThroughSequence !== undefined && (!Number.isSafeInteger(prepared.coverageGapThroughSequence) || prepared.coverageGapThroughSequence < 0 || prepared.lastSequence === undefined || prepared.coverageGapThroughSequence > prepared.lastSequence)) || (prepared.standaloneCoverageGapAcknowledgements !== undefined && prepared.lastSequence === undefined) || !isValidCoverageGapAcknowledgements(prepared.standaloneCoverageGapAcknowledgements, prepared.lastSequence))) {
137
+ throw ( new Error("Agent Host edit attribution returned an invalid prepared flush"));
138
+ }
139
+ if (prepared?.lastSequence !== undefined) {
140
+ await this._waitForMarker(resourceKey, route.connection, prepared.lastSequence);
141
+ }
142
+ if (prepared?.standaloneCoverageGapAcknowledgements !== undefined) {
143
+ this._acknowledgeCoverageGaps(resourceKey, prepared.standaloneCoverageGapAcknowledgements);
144
+ }
145
+ return prepared ? {
146
+ ...prepared,
147
+ commit: async totalModifiedCount => {
148
+ let commitError = ( new Error(`Agent Host edit attribution commit failed: ${prepared.flushToken}`));
149
+ try {
150
+ const result = await this._readOutcome(route.connection, buildCommitEditAttributionResource({
151
+ flushToken: prepared.flushToken,
152
+ totalModifiedCount
153
+ }));
154
+ if (result.outcome === "committed") {
155
+ return;
156
+ }
157
+ commitError = ( new Error(`Agent Host edit attribution commit was not found: ${prepared.flushToken}`));
158
+ } catch (error) {
159
+ commitError = error;
160
+ }
161
+ let cancelResult;
162
+ try {
163
+ cancelResult = await this._readOutcome(route.connection, buildCancelEditAttributionResource({
164
+ flushToken: prepared.flushToken
165
+ }));
166
+ } catch (cancelError) {
167
+ throw ( new AgentHostEditAttributionUnknownOutcomeError(( new AggregateError(
168
+ [commitError, cancelError],
169
+ "Failed to commit or cancel Agent Host edit attribution"
170
+ ))));
171
+ }
172
+ if (cancelResult.outcome === "committed") {
173
+ return;
174
+ }
175
+ throw ( new AgentHostEditAttributionDeferredError(commitError));
176
+ }
177
+ } : undefined;
178
+ } catch (prepareError) {
179
+ return this._recoverFailedPrepare(route.connection, resourceKey, flushToken, prepareError);
180
+ }
181
+ }
182
+ async _recoverFailedPrepare(connection, resourceKey, flushToken, prepareError) {
183
+ let cancelResult;
184
+ try {
185
+ cancelResult = await this._readOutcome(connection, buildCancelEditAttributionResource({
186
+ flushToken
187
+ }));
188
+ } catch (cancelError) {
189
+ throw ( new AgentHostEditAttributionUnknownOutcomeError(( new AggregateError(
190
+ [prepareError, cancelError],
191
+ "Failed to prepare or cancel Agent Host edit attribution"
192
+ ))));
193
+ }
194
+ if (cancelResult.outcome === "committed") {
195
+ let deferCoverageGap = false;
196
+ if (cancelResult.lastSequence !== undefined) {
197
+ try {
198
+ await this._waitForMarker(resourceKey, connection, cancelResult.lastSequence);
199
+ } catch (markerError) {
200
+ throw ( new AgentHostEditAttributionUnknownOutcomeError(( new AggregateError(
201
+ [prepareError, markerError],
202
+ "Committed Agent Host attribution markers did not arrive"
203
+ ))));
204
+ }
205
+ }
206
+ if (cancelResult.standaloneCoverageGapAcknowledgements?.length) {
207
+ try {
208
+ await this._waitForMarker(
209
+ resourceKey,
210
+ connection,
211
+ getLastAcknowledgedSequence(cancelResult.standaloneCoverageGapAcknowledgements)
212
+ );
213
+ this._acknowledgeCoverageGaps(resourceKey, cancelResult.standaloneCoverageGapAcknowledgements);
214
+ } catch {
215
+ this._queuePendingCoverageGapAcknowledgements(resourceKey, cancelResult.standaloneCoverageGapAcknowledgements);
216
+ deferCoverageGap = true;
217
+ }
218
+ }
219
+ return {
220
+ flushToken,
221
+ agentModifiedCount: cancelResult.agentModifiedCount,
222
+ lastSequence: cancelResult.lastSequence,
223
+ coverageGapThroughSequence: cancelResult.coverageGapThroughSequence,
224
+ deferCoverageGap,
225
+ commit: async () => {}
226
+ };
227
+ }
228
+ throw ( new AgentHostEditAttributionDeferredError(prepareError));
229
+ }
230
+ async _waitForMarker(resourceKey, connection, sequence) {
231
+ const isCaughtUp = () => {
232
+ const route = this._routes.get(resourceKey);
233
+ return route?.connection === connection && route.lastSequence >= sequence;
234
+ };
235
+ if (isCaughtUp()) {
236
+ return;
237
+ }
238
+ const marker = await raceTimeout(Event.toPromise(Event.filter(
239
+ this._onDidReceiveMarker.event,
240
+ event => event.resourceKey === resourceKey && event.connection === connection && event.sequence >= sequence
241
+ )), COORDINATION_TIMEOUT);
242
+ if (!marker && !isCaughtUp()) {
243
+ throw ( new Error(`Timed out waiting for Agent Host edit attribution marker: ${sequence}`));
244
+ }
245
+ }
246
+ async _resourceRead(connection, resource) {
247
+ const result = await raceTimeout(connection.resourceRead(resource), COORDINATION_TIMEOUT);
248
+ if (!result) {
249
+ throw ( new Error(`Agent Host edit attribution request timed out: ${resource.path}`));
250
+ }
251
+ return result;
252
+ }
253
+ async _readOutcome(connection, resource) {
254
+ const result = await this._resourceRead(connection, resource);
255
+ const parsed = JSON.parse(result.data);
256
+ if ((parsed.outcome !== "committed" && parsed.outcome !== "cancelled" && parsed.outcome !== "missing") || typeof parsed.agentModifiedCount !== "number" || (parsed.lastSequence !== undefined && (!Number.isSafeInteger(parsed.lastSequence) || parsed.lastSequence < 0)) || (parsed.coverageGapThroughSequence !== undefined && (!Number.isSafeInteger(parsed.coverageGapThroughSequence) || parsed.coverageGapThroughSequence < 0 || parsed.lastSequence === undefined || parsed.coverageGapThroughSequence > parsed.lastSequence)) || (parsed.standaloneCoverageGapAcknowledgements !== undefined && parsed.lastSequence === undefined) || !isValidCoverageGapAcknowledgements(parsed.standaloneCoverageGapAcknowledgements)) {
257
+ throw ( new Error(`Invalid Agent Host edit attribution outcome: ${resource.path}`));
258
+ }
259
+ return {
260
+ outcome: parsed.outcome,
261
+ agentModifiedCount: parsed.agentModifiedCount,
262
+ lastSequence: parsed.lastSequence,
263
+ coverageGapThroughSequence: parsed.coverageGapThroughSequence,
264
+ standaloneCoverageGapAcknowledgements: parsed.standaloneCoverageGapAcknowledgements
265
+ };
266
+ }
267
+ _updateConnectionListeners() {
268
+ this._connectionListeners.clear();
269
+ const activeConnections = ( new Set(
270
+ this._connectionsService.connections.flatMap(info => info.connection ? [info.connection] : [])
271
+ ));
272
+ for (const [resourceKey, route] of this._routes) {
273
+ if (!( activeConnections.has(route.connection))) {
274
+ this._invalidateObservations(resourceKey);
275
+ this._routes.delete(resourceKey);
276
+ }
277
+ }
278
+ for (const connectionInfo of this._connectionsService.connections) {
279
+ const connection = connectionInfo.connection;
280
+ if (!connection) {
281
+ continue;
282
+ }
283
+ this._connectionListeners.add(connection.onDidAction(envelope => {
284
+ const action = envelope.action;
285
+ if (action.type !== ActionType.ChatToolCallComplete) {
286
+ return;
287
+ }
288
+ for (const content of action.result.content ?? []) {
289
+ if (content.type !== ToolResultContentType.FileEdit) {
290
+ continue;
291
+ }
292
+ const marker = getFileEditAttributionMarker(content);
293
+ const resourceUri = content.after?.uri ?? content.before?.uri;
294
+ if (!marker || !resourceUri) {
295
+ continue;
296
+ }
297
+ const resource = toAgentHostUri(( URI.parse(resourceUri)), connectionInfo.authority);
298
+ const resourceKey = this._key(resource);
299
+ const previousRoute = this._routes.get(resourceKey);
300
+ if (previousRoute && (previousRoute.connection !== connection || marker.sequence <= previousRoute.lastSequence)) {
301
+ this._invalidateObservations(resourceKey);
302
+ }
303
+ this._routes.delete(resourceKey);
304
+ this._routes.set(resourceKey, {
305
+ connection,
306
+ resource: ( URI.parse(resourceUri)),
307
+ timestamp: Date.now(),
308
+ lastSequence: marker.sequence
309
+ });
310
+ this._onDidReceiveMarker.fire({
311
+ resourceKey,
312
+ connection,
313
+ sequence: marker.sequence
314
+ });
315
+ while (this._routes.size > MAX_ROUTES) {
316
+ const oldestKey = ( this._routes.keys()).next().value;
317
+ if (oldestKey === undefined) {
318
+ break;
319
+ }
320
+ this._invalidateObservations(oldestKey);
321
+ this._routes.delete(oldestKey);
322
+ }
323
+ if (marker.status === "skipped") {
324
+ this._recordCoverageGap(
325
+ resourceKey,
326
+ marker.sequence,
327
+ marker.untrackedEditCount ?? 1,
328
+ marker.insertedCount
329
+ );
330
+ } else {
331
+ this._recordMarker(resourceKey, marker);
332
+ }
333
+ this._applyPendingCoverageGapAcknowledgements(resourceKey);
334
+ }
335
+ }));
336
+ }
337
+ }
338
+ _recordCoverageGap(resourceKey, sequence, editCount, insertedCount) {
339
+ const existing = this._coverageGaps.get(resourceKey) ?? {
340
+ entries: [],
341
+ timestamp: Date.now()
342
+ };
343
+ if (( existing.entries.some(entry => entry.sequence === sequence))) {
344
+ return;
345
+ }
346
+ existing.entries.push({
347
+ sequence,
348
+ editCount,
349
+ insertedCount
350
+ });
351
+ existing.timestamp = Date.now();
352
+ this._coverageGaps.delete(resourceKey);
353
+ this._coverageGaps.set(resourceKey, existing);
354
+ while (this._coverageGaps.size > MAX_ROUTES) {
355
+ const oldestKey = ( this._coverageGaps.keys()).next().value;
356
+ if (oldestKey === undefined) {
357
+ break;
358
+ }
359
+ this._coverageGaps.delete(oldestKey);
360
+ }
361
+ }
362
+ _acknowledgeCoverageGaps(resourceKey, acknowledgements) {
363
+ const remaining = [];
364
+ for (const acknowledgement of acknowledgements) {
365
+ const acknowledgementKey = coverageGapAcknowledgementKey(resourceKey, acknowledgement.id);
366
+ if (( this._acknowledgedCoverageGapIds.has(acknowledgementKey))) {
367
+ continue;
368
+ }
369
+ const state = this._coverageGaps.get(resourceKey);
370
+ if (!state) {
371
+ this._recordCoverageGapAcknowledgement(acknowledgementKey);
372
+ continue;
373
+ }
374
+ const acknowledgedSequences = ( new Set(acknowledgement.sequences));
375
+ const matched = state.entries.filter(entry => ( acknowledgedSequences.has(entry.sequence)));
376
+ const matchedEditCount = matched.reduce((sum, entry) => sum + entry.editCount, 0);
377
+ const matchedInsertedCount = matched.reduce((sum, entry) => sum + entry.insertedCount, 0);
378
+ if (matched.length !== acknowledgement.sequences.length || matchedEditCount !== acknowledgement.editCount || matchedInsertedCount !== acknowledgement.insertedCount) {
379
+ remaining.push(acknowledgement);
380
+ continue;
381
+ }
382
+ state.entries.splice(0, state.entries.length, ...state.entries.filter(entry => !( acknowledgedSequences.has(entry.sequence))));
383
+ if (state.entries.length > 0) {
384
+ this._coverageGaps.set(resourceKey, state);
385
+ } else {
386
+ this._coverageGaps.delete(resourceKey);
387
+ }
388
+ this._recordCoverageGapAcknowledgement(acknowledgementKey);
389
+ }
390
+ return remaining;
391
+ }
392
+ _recordCoverageGapAcknowledgement(acknowledgementKey) {
393
+ this._acknowledgedCoverageGapIds.delete(acknowledgementKey);
394
+ this._acknowledgedCoverageGapIds.set(acknowledgementKey, Date.now());
395
+ while (this._acknowledgedCoverageGapIds.size > MAX_COVERAGE_GAP_ACKNOWLEDGEMENTS) {
396
+ const oldestKey = ( this._acknowledgedCoverageGapIds.keys()).next().value;
397
+ if (oldestKey === undefined) {
398
+ break;
399
+ }
400
+ this._acknowledgedCoverageGapIds.delete(oldestKey);
401
+ }
402
+ }
403
+ _queuePendingCoverageGapAcknowledgements(resourceKey, acknowledgements) {
404
+ const pending = ( new Map(( (this._pendingCoverageGapAcknowledgements.get(resourceKey)?.acknowledgements ?? []).map(acknowledgement => [acknowledgement.id, acknowledgement]))));
405
+ for (const acknowledgement of acknowledgements) {
406
+ pending.set(acknowledgement.id, acknowledgement);
407
+ }
408
+ this._pendingCoverageGapAcknowledgements.delete(resourceKey);
409
+ this._pendingCoverageGapAcknowledgements.set(resourceKey, {
410
+ acknowledgements: Array.from(( pending.values())),
411
+ timestamp: Date.now()
412
+ });
413
+ while (this._pendingCoverageGapAcknowledgements.size > MAX_ROUTES) {
414
+ const oldestKey = ( this._pendingCoverageGapAcknowledgements.keys()).next().value;
415
+ if (oldestKey === undefined) {
416
+ break;
417
+ }
418
+ this._pendingCoverageGapAcknowledgements.delete(oldestKey);
419
+ }
420
+ }
421
+ _applyPendingCoverageGapAcknowledgements(resourceKey) {
422
+ const pending = this._pendingCoverageGapAcknowledgements.get(resourceKey);
423
+ const route = this._routes.get(resourceKey);
424
+ if (!pending || !route || route.lastSequence < getLastAcknowledgedSequence(pending.acknowledgements)) {
425
+ return;
426
+ }
427
+ this._pendingCoverageGapAcknowledgements.delete(resourceKey);
428
+ const remaining = this._acknowledgeCoverageGaps(resourceKey, pending.acknowledgements);
429
+ if (remaining.length > 0) {
430
+ this._queuePendingCoverageGapAcknowledgements(resourceKey, remaining);
431
+ }
432
+ }
433
+ _registerObservation(resourceKey, before, after) {
434
+ this._prune(resourceKey);
435
+ const observation = {
436
+ id: generateUuid(),
437
+ beforeDigest: createFileEditContentDigest(before),
438
+ afterDigest: createFileEditContentDigest(after),
439
+ timestamp: Date.now(),
440
+ referenceCount: 1
441
+ };
442
+ const observations = this._observations.get(resourceKey) ?? [];
443
+ if (observations.length >= MAX_OBSERVATIONS_PER_RESOURCE) {
444
+ return observation.id;
445
+ }
446
+ observations.push(observation);
447
+ this._observations.set(resourceKey, observations);
448
+ this._tryResolve(resourceKey, observation);
449
+ return observation.id;
450
+ }
451
+ _recordMarker(resourceKey, marker) {
452
+ this._prune(resourceKey);
453
+ const markers = this._markers.get(resourceKey) ?? [];
454
+ if (!( markers.some(candidate => candidate.editId === marker.editId))) {
455
+ markers.push({
456
+ ...marker,
457
+ timestamp: Date.now()
458
+ });
459
+ markers.sort((a, b) => a.sequence - b.sequence);
460
+ removeCompletedCycle(markers, marker.editId);
461
+ while (markers.length > MAX_MARKERS_PER_RESOURCE) {
462
+ markers.shift();
463
+ }
464
+ this._markers.set(resourceKey, markers);
465
+ }
466
+ for (const observation of this._observations.get(resourceKey) ?? []) {
467
+ this._tryResolve(resourceKey, observation);
468
+ }
469
+ }
470
+ _tryResolve(resourceKey, observation) {
471
+ if (observation.resolution) {
472
+ return;
473
+ }
474
+ const markers = this._markers.get(resourceKey);
475
+ if (!markers) {
476
+ return;
477
+ }
478
+ for (let startIndex = 0; startIndex < markers.length; startIndex++) {
479
+ const first = markers[startIndex];
480
+ if (first.beforeDigest !== observation.beforeDigest) {
481
+ continue;
482
+ }
483
+ const consumed = [startIndex];
484
+ let afterDigest = first.afterDigest;
485
+ let sequence = first.sequence;
486
+ while (afterDigest !== observation.afterDigest) {
487
+ const nextIndex = markers.findIndex(
488
+ (marker, index) => index !== startIndex && !consumed.includes(index) && marker.sequence > sequence && marker.beforeDigest === afterDigest
489
+ );
490
+ if (nextIndex < 0) {
491
+ break;
492
+ }
493
+ consumed.push(nextIndex);
494
+ afterDigest = markers[nextIndex].afterDigest;
495
+ sequence = markers[nextIndex].sequence;
496
+ }
497
+ if (afterDigest !== observation.afterDigest) {
498
+ continue;
499
+ }
500
+ const sources = ( consumed.map(index => markers[index].source));
501
+ const firstSource = sources[0];
502
+ const source = firstSource && sources.every(
503
+ candidate => candidate !== undefined && candidate.modelId === firstSource.modelId && candidate.harness === firstSource.harness
504
+ ) ? EditSources.agentHostChatApplyEdits({
505
+ modelId: firstSource.modelId,
506
+ sessionId: firstSource.conversationId,
507
+ requestId: firstSource.requestId,
508
+ harness: firstSource.harness
509
+ }) : undefined;
510
+ observation.resolution = {
511
+ id: observation.id,
512
+ source
513
+ };
514
+ for (const index of consumed.toSorted((a, b) => b - a)) {
515
+ markers.splice(index, 1);
516
+ }
517
+ if (markers.length === 0) {
518
+ this._markers.delete(resourceKey);
519
+ }
520
+ this._onDidSuppress.fire(observation.id);
521
+ this._onDidResolve.fire(observation.resolution);
522
+ return;
523
+ }
524
+ }
525
+ _retainObservation(resourceKey, id) {
526
+ const observation = this._getObservation(resourceKey, id);
527
+ if (observation) {
528
+ observation.referenceCount++;
529
+ }
530
+ }
531
+ _releaseObservation(resourceKey, id) {
532
+ const observations = this._observations.get(resourceKey);
533
+ if (!observations) {
534
+ return;
535
+ }
536
+ const index = observations.findIndex(observation => observation.id === id);
537
+ if (index >= 0) {
538
+ const observation = observations[index];
539
+ observation.referenceCount--;
540
+ if (observation.referenceCount <= 0) {
541
+ observations.splice(index, 1);
542
+ }
543
+ }
544
+ if (observations.length === 0) {
545
+ this._observations.delete(resourceKey);
546
+ }
547
+ }
548
+ _invalidateObservations(resourceKey) {
549
+ this._markers.delete(resourceKey);
550
+ this._coverageGaps.delete(resourceKey);
551
+ this._pendingCoverageGapAcknowledgements.delete(resourceKey);
552
+ const acknowledgementPrefix = coverageGapAcknowledgementKey(resourceKey, "");
553
+ for (const acknowledgementKey of ( this._acknowledgedCoverageGapIds.keys())) {
554
+ if (acknowledgementKey.startsWith(acknowledgementPrefix)) {
555
+ this._acknowledgedCoverageGapIds.delete(acknowledgementKey);
556
+ }
557
+ }
558
+ const observations = this._observations.get(resourceKey);
559
+ if (!observations) {
560
+ return;
561
+ }
562
+ for (const observation of observations) {
563
+ if (observation.resolution) {
564
+ this._onDidInvalidate.fire(observation.id);
565
+ }
566
+ }
567
+ this._observations.delete(resourceKey);
568
+ }
569
+ _prune(resourceKey) {
570
+ const now = Date.now();
571
+ const minimumTimestamp = now - MARKER_TTL;
572
+ const markers = this._markers.get(resourceKey)?.filter(marker => marker.timestamp >= minimumTimestamp);
573
+ if (markers?.length) {
574
+ this._markers.set(resourceKey, markers);
575
+ } else {
576
+ this._markers.delete(resourceKey);
577
+ }
578
+ const observations = this._observations.get(resourceKey)?.filter(
579
+ observation => observation.resolution !== undefined || observation.timestamp >= minimumTimestamp
580
+ );
581
+ if (observations?.length) {
582
+ this._observations.set(resourceKey, observations);
583
+ } else {
584
+ this._observations.delete(resourceKey);
585
+ }
586
+ if ((this._routes.get(resourceKey)?.timestamp ?? now) < now - ROUTE_TTL) {
587
+ this._invalidateObservations(resourceKey);
588
+ this._routes.delete(resourceKey);
589
+ }
590
+ if ((this._coverageGaps.get(resourceKey)?.timestamp ?? now) < now - ROUTE_TTL) {
591
+ this._coverageGaps.delete(resourceKey);
592
+ }
593
+ if ((this._pendingCoverageGapAcknowledgements.get(resourceKey)?.timestamp ?? now) < now - ROUTE_TTL) {
594
+ this._pendingCoverageGapAcknowledgements.delete(resourceKey);
595
+ }
596
+ for (const [acknowledgementKey, timestamp] of this._acknowledgedCoverageGapIds) {
597
+ if (timestamp < now - ROUTE_TTL) {
598
+ this._acknowledgedCoverageGapIds.delete(acknowledgementKey);
599
+ }
600
+ }
601
+ }
602
+ _key(resource) {
603
+ const normalizedResource = resource.scheme === Schemas.vscodeRemote ? ( URI.from({
604
+ scheme: Schemas.file,
605
+ path: resource.path
606
+ })) : resource;
607
+ return this._uriIdentityService.extUri.getComparisonKey(this._uriIdentityService.asCanonicalUri(normalizedResource));
608
+ }
609
+ _getObservation(resourceKey, id) {
610
+ return this._observations.get(resourceKey)?.find(observation => observation.id === id);
611
+ }
612
+ async _waitForResolution(resourceKey, ids, timeoutMs) {
613
+ const unresolved = ( new Set(ids.filter(id => {
614
+ const observation = this._getObservation(resourceKey, id);
615
+ return observation !== undefined && observation.resolution === undefined;
616
+ })));
617
+ if (unresolved.size === 0) {
618
+ return;
619
+ }
620
+ const store = ( new DisposableStore());
621
+ try {
622
+ await raceTimeout(( new Promise(resolve => {
623
+ const complete = id => {
624
+ unresolved.delete(id);
625
+ if (unresolved.size === 0) {
626
+ resolve();
627
+ }
628
+ };
629
+ store.add(this._onDidResolve.event(resolution => complete(resolution.id)));
630
+ store.add(this._onDidInvalidate.event(complete));
631
+ })), timeoutMs);
632
+ } finally {
633
+ store.dispose();
634
+ }
635
+ }
636
+ };
637
+ AgentHostEditMarkerService = ( __decorate([( __param(0, IAgentHostConnectionsService)), ( __param(1, IUriIdentityService))], AgentHostEditMarkerService));
638
+ function isValidCoverageGapAcknowledgements(acknowledgements, lastSequence) {
639
+ if (acknowledgements === undefined) {
640
+ return true;
641
+ }
642
+ if (!Array.isArray(acknowledgements) || acknowledgements.length === 0 || ( new Set(( acknowledgements.map(acknowledgement => acknowledgement.id)))).size !== acknowledgements.length) {
643
+ return false;
644
+ }
645
+ return acknowledgements.every(
646
+ acknowledgement => typeof acknowledgement.id === "string" && acknowledgement.id.length > 0 && Array.isArray(acknowledgement.sequences) && acknowledgement.sequences.length > 0 && acknowledgement.sequences.every(
647
+ sequence => Number.isSafeInteger(sequence) && sequence >= 0 && (lastSequence === undefined || sequence <= lastSequence)
648
+ ) && ( new Set(acknowledgement.sequences)).size === acknowledgement.sequences.length && Number.isSafeInteger(acknowledgement.editCount) && acknowledgement.editCount > 0 && Number.isSafeInteger(acknowledgement.insertedCount) && acknowledgement.insertedCount >= 0
649
+ );
650
+ }
651
+ function getLastAcknowledgedSequence(acknowledgements) {
652
+ return Math.max(...acknowledgements.flatMap(acknowledgement => acknowledgement.sequences));
653
+ }
654
+ function coverageGapAcknowledgementKey(resourceKey, acknowledgementId) {
655
+ return `${resourceKey}\0${acknowledgementId}`;
656
+ }
657
+ function removeCompletedCycle(markers, latestEditId) {
658
+ const latestIndex = markers.findIndex(marker => marker.editId === latestEditId);
659
+ if (latestIndex < 0) {
660
+ return;
661
+ }
662
+ const completedDigest = markers[latestIndex].afterDigest;
663
+ const consumed = [latestIndex];
664
+ let beforeDigest = markers[latestIndex].beforeDigest;
665
+ let sequence = markers[latestIndex].sequence;
666
+ while (true) {
667
+ if (beforeDigest === completedDigest && consumed.length > 1) {
668
+ for (const index of consumed.toSorted((a, b) => b - a)) {
669
+ markers.splice(index, 1);
670
+ }
671
+ return;
672
+ }
673
+ let previousIndex = -1;
674
+ for (let index = markers.length - 1; index >= 0; index--) {
675
+ const marker = markers[index];
676
+ if (marker.sequence < sequence && marker.afterDigest === beforeDigest) {
677
+ previousIndex = index;
678
+ break;
679
+ }
680
+ }
681
+ if (previousIndex < 0) {
682
+ return;
683
+ }
684
+ consumed.push(previousIndex);
685
+ beforeDigest = markers[previousIndex].beforeDigest;
686
+ sequence = markers[previousIndex].sequence;
687
+ }
688
+ }
689
+
690
+ export { AgentHostEditAttributionDeferredError, AgentHostEditAttributionUnknownOutcomeError, AgentHostEditMarkerService };