@vscode/chat-lib 0.4.1-1 → 0.4.1-11

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 (175) hide show
  1. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.js +1 -1
  2. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.js.map +1 -1
  3. package/dist/src/_internal/extension/inlineEdits/common/delay.d.ts +3 -1
  4. package/dist/src/_internal/extension/inlineEdits/common/delay.d.ts.map +1 -1
  5. package/dist/src/_internal/extension/inlineEdits/common/delay.js +6 -0
  6. package/dist/src/_internal/extension/inlineEdits/common/delay.js.map +1 -1
  7. package/dist/src/_internal/extension/inlineEdits/common/editRebase.d.ts.map +1 -1
  8. package/dist/src/_internal/extension/inlineEdits/common/editRebase.js +2 -35
  9. package/dist/src/_internal/extension/inlineEdits/common/editRebase.js.map +1 -1
  10. package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.d.ts +6 -0
  11. package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.d.ts.map +1 -1
  12. package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.js +19 -35
  13. package/dist/src/_internal/extension/inlineEdits/common/userInteractionMonitor.js.map +1 -1
  14. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.d.ts +1 -0
  15. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.d.ts.map +1 -1
  16. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts +12 -1
  17. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts.map +1 -1
  18. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js +147 -95
  19. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js.map +1 -1
  20. package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.d.ts +7 -0
  21. package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.d.ts.map +1 -1
  22. package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.js +18 -3
  23. package/dist/src/_internal/extension/inlineEdits/node/nextEditProviderTelemetry.js.map +1 -1
  24. package/dist/src/_internal/extension/inlineEdits/node/nextEditResult.d.ts +2 -0
  25. package/dist/src/_internal/extension/inlineEdits/node/nextEditResult.d.ts.map +1 -1
  26. package/dist/src/_internal/extension/inlineEdits/node/nextEditResult.js.map +1 -1
  27. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts +11 -1
  28. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts.map +1 -1
  29. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js +144 -52
  30. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js.map +1 -1
  31. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts +6 -3
  32. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts.map +1 -1
  33. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js +9 -3
  34. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js.map +1 -1
  35. package/dist/src/_internal/extension/xtab/common/diffHistoryForPrompt.d.ts +6 -1
  36. package/dist/src/_internal/extension/xtab/common/diffHistoryForPrompt.d.ts.map +1 -1
  37. package/dist/src/_internal/extension/xtab/common/diffHistoryForPrompt.js +3 -1
  38. package/dist/src/_internal/extension/xtab/common/diffHistoryForPrompt.js.map +1 -1
  39. package/dist/src/_internal/extension/xtab/common/lintErrors.js +2 -1
  40. package/dist/src/_internal/extension/xtab/common/lintErrors.js.map +1 -1
  41. package/dist/src/_internal/extension/xtab/common/promptCrafting.d.ts +6 -1
  42. package/dist/src/_internal/extension/xtab/common/promptCrafting.d.ts.map +1 -1
  43. package/dist/src/_internal/extension/xtab/common/promptCrafting.js +43 -6
  44. package/dist/src/_internal/extension/xtab/common/promptCrafting.js.map +1 -1
  45. package/dist/src/_internal/extension/xtab/common/recentFilesForPrompt.d.ts +22 -0
  46. package/dist/src/_internal/extension/xtab/common/recentFilesForPrompt.d.ts.map +1 -1
  47. package/dist/src/_internal/extension/xtab/common/recentFilesForPrompt.js +116 -17
  48. package/dist/src/_internal/extension/xtab/common/recentFilesForPrompt.js.map +1 -1
  49. package/dist/src/_internal/extension/xtab/common/similarFilesContextService.d.ts +10 -0
  50. package/dist/src/_internal/extension/xtab/common/similarFilesContextService.d.ts.map +1 -0
  51. package/dist/src/_internal/extension/xtab/common/similarFilesContextService.js +10 -0
  52. package/dist/src/_internal/extension/xtab/common/similarFilesContextService.js.map +1 -0
  53. package/dist/src/_internal/extension/xtab/common/tags.d.ts +1 -0
  54. package/dist/src/_internal/extension/xtab/common/tags.d.ts.map +1 -1
  55. package/dist/src/_internal/extension/xtab/common/tags.js +1 -0
  56. package/dist/src/_internal/extension/xtab/common/tags.js.map +1 -1
  57. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.js +1 -1
  58. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.js.map +1 -1
  59. package/dist/src/_internal/extension/xtab/node/xtabEndpoint.d.ts.map +1 -1
  60. package/dist/src/_internal/extension/xtab/node/xtabEndpoint.js +1 -0
  61. package/dist/src/_internal/extension/xtab/node/xtabEndpoint.js.map +1 -1
  62. package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.d.ts.map +1 -1
  63. package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.js +3 -2
  64. package/dist/src/_internal/extension/xtab/node/xtabNextCursorPredictor.js.map +1 -1
  65. package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts +4 -1
  66. package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts.map +1 -1
  67. package/dist/src/_internal/extension/xtab/node/xtabProvider.js +91 -20
  68. package/dist/src/_internal/extension/xtab/node/xtabProvider.js.map +1 -1
  69. package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts +4 -0
  70. package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts.map +1 -1
  71. package/dist/src/_internal/platform/authentication/common/copilotToken.js +6 -0
  72. package/dist/src/_internal/platform/authentication/common/copilotToken.js.map +1 -1
  73. package/dist/src/_internal/platform/configuration/common/configurationService.d.ts +26 -15
  74. package/dist/src/_internal/platform/configuration/common/configurationService.d.ts.map +1 -1
  75. package/dist/src/_internal/platform/configuration/common/configurationService.js +29 -18
  76. package/dist/src/_internal/platform/configuration/common/configurationService.js.map +1 -1
  77. package/dist/src/_internal/platform/endpoint/common/capiClient.d.ts.map +1 -1
  78. package/dist/src/_internal/platform/endpoint/common/capiClient.js +1 -0
  79. package/dist/src/_internal/platform/endpoint/common/capiClient.js.map +1 -1
  80. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts +1 -0
  81. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts.map +1 -1
  82. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js +13 -3
  83. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js.map +1 -1
  84. package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts +1 -0
  85. package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts.map +1 -1
  86. package/dist/src/_internal/platform/endpoint/common/endpointProvider.js.map +1 -1
  87. package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.d.ts.map +1 -1
  88. package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.js +1 -0
  89. package/dist/src/_internal/platform/endpoint/node/autoChatEndpoint.js.map +1 -1
  90. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts +1 -0
  91. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts.map +1 -1
  92. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js +3 -2
  93. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js.map +1 -1
  94. package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts +6 -1
  95. package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts.map +1 -1
  96. package/dist/src/_internal/platform/endpoint/node/messagesApi.js +20 -12
  97. package/dist/src/_internal/platform/endpoint/node/messagesApi.js.map +1 -1
  98. package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.d.ts.map +1 -1
  99. package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.js +1 -0
  100. package/dist/src/_internal/platform/endpoint/node/proxyXtabEndpoint.js.map +1 -1
  101. package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts +1 -0
  102. package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts.map +1 -1
  103. package/dist/src/_internal/platform/endpoint/node/responsesApi.js +14 -10
  104. package/dist/src/_internal/platform/endpoint/node/responsesApi.js.map +1 -1
  105. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/triggerOptions.d.ts +8 -0
  106. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/triggerOptions.d.ts.map +1 -0
  107. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/triggerOptions.js +17 -0
  108. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/triggerOptions.js.map +1 -0
  109. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts +44 -0
  110. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts.map +1 -1
  111. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js +71 -2
  112. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js.map +1 -1
  113. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.js +5 -5
  114. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.js.map +1 -1
  115. package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts +15 -1
  116. package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.d.ts.map +1 -1
  117. package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js +22 -1
  118. package/dist/src/_internal/platform/inlineEdits/common/statelessNextEditProvider.js.map +1 -1
  119. package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.d.ts.map +1 -1
  120. package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.js +9 -44
  121. package/dist/src/_internal/platform/inlineEdits/node/inlineEditsModelService.js.map +1 -1
  122. package/dist/src/_internal/platform/nesFetch/common/responseStream.js +2 -35
  123. package/dist/src/_internal/platform/nesFetch/common/responseStream.js.map +1 -1
  124. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js +3 -36
  125. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js.map +1 -1
  126. package/dist/src/_internal/platform/networking/common/anthropic.d.ts +5 -2
  127. package/dist/src/_internal/platform/networking/common/anthropic.d.ts.map +1 -1
  128. package/dist/src/_internal/platform/networking/common/anthropic.js +13 -3
  129. package/dist/src/_internal/platform/networking/common/anthropic.js.map +1 -1
  130. package/dist/src/_internal/platform/networking/common/fetcherService.d.ts +43 -1
  131. package/dist/src/_internal/platform/networking/common/fetcherService.d.ts.map +1 -1
  132. package/dist/src/_internal/platform/networking/common/fetcherService.js +29 -4
  133. package/dist/src/_internal/platform/networking/common/fetcherService.js.map +1 -1
  134. package/dist/src/_internal/platform/networking/common/networking.d.ts +40 -4
  135. package/dist/src/_internal/platform/networking/common/networking.d.ts.map +1 -1
  136. package/dist/src/_internal/platform/networking/common/networking.js +20 -6
  137. package/dist/src/_internal/platform/networking/common/networking.js.map +1 -1
  138. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts +71 -0
  139. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts.map +1 -0
  140. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js +308 -0
  141. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js.map +1 -0
  142. package/dist/src/_internal/platform/proxyModels/node/proxyModelsService.js +4 -37
  143. package/dist/src/_internal/platform/proxyModels/node/proxyModelsService.js.map +1 -1
  144. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.d.ts +1 -0
  145. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.d.ts.map +1 -1
  146. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.js +3 -0
  147. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.js.map +1 -1
  148. package/dist/src/_internal/platform/requestLogger/node/requestLogger.d.ts +2 -0
  149. package/dist/src/_internal/platform/requestLogger/node/requestLogger.d.ts.map +1 -1
  150. package/dist/src/_internal/platform/requestLogger/node/requestLogger.js.map +1 -1
  151. package/dist/src/_internal/platform/telemetry/common/telemetry.d.ts +9 -1
  152. package/dist/src/_internal/platform/telemetry/common/telemetry.d.ts.map +1 -1
  153. package/dist/src/_internal/platform/telemetry/common/telemetry.js +33 -15
  154. package/dist/src/_internal/platform/telemetry/common/telemetry.js.map +1 -1
  155. package/dist/src/_internal/platform/telemetry/node/azureInsightsReporter.d.ts +1 -1
  156. package/dist/src/_internal/platform/telemetry/node/azureInsightsReporter.d.ts.map +1 -1
  157. package/dist/src/_internal/platform/telemetry/node/azureInsightsReporter.js +3 -2
  158. package/dist/src/_internal/platform/telemetry/node/azureInsightsReporter.js.map +1 -1
  159. package/dist/src/_internal/util/common/errors.d.ts +4 -2
  160. package/dist/src/_internal/util/common/errors.d.ts.map +1 -1
  161. package/dist/src/_internal/util/common/errors.js +16 -12
  162. package/dist/src/_internal/util/common/errors.js.map +1 -1
  163. package/dist/src/_internal/util/common/result.js +4 -37
  164. package/dist/src/_internal/util/common/result.js.map +1 -1
  165. package/dist/src/_internal/util/common/test/shims/chatTypes.d.ts +14 -2
  166. package/dist/src/_internal/util/common/test/shims/chatTypes.d.ts.map +1 -1
  167. package/dist/src/_internal/util/common/test/shims/chatTypes.js +17 -3
  168. package/dist/src/_internal/util/common/test/shims/chatTypes.js.map +1 -1
  169. package/dist/src/_internal/util/common/test/shims/vscodeTypesShim.js +1 -1
  170. package/dist/src/_internal/util/common/test/shims/vscodeTypesShim.js.map +1 -1
  171. package/dist/src/main.d.ts.map +1 -1
  172. package/dist/src/main.js +10 -0
  173. package/dist/src/main.js.map +1 -1
  174. package/dist/src/package.json +185 -249
  175. package/package.json +3 -3
@@ -3,50 +3,18 @@
3
3
  * Copyright (c) Microsoft Corporation. All rights reserved.
4
4
  * Licensed under the MIT License. See License.txt in the project root for license information.
5
5
  *--------------------------------------------------------------------------------------------*/
6
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
- if (k2 === undefined) k2 = k;
8
- var desc = Object.getOwnPropertyDescriptor(m, k);
9
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
- desc = { enumerable: true, get: function() { return m[k]; } };
11
- }
12
- Object.defineProperty(o, k2, desc);
13
- }) : (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- o[k2] = m[k];
16
- }));
17
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
- Object.defineProperty(o, "default", { enumerable: true, value: v });
19
- }) : function(o, v) {
20
- o["default"] = v;
21
- });
22
6
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
23
7
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
8
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
9
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
26
10
  return c > 3 && r && Object.defineProperty(target, key, r), r;
27
11
  };
28
- var __importStar = (this && this.__importStar) || (function () {
29
- var ownKeys = function(o) {
30
- ownKeys = Object.getOwnPropertyNames || function (o) {
31
- var ar = [];
32
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
- return ar;
34
- };
35
- return ownKeys(o);
36
- };
37
- return function (mod) {
38
- if (mod && mod.__esModule) return mod;
39
- var result = {};
40
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
- __setModuleDefault(result, mod);
42
- return result;
43
- };
44
- })();
45
12
  var __param = (this && this.__param) || function (paramIndex, decorator) {
46
13
  return function (target, key) { decorator(target, key, paramIndex); }
47
14
  };
15
+ var NextEditProvider_1;
48
16
  Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.NextEditFetchRequest = exports.NextEditProvider = void 0;
17
+ exports.NextEditFetchRequest = exports.NextEditProvider = exports.NesOutcome = void 0;
50
18
  const path_1 = require("path");
51
19
  const configurationService_1 = require("../../../platform/configuration/common/configurationService");
52
20
  const edit_1 = require("../../../platform/inlineEdits/common/dataTypes/edit");
@@ -60,12 +28,12 @@ const capturingToken_1 = require("../../../platform/requestLogger/common/capturi
60
28
  const requestLogger_1 = require("../../../platform/requestLogger/node/requestLogger");
61
29
  const snippyService_1 = require("../../../platform/snippy/common/snippyService");
62
30
  const nullExperimentationService_1 = require("../../../platform/telemetry/common/nullExperimentationService");
63
- const errors = __importStar(require("../../../util/common/errors"));
31
+ const errors_1 = require("../../../util/common/errors");
64
32
  const result_1 = require("../../../util/common/result");
65
33
  const assert_1 = require("../../../util/vs/base/common/assert");
66
34
  const async_1 = require("../../../util/vs/base/common/async");
67
35
  const cache_1 = require("../../../util/vs/base/common/cache");
68
- const errors_1 = require("../../../util/vs/base/common/errors");
36
+ const errors_2 = require("../../../util/vs/base/common/errors");
69
37
  const lifecycle_1 = require("../../../util/vs/base/common/lifecycle");
70
38
  const observable_2 = require("../../../util/vs/base/common/observable");
71
39
  const stopwatch_1 = require("../../../util/vs/base/common/stopwatch");
@@ -107,13 +75,22 @@ function convertLineEditToEdit(nextLineEdit, projectedDocuments, docId) {
107
75
  const suggestedEdit = rootedLineEdit.toEdit();
108
76
  return suggestedEdit;
109
77
  }
110
- let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
78
+ var NesOutcome;
79
+ (function (NesOutcome) {
80
+ NesOutcome["Accepted"] = "accepted";
81
+ NesOutcome["Rejected"] = "rejected";
82
+ NesOutcome["Ignored"] = "ignored";
83
+ })(NesOutcome || (exports.NesOutcome = NesOutcome = {}));
84
+ let NextEditProvider = NextEditProvider_1 = class NextEditProvider extends lifecycle_1.Disposable {
111
85
  get lastRejectionTime() {
112
86
  return this._lastRejectionTime;
113
87
  }
114
88
  get lastTriggerTime() {
115
89
  return this._lastTriggerTime;
116
90
  }
91
+ get lastOutcome() {
92
+ return this._lastOutcome;
93
+ }
117
94
  constructor(_workspace, _statelessNextEditProvider, _historyContextProvider, _xtabHistoryTracker, _debugRecorder, _configService, _snippyService, _logService, _expService, _requestLogger) {
118
95
  super();
119
96
  this._workspace = _workspace;
@@ -149,7 +126,20 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
149
126
  }));
150
127
  }).recomputeInitiallyAndOnChange(this._store);
151
128
  }
129
+ _cancelSpeculativeRequest() {
130
+ if (this._speculativePendingRequest) {
131
+ this._speculativePendingRequest.request.cancellationTokenSource.cancel();
132
+ this._speculativePendingRequest = null;
133
+ }
134
+ }
152
135
  _cancelPendingRequestDueToDocChange(docId, docValue) {
136
+ // Note: we intentionally do NOT cancel the speculative request here.
137
+ // The speculative request's postEditContent represents a *future* document state
138
+ // (after the user would accept the suggestion), so it will almost never match the
139
+ // current document value while the user is still typing. Cancelling here would
140
+ // wastefully kill and recreate the speculative request on every keystroke.
141
+ // Instead, speculative requests are cancelled by the appropriate lifecycle handlers:
142
+ // handleRejection, handleIgnored, _triggerSpeculativeRequest, and _executeNewNextEditRequest.
153
143
  const isAsyncCompletions = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsAsyncCompletions, this._expService);
154
144
  if (isAsyncCompletions || this._pendingStatelessNextEditRequest === null) {
155
145
  return;
@@ -175,7 +165,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
175
165
  }
176
166
  catch (error) {
177
167
  logContext.setError(error);
178
- telemetryBuilder.setNextEditProviderError(errors.toString(error));
168
+ telemetryBuilder.setNextEditProviderError(errors_1.ErrorUtils.toString(error));
179
169
  throw error;
180
170
  }
181
171
  finally {
@@ -190,7 +180,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
190
180
  const doc = this._workspace.getDocument(docId);
191
181
  if (!doc) {
192
182
  logger.trace(`Document "${docId.baseName}" not found`);
193
- throw new errors_1.BugIndicatingError(`Document "${docId.baseName}" not found`);
183
+ throw new errors_2.BugIndicatingError(`Document "${docId.baseName}" not found`);
194
184
  }
195
185
  const documentAtInvocationTime = doc.value.get();
196
186
  const selections = doc.selection.get();
@@ -210,6 +200,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
210
200
  let targetDocumentId = docId;
211
201
  let isRebasedCachedEdit = false;
212
202
  let isSubsequentCachedEdit = false;
203
+ let isFromSpeculativeRequest = false;
213
204
  if (cachedEdit) {
214
205
  logger.trace('using cached edit');
215
206
  const actualEdit = cachedEdit.rebasedEdit || cachedEdit.edit;
@@ -232,7 +223,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
232
223
  const providerRequestStartDateTime = (this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsDebounceUseCoreRequestTime, this._expService)
233
224
  ? (context.requestIssuedDateTime ?? undefined)
234
225
  : undefined);
235
- req = new NextEditFetchRequest(context.requestUuid, logContext, providerRequestStartDateTime);
226
+ req = new NextEditFetchRequest(context.requestUuid, logContext, providerRequestStartDateTime, false);
236
227
  telemetryBuilder.setHeaderRequestId(req.headerRequestId);
237
228
  const startVersion = doc.value.get();
238
229
  logger.trace('awaiting firstEdit promise');
@@ -266,6 +257,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
266
257
  logger.trace('fetch succeeded');
267
258
  logContext.setResponseResults([suggestedNextEdit]); // TODO: other streamed edits?
268
259
  edit = { actualEdit: suggestedNextEdit, isFromCursorJump: result.val.isFromCursorJump };
260
+ isFromSpeculativeRequest = result.val.isFromSpeculativeRequest ?? false;
269
261
  }
270
262
  }
271
263
  }
@@ -280,7 +272,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
280
272
  }
281
273
  else {
282
274
  telemetryBuilder.setStatus('emptyEditsButHasNextCursorPosition');
283
- return new nextEditResult_1.NextEditResult(logContext.requestId, req, { jumpToPosition: error.nextCursorPosition, documentBeforeEdits: documentAtInvocationTime, isFromCursorJump: false });
275
+ return new nextEditResult_1.NextEditResult(logContext.requestId, req, { jumpToPosition: error.nextCursorPosition, documentBeforeEdits: documentAtInvocationTime, isFromCursorJump: false, isSubsequentEdit: false });
284
276
  }
285
277
  }
286
278
  const emptyResult = new nextEditResult_1.NextEditResult(logContext.requestId, req, undefined);
@@ -303,9 +295,9 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
303
295
  logContext.setResult(rootedLineEdit_1.RootedLineEdit.fromEdit(new edit_1.RootedEdit(documentAtInvocationTime, new stringEdit_1.StringEdit([edit.actualEdit]))));
304
296
  (0, assert_1.assert)(currentDocument !== undefined, 'should be defined if edit is defined');
305
297
  telemetryBuilder.setStatus('notAccepted'); // Acceptance pending.
306
- const nextEditResult = new nextEditResult_1.NextEditResult(logContext.requestId, req, { edit: edit.actualEdit, isFromCursorJump: edit.isFromCursorJump, documentBeforeEdits: currentDocument, targetDocumentId });
298
+ const nextEditResult = new nextEditResult_1.NextEditResult(logContext.requestId, req, { edit: edit.actualEdit, isFromCursorJump: edit.isFromCursorJump, documentBeforeEdits: currentDocument, targetDocumentId, isSubsequentEdit: isSubsequentCachedEdit });
307
299
  telemetryBuilder.setHasNextEdit(true);
308
- const delay = this.computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, enforceCacheDelay: context.enforceCacheDelay }, logger);
300
+ const delay = this.computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, isFromSpeculativeRequest, enforceCacheDelay: context.enforceCacheDelay }, logger);
309
301
  if (delay > 0) {
310
302
  await (0, async_1.timeout)(delay);
311
303
  if (cancellationToken.isCancellationRequested) {
@@ -356,7 +348,8 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
356
348
  const existingNextEditRequest = (pendingRequestStillCurrent || nesConfigs.isAsyncCompletions) && !this._pendingStatelessNextEditRequest?.cancellationTokenSource.token.isCancellationRequested
357
349
  && this._pendingStatelessNextEditRequest || undefined;
358
350
  // Check if we can reuse the speculative pending request (from when a suggestion was shown)
359
- const speculativeRequestMatches = this._speculativePendingRequest?.postEditContent === documentAtInvocationTime.value
351
+ const speculativeRequestMatches = this._speculativePendingRequest?.docId === curDocId
352
+ && this._speculativePendingRequest?.postEditContent === documentAtInvocationTime.value
360
353
  && !this._speculativePendingRequest.request.cancellationTokenSource.token.isCancellationRequested;
361
354
  const speculativeRequest = speculativeRequestMatches ? this._speculativePendingRequest?.request : undefined;
362
355
  // Prefer speculative request if it matches (it was specifically created for this post-edit state)
@@ -371,9 +364,14 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
371
364
  const requestStillCurrent = speculativeRequest
372
365
  ? speculativeRequestMatches // For speculative, we already checked it matches
373
366
  : pendingRequestStillCurrent;
367
+ const reusedRequestKind = speculativeRequest ? "speculative" /* ReusedRequestKind.Speculative */ : "async" /* ReusedRequestKind.Async */;
374
368
  if (requestStillCurrent) {
375
- const nextEditResult = await this._joinNextEditRequest(requestToReuse, telemetryBuilder, logContext, cancellationToken);
369
+ const nextEditResult = await this._joinNextEditRequest(requestToReuse, reusedRequestKind, telemetryBuilder, logContext, cancellationToken);
376
370
  telemetryBuilder.setStatelessNextEditTelemetry(nextEditResult.telemetry);
371
+ if (speculativeRequest) {
372
+ const firstEdit = await requestToReuse.firstEdit.p;
373
+ return firstEdit.map(val => ({ ...val, isFromSpeculativeRequest: true }));
374
+ }
377
375
  return nextEditResult.nextEdit.isError() ? nextEditResult.nextEdit : requestToReuse.firstEdit.p;
378
376
  }
379
377
  else if (nesConfigs.isEagerBackupRequest) {
@@ -391,7 +389,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
391
389
  .catch(() => undefined);
392
390
  };
393
391
  // Simultaneously attempt to join + rebase the stale request
394
- const nextEditResult = await this._joinNextEditRequest(requestToReuse, telemetryBuilder, logContext, cancellationToken);
392
+ const nextEditResult = await this._joinNextEditRequest(requestToReuse, reusedRequestKind, telemetryBuilder, logContext, cancellationToken);
395
393
  const cacheResult = await requestToReuse.firstEdit.p;
396
394
  if (cacheResult.isOk() && cacheResult.val.edit) {
397
395
  const rebasedCachedEdit = this._nextEditCache.tryRebaseCacheEntry(cacheResult.val, documentAtInvocationTime, selectionAtInvocationTime);
@@ -415,7 +413,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
415
413
  return backupRes.nextEditResult.nextEdit.isError() ? backupRes.nextEditResult.nextEdit : backupRes.nextEditRequest.firstEdit.p;
416
414
  }
417
415
  else {
418
- const nextEditResult = await this._joinNextEditRequest(requestToReuse, telemetryBuilder, logContext, cancellationToken);
416
+ const nextEditResult = await this._joinNextEditRequest(requestToReuse, reusedRequestKind, telemetryBuilder, logContext, cancellationToken);
419
417
  // Needs rebasing.
420
418
  const cacheResult = await requestToReuse.firstEdit.p;
421
419
  if (cacheResult.isOk() && cacheResult.val.edit) {
@@ -436,7 +434,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
436
434
  && this._pendingStatelessNextEditRequest || undefined;
437
435
  if (existingNextEditRequest2) {
438
436
  logger.trace('reusing 2nd existing next edit request after rebase failed');
439
- const nextEditResult2 = await this._joinNextEditRequest(existingNextEditRequest2, telemetryBuilder, logContext, cancellationToken);
437
+ const nextEditResult2 = await this._joinNextEditRequest(existingNextEditRequest2, "async" /* ReusedRequestKind.Async */, telemetryBuilder, logContext, cancellationToken);
440
438
  telemetryBuilder.setStatelessNextEditTelemetry(nextEditResult2.telemetry);
441
439
  return nextEditResult2.nextEdit.isError() ? nextEditResult2.nextEdit : existingNextEditRequest2.firstEdit.p;
442
440
  }
@@ -449,10 +447,9 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
449
447
  telemetryBuilder.setStatelessNextEditTelemetry(nextEditResult.telemetry);
450
448
  return nextEditResult.nextEdit.isError() ? nextEditResult.nextEdit : nextEditRequest.firstEdit.p;
451
449
  }
452
- async _joinNextEditRequest(nextEditRequest, telemetryBuilder, logContext, cancellationToken) {
453
- // TODO: Will the telemetry look alright in this case?
450
+ async _joinNextEditRequest(nextEditRequest, reusedRequestKind, telemetryBuilder, logContext, cancellationToken) {
454
451
  telemetryBuilder.setHeaderRequestId(nextEditRequest.headerRequestId);
455
- telemetryBuilder.setIsFromCache();
452
+ telemetryBuilder.setReusedRequest(reusedRequestKind);
456
453
  telemetryBuilder.setRequest(nextEditRequest);
457
454
  logContext.setRequestInput(nextEditRequest);
458
455
  logContext.setIsCachedResult(nextEditRequest.logContext);
@@ -477,12 +474,20 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
477
474
  const nLinesEditWindow = (shouldExpandEditWindow
478
475
  ? this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsAutoExpandEditWindowLines, this._expService)
479
476
  : undefined);
480
- const nextEditRequest = new statelessNextEditProvider_1.StatelessNextEditRequest(req.headerRequestId, req.opportunityId, doc.value.get(), projectedDocuments.map(d => d.nextEditDoc), activeDocAndIdx.idx, xtabEditHistory, firstEdit, nLinesEditWindow, logContext, req.log.recordingBookmark, recording, req.providerRequestStartDateTime);
477
+ const nextEditRequest = new statelessNextEditProvider_1.StatelessNextEditRequest(req.headerRequestId, req.opportunityId, doc.value.get(), projectedDocuments.map(d => d.nextEditDoc), activeDocAndIdx.idx, xtabEditHistory, firstEdit, nLinesEditWindow, false, // isSpeculative
478
+ logContext, req.log.recordingBookmark, recording, req.providerRequestStartDateTime);
481
479
  let nextEditResult;
482
480
  if (this._pendingStatelessNextEditRequest) {
483
481
  this._pendingStatelessNextEditRequest.cancellationTokenSource.cancel();
484
482
  this._pendingStatelessNextEditRequest = null;
485
483
  }
484
+ // Cancel speculative request if it doesn't match the document/state
485
+ // of this new request — it was built for a different document or post-edit state.
486
+ if (this._speculativePendingRequest
487
+ && (this._speculativePendingRequest.docId !== curDocId
488
+ || this._speculativePendingRequest.postEditContent !== nextEditRequest.documentBeforeEdits.value)) {
489
+ this._cancelSpeculativeRequest();
490
+ }
486
491
  this._pendingStatelessNextEditRequest = nextEditRequest;
487
492
  const removeFromPending = () => {
488
493
  if (this._pendingStatelessNextEditRequest === nextEditRequest) {
@@ -514,7 +519,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
514
519
  const statePerDoc = new cache_1.CachedFunction((id) => {
515
520
  const doc = projectedDocuments.find(d => d.nextEditDoc.id === id);
516
521
  if (!doc) {
517
- throw new errors_1.BugIndicatingError();
522
+ throw new errors_2.BugIndicatingError();
518
523
  }
519
524
  return {
520
525
  docContents: doc.documentAfterEdits,
@@ -624,8 +629,8 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
624
629
  handleStreamEnd(completionReason, res.value.telemetryBuilder);
625
630
  }
626
631
  catch (err) {
627
- logger.trace(`Error while streaming further edits: ${errors.toString(err)}`);
628
- const errorReason = new statelessNextEditProvider_1.NoNextEditReason.Unexpected(errors.fromUnknown(err));
632
+ logger.trace(`Error while streaming further edits: ${errors_1.ErrorUtils.toString(err)}`);
633
+ const errorReason = new statelessNextEditProvider_1.NoNextEditReason.Unexpected(errors_1.ErrorUtils.fromUnknown(err));
629
634
  handleStreamEnd(errorReason, firstTelemetry);
630
635
  }
631
636
  })();
@@ -679,7 +684,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
679
684
  nextEditRequest.liveDependentants++;
680
685
  return disposables;
681
686
  }
682
- computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, enforceCacheDelay }, logger) {
687
+ computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, isFromSpeculativeRequest, enforceCacheDelay }, logger) {
683
688
  if (!enforceCacheDelay) {
684
689
  logger.trace('[minimumDelay] no minimum delay enforced due to enforceCacheDelay being false');
685
690
  return 0;
@@ -687,6 +692,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
687
692
  const cacheDelay = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsCacheDelay, this._expService);
688
693
  const rebasedCacheDelay = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsRebasedCacheDelay, this._expService);
689
694
  const subsequentCacheDelay = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsSubsequentCacheDelay, this._expService);
695
+ const speculativeRequestDelay = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsSpeculativeRequestDelay, this._expService);
690
696
  let minimumResponseDelay = cacheDelay;
691
697
  if (isRebasedCachedEdit && rebasedCacheDelay !== undefined) {
692
698
  minimumResponseDelay = rebasedCacheDelay;
@@ -694,15 +700,19 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
694
700
  else if (isSubsequentCachedEdit && subsequentCacheDelay !== undefined) {
695
701
  minimumResponseDelay = subsequentCacheDelay;
696
702
  }
703
+ else if (isFromSpeculativeRequest && speculativeRequestDelay !== undefined) {
704
+ minimumResponseDelay = speculativeRequestDelay;
705
+ }
697
706
  const nextEditProviderCallLatency = Date.now() - triggerTime;
698
707
  // if the provider call took longer than the minimum delay, we don't need to delay further
699
708
  const delay = Math.max(0, minimumResponseDelay - nextEditProviderCallLatency);
700
- logger.trace(`[minimumDelay] expected delay: ${minimumResponseDelay}ms, effective delay: ${delay}. isRebasedCachedEdit: ${isRebasedCachedEdit} (rebasedCacheDelay: ${rebasedCacheDelay}), isSubsequentCachedEdit: ${isSubsequentCachedEdit} (subsequentCacheDelay: ${subsequentCacheDelay})`);
709
+ logger.trace(`[minimumDelay] expected delay: ${minimumResponseDelay}ms, effective delay: ${delay}. isRebasedCachedEdit: ${isRebasedCachedEdit} (rebasedCacheDelay: ${rebasedCacheDelay}), isSubsequentCachedEdit: ${isSubsequentCachedEdit} (subsequentCacheDelay: ${subsequentCacheDelay}), isFromSpeculativeRequest: ${isFromSpeculativeRequest} (speculativeRequestDelay: ${speculativeRequestDelay})`);
701
710
  return delay;
702
711
  }
703
712
  handleShown(suggestion) {
704
713
  this._lastShownTime = Date.now();
705
714
  this._lastShownSuggestionId = suggestion.requestId;
715
+ this._lastOutcome = undefined; // clear so that outcome is "pending" until resolved
706
716
  // Trigger speculative request for the post-edit document state
707
717
  const speculativeRequestsEnablement = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsSpeculativeRequests, this._expService);
708
718
  if (speculativeRequestsEnablement === xtabPromptOptions_1.SpeculativeRequestsEnablement.On) {
@@ -723,12 +733,14 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
723
733
  }
724
734
  // Compute the post-edit document content
725
735
  const postEditContent = result.edit.replace(result.documentBeforeEdits.value);
726
- const postEditCursorOffset = result.edit.replaceRange.endExclusive + result.edit.getLengthDelta();
727
- const selections = [new offsetRange_1.OffsetRange(postEditCursorOffset, postEditCursorOffset)];
736
+ const preciseEdit = result.edit.removeCommonSuffixPrefix(result.documentBeforeEdits.value);
737
+ const postEditCursorOffset = preciseEdit.replaceRange.start + preciseEdit.newText.length;
738
+ const postEditCursorOffsetRange = new offsetRange_1.OffsetRange(postEditCursorOffset, postEditCursorOffset);
739
+ const selections = [postEditCursorOffsetRange];
728
740
  const rootedEdit = new edit_1.RootedEdit(result.documentBeforeEdits, new stringEdit_1.StringEdit([result.edit]));
729
741
  const postEditContentST = new abstractText_1.StringText(postEditContent);
730
742
  let cachedEdit = this._nextEditCache.lookupNextEdit(docId, postEditContentST, selections);
731
- let shiftedSelection;
743
+ let shiftedSelection = postEditCursorOffsetRange;
732
744
  if (cachedEdit) {
733
745
  // first cachedEdit should be without edits because of noSuggestions caching
734
746
  if (cachedEdit.edit) {
@@ -736,17 +748,22 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
736
748
  return;
737
749
  }
738
750
  else if (cachedEdit.editWindow) {
739
- const trans = postEditContentST.getTransformer();
740
- const endOfEditWindow = trans.getPosition(cachedEdit.editWindow.endExclusive - 1);
741
- const shiftedCursorLineNumber = (endOfEditWindow.lineNumber + 1 < postEditContentST.lineRange.endLineNumberExclusive
742
- ? endOfEditWindow.lineNumber + 1
743
- : endOfEditWindow.lineNumber);
744
- const shiftedSelectionCursorOffset = trans.getOffset(new position_1.Position(shiftedCursorLineNumber, 1));
745
- shiftedSelection = new offsetRange_1.OffsetRange(shiftedSelectionCursorOffset, shiftedSelectionCursorOffset);
746
- cachedEdit = this._nextEditCache.lookupNextEdit(docId, postEditContentST, [shiftedSelection]);
747
- if (cachedEdit?.edit) {
748
- logger.trace('already have cached edit for post-edit state (after shifting selection)');
749
- return;
751
+ logger.trace('have cached no-suggestions entry for post-edit state, but it has an edit window. Checking if shifting selection based on cursor placement config can yield a cached edit');
752
+ const cursorPlacement = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsSpeculativeRequestsCursorPlacement, this._expService);
753
+ if (cursorPlacement === xtabPromptOptions_1.SpeculativeRequestsCursorPlacement.AfterEditWindow) {
754
+ logger.trace('cursor placement config is AfterEditWindow, shifting selection to after edit window');
755
+ shiftedSelection = NextEditProvider_1.shiftSelectionAfterEditWindow(postEditContentST, cachedEdit.editWindow);
756
+ cachedEdit = this._nextEditCache.lookupNextEdit(docId, postEditContentST, [shiftedSelection]);
757
+ if (cachedEdit?.edit) {
758
+ logger.trace('already have cached edit for post-edit state (after shifting selection)');
759
+ return;
760
+ }
761
+ else {
762
+ logger.trace('no cached edit even after shifting selection');
763
+ }
764
+ }
765
+ else {
766
+ logger.trace(`cursor placement config is ${cursorPlacement}, not shifting selection`);
750
767
  }
751
768
  }
752
769
  else {
@@ -760,7 +777,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
760
777
  return;
761
778
  }
762
779
  // Check if we already have a speculative request for this post-edit state
763
- if (this._speculativePendingRequest?.postEditContent === postEditContent) {
780
+ if (this._speculativePendingRequest?.docId === docId && this._speculativePendingRequest?.postEditContent === postEditContent) {
764
781
  logger.trace('already have speculative request for post-edit state');
765
782
  return;
766
783
  }
@@ -773,8 +790,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
773
790
  return;
774
791
  }
775
792
  // Cancel any previous speculative request
776
- this._speculativePendingRequest?.request.cancellationTokenSource.cancel();
777
- this._speculativePendingRequest = null;
793
+ this._cancelSpeculativeRequest();
778
794
  const historyContext = this._historyContextProvider.getHistoryContext(docId);
779
795
  if (!historyContext) {
780
796
  logger.trace('no history context for speculative request');
@@ -783,20 +799,23 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
783
799
  // Create a speculative request
784
800
  // Use a dummy version since this is speculative and we don't have the actual post-edit version
785
801
  const logContext = new inlineEditLogContext_1.InlineEditRequestLogContext(docId.uri, 0, undefined);
786
- const req = new NextEditFetchRequest(`sp-${suggestion.source.opportunityId}`, logContext, undefined, `sp-${(0, uuid_1.generateUuid)()}`);
787
- logger.trace(`triggering speculative request for post-edit state (opportunityId=${req.opportunityId}, headerRequestId=${req.headerRequestId})`);
802
+ const req = new NextEditFetchRequest(`sp-${suggestion.source.opportunityId}`, logContext, undefined, true, `sp-${(0, uuid_1.generateUuid)()}`);
788
803
  logger.trace(`triggering speculative request for post-edit state (opportunityId=${req.opportunityId}, headerRequestId=${req.headerRequestId})`);
789
804
  try {
790
- const speculativeRequest = await this._createSpeculativeRequest(req, doc, shiftedSelection, historyContext, postEditContent, rootedEdit, result.edit, logger);
805
+ const speculativeRequest = await this._createSpeculativeRequest(req, doc, shiftedSelection, historyContext, postEditContent, rootedEdit, result.edit, {
806
+ triggeredBySpeculativeRequest: suggestion.source.isSpeculative,
807
+ isSubsequentEdit: suggestion.result?.isSubsequentEdit ?? false,
808
+ }, logger);
791
809
  if (speculativeRequest) {
792
810
  this._speculativePendingRequest = {
793
811
  request: speculativeRequest,
812
+ docId,
794
813
  postEditContent,
795
814
  };
796
815
  }
797
816
  }
798
817
  catch (e) {
799
- logger.trace(`speculative request failed: ${errors.toString(e)}`);
818
+ logger.trace(`speculative request failed: ${errors_1.ErrorUtils.toString(e)}`);
800
819
  }
801
820
  }
802
821
  /**
@@ -804,7 +823,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
804
823
  * The request will populate the cache so that when the user accepts the suggestion,
805
824
  * the next NES request can reuse or find the result in cache.
806
825
  */
807
- async _createSpeculativeRequest(req, doc, shiftedSelection, historyContext, postEditContent, rootedEdit, appliedEdit, parentLogger) {
826
+ async _createSpeculativeRequest(req, doc, shiftedSelection, historyContext, postEditContent, rootedEdit, appliedEdit, { triggeredBySpeculativeRequest, isSubsequentEdit }, parentLogger) {
808
827
  const logger = parentLogger.createSubLogger('_createSpeculativeRequest');
809
828
  const curDocId = doc.id;
810
829
  const recording = this._debugRecorder?.getRecentLog();
@@ -827,18 +846,11 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
827
846
  const workspaceRoot = this._workspace.getWorkspaceRoot(curDocId);
828
847
  const postEditEdit = new stringEdit_1.StringEdit([appliedEdit]);
829
848
  const postEditLineEdit = rootedLineEdit_1.RootedLineEdit.fromEdit(new edit_1.RootedEdit(doc.value.get(), postEditEdit)).removeCommonSuffixPrefixLines().edit;
830
- let selection = shiftedSelection;
831
- if (selection === undefined) {
832
- const appliedEditEndPos = postEditText.getTransformer().getPosition(appliedEdit.replaceRange.endExclusive + appliedEdit.getLengthDelta());
833
- const pos = new position_1.Position(appliedEditEndPos.lineNumber, 1);
834
- const offset = postEditText.getTransformer().getOffset(pos);
835
- selection = new offsetRange_1.OffsetRange(offset, offset);
836
- }
837
849
  const nextEditDoc = new statelessNextEditProvider_1.StatelessNextEditDocument(curDocId, workspaceRoot, docHist.languageId, doc.value.get().getLines(), // lines before the NES edit
838
850
  postEditLineEdit, // the NES edit as LineEdit
839
851
  doc.value.get(), // document before NES edit
840
852
  edit_1.Edits.single(postEditEdit), // the NES edit as Edits
841
- selection);
853
+ shiftedSelection);
842
854
  return {
843
855
  recentEdit: new edit_1.RootedEdit(doc.value.get(), postEditEdit),
844
856
  nextEditDoc,
@@ -850,9 +862,29 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
850
862
  const suggestedEdit = { kind: 'edit', docId: curDocId, edit: rootedEdit };
851
863
  xtabEditHistory.push(suggestedEdit);
852
864
  const firstEdit = new async_1.DeferredPromise();
853
- const nLinesEditWindow = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsAutoExpandEditWindowLines, this._expService);
865
+ // FIXME@ulugbekna: implement advanced expansion
866
+ const autoExpandEditWindowLinesSetting = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsSpeculativeRequestsAutoExpandEditWindowLines, this._expService);
867
+ let nLinesEditWindow;
868
+ switch (autoExpandEditWindowLinesSetting) {
869
+ case xtabPromptOptions_1.SpeculativeRequestsAutoExpandEditWindowLines.Off:
870
+ nLinesEditWindow = undefined;
871
+ break;
872
+ case xtabPromptOptions_1.SpeculativeRequestsAutoExpandEditWindowLines.Always:
873
+ nLinesEditWindow = this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsAutoExpandEditWindowLines, this._expService);
874
+ break;
875
+ case xtabPromptOptions_1.SpeculativeRequestsAutoExpandEditWindowLines.Smart: {
876
+ const isModelOnRightTrack = triggeredBySpeculativeRequest || isSubsequentEdit;
877
+ nLinesEditWindow = (isModelOnRightTrack
878
+ ? this._configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsAutoExpandEditWindowLines, this._expService)
879
+ : undefined);
880
+ break;
881
+ }
882
+ default:
883
+ (0, assert_1.assertNever)(autoExpandEditWindowLinesSetting);
884
+ }
854
885
  const nextEditRequest = new statelessNextEditProvider_1.StatelessNextEditRequest(req.headerRequestId, req.opportunityId, postEditText, // documentBeforeEdits is the post-edit state
855
- projectedDocuments.map(d => d.nextEditDoc), activeDocAndIdx.idx, xtabEditHistory, firstEdit, nLinesEditWindow, logContext, undefined, // recordingBookmark
886
+ projectedDocuments.map(d => d.nextEditDoc), activeDocAndIdx.idx, xtabEditHistory, firstEdit, nLinesEditWindow, true, // isSpeculative
887
+ logContext, undefined, // recordingBookmark
856
888
  recording, undefined);
857
889
  logger.trace('starting speculative provider call');
858
890
  // Start the provider call - this runs in the background and populates the cache
@@ -869,7 +901,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
869
901
  const statePerDoc = new cache_1.CachedFunction((id) => {
870
902
  const doc = projectedDocuments.find(d => d.nextEditDoc.id === id);
871
903
  if (!doc) {
872
- throw new errors_1.BugIndicatingError();
904
+ throw new errors_2.BugIndicatingError();
873
905
  }
874
906
  return {
875
907
  docContents: doc.documentAfterEdits,
@@ -929,12 +961,23 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
929
961
  logger.trace(`speculative request completed with ${ithEdit + 1} edits`);
930
962
  }
931
963
  catch (e) {
932
- logger.trace(`speculative provider call error: ${errors.toString(e)}`);
964
+ logger.trace(`speculative provider call error: ${errors_1.ErrorUtils.toString(e)}`);
933
965
  }
934
966
  }
967
+ static shiftSelectionAfterEditWindow(postEditContentST, editWindowOffsetRange) {
968
+ const trans = postEditContentST.getTransformer();
969
+ const endOfEditWindow = trans.getPosition(editWindowOffsetRange.endExclusive - 1);
970
+ const shiftedCursorLineNumber = (endOfEditWindow.lineNumber + 1 < postEditContentST.lineRange.endLineNumberExclusive
971
+ ? endOfEditWindow.lineNumber + 1
972
+ : endOfEditWindow.lineNumber);
973
+ const shiftedSelectionCursorOffset = trans.getOffset(new position_1.Position(shiftedCursorLineNumber, 1));
974
+ const shiftedSelection = new offsetRange_1.OffsetRange(shiftedSelectionCursorOffset, shiftedSelectionCursorOffset);
975
+ return shiftedSelection;
976
+ }
935
977
  handleAcceptance(docId, suggestion) {
936
978
  this.runSnippy(docId, suggestion);
937
979
  this._statelessNextEditProvider.handleAcceptance?.();
980
+ this._lastOutcome = NesOutcome.Accepted;
938
981
  const logger = this._logger.createSubLogger(suggestion.source.opportunityId.substring(4, 8)).createSubLogger('handleAcceptance');
939
982
  if (suggestion === this._lastNextEditResult) {
940
983
  logger.trace('setting shouldExpandEditWindow to true due to acceptance of last suggestion');
@@ -946,6 +989,10 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
946
989
  }
947
990
  handleRejection(docId, suggestion) {
948
991
  (0, types_1.assertType)(suggestion.result, '@ulugbekna: undefined edit cannot be rejected?');
992
+ // The user rejected the suggestion, so the speculative request (which
993
+ // predicted the post-accept state) will never be reused. Cancel it to
994
+ // avoid wasting a server slot.
995
+ this._cancelSpeculativeRequest();
949
996
  const shownDuration = Date.now() - this._lastShownTime;
950
997
  if (shownDuration > 1000 && suggestion.result.edit) {
951
998
  // we can argue that the user had the time to review this
@@ -954,14 +1001,18 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
954
1001
  this._nextEditCache.rejectedNextEdit(suggestion.source.headerRequestId);
955
1002
  }
956
1003
  this._lastRejectionTime = Date.now();
1004
+ this._lastOutcome = NesOutcome.Rejected;
957
1005
  this._statelessNextEditProvider.handleRejection?.();
958
1006
  }
959
1007
  handleIgnored(docId, suggestion, supersededBy) {
1008
+ this._lastOutcome = NesOutcome.Ignored;
960
1009
  // Check if this was the last shown suggestion
961
1010
  const wasShown = this._lastShownSuggestionId === suggestion.requestId;
962
1011
  const wasSuperseded = supersededBy !== undefined;
963
1012
  if (wasShown && !wasSuperseded) {
964
- // Was shown to the user
1013
+ // The shown suggestion was dismissed (not superseded by a new one),
1014
+ // so the speculative request for its post-accept state is useless.
1015
+ this._cancelSpeculativeRequest();
965
1016
  this._statelessNextEditProvider.handleIgnored?.();
966
1017
  }
967
1018
  }
@@ -977,7 +1028,7 @@ let NextEditProvider = class NextEditProvider extends lifecycle_1.Disposable {
977
1028
  }
978
1029
  };
979
1030
  exports.NextEditProvider = NextEditProvider;
980
- exports.NextEditProvider = NextEditProvider = __decorate([
1031
+ exports.NextEditProvider = NextEditProvider = NextEditProvider_1 = __decorate([
981
1032
  __param(5, configurationService_1.IConfigurationService),
982
1033
  __param(6, snippyService_1.ISnippyService),
983
1034
  __param(7, logService_1.ILogService),
@@ -986,15 +1037,16 @@ exports.NextEditProvider = NextEditProvider = __decorate([
986
1037
  ], NextEditProvider);
987
1038
  function assertDefined(value) {
988
1039
  if (!value) {
989
- throw new errors_1.BugIndicatingError('expected value to be defined, but it was not');
1040
+ throw new errors_2.BugIndicatingError('expected value to be defined, but it was not');
990
1041
  }
991
1042
  return value;
992
1043
  }
993
1044
  class NextEditFetchRequest {
994
- constructor(opportunityId, log, providerRequestStartDateTime, headerRequestId = (0, uuid_1.generateUuid)()) {
1045
+ constructor(opportunityId, log, providerRequestStartDateTime, isSpeculative, headerRequestId = (0, uuid_1.generateUuid)()) {
995
1046
  this.opportunityId = opportunityId;
996
1047
  this.log = log;
997
1048
  this.providerRequestStartDateTime = providerRequestStartDateTime;
1049
+ this.isSpeculative = isSpeculative;
998
1050
  this.headerRequestId = headerRequestId;
999
1051
  }
1000
1052
  }