@vscode/chat-lib 0.43.2026040705 → 0.43.2026040706-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 (194) hide show
  1. package/dist/src/_internal/extension/common/constants.d.ts +2 -1
  2. package/dist/src/_internal/extension/common/constants.d.ts.map +1 -1
  3. package/dist/src/_internal/extension/common/constants.js +3 -0
  4. package/dist/src/_internal/extension/common/constants.js.map +1 -1
  5. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.d.ts +1 -5
  6. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.d.ts.map +1 -1
  7. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.js +3 -11
  8. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/ghostText/completionsFromNetwork.js.map +1 -1
  9. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.d.ts +0 -30
  10. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.d.ts.map +1 -1
  11. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.js +4 -82
  12. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/networking.js.map +1 -1
  13. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/fetch.d.ts +2 -10
  14. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/fetch.d.ts.map +1 -1
  15. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/fetch.js +26 -173
  16. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/fetch.js.map +1 -1
  17. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.d.ts +11 -0
  18. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.d.ts.map +1 -1
  19. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.js +21 -3
  20. package/dist/src/_internal/extension/inlineEdits/node/nextEditCache.js.map +1 -1
  21. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts +2 -2
  22. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.d.ts.map +1 -1
  23. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js +34 -12
  24. package/dist/src/_internal/extension/inlineEdits/node/nextEditProvider.js.map +1 -1
  25. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts +1 -1
  26. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.d.ts.map +1 -1
  27. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js +37 -24
  28. package/dist/src/_internal/extension/prompt/node/chatMLFetcher.js.map +1 -1
  29. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.d.ts.map +1 -1
  30. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js +4 -2
  31. package/dist/src/_internal/extension/prompt/node/chatMLFetcherTelemetry.js.map +1 -1
  32. package/dist/src/_internal/extension/xtab/common/fetchStreamError.d.ts +10 -0
  33. package/dist/src/_internal/extension/xtab/common/fetchStreamError.d.ts.map +1 -0
  34. package/dist/src/_internal/extension/xtab/common/fetchStreamError.js +19 -0
  35. package/dist/src/_internal/extension/xtab/common/fetchStreamError.js.map +1 -0
  36. package/dist/src/_internal/extension/xtab/node/cursorLineDivergence.d.ts +44 -0
  37. package/dist/src/_internal/extension/xtab/node/cursorLineDivergence.d.ts.map +1 -0
  38. package/dist/src/_internal/extension/xtab/node/cursorLineDivergence.js +181 -0
  39. package/dist/src/_internal/extension/xtab/node/cursorLineDivergence.js.map +1 -0
  40. package/dist/src/_internal/extension/xtab/node/editIntent.d.ts +31 -0
  41. package/dist/src/_internal/extension/xtab/node/editIntent.d.ts.map +1 -0
  42. package/dist/src/_internal/extension/xtab/node/editIntent.js +193 -0
  43. package/dist/src/_internal/extension/xtab/node/editIntent.js.map +1 -0
  44. package/dist/src/_internal/extension/xtab/node/responseFormatHandlers.d.ts +52 -0
  45. package/dist/src/_internal/extension/xtab/node/responseFormatHandlers.d.ts.map +1 -0
  46. package/dist/src/_internal/extension/xtab/node/responseFormatHandlers.js +134 -0
  47. package/dist/src/_internal/extension/xtab/node/responseFormatHandlers.js.map +1 -0
  48. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.d.ts +1 -1
  49. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.d.ts.map +1 -1
  50. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.js +5 -5
  51. package/dist/src/_internal/extension/xtab/node/xtabCustomDiffPatchResponseHandler.js.map +1 -1
  52. package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts +10 -37
  53. package/dist/src/_internal/extension/xtab/node/xtabProvider.d.ts.map +1 -1
  54. package/dist/src/_internal/extension/xtab/node/xtabProvider.js +315 -361
  55. package/dist/src/_internal/extension/xtab/node/xtabProvider.js.map +1 -1
  56. package/dist/src/_internal/extension/xtab/node/xtabUtils.d.ts +10 -0
  57. package/dist/src/_internal/extension/xtab/node/xtabUtils.d.ts.map +1 -1
  58. package/dist/src/_internal/extension/xtab/node/xtabUtils.js +24 -0
  59. package/dist/src/_internal/extension/xtab/node/xtabUtils.js.map +1 -1
  60. package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts +1 -0
  61. package/dist/src/_internal/platform/authentication/common/copilotToken.d.ts.map +1 -1
  62. package/dist/src/_internal/platform/authentication/common/copilotToken.js +3 -0
  63. package/dist/src/_internal/platform/authentication/common/copilotToken.js.map +1 -1
  64. package/dist/src/_internal/platform/chat/common/chatMLFetcher.d.ts +1 -0
  65. package/dist/src/_internal/platform/chat/common/chatMLFetcher.d.ts.map +1 -1
  66. package/dist/src/_internal/platform/chat/common/chatMLFetcher.js +4 -0
  67. package/dist/src/_internal/platform/chat/common/chatMLFetcher.js.map +1 -1
  68. package/dist/src/_internal/platform/chat/common/commonTypes.d.ts.map +1 -1
  69. package/dist/src/_internal/platform/chat/common/commonTypes.js +34 -4
  70. package/dist/src/_internal/platform/chat/common/commonTypes.js.map +1 -1
  71. package/dist/src/_internal/platform/configuration/common/configurationService.d.ts +30 -13
  72. package/dist/src/_internal/platform/configuration/common/configurationService.d.ts.map +1 -1
  73. package/dist/src/_internal/platform/configuration/common/configurationService.js +37 -20
  74. package/dist/src/_internal/platform/configuration/common/configurationService.js.map +1 -1
  75. package/dist/src/_internal/platform/configuration/common/defaultsOnlyConfigurationService.d.ts +1 -1
  76. package/dist/src/_internal/platform/configuration/common/defaultsOnlyConfigurationService.d.ts.map +1 -1
  77. package/dist/src/_internal/platform/configuration/common/defaultsOnlyConfigurationService.js +1 -1
  78. package/dist/src/_internal/platform/configuration/common/defaultsOnlyConfigurationService.js.map +1 -1
  79. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts +20 -0
  80. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.d.ts.map +1 -1
  81. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js +49 -2
  82. package/dist/src/_internal/platform/endpoint/common/chatModelCapabilities.js.map +1 -1
  83. package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts +2 -0
  84. package/dist/src/_internal/platform/endpoint/common/endpointProvider.d.ts.map +1 -1
  85. package/dist/src/_internal/platform/endpoint/common/endpointProvider.js.map +1 -1
  86. package/dist/src/_internal/platform/endpoint/common/statefulMarkerContainer.d.ts +5 -0
  87. package/dist/src/_internal/platform/endpoint/common/statefulMarkerContainer.d.ts.map +1 -1
  88. package/dist/src/_internal/platform/endpoint/common/statefulMarkerContainer.js +13 -0
  89. package/dist/src/_internal/platform/endpoint/common/statefulMarkerContainer.js.map +1 -1
  90. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts +14 -2
  91. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.d.ts.map +1 -1
  92. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js +41 -71
  93. package/dist/src/_internal/platform/endpoint/node/chatEndpoint.js.map +1 -1
  94. package/dist/src/_internal/platform/endpoint/node/imageLimits.d.ts +14 -0
  95. package/dist/src/_internal/platform/endpoint/node/imageLimits.d.ts.map +1 -0
  96. package/dist/src/_internal/platform/endpoint/node/imageLimits.js +156 -0
  97. package/dist/src/_internal/platform/endpoint/node/imageLimits.js.map +1 -0
  98. package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts +4 -12
  99. package/dist/src/_internal/platform/endpoint/node/messagesApi.d.ts.map +1 -1
  100. package/dist/src/_internal/platform/endpoint/node/messagesApi.js +39 -162
  101. package/dist/src/_internal/platform/endpoint/node/messagesApi.js.map +1 -1
  102. package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts +15 -2
  103. package/dist/src/_internal/platform/endpoint/node/responsesApi.d.ts.map +1 -1
  104. package/dist/src/_internal/platform/endpoint/node/responsesApi.js +259 -42
  105. package/dist/src/_internal/platform/endpoint/node/responsesApi.js.map +1 -1
  106. package/dist/src/_internal/platform/git/common/gitService.d.ts +8 -11
  107. package/dist/src/_internal/platform/git/common/gitService.d.ts.map +1 -1
  108. package/dist/src/_internal/platform/git/common/gitService.js.map +1 -1
  109. package/dist/src/_internal/platform/github/common/githubAPI.d.ts +1 -0
  110. package/dist/src/_internal/platform/github/common/githubAPI.d.ts.map +1 -1
  111. package/dist/src/_internal/platform/github/common/githubAPI.js +2 -0
  112. package/dist/src/_internal/platform/github/common/githubAPI.js.map +1 -1
  113. package/dist/src/_internal/platform/github/common/githubService.d.ts +3 -2
  114. package/dist/src/_internal/platform/github/common/githubService.d.ts.map +1 -1
  115. package/dist/src/_internal/platform/github/common/githubService.js.map +1 -1
  116. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts +15 -0
  117. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.d.ts.map +1 -1
  118. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js +17 -1
  119. package/dist/src/_internal/platform/inlineEdits/common/dataTypes/xtabPromptOptions.js.map +1 -1
  120. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.d.ts +12 -3
  121. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.d.ts.map +1 -1
  122. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.js +72 -46
  123. package/dist/src/_internal/platform/inlineEdits/common/inlineEditLogContext.js.map +1 -1
  124. package/dist/src/_internal/platform/inlineEdits/common/utils/utils.d.ts +3 -0
  125. package/dist/src/_internal/platform/inlineEdits/common/utils/utils.d.ts.map +1 -1
  126. package/dist/src/_internal/platform/inlineEdits/common/utils/utils.js +12 -0
  127. package/dist/src/_internal/platform/inlineEdits/common/utils/utils.js.map +1 -1
  128. package/dist/src/_internal/platform/log/common/logService.d.ts +5 -0
  129. package/dist/src/_internal/platform/log/common/logService.d.ts.map +1 -1
  130. package/dist/src/_internal/platform/log/common/logService.js +22 -0
  131. package/dist/src/_internal/platform/log/common/logService.js.map +1 -1
  132. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.d.ts +1 -1
  133. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.d.ts.map +1 -1
  134. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js +1 -1
  135. package/dist/src/_internal/platform/nesFetch/node/completionsFetchServiceImpl.js.map +1 -1
  136. package/dist/src/_internal/platform/networking/common/anthropic.d.ts +0 -58
  137. package/dist/src/_internal/platform/networking/common/anthropic.d.ts.map +1 -1
  138. package/dist/src/_internal/platform/networking/common/anthropic.js +6 -67
  139. package/dist/src/_internal/platform/networking/common/anthropic.js.map +1 -1
  140. package/dist/src/_internal/platform/networking/common/fetch.d.ts +0 -12
  141. package/dist/src/_internal/platform/networking/common/fetch.d.ts.map +1 -1
  142. package/dist/src/_internal/platform/networking/common/fetch.js +5 -1
  143. package/dist/src/_internal/platform/networking/common/fetch.js.map +1 -1
  144. package/dist/src/_internal/platform/networking/common/fetcherService.d.ts +1 -0
  145. package/dist/src/_internal/platform/networking/common/fetcherService.d.ts.map +1 -1
  146. package/dist/src/_internal/platform/networking/common/fetcherService.js.map +1 -1
  147. package/dist/src/_internal/platform/networking/common/networking.d.ts +22 -4
  148. package/dist/src/_internal/platform/networking/common/networking.d.ts.map +1 -1
  149. package/dist/src/_internal/platform/networking/common/networking.js.map +1 -1
  150. package/dist/src/_internal/platform/networking/node/chatStream.d.ts +10 -0
  151. package/dist/src/_internal/platform/networking/node/chatStream.d.ts.map +1 -1
  152. package/dist/src/_internal/platform/networking/node/chatStream.js +28 -0
  153. package/dist/src/_internal/platform/networking/node/chatStream.js.map +1 -1
  154. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts +24 -5
  155. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.d.ts.map +1 -1
  156. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js +67 -20
  157. package/dist/src/_internal/platform/networking/node/chatWebSocketManager.js.map +1 -1
  158. package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts +15 -1
  159. package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.d.ts.map +1 -1
  160. package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js +51 -7
  161. package/dist/src/_internal/platform/networking/node/chatWebSocketTelemetry.js.map +1 -1
  162. package/dist/src/_internal/platform/otel/common/genAiEvents.d.ts.map +1 -1
  163. package/dist/src/_internal/platform/otel/common/genAiEvents.js +10 -2
  164. package/dist/src/_internal/platform/otel/common/genAiEvents.js.map +1 -1
  165. package/dist/src/_internal/platform/otel/common/index.d.ts +1 -1
  166. package/dist/src/_internal/platform/otel/common/index.d.ts.map +1 -1
  167. package/dist/src/_internal/platform/otel/common/index.js +2 -1
  168. package/dist/src/_internal/platform/otel/common/index.js.map +1 -1
  169. package/dist/src/_internal/platform/otel/common/messageFormatters.d.ts +13 -1
  170. package/dist/src/_internal/platform/otel/common/messageFormatters.d.ts.map +1 -1
  171. package/dist/src/_internal/platform/otel/common/messageFormatters.js +98 -0
  172. package/dist/src/_internal/platform/otel/common/messageFormatters.js.map +1 -1
  173. package/dist/src/_internal/platform/requestLogger/common/requestLogger.d.ts +170 -0
  174. package/dist/src/_internal/platform/requestLogger/common/requestLogger.d.ts.map +1 -0
  175. package/dist/src/_internal/platform/requestLogger/common/requestLogger.js +145 -0
  176. package/dist/src/_internal/platform/requestLogger/common/requestLogger.js.map +1 -0
  177. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.d.ts +4 -4
  178. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.d.ts.map +1 -1
  179. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.js +1 -3
  180. package/dist/src/_internal/platform/requestLogger/node/nullRequestLogger.js.map +1 -1
  181. package/dist/src/_internal/platform/requestLogger/node/requestLogger.d.ts +4 -167
  182. package/dist/src/_internal/platform/requestLogger/node/requestLogger.d.ts.map +1 -1
  183. package/dist/src/_internal/platform/requestLogger/node/requestLogger.js +3 -139
  184. package/dist/src/_internal/platform/requestLogger/node/requestLogger.js.map +1 -1
  185. package/dist/src/main.d.ts +2 -0
  186. package/dist/src/main.d.ts.map +1 -1
  187. package/dist/src/main.js +48 -6
  188. package/dist/src/main.js.map +1 -1
  189. package/dist/src/package.json +192 -151
  190. package/package.json +70 -71
  191. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/stream.d.ts +0 -182
  192. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/stream.d.ts.map +0 -1
  193. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/stream.js +0 -558
  194. package/dist/src/_internal/extension/completions-core/vscode-node/lib/src/openai/stream.js.map +0 -1
@@ -47,7 +47,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
47
47
  };
48
48
  var XtabProvider_1;
49
49
  Object.defineProperty(exports, "__esModule", { value: true });
50
- exports.EditIntentParseMode = exports.XtabProvider = void 0;
50
+ exports.XtabProvider = void 0;
51
51
  exports.filterOutEditsWithSubstrings = filterOutEditsWithSubstrings;
52
52
  exports.computeAreaAroundEditWindowLinesRange = computeAreaAroundEditWindowLinesRange;
53
53
  exports.mapChatFetcherErrorToNoNextEditReason = mapChatFetcherErrorToNoNextEditReason;
@@ -55,8 +55,6 @@ exports.overrideModelConfig = overrideModelConfig;
55
55
  exports.pickSystemPrompt = pickSystemPrompt;
56
56
  exports.determineLanguageContextOptions = determineLanguageContextOptions;
57
57
  exports.getPredictionContents = getPredictionContents;
58
- exports.parseEditIntentFromStream = parseEditIntentFromStream;
59
- exports.findMergeConflictMarkersRange = findMergeConflictMarkersRange;
60
58
  const chatMLFetcher_1 = require("../../../platform/chat/common/chatMLFetcher");
61
59
  const commonTypes_1 = require("../../../platform/chat/common/commonTypes");
62
60
  const configurationService_1 = require("../../../platform/configuration/common/configurationService");
@@ -81,10 +79,12 @@ const nullExperimentationService_1 = require("../../../platform/telemetry/common
81
79
  const workspaceService_1 = require("../../../platform/workspace/common/workspaceService");
82
80
  const async_1 = require("../../../util/common/async");
83
81
  const asyncIterableUtils_1 = require("../../../util/common/asyncIterableUtils");
82
+ const backwardCompatSetting_1 = require("../../../util/common/backwardCompatSetting");
84
83
  const errors_1 = require("../../../util/common/errors");
85
84
  const result_1 = require("../../../util/common/result");
86
85
  const assert_1 = require("../../../util/vs/base/common/assert");
87
86
  const async_2 = require("../../../util/vs/base/common/async");
87
+ const cancellation_1 = require("../../../util/vs/base/common/cancellation");
88
88
  const path_1 = require("../../../util/vs/base/common/path");
89
89
  const stopwatch_1 = require("../../../util/vs/base/common/stopwatch");
90
90
  const uri_1 = require("../../../util/vs/base/common/uri");
@@ -95,11 +95,13 @@ const range_1 = require("../../../util/vs/editor/common/core/range");
95
95
  const lineRange_1 = require("../../../util/vs/editor/common/core/ranges/lineRange");
96
96
  const offsetRange_1 = require("../../../util/vs/editor/common/core/ranges/offsetRange");
97
97
  const abstractText_1 = require("../../../util/vs/editor/common/core/text/abstractText");
98
+ const positionToOffset_1 = require("../../../util/vs/editor/common/core/text/positionToOffset");
98
99
  const instantiation_1 = require("../../../util/vs/platform/instantiation/common/instantiation");
99
100
  const vscodeTypesShim_1 = require("../../../util/common/test/shims/vscodeTypesShim");
100
101
  const nearbyCursorInlineEditProvider_1 = require("../../inlineEdits/common/nearbyCursorInlineEditProvider");
101
102
  const userInteractionMonitor_1 = require("../../inlineEdits/common/userInteractionMonitor");
102
103
  const importFiltering_1 = require("../../inlineEdits/node/importFiltering");
104
+ const fetchStreamError_1 = require("../common/fetchStreamError");
103
105
  const inlineSuggestion_1 = require("../common/inlineSuggestion");
104
106
  const lintErrors_1 = require("../common/lintErrors");
105
107
  const promptCrafting_1 = require("../common/promptCrafting");
@@ -109,6 +111,9 @@ const systemMessages_1 = require("../common/systemMessages");
109
111
  const tags_1 = require("../common/tags");
110
112
  const terminalOutput_1 = require("../common/terminalOutput");
111
113
  const xtabCurrentDocument_1 = require("../common/xtabCurrentDocument");
114
+ const cursorLineDivergence_1 = require("./cursorLineDivergence");
115
+ const editIntent_1 = require("./editIntent");
116
+ const responseFormatHandlers_1 = require("./responseFormatHandlers");
112
117
  const xtabCustomDiffPatchResponseHandler_1 = require("./xtabCustomDiffPatchResponseHandler");
113
118
  const xtabEndpoint_1 = require("./xtabEndpoint");
114
119
  const xtabNextCursorPredictor_1 = require("./xtabNextCursorPredictor");
@@ -134,6 +139,27 @@ var RetryState;
134
139
  }
135
140
  RetryState.Retrying = Retrying;
136
141
  })(RetryState || (RetryState = {}));
142
+ var FetchResult;
143
+ (function (FetchResult) {
144
+ class Lines {
145
+ constructor(linesStream, getResponseSoFar, fetchRequestStopWatch) {
146
+ this.linesStream = linesStream;
147
+ this.getResponseSoFar = getResponseSoFar;
148
+ this.fetchRequestStopWatch = fetchRequestStopWatch;
149
+ }
150
+ }
151
+ FetchResult.Lines = Lines;
152
+ class ModelNotFound {
153
+ static { this.INSTANCE = new ModelNotFound(); }
154
+ }
155
+ FetchResult.ModelNotFound = ModelNotFound;
156
+ class FetchFailure {
157
+ constructor(reason) {
158
+ this.reason = reason;
159
+ }
160
+ }
161
+ FetchResult.FetchFailure = FetchFailure;
162
+ })(FetchResult || (FetchResult = {}));
137
163
  let XtabProvider = class XtabProvider {
138
164
  static { XtabProvider_1 = this; }
139
165
  static { this.ID = configurationService_1.XTabProviderId; }
@@ -174,7 +200,8 @@ let XtabProvider = class XtabProvider {
174
200
  return new statelessNextEditProvider_1.WithStatelessProviderTelemetry(noSuggestionReason, telemetry.build(result_1.Result.error(noSuggestionReason)));
175
201
  }
176
202
  const delaySession = this.userInteractionMonitor.createDelaySession(request.providerRequestStartDateTime);
177
- const iterator = this.doGetNextEdit(request, delaySession, logger, logContext, cancellationToken, telemetry, RetryState.NotRetrying.INSTANCE);
203
+ const tracing = { tracer: logger, logContext, telemetry };
204
+ const iterator = this.doGetNextEdit(request, delaySession, tracing, cancellationToken, RetryState.NotRetrying.INSTANCE);
178
205
  let res = await iterator.next(); // for-async-await loop doesn't work because we need to access the final return value
179
206
  while (!res.done) {
180
207
  yield new statelessNextEditProvider_1.WithStatelessProviderTelemetry(res.value, telemetry.build(result_1.Result.ok(undefined)));
@@ -195,29 +222,30 @@ let XtabProvider = class XtabProvider {
195
222
  logContext.setProviderEndTime();
196
223
  }
197
224
  }
198
- doGetNextEdit(request, delaySession, logger, logContext, cancellationToken, telemetryBuilder, retryState) {
199
- return this.doGetNextEditWithSelection(request, (0, nearbyCursorInlineEditProvider_1.getOrDeduceSelectionFromLastEdit)(request.getActiveDocument()), delaySession, logger, logContext, cancellationToken, telemetryBuilder, retryState);
225
+ doGetNextEdit(request, delaySession, tracing, cancellationToken, retryState) {
226
+ return this.doGetNextEditWithSelection(request, (0, nearbyCursorInlineEditProvider_1.getOrDeduceSelectionFromLastEdit)(request.getActiveDocument()), delaySession, tracing, cancellationToken, retryState);
200
227
  }
201
- async *doGetNextEditWithSelection(request, selection, delaySession, parentTracer, logContext, cancellationToken, telemetryBuilder, retryState,
228
+ async *doGetNextEditWithSelection(request, selection, delaySession, tracing, cancellationToken, retryState,
202
229
  /**
203
230
  * For cursor jump scenarios, this is the edit window around the original cursor position
204
231
  * (before the jump). When provided, yielded edits will include this as `originalWindow`
205
232
  * so the cache can serve the edit when the cursor is in either location.
206
233
  */
207
234
  originalEditWindow) {
208
- const tracer = parentTracer.createSubLogger(['XtabProvider', 'doGetNextEditWithSelection']);
235
+ const tracer = tracing.tracer.createSubLogger(['XtabProvider', 'doGetNextEditWithSelection']);
236
+ const { logContext, telemetry } = tracing;
209
237
  const activeDocument = request.getActiveDocument();
210
238
  if (selection === null) {
211
239
  return new statelessNextEditProvider_1.NoNextEditReason.Uncategorized(new Error('NoSelection'));
212
240
  }
213
241
  const { promptOptions, modelServiceConfig } = this.determineModelConfiguration(activeDocument);
214
- telemetryBuilder.setModelConfig(JSON.stringify(modelServiceConfig));
215
- const endpoint = this.getEndpointWithLogging(promptOptions.modelName, logContext, telemetryBuilder);
242
+ telemetry.setModelConfig(JSON.stringify(modelServiceConfig));
243
+ const endpoint = this.getEndpointWithLogging(promptOptions.modelName, logContext, telemetry);
216
244
  const cursorPosition = new position_1.Position(selection.endLineNumber, selection.endColumn);
217
245
  const currentDocument = new xtabCurrentDocument_1.CurrentDocument(activeDocument.documentAfterEdits, cursorPosition);
218
- this._configureDebounceTimings(request, currentDocument, promptOptions, telemetryBuilder, delaySession, tracer);
246
+ this._configureDebounceTimings(request, currentDocument, promptOptions, telemetry, delaySession, tracer);
219
247
  const areaAroundEditWindowLinesRange = computeAreaAroundEditWindowLinesRange(currentDocument);
220
- const editWindowLinesRange = this.computeEditWindowLinesRange(currentDocument, request, tracer, telemetryBuilder);
248
+ const editWindowLinesRange = this.computeEditWindowLinesRange(currentDocument, request, tracer, telemetry);
221
249
  const cursorOriginalLinesOffset = Math.max(0, currentDocument.cursorLineOffset - editWindowLinesRange.start);
222
250
  const editWindowLastLineLength = currentDocument.transformer.getLineLength(editWindowLinesRange.endExclusive);
223
251
  const editWindow = currentDocument.transformer.getOffsetRange(new range_1.Range(editWindowLinesRange.start + 1, 1, editWindowLinesRange.endExclusive, editWindowLastLineLength + 1));
@@ -242,25 +270,25 @@ let XtabProvider = class XtabProvider {
242
270
  return new statelessNextEditProvider_1.NoNextEditReason.PromptTooLarge('currentFile');
243
271
  }
244
272
  const { clippedTaggedCurrentDoc, areaAroundCodeToEdit } = taggedCurrentFileContentResult.val;
245
- telemetryBuilder.setNLinesOfCurrentFileInPrompt(clippedTaggedCurrentDoc.lines.length);
273
+ telemetry.setNLinesOfCurrentFileInPrompt(clippedTaggedCurrentDoc.lines.length);
246
274
  const { aggressivenessLevel, userHappinessScore } = this.userInteractionMonitor.getAggressivenessLevel();
247
275
  // Log user's raw aggressiveness setting when explicitly changed from default
248
276
  const userAggressivenessSetting = this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.Advanced.InlineEditsAggressiveness, this.expService);
249
- telemetryBuilder.setUserAggressivenessSetting(userAggressivenessSetting);
277
+ telemetry.setUserAggressivenessSetting(userAggressivenessSetting);
250
278
  // Log aggressiveness level and user happiness score
251
- telemetryBuilder.setXtabAggressivenessLevel(aggressivenessLevel);
279
+ telemetry.setXtabAggressivenessLevel(aggressivenessLevel);
252
280
  if (userHappinessScore !== undefined) {
253
- telemetryBuilder.setXtabUserHappinessScore(userHappinessScore);
281
+ telemetry.setXtabUserHappinessScore(userHappinessScore);
254
282
  }
255
- const langCtx = await this.getAndProcessLanguageContext(request, delaySession, activeDocument, cursorPosition, promptOptions, tracer, logContext, cancellationToken);
283
+ const langCtx = await this.getAndProcessLanguageContext(request, delaySession, activeDocument, cursorPosition, promptOptions, { tracer, logContext, telemetry }, cancellationToken);
256
284
  if (cancellationToken.isCancellationRequested) {
257
285
  return new statelessNextEditProvider_1.NoNextEditReason.GotCancelled('afterLanguageContextAwait');
258
286
  }
259
287
  const lintErrors = new lintErrors_1.LintErrors(activeDocument.id, currentDocument, this.langDiagService, request.xtabEditHistory);
260
288
  const promptPieces = new promptCrafting_1.PromptPieces(currentDocument, editWindowLinesRange, areaAroundEditWindowLinesRange, activeDocument, request.xtabEditHistory, clippedTaggedCurrentDoc.lines, areaAroundCodeToEdit, langCtx, aggressivenessLevel, lintErrors, XtabProvider_1.computeTokens, promptOptions);
261
289
  const { prompt: userPrompt, nDiffsInPrompt, diffTokensInPrompt } = (0, promptCrafting_1.getUserPrompt)(promptPieces);
262
- telemetryBuilder.setNDiffsInPrompt(nDiffsInPrompt);
263
- telemetryBuilder.setDiffTokensInPrompt(diffTokensInPrompt);
290
+ telemetry.setNDiffsInPrompt(nDiffsInPrompt);
291
+ telemetry.setDiffTokensInPrompt(diffTokensInPrompt);
264
292
  const responseFormat = xtabPromptOptions.ResponseFormat.fromPromptingStrategy(promptOptions.promptingStrategy);
265
293
  const prediction = this.getPredictedOutput(activeDocument, editWindowLines, responseFormat);
266
294
  const messages = (0, xtabUtils_1.constructMessages)({
@@ -268,35 +296,47 @@ let XtabProvider = class XtabProvider {
268
296
  userMsg: userPrompt,
269
297
  });
270
298
  logContext.setPrompt(messages);
271
- telemetryBuilder.setPrompt(messages);
299
+ telemetry.setPrompt(messages);
272
300
  const HARD_CHAR_LIMIT = 30000 * 4; // 30K tokens, assuming 4 chars per token -- we use approximation here because counting tokens exactly is time-consuming
273
301
  const promptCharCount = (0, xtabUtils_1.charCount)(messages);
274
302
  if (promptCharCount > HARD_CHAR_LIMIT) {
275
303
  return new statelessNextEditProvider_1.NoNextEditReason.PromptTooLarge('final');
276
304
  }
277
- await this.debounce(delaySession, retryState, tracer, telemetryBuilder, cancellationToken);
305
+ await this.debounce(delaySession, retryState, tracer, telemetry, cancellationToken);
278
306
  if (cancellationToken.isCancellationRequested) {
279
307
  return new statelessNextEditProvider_1.NoNextEditReason.GotCancelled('afterDebounce');
280
308
  }
281
309
  // Fire-and-forget: collect lint errors and terminal output for telemetry in background to avoid blocking the main path
282
310
  Promise.resolve().then(() => {
283
311
  const lintErrorsData = lintErrors.getData();
284
- telemetryBuilder.setLintErrors(lintErrorsData);
312
+ telemetry.setLintErrors(lintErrorsData);
285
313
  logContext.setDiagnosticsData(lintErrorsData);
286
314
  const terminalOutputData = this.terminalMonitor.getData();
287
- telemetryBuilder.setTerminalOutput(terminalOutputData);
315
+ telemetry.setTerminalOutput(terminalOutputData);
288
316
  logContext.setTerminalData(terminalOutputData);
289
317
  });
290
318
  // Fire-and-forget: compute GhostText-style similar files context for telemetry
291
- telemetryBuilder.setSimilarFilesContext(this.similarFilesContextService.compute(activeDocument.id.uri, activeDocument.languageId, activeDocument.documentAfterEdits.value, currentDocument.cursorOffset));
319
+ telemetry.setSimilarFilesContext(this.similarFilesContextService.compute(activeDocument.id.uri, activeDocument.languageId, activeDocument.documentAfterEdits.value, currentDocument.cursorOffset));
292
320
  request.fetchIssued = true;
293
- return yield* this.streamEditsWithFiltering(request, endpoint, modelServiceConfig, messages, clippedTaggedCurrentDoc, editWindow, editWindowLines, cursorOriginalLinesOffset, editWindowLinesRange, promptPieces, prediction, {
321
+ const editStreamCtx = {
322
+ endpoint,
323
+ modelServiceConfig,
324
+ messages,
325
+ clippedTaggedCurrentDoc,
326
+ editWindowInfo: {
327
+ editWindow,
328
+ editWindowLines,
329
+ cursorOriginalLinesOffset,
330
+ editWindowLineRange: editWindowLinesRange,
331
+ },
332
+ promptPieces,
333
+ prediction,
334
+ originalEditWindow,
335
+ };
336
+ return yield* this.streamEditsWithFiltering(request, editStreamCtx, {
294
337
  shouldRemoveCursorTagFromResponse,
295
338
  responseFormat,
296
- retryState,
297
- aggressivenessLevel,
298
- userHappinessScore,
299
- }, delaySession, tracer, telemetryBuilder, logContext, cancellationToken, originalEditWindow);
339
+ }, { aggressivenessLevel, userHappinessScore }, retryState, delaySession, { tracer, logContext, telemetry }, cancellationToken);
300
340
  }
301
341
  _configureDebounceTimings(request, currentDocument, promptOptions, telemetry, delaySession, tracer) {
302
342
  const isCursorAtEndOfLine = currentDocument.isCursorAtEndOfLine();
@@ -356,17 +396,17 @@ let XtabProvider = class XtabProvider {
356
396
  tracer.trace(`Aggressiveness ${userAggressiveness}: min response time set to ${minResponseTimeMs}ms`);
357
397
  }
358
398
  }
359
- getAndProcessLanguageContext(request, delaySession, activeDocument, cursorPosition, promptOptions, tracer, logContext, cancellationToken) {
399
+ getAndProcessLanguageContext(request, delaySession, activeDocument, cursorPosition, promptOptions, tracing, cancellationToken) {
360
400
  const recordingEnabled = this.configService.getConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsLogContextRecorderEnabled);
361
401
  if (!promptOptions.languageContext.enabled && !recordingEnabled) {
362
402
  return Promise.resolve(undefined);
363
403
  }
364
- const langCtxPromise = this.getLanguageContext(request, delaySession, activeDocument, cursorPosition, tracer, logContext, cancellationToken);
404
+ const langCtxPromise = this.getLanguageContext(request, delaySession, activeDocument, cursorPosition, tracing, cancellationToken);
365
405
  // if recording, add diagnostics for the file to the recording and hook up the language context promise to write to the recording
366
406
  if (recordingEnabled) {
367
407
  langCtxPromise.then(langCtxs => {
368
408
  if (langCtxs) {
369
- logContext.setLanguageContext(langCtxs);
409
+ tracing.logContext.setLanguageContext(langCtxs);
370
410
  }
371
411
  });
372
412
  }
@@ -374,7 +414,7 @@ let XtabProvider = class XtabProvider {
374
414
  ? langCtxPromise
375
415
  : Promise.resolve(undefined);
376
416
  }
377
- async getLanguageContext(request, delaySession, activeDocument, cursorPosition, tracer, logContext, cancellationToken) {
417
+ async getLanguageContext(request, delaySession, activeDocument, cursorPosition, tracing, cancellationToken) {
378
418
  try {
379
419
  const textDoc = this.workspaceService.textDocuments.find(doc => doc.uri.toString() === activeDocument.id.uri);
380
420
  if (textDoc === undefined) {
@@ -434,14 +474,15 @@ let XtabProvider = class XtabProvider {
434
474
  return { start, end, items: langCtxItems };
435
475
  }
436
476
  catch (error) {
437
- logContext.setError(errors_1.ErrorUtils.fromUnknown(error));
438
- tracer.trace(`Failed to fetch language context: ${error}`);
477
+ tracing.logContext.setError(errors_1.ErrorUtils.fromUnknown(error));
478
+ tracing.tracer.trace(`Failed to fetch language context: ${error}`);
439
479
  return undefined;
440
480
  }
441
481
  }
442
- async *streamEditsWithFiltering(request, endpoint, modelServiceConfig, messages, clippedTaggedCurrentDoc, editWindow, editWindowLines, cursorOriginalLinesOffset, editWindowLineRange, promptPieces, prediction, opts, delaySession, parentTracer, telemetryBuilder, logContext, cancellationToken, originalEditWindow) {
443
- const tracer = parentTracer.createSubLogger('streamEditsWithFiltering');
444
- const iterator = this.streamEdits(request, endpoint, modelServiceConfig, messages, clippedTaggedCurrentDoc, editWindow, editWindowLines, cursorOriginalLinesOffset, editWindowLineRange, promptPieces, prediction, opts, delaySession, tracer, telemetryBuilder, logContext, cancellationToken, originalEditWindow);
482
+ async *streamEditsWithFiltering(request, editStreamCtx, responseOpts, fetchMetadata, retryState, delaySession, tracing, cancellationToken) {
483
+ const tracer = tracing.tracer.createSubLogger('streamEditsWithFiltering');
484
+ const subTracing = { ...tracing, tracer };
485
+ const iterator = this.streamEdits(request, editStreamCtx, responseOpts, fetchMetadata, retryState, delaySession, subTracing, cancellationToken);
445
486
  let nEdits = 0;
446
487
  let r = await iterator.next();
447
488
  while (!r.done) {
@@ -461,22 +502,43 @@ let XtabProvider = class XtabProvider {
461
502
  if (nEdits === 0 &&
462
503
  r.value instanceof statelessNextEditProvider_1.NoNextEditReason.NoSuggestions // only retry if there was no error, cancellation, etc.
463
504
  ) {
464
- return yield* this.doGetNextEditsWithCursorJump(request, modelServiceConfig, editWindow, promptPieces, delaySession, parentTracer, logContext, cancellationToken, telemetryBuilder, opts.retryState);
505
+ return yield* this.doGetNextEditsWithCursorJump(request, editStreamCtx, delaySession, tracing, cancellationToken, retryState);
465
506
  }
466
507
  return r.value;
467
508
  }
468
- async *streamEdits(request, endpoint, modelServiceConfig, messages, clippedTaggedCurrentDoc, editWindow, editWindowLines, cursorOriginalLinesOffset, editWindowLineRange, promptPieces, prediction, opts, delaySession, parentTracer, telemetryBuilder, logContext, cancellationToken, originalEditWindow) {
469
- const tracer = parentTracer.createSubLogger('streamEdits');
470
- const targetDocument = request.getActiveDocument().id;
509
+ async *streamEdits(request, editStreamCtx, responseOpts, fetchMetadata, retryState, delaySession, tracing, cancellationToken) {
510
+ const tracer = tracing.tracer.createSubLogger('streamEdits');
511
+ // Create a local cancellation source linked to the caller's token.
512
+ // This lets us cancel the fetch immediately on cursor-line divergence
513
+ // without reaching into the request's CancellationTokenSource (which
514
+ // is owned by nextEditProvider.ts).
515
+ const fetchCts = new cancellation_1.CancellationTokenSource(cancellationToken);
516
+ const fetchCancellationToken = fetchCts.token;
517
+ try {
518
+ return yield* this._streamEditsImpl(request, editStreamCtx, responseOpts, fetchMetadata, retryState, delaySession, { ...tracing, tracer }, cancellationToken, fetchCts, fetchCancellationToken);
519
+ }
520
+ finally {
521
+ fetchCts.dispose();
522
+ }
523
+ }
524
+ /**
525
+ * Initiates the HTTP fetch, sets up the streaming pipeline, and returns either
526
+ * a clean line stream (with cursor-tag removal and latency logging applied)
527
+ * or an error / retry signal.
528
+ *
529
+ * This method encapsulates all fetch infrastructure so that downstream response
530
+ * format handlers only need an `AsyncIterable<string>` line stream.
531
+ */
532
+ async _performFetch(endpoint, messages, prediction, requestId, fetchMetadata, shouldRemoveCursorTagFromResponse, editWindow, documentBeforeEdits, fetchCancellationToken, tracing) {
533
+ const { tracer, logContext, telemetry } = tracing;
471
534
  const useFetcher = this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.NextEditSuggestionsFetcher, this.expService) || undefined;
472
535
  const fetchStreamSource = new chatMLFetcher_1.FetchStreamSource();
473
536
  const fetchRequestStopWatch = new stopwatch_1.StopWatch();
474
537
  let responseSoFar = '';
475
- let chatResponseFailure;
476
538
  let ttft;
477
539
  const firstTokenReceived = new async_2.DeferredPromise();
478
- logContext.setHeaderRequestId(request.headerRequestId);
479
- telemetryBuilder.setFetchStartedAt();
540
+ logContext.setHeaderRequestId(requestId);
541
+ telemetry.setFetchStartedAt();
480
542
  logContext.setFetchStartTime();
481
543
  // we must not await this promise because we want to stream edits as they come in
482
544
  const fetchResultPromise = endpoint.makeChatRequest2({
@@ -504,48 +566,51 @@ let XtabProvider = class XtabProvider {
504
566
  },
505
567
  userInitiatedRequest: undefined,
506
568
  telemetryProperties: {
507
- requestId: request.headerRequestId,
569
+ requestId,
508
570
  },
509
571
  useFetcher,
510
572
  customMetadata: {
511
- aggressivenessLevel: opts.aggressivenessLevel,
512
- userHappinessScore: opts.userHappinessScore,
573
+ aggressivenessLevel: fetchMetadata.aggressivenessLevel,
574
+ userHappinessScore: fetchMetadata.userHappinessScore,
513
575
  },
514
- }, cancellationToken);
515
- telemetryBuilder.setResponse(fetchResultPromise.then((response) => ({ response, ttft })));
576
+ }, fetchCancellationToken);
577
+ telemetry.setResponse(fetchResultPromise.then((response) => ({ response, ttft })));
516
578
  logContext.setFullResponse(fetchResultPromise.then((response) => response.type === commonTypes_1.ChatFetchResponseType.Success ? response.value : undefined));
517
- const fetchRes = await Promise.race([firstTokenReceived.p, fetchResultPromise]);
518
- if (fetchRes && fetchRes.type !== commonTypes_1.ChatFetchResponseType.Success) {
519
- if (fetchRes.type === commonTypes_1.ChatFetchResponseType.NotFound &&
520
- !this.forceUseDefaultModel // if we haven't already forced using the default model; otherwise, this could cause an infinite loop
521
- ) {
522
- this.forceUseDefaultModel = true;
523
- return yield* this.doGetNextEdit(request, delaySession, tracer, logContext, cancellationToken, telemetryBuilder, opts.retryState); // use the same retry state
524
- }
525
- // diff-patch based model returns no choices if it has no edits to suggest
526
- if (fetchRes.type === commonTypes_1.ChatFetchResponseType.Unknown && fetchRes.reason === commonTypes_1.RESPONSE_CONTAINED_NO_CHOICES) {
527
- return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
528
- }
529
- return mapChatFetcherErrorToNoNextEditReason(fetchRes);
530
- }
531
579
  fetchResultPromise
532
580
  .then((response) => {
533
- // this's a way to signal the edit-pushing code to know if the request failed and
534
- // it shouldn't push edits constructed from an erroneous response
535
- chatResponseFailure = response.type !== commonTypes_1.ChatFetchResponseType.Success ? response : undefined;
581
+ if (response.type !== commonTypes_1.ChatFetchResponseType.Success) {
582
+ fetchStreamSource.reject(new fetchStreamError_1.FetchStreamError(mapChatFetcherErrorToNoNextEditReason(response)));
583
+ }
584
+ else {
585
+ fetchStreamSource.resolve();
586
+ }
536
587
  })
537
588
  .catch((err) => {
538
589
  // in principle this shouldn't happen because ChatMLFetcher's fetchOne should not throw
539
590
  logContext.setError(errors_1.ErrorUtils.fromUnknown(err));
540
591
  logContext.addLog(`ChatMLFetcher fetch call threw -- this's UNEXPECTED!`);
592
+ fetchStreamSource.reject(errors_1.ErrorUtils.fromUnknown(err));
541
593
  }).finally(() => {
542
594
  logContext.setFetchEndTime();
543
595
  if (!firstTokenReceived.isSettled) {
544
596
  firstTokenReceived.complete();
545
597
  }
546
- fetchStreamSource.resolve();
547
598
  logContext.setResponse(responseSoFar);
548
599
  });
600
+ const fetchRes = await Promise.race([firstTokenReceived.p, fetchResultPromise]);
601
+ if (fetchRes && fetchRes.type !== commonTypes_1.ChatFetchResponseType.Success) {
602
+ if (fetchRes.type === commonTypes_1.ChatFetchResponseType.NotFound &&
603
+ !this.forceUseDefaultModel // if we haven't already forced using the default model; otherwise, this could cause an infinite loop
604
+ ) {
605
+ this.forceUseDefaultModel = true;
606
+ return FetchResult.ModelNotFound.INSTANCE;
607
+ }
608
+ // diff-patch based model returns no choices if it has no edits to suggest
609
+ if (fetchRes.type === commonTypes_1.ChatFetchResponseType.Unknown && fetchRes.reason === commonTypes_1.RESPONSE_CONTAINED_NO_CHOICES) {
610
+ return new FetchResult.FetchFailure(new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(documentBeforeEdits, editWindow));
611
+ }
612
+ return new FetchResult.FetchFailure(mapChatFetcherErrorToNoNextEditReason(fetchRes));
613
+ }
549
614
  const llmLinesStream = asyncIterableUtils_1.AsyncIterUtilsExt.splitLines(asyncIterableUtils_1.AsyncIterUtils.map(fetchStreamSource.stream, (chunk) => chunk.delta.text));
550
615
  // logging of times
551
616
  // removal of cursor tag if option is set
@@ -554,119 +619,132 @@ let XtabProvider = class XtabProvider {
554
619
  for await (const v of llmLinesStream) {
555
620
  const trace = `Line ${i++} emitted with latency ${fetchRequestStopWatch.elapsed()} ms`;
556
621
  tracer.trace(trace);
557
- yield opts.shouldRemoveCursorTagFromResponse
622
+ yield shouldRemoveCursorTagFromResponse
558
623
  ? v.replaceAll(tags_1.PromptTags.CURSOR, '')
559
624
  : v;
560
625
  }
561
626
  })();
562
- const isFromCursorJump = opts.retryState instanceof RetryState.Retrying && opts.retryState.reason === 'cursorJump';
563
- let cleanedLinesStream;
564
- if (opts.responseFormat === xtabPromptOptions.ResponseFormat.EditWindowOnly) {
565
- cleanedLinesStream = linesStream;
566
- }
567
- else if (opts.responseFormat === xtabPromptOptions.ResponseFormat.EditWindowWithEditIntent ||
568
- opts.responseFormat === xtabPromptOptions.ResponseFormat.EditWindowWithEditIntentShort) {
569
- // Determine parse mode based on response format
570
- const parseMode = opts.responseFormat === xtabPromptOptions.ResponseFormat.EditWindowWithEditIntentShort
571
- ? EditIntentParseMode.ShortName
572
- : EditIntentParseMode.Tags;
573
- // Parse the edit_intent from the response
574
- const { editIntent, remainingLinesStream, parseError } = await parseEditIntentFromStream(linesStream, tracer, parseMode);
575
- // Log the edit intent for telemetry
576
- telemetryBuilder.setEditIntent(editIntent);
577
- // Log parse errors for telemetry - this helps detect malformed model output during flights
578
- if (parseError) {
579
- telemetryBuilder.setEditIntentParseError(parseError);
580
- }
581
- // Check if we should show this edit based on intent and aggressiveness
582
- if (!xtabPromptOptions.EditIntent.shouldShowEdit(editIntent, promptPieces.aggressivenessLevel)) {
583
- tracer.trace(`Filtered out edit due to edit intent "${editIntent}" with aggressiveness "${promptPieces.aggressivenessLevel}"`);
584
- return new statelessNextEditProvider_1.NoNextEditReason.FilteredOut(`editIntent:${editIntent} aggressivenessLevel:${promptPieces.aggressivenessLevel}`);
585
- }
586
- cleanedLinesStream = remainingLinesStream;
587
- }
588
- else if (opts.responseFormat === xtabPromptOptions.ResponseFormat.CustomDiffPatch) {
589
- const activeDoc = request.getActiveDocument();
590
- const currentDocument = promptPieces.currentDocument;
591
- const lastLine = currentDocument.lines[clippedTaggedCurrentDoc.keptRange.endExclusive - 1];
592
- const lastLineLength = lastLine.length;
593
- const pseudoEditWindow = currentDocument.transformer.getOffsetRange(new range_1.Range(clippedTaggedCurrentDoc.keptRange.start + 1, 1, clippedTaggedCurrentDoc.keptRange.endExclusive, lastLineLength + 1));
594
- return yield* xtabCustomDiffPatchResponseHandler_1.XtabCustomDiffPatchResponseHandler.handleResponse(linesStream, currentDocument, activeDoc.id, activeDoc.workspaceRoot, pseudoEditWindow, tracer, () => chatResponseFailure ? mapChatFetcherErrorToNoNextEditReason(chatResponseFailure) : undefined);
595
- }
596
- else if (opts.responseFormat === xtabPromptOptions.ResponseFormat.UnifiedWithXml) {
597
- const linesIter = linesStream[Symbol.asyncIterator]();
598
- const firstLine = await linesIter.next();
599
- if (chatResponseFailure !== undefined) { // handle fetch failure
600
- return new statelessNextEditProvider_1.NoNextEditReason.Unexpected(errors_1.ErrorUtils.fromUnknown(chatResponseFailure));
627
+ return new FetchResult.Lines(linesStream, () => responseSoFar, fetchRequestStopWatch);
628
+ }
629
+ async *_streamEditsImpl(request, editStreamCtx, responseOpts, fetchMetadata, retryState, delaySession, tracing, cancellationToken, fetchCts, fetchCancellationToken) {
630
+ const { tracer, logContext, telemetry } = tracing;
631
+ const { endpoint, messages, clippedTaggedCurrentDoc, editWindowInfo, promptPieces, prediction, originalEditWindow } = editStreamCtx;
632
+ const { editWindow, editWindowLines, cursorOriginalLinesOffset, editWindowLineRange } = editWindowInfo;
633
+ const targetDocument = request.getActiveDocument().id;
634
+ // Phase 1: Fetch lifecycle initiate HTTP request and produce a clean line stream
635
+ const fetchResult = await this._performFetch(endpoint, messages, prediction, request.headerRequestId, fetchMetadata, responseOpts.shouldRemoveCursorTagFromResponse, editWindow, request.documentBeforeEdits, fetchCancellationToken, tracing);
636
+ if (fetchResult instanceof FetchResult.ModelNotFound) {
637
+ return yield* this.doGetNextEdit(request, delaySession, tracing, cancellationToken, retryState);
638
+ }
639
+ if (fetchResult instanceof FetchResult.FetchFailure) {
640
+ return fetchResult.reason;
641
+ }
642
+ const { linesStream, getResponseSoFar, fetchRequestStopWatch } = fetchResult;
643
+ // Phase 2: Dispatch to the appropriate response format handler
644
+ const isFromCursorJump = retryState instanceof RetryState.Retrying && retryState.reason === 'cursorJump';
645
+ let parseResult;
646
+ try {
647
+ switch (responseOpts.responseFormat) {
648
+ case xtabPromptOptions.ResponseFormat.EditWindowOnly: {
649
+ parseResult = (0, responseFormatHandlers_1.handleEditWindowOnly)(linesStream);
650
+ break;
651
+ }
652
+ case xtabPromptOptions.ResponseFormat.CodeBlock: {
653
+ parseResult = (0, responseFormatHandlers_1.handleCodeBlock)(linesStream);
654
+ break;
655
+ }
656
+ case xtabPromptOptions.ResponseFormat.EditWindowWithEditIntent:
657
+ case xtabPromptOptions.ResponseFormat.EditWindowWithEditIntentShort: {
658
+ const parseMode = responseOpts.responseFormat === xtabPromptOptions.ResponseFormat.EditWindowWithEditIntentShort
659
+ ? editIntent_1.EditIntentParseMode.ShortName
660
+ : editIntent_1.EditIntentParseMode.Tags;
661
+ parseResult = await (0, responseFormatHandlers_1.handleEditWindowWithEditIntent)(linesStream, tracer, parseMode);
662
+ break;
663
+ }
664
+ case xtabPromptOptions.ResponseFormat.CustomDiffPatch: {
665
+ const activeDoc = request.getActiveDocument();
666
+ const currentDocument = promptPieces.currentDocument;
667
+ const lastLine = currentDocument.lines[clippedTaggedCurrentDoc.keptRange.endExclusive - 1];
668
+ const lastLineLength = lastLine.length;
669
+ const pseudoEditWindow = currentDocument.transformer.getOffsetRange(new range_1.Range(clippedTaggedCurrentDoc.keptRange.start + 1, 1, clippedTaggedCurrentDoc.keptRange.endExclusive, lastLineLength + 1));
670
+ parseResult = new responseFormatHandlers_1.ResponseParseResult.DirectEdits(xtabCustomDiffPatchResponseHandler_1.XtabCustomDiffPatchResponseHandler.handleResponse(linesStream, currentDocument, activeDoc.id, activeDoc.workspaceRoot, pseudoEditWindow, tracer));
671
+ break;
672
+ }
673
+ case xtabPromptOptions.ResponseFormat.UnifiedWithXml: {
674
+ parseResult = await (0, responseFormatHandlers_1.handleUnifiedWithXml)(linesStream, {
675
+ editWindowLines,
676
+ editWindowLineRange,
677
+ cursorOriginalLinesOffset,
678
+ cursorColumnZeroBased: promptPieces.currentDocument.cursorPosition.column - 1,
679
+ editWindow,
680
+ originalEditWindow,
681
+ targetDocument,
682
+ isFromCursorJump,
683
+ }, request.documentBeforeEdits, tracer);
684
+ break;
685
+ }
686
+ default:
687
+ (0, assert_1.assertNever)(responseOpts.responseFormat);
601
688
  }
602
- if (firstLine.done) { // no lines in response -- unexpected case but take as no suggestions
603
- return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
689
+ // Handle result uniformly
690
+ if (parseResult instanceof responseFormatHandlers_1.ResponseParseResult.Done) {
691
+ return parseResult.reason;
604
692
  }
605
- const trimmedLines = firstLine.value.trim();
606
- if (trimmedLines === tags_1.ResponseTags.NO_CHANGE.start) {
607
- return yield* this.doGetNextEditsWithCursorJump(request, modelServiceConfig, editWindow, promptPieces, delaySession, tracer, logContext, cancellationToken, telemetryBuilder, opts.retryState);
693
+ if (parseResult instanceof responseFormatHandlers_1.ResponseParseResult.DirectEdits) {
694
+ return yield* parseResult.stream;
608
695
  }
609
- if (trimmedLines === tags_1.ResponseTags.INSERT.start) {
610
- const lineWithCursorContinued = await linesIter.next();
611
- if (lineWithCursorContinued.done || lineWithCursorContinued.value.includes(tags_1.ResponseTags.INSERT.end)) {
612
- return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
696
+ // parseResult is EditWindowLines — log edit-intent telemetry and apply aggressiveness filter
697
+ if (parseResult.editIntentMetadata) {
698
+ const { intent, parseError } = parseResult.editIntentMetadata;
699
+ telemetry.setEditIntent(intent);
700
+ if (parseError) {
701
+ telemetry.setEditIntentParseError(parseError);
613
702
  }
614
- const cursorColumnOffsetZeroBased = promptPieces.currentDocument.cursorPosition.column - 1;
615
- const edit = new lineEdit_1.LineReplacement(new lineRange_1.LineRange(editWindowLineRange.start + cursorOriginalLinesOffset + 1 /* 0-based to 1-based */, editWindowLineRange.start + cursorOriginalLinesOffset + 2), [editWindowLines[cursorOriginalLinesOffset].slice(0, cursorColumnOffsetZeroBased) + lineWithCursorContinued.value + editWindowLines[cursorOriginalLinesOffset].slice(cursorColumnOffsetZeroBased)]);
616
- yield { edit, isFromCursorJump, window: editWindow, originalWindow: originalEditWindow, targetDocument };
617
- const lines = [];
618
- let v = await linesIter.next();
619
- while (!v.done) {
620
- if (v.value.includes(tags_1.ResponseTags.INSERT.end)) {
621
- break;
622
- }
623
- else {
624
- lines.push(v.value);
625
- }
626
- v = await linesIter.next();
703
+ if (!xtabPromptOptions.EditIntent.shouldShowEdit(intent, promptPieces.aggressivenessLevel)) {
704
+ tracer.trace(`Filtered out edit due to edit intent "${intent}" with aggressiveness "${promptPieces.aggressivenessLevel}"`);
705
+ return new statelessNextEditProvider_1.NoNextEditReason.FilteredOut(`editIntent:${intent} aggressivenessLevel:${promptPieces.aggressivenessLevel}`);
627
706
  }
628
- const line = editWindowLineRange.start + cursorOriginalLinesOffset + 2;
629
- yield {
630
- edit: new lineEdit_1.LineReplacement(new lineRange_1.LineRange(line, line), lines),
631
- isFromCursorJump,
632
- window: editWindow,
633
- originalWindow: originalEditWindow,
634
- targetDocument,
635
- };
636
- return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
637
707
  }
638
- if (trimmedLines === tags_1.ResponseTags.EDIT.start) {
639
- cleanedLinesStream = (async function* () {
640
- let v = await linesIter.next();
641
- while (!v.done) {
642
- if (v.value.includes(tags_1.ResponseTags.EDIT.end)) {
643
- return;
644
- }
645
- yield v.value;
646
- v = await linesIter.next();
647
- }
648
- })();
649
- }
650
- else {
651
- return new statelessNextEditProvider_1.NoNextEditReason.Unexpected(new Error(`unexpected tag ${trimmedLines}`));
652
- }
653
- }
654
- else if (opts.responseFormat === xtabPromptOptions.ResponseFormat.CodeBlock) {
655
- cleanedLinesStream = (0, xtabUtils_1.linesWithBackticksRemoved)(linesStream);
656
- }
657
- else {
658
- (0, assert_1.assertNever)(opts.responseFormat);
659
- }
660
- const diffOptions = {
661
- emitFastCursorLineChange: responseProcessor_1.ResponseProcessor.mapEmitFastCursorLineChange(this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabProviderEmitFastCursorLineChange, this.expService)),
662
- nLinesToConverge: this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabNNonSignificantLinesToConverge, this.expService),
663
- nSignificantLinesToConverge: this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabNSignificantLinesToConverge, this.expService),
664
- };
665
- tracer.trace(`starting to diff stream against edit window lines with latency ${fetchRequestStopWatch.elapsed()} ms`);
666
- let i = 0;
667
- let hasBeenDelayed = false;
668
- try {
669
- for await (const edit of responseProcessor_1.ResponseProcessor.diff(editWindowLines, cleanedLinesStream, cursorOriginalLinesOffset, diffOptions)) {
708
+ const cleanedLinesStream = parseResult.lines;
709
+ const diffOptions = {
710
+ emitFastCursorLineChange: responseProcessor_1.ResponseProcessor.mapEmitFastCursorLineChange(this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabProviderEmitFastCursorLineChange, this.expService)),
711
+ nLinesToConverge: this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabNNonSignificantLinesToConverge, this.expService),
712
+ nSignificantLinesToConverge: this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabNSignificantLinesToConverge, this.expService),
713
+ };
714
+ tracer.trace(`starting to diff stream against edit window lines with latency ${fetchRequestStopWatch.elapsed()} ms`);
715
+ // Wrap the line stream to detect early divergence between the user's
716
+ // intermediate edits and the model's streamed output.
717
+ // In `Cursor` mode only the cursor line is checked; in `EditWindow`
718
+ // mode every line in the edit window is checked.
719
+ //
720
+ // We check compatibility using `isModelLineCompatible`: the user's
721
+ // line change must be contained within the model's line change range
722
+ // and match via the helper's `startsWith` / auto-close subsequence rules.
723
+ const earlyDivergenceMode = (0, backwardCompatSetting_1.backwardCompatSetting)(this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabEarlyCursorLineDivergenceCancellation, this.expService), (value) => {
724
+ switch (value) {
725
+ case false:
726
+ case undefined:
727
+ return xtabPromptOptions_1.EarlyDivergenceCancellationMode.Off;
728
+ case true:
729
+ return xtabPromptOptions_1.EarlyDivergenceCancellationMode.Cursor;
730
+ case xtabPromptOptions_1.EarlyDivergenceCancellationMode.Off:
731
+ case xtabPromptOptions_1.EarlyDivergenceCancellationMode.Cursor:
732
+ case xtabPromptOptions_1.EarlyDivergenceCancellationMode.EditWindow:
733
+ return value;
734
+ default:
735
+ return xtabPromptOptions_1.EarlyDivergenceCancellationMode.Off;
736
+ }
737
+ });
738
+ let lineDiverged = false;
739
+ const divergenceCheckedStream = earlyDivergenceMode === xtabPromptOptions_1.EarlyDivergenceCancellationMode.Off
740
+ ? cleanedLinesStream
741
+ : linesWithIntermediateEditDivergenceCheck(cleanedLinesStream, cursorOriginalLinesOffset, request, editWindowLineRange, editWindowLines, fetchCts, tracing, (value) => { lineDiverged = value; }, earlyDivergenceMode);
742
+ let i = 0;
743
+ let hasBeenDelayed = false;
744
+ for await (const edit of responseProcessor_1.ResponseProcessor.diff(editWindowLines, divergenceCheckedStream, cursorOriginalLinesOffset, diffOptions)) {
745
+ if (lineDiverged) {
746
+ break;
747
+ }
670
748
  tracer.trace(`ResponseProcessor streamed edit #${i} with latency ${fetchRequestStopWatch.elapsed()} ms`);
671
749
  const singleLineEdits = [];
672
750
  if (edit.lineRange.startLineNumber === edit.lineRange.endLineNumberExclusive || // we don't want to run diff on insertion
@@ -690,15 +768,12 @@ let XtabProvider = class XtabProvider {
690
768
  singleLineEdits.push(singleLineEdit);
691
769
  }
692
770
  }
693
- if (chatResponseFailure) { // do not emit edits if chat response failed
694
- break;
695
- }
696
- logContext.setResponse(responseSoFar);
771
+ logContext.setResponse(getResponseSoFar());
697
772
  for (const singleLineEdit of singleLineEdits) {
698
773
  tracer.trace(`extracting edit #${i}: ${singleLineEdit.toString()}`);
699
774
  if (!hasBeenDelayed) { // delay only the first one
700
775
  hasBeenDelayed = true;
701
- const artificialDelay = this.determineArtificialDelayMs(delaySession, tracer, telemetryBuilder);
776
+ const artificialDelay = this.determineArtificialDelayMs(delaySession, tracer, telemetry);
702
777
  if (artificialDelay) {
703
778
  await (0, async_2.timeout)(artificialDelay);
704
779
  tracer.trace(`Artificial delay of ${artificialDelay} ms completed`);
@@ -711,20 +786,24 @@ let XtabProvider = class XtabProvider {
711
786
  i++;
712
787
  }
713
788
  }
714
- if (chatResponseFailure) {
715
- return mapChatFetcherErrorToNoNextEditReason(chatResponseFailure);
789
+ if (lineDiverged) {
790
+ return new statelessNextEditProvider_1.NoNextEditReason.GotCancelled(earlyDivergenceMode === xtabPromptOptions_1.EarlyDivergenceCancellationMode.Cursor ? 'cursorLineDiverged' : 'editWindowLineDiverged');
716
791
  }
717
792
  return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
718
793
  }
719
794
  catch (err) {
795
+ if (err instanceof fetchStreamError_1.FetchStreamError) {
796
+ return err.reason;
797
+ }
720
798
  logContext.setError(err);
721
- // Properly handle the error by pushing it as a result
722
799
  return new statelessNextEditProvider_1.NoNextEditReason.Unexpected(errors_1.ErrorUtils.fromUnknown(err));
723
800
  }
724
801
  }
725
- async *doGetNextEditsWithCursorJump(request, modelConfig, editWindow, promptPieces, delaySession, tracer, logContext, cancellationToken, telemetryBuilder, retryState) {
802
+ async *doGetNextEditsWithCursorJump(request, editStreamCtx, delaySession, tracing, cancellationToken, retryState) {
803
+ const { tracer, telemetry } = tracing;
804
+ const { editWindowInfo: { editWindow }, modelServiceConfig, promptPieces } = editStreamCtx;
726
805
  const noSuggestions = new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
727
- const nextCursorLinePrediction = this.nextCursorPredictor.determineEnablement(modelConfig.supportsNextCursorLinePrediction);
806
+ const nextCursorLinePrediction = this.nextCursorPredictor.determineEnablement(modelServiceConfig.supportsNextCursorLinePrediction);
728
807
  if (nextCursorLinePrediction === undefined || retryState instanceof RetryState.Retrying) {
729
808
  return noSuggestions;
730
809
  }
@@ -732,7 +811,7 @@ let XtabProvider = class XtabProvider {
732
811
  tracer.trace('Skipping cursor prediction: user typed during request');
733
812
  return new statelessNextEditProvider_1.NoNextEditReason.GotCancelled('beforeNextCursorPredictionFetchUserTyped');
734
813
  }
735
- const nextCursorLineR = await this.nextCursorPredictor.predictNextCursorPosition(promptPieces, tracer, telemetryBuilder, cancellationToken);
814
+ const nextCursorLineR = await this.nextCursorPredictor.predictNextCursorPosition(promptPieces, tracer, telemetry, cancellationToken);
736
815
  if (cancellationToken.isCancellationRequested) {
737
816
  return new statelessNextEditProvider_1.NoNextEditReason.GotCancelled('afterNextCursorPredictionFetch');
738
817
  }
@@ -742,26 +821,26 @@ let XtabProvider = class XtabProvider {
742
821
  }
743
822
  if (nextCursorLineR.isError()) {
744
823
  tracer.trace(`Predicted next cursor line error: ${nextCursorLineR.err.message}`);
745
- telemetryBuilder.setNextCursorLineError(nextCursorLineR.err.message);
824
+ telemetry.setNextCursorLineError(nextCursorLineR.err.message);
746
825
  return noSuggestions;
747
826
  }
748
827
  const prediction = nextCursorLineR.val;
749
828
  if (prediction.kind === 'differentFile') {
750
- return yield* this.handleCrossFilePrediction(prediction, nextCursorLinePrediction, request, editWindow, promptPieces, delaySession, tracer, logContext, cancellationToken, telemetryBuilder);
829
+ return yield* this.handleCrossFilePrediction(prediction, nextCursorLinePrediction, request, editStreamCtx, delaySession, tracing, cancellationToken);
751
830
  }
752
831
  const nextCursorLineZeroBased = prediction.lineNumber;
753
832
  const lineDistanceFromCursorLine = nextCursorLineZeroBased - promptPieces.currentDocument.cursorLineOffset;
754
- telemetryBuilder.setNextCursorLineDistance(lineDistanceFromCursorLine);
755
- telemetryBuilder.setNextCursorIsCrossFile(false);
833
+ telemetry.setNextCursorLineDistance(lineDistanceFromCursorLine);
834
+ telemetry.setNextCursorIsCrossFile(false);
756
835
  tracer.trace(`Predicted next cursor line: ${nextCursorLineZeroBased}`);
757
836
  if (nextCursorLineZeroBased >= promptPieces.currentDocument.lines.length) { // >= because the line index is zero-based
758
837
  tracer.trace(`Predicted next cursor line error: exceedsDocumentLines`);
759
- telemetryBuilder.setNextCursorLineError('exceedsDocumentLines');
838
+ telemetry.setNextCursorLineError('exceedsDocumentLines');
760
839
  return noSuggestions;
761
840
  }
762
841
  if (promptPieces.editWindowLinesRange.contains(nextCursorLineZeroBased)) {
763
842
  tracer.trace(`Predicted next cursor line error: withinEditWindow`);
764
- telemetryBuilder.setNextCursorLineError('withinEditWindow');
843
+ telemetry.setNextCursorLineError('withinEditWindow');
765
844
  return noSuggestions;
766
845
  }
767
846
  const nextCursorLineOneBased = nextCursorLineZeroBased + 1;
@@ -774,7 +853,7 @@ let XtabProvider = class XtabProvider {
774
853
  return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow, nextCursorPosition);
775
854
  }
776
855
  case nextCursorLinePrediction_1.NextCursorLinePrediction.OnlyWithEdit: {
777
- const v = this.doGetNextEditWithSelection(request, new range_1.Range(nextCursorLineOneBased, nextCursorColumn, nextCursorLineOneBased, nextCursorColumn), delaySession, tracer, logContext, cancellationToken, telemetryBuilder, new RetryState.Retrying('cursorJump'), editWindow);
856
+ const v = this.doGetNextEditWithSelection(request, new range_1.Range(nextCursorLineOneBased, nextCursorColumn, nextCursorLineOneBased, nextCursorColumn), delaySession, tracing, cancellationToken, new RetryState.Retrying('cursorJump'), editWindow);
778
857
  return yield* v;
779
858
  }
780
859
  default: {
@@ -782,11 +861,13 @@ let XtabProvider = class XtabProvider {
782
861
  }
783
862
  }
784
863
  }
785
- async *handleCrossFilePrediction(prediction, nextCursorLinePrediction, request, editWindow, promptPieces, delaySession, tracer, logContext, cancellationToken, telemetryBuilder) {
864
+ async *handleCrossFilePrediction(prediction, nextCursorLinePrediction, request, editStreamCtx, delaySession, tracing, cancellationToken) {
865
+ const { tracer, telemetry } = tracing;
866
+ const { editWindowInfo: { editWindow }, promptPieces } = editStreamCtx;
786
867
  const workspaceRoot = promptPieces.activeDoc.workspaceRoot;
787
868
  if (!workspaceRoot && !(0, path_1.isAbsolute)(prediction.filePath)) {
788
869
  tracer.trace('Predicted cross-file cursor jump error: noWorkspaceRoot');
789
- telemetryBuilder.setNextCursorLineError('crossFile:noWorkspaceRoot');
870
+ telemetry.setNextCursorLineError('crossFile:noWorkspaceRoot');
790
871
  return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow);
791
872
  }
792
873
  const targetUri = (0, path_1.isAbsolute)(prediction.filePath)
@@ -795,7 +876,7 @@ let XtabProvider = class XtabProvider {
795
876
  const targetDocumentId = documentId_1.DocumentId.create(targetUri.toString());
796
877
  const nextCursorLineOneBased = prediction.lineNumber + 1;
797
878
  const nextCursorPosition = new position_1.Position(nextCursorLineOneBased, 1);
798
- telemetryBuilder.setNextCursorIsCrossFile(true);
879
+ telemetry.setNextCursorIsCrossFile(true);
799
880
  tracer.trace(`Predicted cross-file cursor jump: ${prediction.filePath}:${prediction.lineNumber}`);
800
881
  switch (nextCursorLinePrediction) {
801
882
  case nextCursorLinePrediction_1.NextCursorLinePrediction.Jump: {
@@ -808,7 +889,7 @@ let XtabProvider = class XtabProvider {
808
889
  }
809
890
  catch (err) {
810
891
  tracer.trace(`Failed to open target file for cross-file edit: ${errors_1.ErrorUtils.fromUnknown(err).message}`);
811
- telemetryBuilder.setNextCursorLineError('crossFile:failedToOpenFile');
892
+ telemetry.setNextCursorLineError('crossFile:failedToOpenFile');
812
893
  return new statelessNextEditProvider_1.NoNextEditReason.NoSuggestions(request.documentBeforeEdits, editWindow, nextCursorPosition, targetDocumentId);
813
894
  }
814
895
  if (cancellationToken.isCancellationRequested) {
@@ -821,7 +902,7 @@ let XtabProvider = class XtabProvider {
821
902
  const targetContent = new abstractText_1.StringText(targetTextDoc.getText());
822
903
  const syntheticDoc = new statelessNextEditProvider_1.StatelessNextEditDocument(targetDocumentId, promptPieces.activeDoc.workspaceRoot, languageId_1.LanguageId.create(targetTextDoc.languageId), targetContent.getLines(), lineEdit_1.LineEdit.empty, targetContent, new edit_1.Edits(stringEdit_1.StringEdit, []));
823
904
  const syntheticRequest = new statelessNextEditProvider_1.StatelessNextEditRequest(request.headerRequestId, request.opportunityId, targetContent, [syntheticDoc], 0, request.xtabEditHistory, new async_2.DeferredPromise(), request.expandedEditWindowNLines, request.isSpeculative, request.logContext, request.recordingBookmark, request.recording, request.providerRequestStartDateTime);
824
- return yield* this.doGetNextEditWithSelection(syntheticRequest, new range_1.Range(nextCursorLineOneBased, 1, nextCursorLineOneBased, 1), delaySession, tracer, logContext, cancellationToken, telemetryBuilder, new RetryState.Retrying('cursorJump'), editWindow);
905
+ return yield* this.doGetNextEditWithSelection(syntheticRequest, new range_1.Range(nextCursorLineOneBased, 1, nextCursorLineOneBased, 1), delaySession, tracing, cancellationToken, new RetryState.Retrying('cursorJump'), editWindow);
825
906
  }
826
907
  default: {
827
908
  (0, assert_1.assertNever)(nextCursorLinePrediction);
@@ -873,7 +954,7 @@ let XtabProvider = class XtabProvider {
873
954
  const maxMergeConflictLines = this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabMaxMergeConflictLines, this.expService);
874
955
  if (maxMergeConflictLines) {
875
956
  const tentativeEditWindow = new offsetRange_1.OffsetRange(codeToEditStart, codeToEditEndExcl);
876
- const mergeConflictRange = findMergeConflictMarkersRange(currentDocLines, tentativeEditWindow, maxMergeConflictLines);
957
+ const mergeConflictRange = (0, xtabUtils_1.findMergeConflictMarkersRange)(currentDocLines, tentativeEditWindow, maxMergeConflictLines);
877
958
  if (mergeConflictRange) {
878
959
  const onlyMergeConflictLines = this.configService.getExperimentBasedConfig(configurationService_1.ConfigKey.TeamInternal.InlineEditsXtabOnlyMergeConflictLines, this.expService);
879
960
  telemetry.setMergeConflictExpanded(onlyMergeConflictLines ? 'only' : 'normal');
@@ -1191,176 +1272,49 @@ function getPredictionContents(doc, editWindowLines, responseFormat) {
1191
1272
  (0, assert_1.assertNever)(responseFormat);
1192
1273
  }
1193
1274
  }
1194
- /**
1195
- * Mode for parsing edit intent from the model response.
1196
- */
1197
- var EditIntentParseMode;
1198
- (function (EditIntentParseMode) {
1199
- /** Parse using XML-style tags: <|edit_intent|>value<|/edit_intent|> */
1200
- EditIntentParseMode["Tags"] = "tags";
1201
- /** Parse using short names on the first line: N|L|M|H */
1202
- EditIntentParseMode["ShortName"] = "shortName";
1203
- })(EditIntentParseMode || (exports.EditIntentParseMode = EditIntentParseMode = {}));
1204
- /**
1205
- * Parses the edit_intent from the first line of the response stream.
1206
- * The edit_intent MUST be on the first line, otherwise it's treated as not provided.
1207
- * Returns the parsed EditIntent and a new stream with the remaining content.
1208
- *
1209
- * Supports two modes:
1210
- * - Tags (default): <|edit_intent|>low|medium|high|no_edit<|/edit_intent|>
1211
- * - ShortName: N|L|M|H on the first line
1212
- *
1213
- * @param linesStream The stream of lines from the model response
1214
- * @param tracer Logger for tracing
1215
- * @param mode The parse mode (Tags or ShortName), defaults to Tags
1216
- */
1217
- async function parseEditIntentFromStream(linesStream, tracer, mode = EditIntentParseMode.Tags) {
1218
- if (mode === EditIntentParseMode.ShortName) {
1219
- return parseEditIntentFromStreamShortName(linesStream, tracer);
1220
- }
1221
- return parseEditIntentFromStreamTags(linesStream, tracer);
1222
- }
1223
- /**
1224
- * Parses the edit_intent using short name format (N|L|M|H on first line).
1225
- */
1226
- async function parseEditIntentFromStreamShortName(linesStream, tracer) {
1227
- let editIntent = xtabPromptOptions.EditIntent.High; // Default to high (always show) if no short name found
1228
- let parseError;
1229
- const linesIter = linesStream[Symbol.asyncIterator]();
1230
- const firstLineResult = await linesIter.next();
1231
- if (firstLineResult.done) {
1232
- // Empty stream
1233
- parseError = 'emptyResponse';
1234
- tracer.warn(`Empty response stream, no edit_intent short name found`);
1235
- const remainingLinesStream = (async function* () { })();
1236
- return { editIntent, remainingLinesStream, parseError };
1237
- }
1238
- const firstLine = firstLineResult.value.trim();
1239
- // Check if the first line is a single character short name
1240
- const parsedIntent = xtabPromptOptions.EditIntent.fromShortName(firstLine);
1241
- if (parsedIntent !== undefined) {
1242
- editIntent = parsedIntent;
1243
- tracer.trace(`Parsed edit_intent short name from first line: "${firstLine}" -> ${editIntent}`);
1244
- // Create a new stream with the remaining lines (excluding the short name line)
1245
- const remainingLinesStream = (async function* () {
1246
- let next = await linesIter.next();
1247
- while (!next.done) {
1248
- yield next.value;
1249
- next = await linesIter.next();
1250
- }
1251
- })();
1252
- return { editIntent, remainingLinesStream, parseError };
1275
+ async function* linesWithIntermediateEditDivergenceCheck(cleanedLinesStream, cursorOriginalLinesOffset, request, editWindowLineRange, editWindowLines, fetchCts, { tracer }, setLineDiverged, mode) {
1276
+ const intermediateEdit = request.intermediateUserEdit;
1277
+ if (!intermediateEdit || intermediateEdit.isEmpty()) {
1278
+ yield* cleanedLinesStream;
1279
+ return;
1253
1280
  }
1254
- // Short name not found or invalid
1255
- parseError = `unknownIntentValue:${firstLine}`;
1256
- tracer.warn(`Edit intent parse error: ${parseError} (using Xtab275EditIntentShort prompting strategy). ` +
1257
- `Defaulting to High (always show). First line was: "${firstLine.substring(0, 100)}..."`);
1258
- // Return the first line plus the rest of the stream
1259
- const remainingLinesStream = (async function* () {
1260
- yield firstLineResult.value; // Use original value, not trimmed
1261
- let next = await linesIter.next();
1262
- while (!next.done) {
1263
- yield next.value;
1264
- next = await linesIter.next();
1281
+ const transformer = request.documentBeforeEdits.getTransformer();
1282
+ // Precompute the post-edit document once to avoid O(lines * docSize) in EditWindow mode.
1283
+ const currentDoc = intermediateEdit.apply(transformer.text);
1284
+ const currentTransformer = new positionToOffset_1.PositionOffsetTransformer(currentDoc);
1285
+ const precomputed = { currentDoc, currentTransformer };
1286
+ const shouldCheckLine = (lineIdx) => {
1287
+ if (lineIdx >= editWindowLines.length) {
1288
+ return false;
1289
+ }
1290
+ switch (mode) {
1291
+ case xtabPromptOptions_1.EarlyDivergenceCancellationMode.Cursor:
1292
+ return lineIdx === cursorOriginalLinesOffset;
1293
+ case xtabPromptOptions_1.EarlyDivergenceCancellationMode.EditWindow:
1294
+ return true;
1265
1295
  }
1266
- })();
1267
- return { editIntent, remainingLinesStream, parseError };
1268
- }
1269
- /**
1270
- * Parses the edit_intent tag from the first line of the response stream (original tag-based format).
1271
- */
1272
- async function parseEditIntentFromStreamTags(linesStream, tracer) {
1273
- const EDIT_INTENT_START_TAG = '<|edit_intent|>';
1274
- const EDIT_INTENT_END_TAG = '<|/edit_intent|>';
1275
- let editIntent = xtabPromptOptions.EditIntent.High; // Default to high (always show) if no tag found
1276
- let parseError;
1277
- const linesIter = linesStream[Symbol.asyncIterator]();
1278
- const firstLineResult = await linesIter.next();
1279
- if (firstLineResult.done) {
1280
- // Empty stream
1281
- parseError = 'emptyResponse';
1282
- tracer.warn(`Empty response stream, no edit_intent tag found`);
1283
- const remainingLinesStream = (async function* () { })();
1284
- return { editIntent, remainingLinesStream, parseError };
1285
- }
1286
- const firstLine = firstLineResult.value;
1287
- // Check if the first line contains the complete edit_intent tag
1288
- const startIdx = firstLine.indexOf(EDIT_INTENT_START_TAG);
1289
- const endIdx = firstLine.indexOf(EDIT_INTENT_END_TAG);
1290
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
1291
- // Found complete tag on first line
1292
- const intentValue = firstLine.substring(startIdx + EDIT_INTENT_START_TAG.length, endIdx).trim().toLowerCase();
1293
- // Check if it's a known intent value
1294
- const knownIntentValues = ['no_edit', 'low', 'medium', 'high'];
1295
- if (!knownIntentValues.includes(intentValue)) {
1296
- parseError = `unknownIntentValue:${intentValue}`;
1297
- tracer.warn(`Unknown edit_intent value: "${intentValue}", defaulting to High`);
1298
- }
1299
- editIntent = xtabPromptOptions.EditIntent.fromString(intentValue);
1300
- tracer.trace(`Parsed edit_intent from first line: "${intentValue}" -> ${editIntent}`);
1301
- // Calculate remaining content after the end tag on the first line
1302
- const afterEndTag = firstLine.substring(endIdx + EDIT_INTENT_END_TAG.length);
1303
- // Create a new stream that first yields remaining content from first line, then continues
1304
- const remainingLinesStream = (async function* () {
1305
- // Only yield remaining content from first line if non-empty
1306
- if (afterEndTag.trim() !== '') {
1307
- yield afterEndTag;
1308
- }
1309
- // Continue with rest of the stream
1310
- let next = await linesIter.next();
1311
- while (!next.done) {
1312
- yield next.value;
1313
- next = await linesIter.next();
1314
- }
1315
- })();
1316
- return { editIntent, remainingLinesStream, parseError };
1317
- }
1318
- // Determine the parse error type
1319
- if (startIdx !== -1 && endIdx === -1) {
1320
- // Start tag found but no end tag - malformed (possibly split across lines)
1321
- parseError = 'malformedTag:startWithoutEnd';
1322
- }
1323
- else if (startIdx === -1 && endIdx !== -1) {
1324
- // End tag found but no start tag - malformed
1325
- parseError = 'malformedTag:endWithoutStart';
1326
- }
1327
- else {
1328
- // No tag found at all
1329
- parseError = 'noTagFound';
1330
- }
1331
- tracer.warn(`Edit intent parse error: ${parseError} (using Xtab275EditIntent prompting strategy). ` +
1332
- `Defaulting to High (always show). First line was: "${firstLine.substring(0, 100)}..."`);
1333
- // Return the first line plus the rest of the stream
1334
- const remainingLinesStream = (async function* () {
1335
- yield firstLine;
1336
- let next = await linesIter.next();
1337
- while (!next.done) {
1338
- yield next.value;
1339
- next = await linesIter.next();
1340
- }
1341
- })();
1342
- return { editIntent, remainingLinesStream, parseError };
1343
- }
1344
- /**
1345
- * Finds the range of lines containing merge conflict markers within a specified edit window.
1346
- *
1347
- * @param lines - Array of strings representing the lines of text to search through
1348
- * @param editWindowRange - The range within which to search for merge conflict markers
1349
- * @param maxMergeConflictLines - Maximum number of lines to search for conflict markers
1350
- * @returns An OffsetRange object representing the start and end of the conflict markers, or undefined if not found
1351
- */
1352
- function findMergeConflictMarkersRange(lines, editWindowRange, maxMergeConflictLines) {
1353
- for (let i = editWindowRange.start; i < Math.min(lines.length, editWindowRange.endExclusive); ++i) {
1354
- if (!lines[i].startsWith('<<<<<<<')) {
1355
- continue;
1356
- }
1357
- // found start of merge conflict markers -- now find the end
1358
- for (let j = i + 1; j < lines.length && (j - i) < maxMergeConflictLines; ++j) {
1359
- if (lines[j].startsWith('>>>>>>>')) {
1360
- return new offsetRange_1.OffsetRange(i, j + 1 /* because endExclusive */);
1296
+ };
1297
+ let lineIdx = 0;
1298
+ for await (const line of cleanedLinesStream) {
1299
+ if (shouldCheckLine(lineIdx)) {
1300
+ const docLineIdx = editWindowLineRange.start + lineIdx;
1301
+ const currentLine = (0, cursorLineDivergence_1.getCurrentLine)(transformer, docLineIdx, intermediateEdit, precomputed);
1302
+ if (currentLine !== undefined) {
1303
+ const originalLine = editWindowLines[lineIdx];
1304
+ if (currentLine !== originalLine // user changed this line
1305
+ && !(0, cursorLineDivergence_1.isModelLineCompatible)(originalLine, currentLine, line) // model's line isn't compatible with user's typing
1306
+ ) {
1307
+ setLineDiverged(true);
1308
+ tracer.trace(`Line ${lineIdx} DIVERGED (mode=${mode}): model="${line}" current="${currentLine}"`);
1309
+ // Cancel our local fetch token so the HTTP request is
1310
+ // aborted immediately. We own this token, so this is safe.
1311
+ fetchCts.cancel();
1312
+ return;
1313
+ }
1361
1314
  }
1362
1315
  }
1316
+ yield line;
1317
+ lineIdx++;
1363
1318
  }
1364
- return undefined;
1365
1319
  }
1366
1320
  //# sourceMappingURL=xtabProvider.js.map