@aws/lsp-codewhisperer 0.0.72 → 0.0.73

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 (49) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/out/language-server/agenticChat/agenticChatController.js +111 -66
  3. package/out/language-server/agenticChat/agenticChatController.js.map +1 -1
  4. package/out/language-server/agenticChat/agenticChatResultStream.d.ts +4 -27
  5. package/out/language-server/agenticChat/agenticChatResultStream.js +14 -31
  6. package/out/language-server/agenticChat/agenticChatResultStream.js.map +1 -1
  7. package/out/language-server/agenticChat/tools/fileSearch.d.ts +1 -0
  8. package/out/language-server/agenticChat/tools/fileSearch.js +4 -0
  9. package/out/language-server/agenticChat/tools/fileSearch.js.map +1 -1
  10. package/out/language-server/inline-completion/codePercentage.d.ts +2 -0
  11. package/out/language-server/inline-completion/codePercentage.js +10 -2
  12. package/out/language-server/inline-completion/codePercentage.js.map +1 -1
  13. package/out/language-server/inline-completion/codeWhispererServer.js +52 -37
  14. package/out/language-server/inline-completion/codeWhispererServer.js.map +1 -1
  15. package/out/language-server/inline-completion/constants.d.ts +1 -0
  16. package/out/language-server/inline-completion/constants.js +26 -1
  17. package/out/language-server/inline-completion/constants.js.map +1 -1
  18. package/out/language-server/inline-completion/diffUtils.d.ts +15 -0
  19. package/out/language-server/inline-completion/diffUtils.js +53 -0
  20. package/out/language-server/inline-completion/diffUtils.js.map +1 -1
  21. package/out/language-server/inline-completion/editCompletionHandler.js +23 -15
  22. package/out/language-server/inline-completion/editCompletionHandler.js.map +1 -1
  23. package/out/language-server/inline-completion/session/sessionManager.d.ts +2 -4
  24. package/out/language-server/inline-completion/session/sessionManager.js +3 -6
  25. package/out/language-server/inline-completion/session/sessionManager.js.map +1 -1
  26. package/out/language-server/inline-completion/telemetry.d.ts +3 -3
  27. package/out/language-server/inline-completion/telemetry.js +6 -10
  28. package/out/language-server/inline-completion/telemetry.js.map +1 -1
  29. package/out/language-server/workspaceContext/IdleWorkspaceManager.d.ts +13 -0
  30. package/out/language-server/workspaceContext/IdleWorkspaceManager.js +39 -0
  31. package/out/language-server/workspaceContext/IdleWorkspaceManager.js.map +1 -0
  32. package/out/language-server/workspaceContext/artifactManager.js +14 -0
  33. package/out/language-server/workspaceContext/artifactManager.js.map +1 -1
  34. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.d.ts +1 -1
  35. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js +2 -1
  36. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js.map +1 -1
  37. package/out/language-server/workspaceContext/workspaceContextServer.js +2 -6
  38. package/out/language-server/workspaceContext/workspaceContextServer.js.map +1 -1
  39. package/out/language-server/workspaceContext/workspaceFolderManager.d.ts +8 -5
  40. package/out/language-server/workspaceContext/workspaceFolderManager.js +109 -82
  41. package/out/language-server/workspaceContext/workspaceFolderManager.js.map +1 -1
  42. package/out/shared/codeWhispererService.js +35 -9
  43. package/out/shared/codeWhispererService.js.map +1 -1
  44. package/out/shared/telemetry/telemetryService.d.ts +2 -2
  45. package/out/shared/telemetry/telemetryService.js +5 -7
  46. package/out/shared/telemetry/telemetryService.js.map +1 -1
  47. package/out/shared/utils.js +4 -1
  48. package/out/shared/utils.js.map +1 -1
  49. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.73](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.72...lsp-codewhisperer/v0.0.73) (2025-08-11)
4
+
5
+
6
+ ### Features
7
+
8
+ * **amazonq:** read tool ui revamp ([c65428b](https://github.com/aws/language-servers/commit/c65428bab2cf5e47badf1e3a9453babcf881e60c))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **amazonq:** add fallback classpath generation ([#2077](https://github.com/aws/language-servers/issues/2077)) ([3a6ef14](https://github.com/aws/language-servers/commit/3a6ef14e78fa2e75b837bba6524751d65038f416))
14
+ * **amazonq:** emit failed status for amazonq_invokeLLM ([#2071](https://github.com/aws/language-servers/issues/2071)) ([ee52a41](https://github.com/aws/language-servers/commit/ee52a41bc869b275fff708d7955b59f43b93bbd4))
15
+ * **amazonq:** fix fallout of [#2051](https://github.com/aws/language-servers/issues/2051) ([#2057](https://github.com/aws/language-servers/issues/2057)) ([565066b](https://github.com/aws/language-servers/commit/565066bb61adda60333c9646db958d4208bcc8af))
16
+ * **amazonq:** leverage lcs to find the chars added and removed ([#2092](https://github.com/aws/language-servers/issues/2092)) ([40379a8](https://github.com/aws/language-servers/commit/40379a887f8d42cc184239ca3175b4e673cc5286))
17
+ * **amazonq:** skips continuous monitoring when WCS sees workspace as idle ([#2066](https://github.com/aws/language-servers/issues/2066)) ([9cb959d](https://github.com/aws/language-servers/commit/9cb959d4cc450d0907f8bf5265ba01d2aa68bcd0))
18
+ * creating a new sesion for Edits trigger with next token ([#2094](https://github.com/aws/language-servers/issues/2094)) ([1da8730](https://github.com/aws/language-servers/commit/1da8730b6ed6ad53b6561368bf722e56d59596a4))
19
+ * remove edit cache logic ([#2079](https://github.com/aws/language-servers/issues/2079)) ([9bc5b9c](https://github.com/aws/language-servers/commit/9bc5b9c1d77e5fee6f518f7f5016d3a0043a5a77))
20
+ * sessionManager misused because there are 2 types of manager now ([#2090](https://github.com/aws/language-servers/issues/2090)) ([8db059a](https://github.com/aws/language-servers/commit/8db059ab83d94fd7c3ba3eb265044add31c80aea))
21
+ * update client name to support Sagemaker AI origin for agentic chat ([#2093](https://github.com/aws/language-servers/issues/2093)) ([a746fe8](https://github.com/aws/language-servers/commit/a746fe845d5e09563b475f01ce44059dca9fd10f))
22
+
3
23
  ## [0.0.72](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.71...lsp-codewhisperer/v0.0.72) (2025-08-06)
4
24
 
5
25
 
@@ -65,6 +65,7 @@ const path_1 = require("@aws/lsp-core/out/util/path");
65
65
  const agenticChatControllerHelper_1 = require("./utils/agenticChatControllerHelper");
66
66
  const activeUserTracker_1 = require("../../shared/activeUserTracker");
67
67
  const displayFindings_1 = require("./tools/qCodeAnalysis/displayFindings");
68
+ const IdleWorkspaceManager_1 = require("../workspaceContext/IdleWorkspaceManager");
68
69
  class AgenticChatController {
69
70
  #features;
70
71
  #chatSessionManagementService;
@@ -465,6 +466,7 @@ class AgenticChatController {
465
466
  async onChatPrompt(params, token) {
466
467
  // Phase 1: Initial Setup - This happens only once
467
468
  params.prompt.prompt = (0, utils_2.sanitizeInput)(params.prompt.prompt || '');
469
+ IdleWorkspaceManager_1.IdleWorkspaceManager.recordActivityTimestamp();
468
470
  const maybeDefaultResponse = !params.prompt.command && (0, utils_1.getDefaultChatResponse)(params.prompt.prompt);
469
471
  if (maybeDefaultResponse) {
470
472
  return maybeDefaultResponse;
@@ -844,6 +846,8 @@ class AgenticChatController {
844
846
  shouldDisplayMessage = false;
845
847
  // set the in progress tool use UI status to Error
846
848
  await chatResultStream.updateOngoingProgressResult('Error');
849
+ // emit invokeLLM event with status Failed for timeout calls
850
+ this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChat', undefined, undefined, 'Failed', this.#features.runtime.serverInfo.version ?? '', session.modelId, llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
847
851
  continue;
848
852
  }
849
853
  // Add the current assistantResponse message to the history DB
@@ -881,7 +885,7 @@ class AgenticChatController {
881
885
  if (pendingToolUses.length === 0) {
882
886
  this.recordChunk('agent_loop_done');
883
887
  // No more tool uses, we're done
884
- this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChat', undefined, undefined, 'Succeeded', this.#features.runtime.serverInfo.version ?? '', session.modelId, llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
888
+ this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChat', undefined, undefined, result.success ? 'Succeeded' : 'Failed', this.#features.runtime.serverInfo.version ?? '', session.modelId, llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
885
889
  finalResult = result;
886
890
  break;
887
891
  }
@@ -1112,8 +1116,7 @@ class AgenticChatController {
1112
1116
  this.#toolStartTime = Date.now();
1113
1117
  // remove progress UI
1114
1118
  await chatResultStream.removeResultBlockAndUpdateUI(agenticChatResultStream_1.progressPrefix + toolUse.toolUseId);
1115
- // fsRead and listDirectory write to an existing card and could show nothing in the current position
1116
- if (![toolConstants_1.FS_WRITE, toolConstants_1.FS_REPLACE, toolConstants_1.FS_READ, toolConstants_1.LIST_DIRECTORY].includes(toolUse.name)) {
1119
+ if (![toolConstants_1.FS_WRITE, toolConstants_1.FS_REPLACE].includes(toolUse.name)) {
1117
1120
  await this.#showUndoAllIfRequired(chatResultStream, session);
1118
1121
  }
1119
1122
  // fsWrite can take a long time, so we render fsWrite Explanatory upon partial streaming responses.
@@ -1270,10 +1273,14 @@ class AgenticChatController {
1270
1273
  switch (toolUse.name) {
1271
1274
  case toolConstants_1.FS_READ:
1272
1275
  case toolConstants_1.LIST_DIRECTORY:
1276
+ const readToolResult = await this.#processReadTool(toolUse, chatResultStream);
1277
+ if (readToolResult) {
1278
+ await chatResultStream.writeResultBlock(readToolResult);
1279
+ }
1280
+ break;
1273
1281
  case toolConstants_1.FILE_SEARCH:
1274
- const initialListDirResult = this.#processReadOrListOrSearch(toolUse, chatResultStream);
1275
- if (initialListDirResult) {
1276
- await chatResultStream.writeResultBlock(initialListDirResult);
1282
+ if ((0, fileSearch_1.isFileSearchParams)(toolUse.input)) {
1283
+ await this.#processFileSearchTool(toolUse.input, toolUse.toolUseId, result, chatResultStream);
1277
1284
  }
1278
1285
  break;
1279
1286
  // no need to write tool result for listDir,fsRead,fileSearch into chat stream
@@ -1617,7 +1624,6 @@ class AgenticChatController {
1617
1624
  return;
1618
1625
  }
1619
1626
  const toolMsgId = toolUse.toolUseId;
1620
- const chatMsgId = chatResultStream.getResult().messageId;
1621
1627
  let headerEmitted = false;
1622
1628
  const initialHeader = {
1623
1629
  body: 'shell',
@@ -1649,12 +1655,6 @@ class AgenticChatController {
1649
1655
  body: '```',
1650
1656
  header: completedHeader,
1651
1657
  });
1652
- await chatResultStream.writeResultBlock({
1653
- type: 'answer',
1654
- messageId: chatMsgId,
1655
- body: '',
1656
- header: undefined,
1657
- });
1658
1658
  this.#stoppedToolUses.add(toolMsgId);
1659
1659
  },
1660
1660
  });
@@ -2085,72 +2085,123 @@ class AgenticChatController {
2085
2085
  },
2086
2086
  };
2087
2087
  }
2088
- #processReadOrListOrSearch(toolUse, chatResultStream) {
2089
- let messageIdToUpdate = toolUse.toolUseId;
2090
- const currentId = chatResultStream.getMessageIdToUpdateForTool(toolUse.name);
2091
- if (currentId) {
2092
- messageIdToUpdate = currentId;
2093
- }
2094
- else {
2095
- chatResultStream.setMessageIdToUpdateForTool(toolUse.name, messageIdToUpdate);
2096
- }
2088
+ async #processFileSearchTool(toolInput, toolUseId, result, chatResultStream) {
2089
+ if (typeof result.output.content !== 'string')
2090
+ return;
2091
+ const { queryName, path: inputPath } = toolInput;
2092
+ const resultCount = result.output.content
2093
+ .split('\n')
2094
+ .filter(line => line.trim().startsWith('[F]') || line.trim().startsWith('[D]')).length;
2095
+ const chatMessage = {
2096
+ type: 'tool',
2097
+ messageId: toolUseId,
2098
+ header: {
2099
+ body: `Searched for "${queryName}" in `,
2100
+ icon: 'search',
2101
+ status: {
2102
+ text: `${resultCount} result${resultCount !== 1 ? 's' : ''} found`,
2103
+ },
2104
+ fileList: {
2105
+ filePaths: [inputPath],
2106
+ details: {
2107
+ [inputPath]: {
2108
+ description: inputPath,
2109
+ visibleName: path.basename(inputPath),
2110
+ clickable: false,
2111
+ },
2112
+ },
2113
+ },
2114
+ },
2115
+ };
2116
+ await chatResultStream.writeResultBlock(chatMessage);
2117
+ }
2118
+ async #processReadTool(toolUse, chatResultStream) {
2097
2119
  let currentPaths = [];
2098
2120
  if (toolUse.name === toolConstants_1.FS_READ) {
2099
- currentPaths = toolUse.input?.paths;
2121
+ currentPaths = toolUse.input?.paths || [];
2100
2122
  }
2101
- else {
2102
- currentPaths.push(toolUse.input?.path);
2123
+ else if (toolUse.name === toolConstants_1.LIST_DIRECTORY) {
2124
+ const singlePath = toolUse.input?.path;
2125
+ if (singlePath) {
2126
+ currentPaths = [singlePath];
2127
+ }
2103
2128
  }
2104
- if (!currentPaths)
2105
- return;
2106
- for (const currentPath of currentPaths) {
2107
- const existingPaths = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths || [];
2108
- // Check if path already exists in the list
2109
- const isPathAlreadyProcessed = existingPaths.some(path => path.relativeFilePath === currentPath);
2110
- if (!isPathAlreadyProcessed) {
2111
- const currentFileDetail = {
2112
- relativeFilePath: currentPath,
2113
- lineRanges: [{ first: -1, second: -1 }],
2114
- };
2115
- chatResultStream.addMessageOperation(messageIdToUpdate, toolUse.name, [
2116
- ...existingPaths,
2117
- currentFileDetail,
2118
- ]);
2129
+ else if (toolUse.name === toolConstants_1.FILE_SEARCH) {
2130
+ const queryName = toolUse.input?.queryName;
2131
+ if (queryName) {
2132
+ currentPaths = [queryName];
2119
2133
  }
2120
2134
  }
2135
+ else {
2136
+ return;
2137
+ }
2138
+ if (currentPaths.length === 0)
2139
+ return;
2140
+ // Check if the last message is the same tool type
2141
+ const lastMessage = chatResultStream.getLastMessage();
2142
+ const isSameToolType = lastMessage?.type === 'tool' && lastMessage.header?.icon === this.#toolToIcon(toolUse.name);
2143
+ let allPaths = currentPaths;
2144
+ if (isSameToolType && lastMessage.messageId) {
2145
+ // Combine with existing paths and overwrite the last message
2146
+ const existingPaths = lastMessage.header?.fileList?.filePaths || [];
2147
+ allPaths = [...existingPaths, ...currentPaths];
2148
+ const blockId = chatResultStream.getMessageBlockId(lastMessage.messageId);
2149
+ if (blockId !== undefined) {
2150
+ // Create the updated message with combined paths
2151
+ const updatedMessage = this.#createFileListToolMessage(toolUse, allPaths, lastMessage.messageId);
2152
+ // Overwrite the existing block
2153
+ await chatResultStream.overwriteResultBlock(updatedMessage, blockId);
2154
+ return undefined; // Don't return a message since we already wrote it
2155
+ }
2156
+ }
2157
+ // Create new message with current paths
2158
+ return this.#createFileListToolMessage(toolUse, allPaths, toolUse.toolUseId);
2159
+ }
2160
+ #createFileListToolMessage(toolUse, filePaths, messageId) {
2161
+ const itemCount = filePaths.length;
2121
2162
  let title;
2122
- const itemCount = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths.length;
2123
- const filePathsPushed = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths ?? [];
2124
- if (!itemCount) {
2163
+ if (itemCount === 0) {
2125
2164
  title = 'Gathering context';
2126
2165
  }
2127
2166
  else {
2128
2167
  title =
2129
2168
  toolUse.name === toolConstants_1.FS_READ
2130
2169
  ? `${itemCount} file${itemCount > 1 ? 's' : ''} read`
2131
- : toolUse.name === toolConstants_1.FILE_SEARCH
2132
- ? `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} searched`
2133
- : `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} listed`;
2170
+ : toolUse.name === toolConstants_1.LIST_DIRECTORY
2171
+ ? `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} listed`
2172
+ : '';
2134
2173
  }
2135
2174
  const details = {};
2136
- for (const item of filePathsPushed) {
2137
- details[item.relativeFilePath] = {
2138
- lineRanges: item.lineRanges,
2139
- description: item.relativeFilePath,
2175
+ for (const filePath of filePaths) {
2176
+ details[filePath] = {
2177
+ description: filePath,
2178
+ visibleName: path.basename(filePath),
2179
+ clickable: toolUse.name === toolConstants_1.FS_READ,
2140
2180
  };
2141
2181
  }
2142
- const fileList = {
2143
- rootFolderTitle: title,
2144
- filePaths: filePathsPushed.map(item => item.relativeFilePath),
2145
- details,
2146
- };
2147
2182
  return {
2148
2183
  type: 'tool',
2149
- fileList,
2150
- messageId: messageIdToUpdate,
2151
- body: '',
2184
+ header: {
2185
+ body: title,
2186
+ icon: this.#toolToIcon(toolUse.name),
2187
+ fileList: {
2188
+ filePaths,
2189
+ details,
2190
+ },
2191
+ },
2192
+ messageId,
2152
2193
  };
2153
2194
  }
2195
+ #toolToIcon(toolName) {
2196
+ switch (toolName) {
2197
+ case toolConstants_1.FS_READ:
2198
+ return 'eye';
2199
+ case toolConstants_1.LIST_DIRECTORY:
2200
+ return 'check-list';
2201
+ default:
2202
+ return undefined;
2203
+ }
2204
+ }
2154
2205
  /**
2155
2206
  * Process grep search results and format them for display in the chat UI
2156
2207
  */
@@ -2158,14 +2209,7 @@ class AgenticChatController {
2158
2209
  if (toolUse.name !== toolConstants_1.GREP_SEARCH) {
2159
2210
  return undefined;
2160
2211
  }
2161
- let messageIdToUpdate = toolUse.toolUseId;
2162
- const currentId = chatResultStream.getMessageIdToUpdateForTool(toolUse.name);
2163
- if (currentId) {
2164
- messageIdToUpdate = currentId;
2165
- }
2166
- else {
2167
- chatResultStream.setMessageIdToUpdateForTool(toolUse.name, messageIdToUpdate);
2168
- }
2212
+ const messageIdToUpdate = toolUse.toolUseId;
2169
2213
  // Extract search results from the tool output
2170
2214
  const output = result.output.content;
2171
2215
  if (!output || !output.fileMatches || !Array.isArray(output.fileMatches)) {
@@ -2414,6 +2458,7 @@ class AgenticChatController {
2414
2458
  const metric = new metric_1.Metric({
2415
2459
  cwsprChatConversationType: 'Chat',
2416
2460
  });
2461
+ IdleWorkspaceManager_1.IdleWorkspaceManager.recordActivityTimestamp();
2417
2462
  const triggerContext = await this.#getInlineChatTriggerContext(params);
2418
2463
  let response;
2419
2464
  let requestInput;