@aws/lsp-codewhisperer 0.0.62 → 0.0.64

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 (88) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/out/language-server/agenticChat/agenticChatController.d.ts +3 -2
  3. package/out/language-server/agenticChat/agenticChatController.js +101 -27
  4. package/out/language-server/agenticChat/agenticChatController.js.map +1 -1
  5. package/out/language-server/agenticChat/constants/constants.d.ts +9 -0
  6. package/out/language-server/agenticChat/constants/constants.js +16 -0
  7. package/out/language-server/agenticChat/constants/constants.js.map +1 -0
  8. package/out/language-server/agenticChat/constants/modelSelection.d.ts +7 -0
  9. package/out/language-server/agenticChat/constants/modelSelection.js +21 -0
  10. package/out/language-server/agenticChat/constants/modelSelection.js.map +1 -0
  11. package/out/language-server/agenticChat/context/additionalContextProvider.d.ts +5 -0
  12. package/out/language-server/agenticChat/context/additionalContextProvider.js +52 -13
  13. package/out/language-server/agenticChat/context/additionalContextProvider.js.map +1 -1
  14. package/out/language-server/agenticChat/context/contextCommandsProvider.js +1 -1
  15. package/out/language-server/agenticChat/context/contextCommandsProvider.js.map +1 -1
  16. package/out/language-server/agenticChat/qAgenticChatServer.js +3 -0
  17. package/out/language-server/agenticChat/qAgenticChatServer.js.map +1 -1
  18. package/out/language-server/agenticChat/tools/executeBash.js +3 -2
  19. package/out/language-server/agenticChat/tools/executeBash.js.map +1 -1
  20. package/out/language-server/agenticChat/tools/fsWrite.js +7 -0
  21. package/out/language-server/agenticChat/tools/fsWrite.js.map +1 -1
  22. package/out/language-server/agenticChat/tools/mcp/chokidarFileWatcher.d.ts +8 -0
  23. package/out/language-server/agenticChat/tools/mcp/chokidarFileWatcher.js +47 -0
  24. package/out/language-server/agenticChat/tools/mcp/chokidarFileWatcher.js.map +1 -0
  25. package/out/language-server/agenticChat/tools/mcp/mcpEventHandler.d.ts +4 -0
  26. package/out/language-server/agenticChat/tools/mcp/mcpEventHandler.js +87 -8
  27. package/out/language-server/agenticChat/tools/mcp/mcpEventHandler.js.map +1 -1
  28. package/out/language-server/agenticChat/tools/toolServer.js +1 -1
  29. package/out/language-server/agenticChat/tools/toolServer.js.map +1 -1
  30. package/out/language-server/agenticChat/utils/agenticChatControllerHelper.d.ts +8 -0
  31. package/out/language-server/agenticChat/utils/agenticChatControllerHelper.js +15 -0
  32. package/out/language-server/agenticChat/utils/agenticChatControllerHelper.js.map +1 -0
  33. package/out/language-server/agenticChat/utils/pathValidation.d.ts +21 -0
  34. package/out/language-server/agenticChat/utils/pathValidation.js +44 -0
  35. package/out/language-server/agenticChat/utils/pathValidation.js.map +1 -0
  36. package/out/language-server/chat/chatController.d.ts +1 -1
  37. package/out/language-server/chat/chatController.js.map +1 -1
  38. package/out/language-server/chat/telemetry/chatTelemetryController.d.ts +1 -1
  39. package/out/language-server/chat/telemetry/chatTelemetryController.js +2 -1
  40. package/out/language-server/chat/telemetry/chatTelemetryController.js.map +1 -1
  41. package/out/language-server/inline-completion/codeWhispererServer.js +53 -29
  42. package/out/language-server/inline-completion/codeWhispererServer.js.map +1 -1
  43. package/out/language-server/localProjectContext/localProjectContextServer.js +21 -5
  44. package/out/language-server/localProjectContext/localProjectContextServer.js.map +1 -1
  45. package/out/language-server/netTransform/artifactManager.d.ts +4 -1
  46. package/out/language-server/netTransform/artifactManager.js +53 -2
  47. package/out/language-server/netTransform/artifactManager.js.map +1 -1
  48. package/out/language-server/netTransform/models.d.ts +32 -2
  49. package/out/language-server/netTransform/models.js.map +1 -1
  50. package/out/language-server/netTransform/tests/mockData.js +1 -1
  51. package/out/language-server/netTransform/tests/mockData.js.map +1 -1
  52. package/out/language-server/workspaceContext/dependency/dependencyEventBundler.d.ts +3 -3
  53. package/out/language-server/workspaceContext/dependency/dependencyEventBundler.js +3 -3
  54. package/out/language-server/workspaceContext/dependency/dependencyHandler/JSTSDependencyHandler.js +1 -2
  55. package/out/language-server/workspaceContext/dependency/dependencyHandler/JSTSDependencyHandler.js.map +1 -1
  56. package/out/language-server/workspaceContext/dependency/dependencyHandler/JavaDependencyHandler.js +1 -2
  57. package/out/language-server/workspaceContext/dependency/dependencyHandler/JavaDependencyHandler.js.map +1 -1
  58. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.d.ts +5 -6
  59. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js +17 -27
  60. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js.map +1 -1
  61. package/out/language-server/workspaceContext/dependency/dependencyHandler/PythonDependencyHandler.js +1 -2
  62. package/out/language-server/workspaceContext/dependency/dependencyHandler/PythonDependencyHandler.js.map +1 -1
  63. package/out/language-server/workspaceContext/util.js +3 -1
  64. package/out/language-server/workspaceContext/util.js.map +1 -1
  65. package/out/language-server/workspaceContext/workspaceContextServer.js +21 -10
  66. package/out/language-server/workspaceContext/workspaceContextServer.js.map +1 -1
  67. package/out/language-server/workspaceContext/workspaceFolderManager.d.ts +1 -2
  68. package/out/language-server/workspaceContext/workspaceFolderManager.js +24 -30
  69. package/out/language-server/workspaceContext/workspaceFolderManager.js.map +1 -1
  70. package/out/shared/constants.d.ts +1 -0
  71. package/out/shared/constants.js +2 -1
  72. package/out/shared/constants.js.map +1 -1
  73. package/out/shared/imageVerification.d.ts +1 -0
  74. package/out/shared/imageVerification.js +3 -2
  75. package/out/shared/imageVerification.js.map +1 -1
  76. package/out/shared/languageDetection.js +1 -1
  77. package/out/shared/languageDetection.js.map +1 -1
  78. package/out/shared/streamingClientService.js +2 -2
  79. package/out/shared/streamingClientService.js.map +1 -1
  80. package/out/shared/telemetry/telemetryService.js +1 -2
  81. package/out/shared/telemetry/telemetryService.js.map +1 -1
  82. package/out/shared/testUtils.d.ts +9 -0
  83. package/out/shared/testUtils.js +12 -1
  84. package/out/shared/testUtils.js.map +1 -1
  85. package/package.json +2 -2
  86. package/out/language-server/agenticChat/constants.d.ts +0 -8
  87. package/out/language-server/agenticChat/constants.js +0 -12
  88. package/out/language-server/agenticChat/constants.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.64](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.63...lsp-codewhisperer/v0.0.64) (2025-07-11)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **amazonq:** add files created by fsWrite tool to @Files list ([#1784](https://github.com/aws/language-servers/issues/1784)) ([cfeb3be](https://github.com/aws/language-servers/commit/cfeb3be43e425fae89d795cacad62031cc1ee029))
9
+ * **amazonq:** remove the deep copy logic in updateRequestInputWithToolResults ([#1870](https://github.com/aws/language-servers/issues/1870)) ([f209a15](https://github.com/aws/language-servers/commit/f209a15785106af43fd97bfa99b393a13d9a9bab))
10
+ * use absolute file path for shell ([#1871](https://github.com/aws/language-servers/issues/1871)) ([f863735](https://github.com/aws/language-servers/commit/f863735c8dc734a1af4b26fbe8b9c436a32c21ca))
11
+
12
+
13
+ ### Reverts
14
+
15
+ * adding files on VSC windows properly triggers reindexing ([#1820](https://github.com/aws/language-servers/issues/1820))" ([#1860](https://github.com/aws/language-servers/issues/1860)) ([423cdbc](https://github.com/aws/language-servers/commit/423cdbc48d9439e29ba69c37dc289a739f83475f))
16
+ * revert: adding files on VSC windows properly triggers reindexing ([#18](https://github.com/aws/language-servers/issues/18)…" ([#1862](https://github.com/aws/language-servers/issues/1862)) ([8e0c88b](https://github.com/aws/language-servers/commit/8e0c88b91d4f04e3209bbe35ee5678793c94b0f1))
17
+
18
+ ## [0.0.63](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.62...lsp-codewhisperer/v0.0.63) (2025-07-08)
19
+
20
+
21
+ ### Features
22
+
23
+ * added file watchers to listen to mcp and persona config ([#1714](https://github.com/aws/language-servers/issues/1714)) ([4c5a7f8](https://github.com/aws/language-servers/commit/4c5a7f893bad37bea1946d37d06f57197c3ef04b))
24
+ * adding streakLength back for UserTriggerDecisionEvent ([#1841](https://github.com/aws/language-servers/issues/1841)) ([7052132](https://github.com/aws/language-servers/commit/7052132a5198944ef05ddbf857d622ba518e71da))
25
+ * **amazonq:** add transformation preferences functionality to input gen ([#1792](https://github.com/aws/language-servers/issues/1792)) ([095f737](https://github.com/aws/language-servers/commit/095f737b86e6234b2568c6d4deafbbb90967bdbc))
26
+ * **amazonq:** update workspace context server A/B testing filter ([#1830](https://github.com/aws/language-servers/issues/1830)) ([faeeee3](https://github.com/aws/language-servers/commit/faeeee3da7a8712f3501055ba8d485528185cdb6))
27
+ * **flags:** change flag name to enablewebformtransform([#1804](https://github.com/aws/language-servers/issues/1804)) ([3b6c3be](https://github.com/aws/language-servers/commit/3b6c3be7630248cd00c19c16637f016d799ef8d1))
28
+ * passing partialResultToken to onInlineCompletionHandler result for EDITS ([#1840](https://github.com/aws/language-servers/issues/1840)) ([270d5a3](https://github.com/aws/language-servers/commit/270d5a3c5adba6b49d938f310ac89ae9b7fbc401))
29
+ * support listAvailableModels server request ([#1808](https://github.com/aws/language-servers/issues/1808)) ([9f1ddb3](https://github.com/aws/language-servers/commit/9f1ddb327778dba6da49337b79c5fef19023b52d))
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * adding agenticcoding field to amazonqaddMessage metric([#1849](https://github.com/aws/language-servers/issues/1849)) ([d677c52](https://github.com/aws/language-servers/commit/d677c52c6139859bc0f2dd8e7ffe6a85b87db3f6))
35
+ * adding files on VSC windows properly triggers reindexing ([#1820](https://github.com/aws/language-servers/issues/1820)) ([0c2d8eb](https://github.com/aws/language-servers/commit/0c2d8eb7dd875dfe86d1b2d094ec53a2a1221b97))
36
+ * **amazonq:** allow taking .jpg file as image context, add image cont… ([#1814](https://github.com/aws/language-servers/issues/1814)) ([4d36fa4](https://github.com/aws/language-servers/commit/4d36fa4a0a04692dba720bc0288c6cee7f45a1fc))
37
+ * **amazonq:** change the customer UI message to out of the workspace ([#1822](https://github.com/aws/language-servers/issues/1822)) ([624def5](https://github.com/aws/language-servers/commit/624def51e4d9e21ee8d045ffe528455b69cdfecb))
38
+ * **amazonq:** change the image filter used in open file dialog ([#1838](https://github.com/aws/language-servers/issues/1838)) ([d9da4cb](https://github.com/aws/language-servers/commit/d9da4cbb7b1995ef43aaba1b7e67d26fd61a3c57))
39
+ * **amazonq:** fix to add upper limit validation for tool description ([#1760](https://github.com/aws/language-servers/issues/1760)) ([2d18a3b](https://github.com/aws/language-servers/commit/2d18a3ba69d22b26dea5170656d79b9eacc202b1))
40
+ * **amazonq:** fix typo in image context list ([#1836](https://github.com/aws/language-servers/issues/1836)) ([179b553](https://github.com/aws/language-servers/commit/179b553a1444201e696fd52e7705dc0c05154eab))
41
+ * **amazonq:** handle undefined paths gracefully and retry ([#1825](https://github.com/aws/language-servers/issues/1825)) ([c52b017](https://github.com/aws/language-servers/commit/c52b017eef0666433cbb0b6d8086254dc1af5fee))
42
+ * **amazonq:** include tsx and jsx files in workspace context server ([#1790](https://github.com/aws/language-servers/issues/1790)) ([79691ef](https://github.com/aws/language-servers/commit/79691ef607d9bc98032fe2e59a5031601a4dba9a))
43
+ * **amazonq:** make workspace context server upload dependency chunks sequentially ([#1769](https://github.com/aws/language-servers/issues/1769)) ([c8329e6](https://github.com/aws/language-servers/commit/c8329e6b90be2c24d72a4525b8903384746de2ab))
44
+ * **amazonq:** prevent WCS matching workspaceFolder with only prefix ([#1782](https://github.com/aws/language-servers/issues/1782)) ([988d952](https://github.com/aws/language-servers/commit/988d952485b0f026200a19d17cacd323cd9e359e))
45
+ * **amazonq:** shouldn't exit inline flow before we're sure there is no Edit/Completion trigger ([#1819](https://github.com/aws/language-servers/issues/1819)) ([dc8d89b](https://github.com/aws/language-servers/commit/dc8d89b39ee230aba6cfb032f81bda3476a5cc84))
46
+ * imagecontext image name bug, mutliple images in pinned context ([#1834](https://github.com/aws/language-servers/issues/1834)) ([27d60ab](https://github.com/aws/language-servers/commit/27d60ab5f5249635a9e73be1ee96ecb820133f9a))
47
+ * remove redundent thinking... for file operations ([#1839](https://github.com/aws/language-servers/issues/1839)) ([0078602](https://github.com/aws/language-servers/commit/00786023c9c257c9bb8066c36715864b32b4e069))
48
+ * should always trigger EDIT suggestion if triggering via acceptance ([#1826](https://github.com/aws/language-servers/issues/1826)) ([6c9e522](https://github.com/aws/language-servers/commit/6c9e5225a58d7cf43931d84e7ae63275d6f9c066))
49
+
3
50
  ## [0.0.62](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.61...lsp-codewhisperer/v0.0.62) (2025-07-02)
4
51
 
5
52
 
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import { ToolUse } from '@amzn/codewhisperer-streaming';
6
6
  import { ChatCommandInput } from '../../shared/streamingClientService';
7
- import { Status, ButtonClickParams, ButtonClickResult, InlineChatResultParams, PromptInputOptionChangeParams, RuleClickParams, ListRulesParams, ActiveEditorChangedParams, PinnedContextParams, ExecuteCommandParams, FollowUpClickParams, OpenFileDialogParams, OpenFileDialogResult } from '@aws/language-server-runtimes/protocol';
7
+ import { Status, ButtonClickParams, ButtonClickResult, InlineChatResultParams, PromptInputOptionChangeParams, RuleClickParams, ListRulesParams, ActiveEditorChangedParams, PinnedContextParams, ExecuteCommandParams, FollowUpClickParams, ListAvailableModelsParams, ListAvailableModelsResult, OpenFileDialogParams, OpenFileDialogResult } from '@aws/language-server-runtimes/protocol';
8
8
  import { FeedbackParams, InsertToCursorPositionParams, InlineChatParams, ConversationClickParams, ListConversationsParams, ListMcpServersParams, McpServerClickParams, TabBarActionParams, CreatePromptParams, FileClickParams } from '@aws/language-server-runtimes/protocol';
9
9
  import { CancellationToken, Chat, ChatParams, ChatResult, EndChatParams, QuickActionParams, ResponseError, TabAddParams, TabRemoveParams, TabChangeParams, InlineChatResult } from '@aws/language-server-runtimes/server-interface';
10
10
  import { Features, LspHandlers } from '../types';
@@ -16,7 +16,7 @@ import { ChatSessionService } from '../chat/chatSessionService';
16
16
  import { AgenticChatResultStream } from './agenticChatResultStream';
17
17
  import { AdditionalContentEntryAddition } from './context/agenticChatTriggerContext';
18
18
  import { PaidTierMode } from '../paidTier/paidTier';
19
- type ChatHandlers = Omit<LspHandlers<Chat>, 'openTab' | 'sendChatUpdate' | 'sendContextCommands' | 'onListConversations' | 'onConversationClick' | 'onListMcpServers' | 'onMcpServerClick' | 'onTabBarAction' | 'getSerializedChat' | 'chatOptionsUpdate' | 'onListMcpServers' | 'onMcpServerClick' | 'onListRules' | 'sendPinnedContext' | 'onActiveEditorChanged' | 'onPinnedContextAdd' | 'onPinnedContextRemove' | 'onOpenFileDialog' | 'onListAvailableModels'>;
19
+ type ChatHandlers = Omit<LspHandlers<Chat>, 'openTab' | 'sendChatUpdate' | 'sendContextCommands' | 'onListConversations' | 'onConversationClick' | 'onListMcpServers' | 'onMcpServerClick' | 'onTabBarAction' | 'getSerializedChat' | 'chatOptionsUpdate' | 'onListRules' | 'sendPinnedContext' | 'onActiveEditorChanged' | 'onPinnedContextAdd' | 'onPinnedContextRemove' | 'onOpenFileDialog' | 'onListAvailableModels'>;
20
20
  export declare class AgenticChatController implements ChatHandlers {
21
21
  #private;
22
22
  constructor(chatSessionManagementService: ChatSessionManagementService, features: Features, telemetryService: TelemetryService, serviceManager?: AmazonQBaseServiceManager);
@@ -42,6 +42,7 @@ export declare class AgenticChatController implements ChatHandlers {
42
42
  list: import("@aws/language-server-runtimes/protocol").DetailedListGroup[];
43
43
  }>;
44
44
  onMcpServerClick(params: McpServerClickParams): Promise<any>;
45
+ onListAvailableModels(params: ListAvailableModelsParams): Promise<ListAvailableModelsResult>;
45
46
  onChatPrompt(params: ChatParams, token: CancellationToken): Promise<ChatResult | ResponseError<ChatResult>>;
46
47
  truncatePinnedContext(remainingCharacterBudget: number, pinnedContext?: AdditionalContentEntryAddition[]): number;
47
48
  /**
@@ -38,12 +38,13 @@ const listDirectory_1 = require("./tools/listDirectory");
38
38
  const fsWrite_1 = require("./tools/fsWrite");
39
39
  const executeBash_1 = require("./tools/executeBash");
40
40
  const toolShared_1 = require("./tools/toolShared");
41
+ const pathValidation_1 = require("./utils/pathValidation");
41
42
  const grepSearch_1 = require("./tools/grepSearch");
42
43
  const fileSearch_1 = require("./tools/fileSearch");
43
44
  const fsReplace_1 = require("./tools/fsReplace");
44
45
  const lsp_core_2 = require("@aws/lsp-core");
45
46
  const diff_1 = require("diff");
46
- const constants_2 = require("./constants");
47
+ const constants_2 = require("./constants/constants");
47
48
  const errors_2 = require("./errors");
48
49
  const vscode_uri_1 = require("vscode-uri");
49
50
  const executeBash_2 = require("./tools/executeBash");
@@ -54,8 +55,10 @@ const mcpManager_1 = require("./tools/mcp/mcpManager");
54
55
  const mcpTool_1 = require("./tools/mcp/mcpTool");
55
56
  const paidTier_1 = require("../paidTier/paidTier");
56
57
  const util_1 = require("./tools/chatDb/util");
58
+ const modelSelection_1 = require("./constants/modelSelection");
57
59
  const imageVerification_1 = require("../../shared/imageVerification");
58
60
  const path_1 = require("@aws/lsp-core/out/util/path");
61
+ const agenticChatControllerHelper_1 = require("./utils/agenticChatControllerHelper");
59
62
  class AgenticChatController {
60
63
  #features;
61
64
  #chatSessionManagementService;
@@ -204,6 +207,10 @@ class AgenticChatController {
204
207
  }
205
208
  else {
206
209
  await this.#features.workspace.fs.rm(input.path);
210
+ void localProjectContextController_1.LocalProjectContextController.getInstance().then(controller => {
211
+ const filePath = vscode_uri_1.URI.file(input.path).fsPath;
212
+ return controller.updateIndexAndContextCommand([filePath], false);
213
+ });
207
214
  }
208
215
  }
209
216
  #updateUndoButtonAfterClick(tabId, toolUseId, session) {
@@ -267,7 +274,7 @@ class AgenticChatController {
267
274
  if (params.fileType === 'image') {
268
275
  // 1. Prompt user for file selection
269
276
  const supportedExtensions = imageVerification_1.DEFAULT_IMAGE_VERIFICATION_OPTIONS.supportedExtensions;
270
- const filters = { 'Image Files': supportedExtensions.map(ext => `*.${ext}`) };
277
+ const filters = { 'Image Files': supportedExtensions };
271
278
  const result = await this.#features.lsp.window.showOpenDialog({
272
279
  canSelectFiles: true,
273
280
  canSelectFolders: false,
@@ -287,7 +294,7 @@ class AgenticChatController {
287
294
  let errorMessage;
288
295
  for (const filePath of result.uris) {
289
296
  // Extract filename from the URI for error messages
290
- const fileName = filePath.split('/').pop() || '';
297
+ const fileName = path.basename(filePath) || '';
291
298
  const sanitizedPath = (0, path_1.sanitize)(filePath);
292
299
  // Get file size and content for verification
293
300
  const size = await this.#features.workspace.fs.getFileSize(sanitizedPath);
@@ -363,6 +370,7 @@ class AgenticChatController {
363
370
  this.#chatHistoryDb.close();
364
371
  this.#contextCommandsProvider?.dispose();
365
372
  this.#userWrittenCodeTracker?.dispose();
373
+ this.#mcpEventHandler.dispose();
366
374
  }
367
375
  async onListConversations(params) {
368
376
  return this.#tabBarController.onListConversations(params);
@@ -382,6 +390,28 @@ class AgenticChatController {
382
390
  async onMcpServerClick(params) {
383
391
  return this.#mcpEventHandler.onMcpServerClick(params);
384
392
  }
393
+ async onListAvailableModels(params) {
394
+ const region = AmazonQTokenServiceManager_1.AmazonQTokenServiceManager.getInstance().getRegion();
395
+ const models = region && modelSelection_1.MODEL_OPTIONS_FOR_REGION[region] ? modelSelection_1.MODEL_OPTIONS_FOR_REGION[region] : modelSelection_1.MODEL_OPTIONS;
396
+ const sessionResult = this.#chatSessionManagementService.getSession(params.tabId);
397
+ const { data: session, success } = sessionResult;
398
+ if (!success) {
399
+ return {
400
+ tabId: params.tabId,
401
+ models: models,
402
+ };
403
+ }
404
+ const savedModelId = this.#chatHistoryDb.getModelId();
405
+ const selectedModelId = savedModelId && models.some(model => model.id === savedModelId)
406
+ ? savedModelId
407
+ : (0, agenticChatControllerHelper_1.getLatestAvailableModel)(region).id;
408
+ session.modelId = selectedModelId;
409
+ return {
410
+ tabId: params.tabId,
411
+ models: models,
412
+ selectedModelId: selectedModelId,
413
+ };
414
+ }
385
415
  async #sendProgressToClient(chunk, partialResultToken) {
386
416
  if (!(0, utils_2.isNullish)(partialResultToken)) {
387
417
  await this.#features.lsp.sendProgress(protocol_1.chatRequestType, partialResultToken, chunk);
@@ -433,6 +463,9 @@ class AgenticChatController {
433
463
  await chatResultStream.updateOngoingProgressResult('Canceled');
434
464
  // Finally, send telemetry/metrics
435
465
  this.#telemetryController.emitInteractWithAgenticChat('StopChat', params.tabId, session.pairProgrammingMode, session.getConversationType());
466
+ metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version);
467
+ metric.setDimension('codewhispererCustomizationArn', this.#customizationArn);
468
+ metric.setDimension('enabled', session.pairProgrammingMode);
436
469
  await this.#telemetryController.emitAddMessageMetric(params.tabId, metric.metric, 'Cancelled');
437
470
  });
438
471
  session.setConversationType('AgenticChat');
@@ -455,6 +488,8 @@ class AgenticChatController {
455
488
  const contextItems = [...additionalContext, ...activeFile];
456
489
  triggerContext.documentReference = this.#additionalContextProvider.getFileListFromContext(contextItems);
457
490
  const customContext = await this.#additionalContextProvider.getImageBlocksFromContext(params.context, params.tabId);
491
+ // Add image context to triggerContext.documentReference for transparency
492
+ await this.#additionalContextProvider.appendCustomContextToTriggerContext(triggerContext, params.context, params.tabId);
458
493
  // Get the initial request input
459
494
  const initialRequestInput = await this.#prepareRequestInput(params, session, triggerContext, additionalContext, chatResultStream, customContext);
460
495
  // Generate a unique ID for this prompt
@@ -593,7 +628,7 @@ class AgenticChatController {
593
628
  this.#debug(`LLM Response Latency: ${llmLatency}`);
594
629
  // This is needed to handle the case where the response stream times out
595
630
  // and we want to auto-retry
596
- if (!result.success && result.error.startsWith(constants_2.responseTimeoutPartialMsg)) {
631
+ if (!result.success && result.error.startsWith(constants_2.RESPONSE_TIMEOUT_PARTIAL_MSG)) {
597
632
  const content = 'You took too long to respond - try to split up the work into smaller steps. Do not apologize.';
598
633
  if (this.#isPromptCanceled(token, session, promptId)) {
599
634
  // Only skip adding message to the history DB, continue executing to avoid unexpected stop for the conversation
@@ -648,7 +683,7 @@ class AgenticChatController {
648
683
  if (pendingToolUses.length === 0) {
649
684
  this.recordChunk('agent_loop_done');
650
685
  // No more tool uses, we're done
651
- this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChat', undefined, undefined, 'Succeeded', this.#features.runtime.serverInfo.version ?? '', llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode);
686
+ 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);
652
687
  finalResult = result;
653
688
  break;
654
689
  }
@@ -669,7 +704,7 @@ class AgenticChatController {
669
704
  metric.setDimension('requestIds', metric.metric.requestIds);
670
705
  const toolNames = this.#toolUseLatencies.map(item => item.toolName);
671
706
  const toolUseIds = this.#toolUseLatencies.map(item => item.toolUseId);
672
- this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChatWithToolUse', toolNames ?? undefined, toolUseIds ?? undefined, 'Succeeded', this.#features.runtime.serverInfo.version ?? '', llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode);
707
+ this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChatWithToolUse', toolNames ?? undefined, toolUseIds ?? undefined, 'Succeeded', this.#features.runtime.serverInfo.version ?? '', session.modelId, llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode);
673
708
  }
674
709
  else {
675
710
  // Send an error card to UI?
@@ -678,7 +713,7 @@ class AgenticChatController {
678
713
  status: codewhisperer_streaming_1.ToolResultStatus.ERROR,
679
714
  content: [{ text: result.error }],
680
715
  }));
681
- this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChatWithToolUse', undefined, undefined, 'Failed', this.#features.runtime.serverInfo.version ?? '', llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode);
716
+ this.#telemetryController.emitAgencticLoop_InvokeLLM(response.$metadata.requestId, conversationId, 'AgenticChatWithToolUse', undefined, undefined, 'Failed', this.#features.runtime.serverInfo.version ?? '', session.modelId, llmLatency, this.#toolCallLatencies, this.#timeToFirstChunk, this.#timeBetweenChunks, session.pairProgrammingMode);
682
717
  if (result.error.startsWith('ToolUse input is invalid JSON:')) {
683
718
  content =
684
719
  'Your toolUse input is incomplete, try again. If the error happens consistently, break this task down into multiple tool uses with smaller input. Do not apologize.';
@@ -724,7 +759,7 @@ class AgenticChatController {
724
759
  */
725
760
  truncateRequest(request, pinnedContext) {
726
761
  // TODO: Confirm if this limit applies to SendMessage and rename this constant
727
- let remainingCharacterBudget = constants_2.generateAssistantResponseInputLimit;
762
+ let remainingCharacterBudget = constants_2.GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT;
728
763
  if (!request?.conversationState?.currentMessage?.userInputMessage) {
729
764
  return remainingCharacterBudget;
730
765
  }
@@ -732,9 +767,9 @@ class AgenticChatController {
732
767
  // 1. prioritize user input message
733
768
  let truncatedUserInputMessage = '';
734
769
  if (message) {
735
- if (message.length > constants_2.generateAssistantResponseInputLimit) {
736
- this.#debug(`Truncating userInputMessage to ${constants_2.generateAssistantResponseInputLimit} characters}`);
737
- truncatedUserInputMessage = message.substring(0, constants_2.generateAssistantResponseInputLimit);
770
+ if (message.length > constants_2.GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT) {
771
+ this.#debug(`Truncating userInputMessage to ${constants_2.GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT} characters}`);
772
+ truncatedUserInputMessage = message.substring(0, constants_2.GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT);
738
773
  remainingCharacterBudget = remainingCharacterBudget - truncatedUserInputMessage.length;
739
774
  request.conversationState.currentMessage.userInputMessage.content = truncatedUserInputMessage;
740
775
  }
@@ -1135,7 +1170,7 @@ class AgenticChatController {
1135
1170
  #shouldSendBackErrorContent(toolResult) {
1136
1171
  if (toolResult.status === codewhisperer_streaming_1.ToolResultStatus.ERROR) {
1137
1172
  for (const content of toolResult.content ?? []) {
1138
- if (content.json && JSON.stringify(content.json).includes(constants_2.outputLimitExceedsPartialMsg)) {
1173
+ if (content.json && JSON.stringify(content.json).includes(constants_2.OUTPUT_LIMIT_EXCEEDS_PARTIAL_MSG)) {
1139
1174
  // do not send the content response back for this case to avoid unnecessary messages
1140
1175
  return false;
1141
1176
  }
@@ -1230,7 +1265,7 @@ class AgenticChatController {
1230
1265
  }
1231
1266
  if ((result.text && result.text.length > maxToolResponseSize) ||
1232
1267
  (result.json && JSON.stringify(result.json).length > maxToolResponseSize)) {
1233
- throw Error(`${toolUse.name} ${constants_2.outputLimitExceedsPartialMsg} ${maxToolResponseSize}`);
1268
+ throw Error(`${toolUse.name} ${constants_2.OUTPUT_LIMIT_EXCEEDS_PARTIAL_MSG} ${maxToolResponseSize}`);
1234
1269
  }
1235
1270
  }
1236
1271
  /**
@@ -1463,9 +1498,30 @@ class AgenticChatController {
1463
1498
  body = '```shell\n' + commandString;
1464
1499
  break;
1465
1500
  }
1466
- case 'fsReplace':
1467
1501
  case 'fsWrite': {
1468
1502
  const writeFilePath = toolUse.input.path;
1503
+ // Validate the path using our synchronous utility
1504
+ (0, pathValidation_1.validatePathBasic)(writeFilePath);
1505
+ this.#debug(`Processing ${toolUse.name} for path: ${writeFilePath}`);
1506
+ buttons = [{ id: 'allow-tools', text: 'Allow', icon: 'ok', status: 'clear' }];
1507
+ header = {
1508
+ icon: 'warning',
1509
+ iconForegroundStatus: 'warning',
1510
+ body: builtInPermission
1511
+ ? '#### Allow file modification'
1512
+ : '#### Allow file modification outside of your workspace',
1513
+ buttons,
1514
+ };
1515
+ body = builtInPermission
1516
+ ? `I need permission to modify files.\n\`${writeFilePath}\``
1517
+ : `I need permission to modify files outside of your workspace.\n\`${writeFilePath}\``;
1518
+ break;
1519
+ }
1520
+ case 'fsReplace': {
1521
+ const writeFilePath = toolUse.input.path;
1522
+ // For replace, we need to verify the file exists
1523
+ (0, pathValidation_1.validatePathExists)(writeFilePath);
1524
+ this.#debug(`Processing ${toolUse.name} for path: ${writeFilePath}`);
1469
1525
  buttons = [{ id: 'allow-tools', text: 'Allow', icon: 'ok', status: 'clear' }];
1470
1526
  header = {
1471
1527
  icon: 'warning',
@@ -1477,7 +1533,7 @@ class AgenticChatController {
1477
1533
  };
1478
1534
  body = builtInPermission
1479
1535
  ? `I need permission to modify files.\n\`${writeFilePath}\``
1480
- : `I need permission to modify files in your workspace.\n\`${writeFilePath}\``;
1536
+ : `I need permission to modify files outside of your workspace.\n\`${writeFilePath}\``;
1481
1537
  break;
1482
1538
  }
1483
1539
  case 'fsRead':
@@ -1493,6 +1549,9 @@ class AgenticChatController {
1493
1549
  };
1494
1550
  if (toolName === 'fsRead') {
1495
1551
  const paths = toolUse.input.paths;
1552
+ // Validate paths using our synchronous utility
1553
+ (0, pathValidation_1.validatePaths)(paths);
1554
+ this.#debug(`Processing ${toolUse.name} for paths: ${JSON.stringify(paths)}`);
1496
1555
  const formattedPaths = [];
1497
1556
  paths.forEach(element => formattedPaths.push(`\`${element}\``));
1498
1557
  body = builtInPermission
@@ -1501,6 +1560,9 @@ class AgenticChatController {
1501
1560
  }
1502
1561
  else {
1503
1562
  const readFilePath = toolUse.input.path;
1563
+ // Validate the path using our synchronous utility
1564
+ (0, pathValidation_1.validatePathExists)(readFilePath);
1565
+ this.#debug(`Processing ${toolUse.name} for path: ${readFilePath}`);
1504
1566
  body = builtInPermission
1505
1567
  ? `I need permission to list directories.\n\`${readFilePath}\``
1506
1568
  : `I need permission to list directories outside the workspace.\n\`${readFilePath}\``;
@@ -1716,7 +1778,7 @@ class AgenticChatController {
1716
1778
  */
1717
1779
  #updateRequestInputWithToolResults(requestInput, toolResults, content) {
1718
1780
  // Create a deep copy of the request input
1719
- const updatedRequestInput = JSON.parse(JSON.stringify(requestInput));
1781
+ const updatedRequestInput = structuredClone(requestInput);
1720
1782
  // Add tool results to the request
1721
1783
  updatedRequestInput.conversationState.currentMessage.userInputMessage.userInputMessageContext.toolResults =
1722
1784
  [];
@@ -1811,6 +1873,8 @@ class AgenticChatController {
1811
1873
  const requestID = (0, utils_2.getRequestID)(err) ?? '';
1812
1874
  metric.setDimension('cwsprChatResponseCode', (0, utils_2.getHttpStatusCode)(err) ?? 0);
1813
1875
  metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version);
1876
+ metric.setDimension('codewhispererCustomizationArn', this.#customizationArn);
1877
+ metric.setDimension('enabled', agenticCodingMode);
1814
1878
  metric.metric.requestIds = [requestID];
1815
1879
  metric.metric.cwsprChatMessageId = errorMessageId;
1816
1880
  metric.metric.cwsprChatConversationId = conversationId;
@@ -1841,7 +1905,7 @@ class AgenticChatController {
1841
1905
  this.#telemetryController.emitMessageResponseError(tabId, metric.metric, requestID, customErrMessage, agenticCodingMode);
1842
1906
  }
1843
1907
  else {
1844
- this.#telemetryController.emitMessageResponseError(tabId, metric.metric, requestID, errorMessage ?? constants_2.genericErrorMsg, agenticCodingMode);
1908
+ this.#telemetryController.emitMessageResponseError(tabId, metric.metric, requestID, errorMessage ?? constants_2.GENERIC_ERROR_MS, agenticCodingMode);
1845
1909
  }
1846
1910
  let authFollowType = undefined;
1847
1911
  // first check if there is an AmazonQ related auth follow up
@@ -1907,7 +1971,7 @@ class AgenticChatController {
1907
1971
  this.#features.logging.error(`Unknown Error: ${lsp_core_2.loggingUtils.formatErr(err)}`);
1908
1972
  return new server_interface_1.ResponseError(server_interface_1.LSPErrorCodes.RequestFailed, err.message, {
1909
1973
  type: 'answer',
1910
- body: requestID ? `${constants_2.genericErrorMsg} \n\nRequest ID: ${requestID}` : constants_2.genericErrorMsg,
1974
+ body: requestID ? `${constants_2.GENERIC_ERROR_MS} \n\nRequest ID: ${requestID}` : constants_2.GENERIC_ERROR_MS,
1911
1975
  messageId: errorMessageId,
1912
1976
  buttons: [],
1913
1977
  });
@@ -2099,11 +2163,13 @@ class AgenticChatController {
2099
2163
  });
2100
2164
  }
2101
2165
  onSourceLinkClick() { }
2102
- onTabAdd(params) {
2103
- this.#telemetryController.activeTabId = params.tabId;
2166
+ /**
2167
+ * @deprecated use aws/chat/listAvailableModels server request instead
2168
+ */
2169
+ #legacySetModelId(tabId, session) {
2104
2170
  // Since model selection is mandatory, the only time modelId is not set is when the chat history is empty.
2105
2171
  // In that case, we use the default modelId.
2106
- let modelId = this.#chatHistoryDb.getModelId() ?? constants_2.defaultModelId;
2172
+ let modelId = this.#chatHistoryDb.getModelId() ?? constants_2.DEFAULT_MODEL_ID;
2107
2173
  const region = AmazonQTokenServiceManager_1.AmazonQTokenServiceManager.getInstance().getRegion();
2108
2174
  if (region === 'eu-central-1') {
2109
2175
  // Only 3.7 Sonnet is available in eu-central-1 for now
@@ -2111,7 +2177,11 @@ class AgenticChatController {
2111
2177
  // @ts-ignore
2112
2178
  this.#features.chat.chatOptionsUpdate({ region });
2113
2179
  }
2114
- this.#features.chat.chatOptionsUpdate({ modelId: modelId, tabId: params.tabId });
2180
+ this.#features.chat.chatOptionsUpdate({ modelId: modelId, tabId: tabId });
2181
+ session.modelId = modelId;
2182
+ }
2183
+ onTabAdd(params) {
2184
+ this.#telemetryController.activeTabId = params.tabId;
2115
2185
  if (!params.restoredTab) {
2116
2186
  this.sendPinnedContext(params.tabId);
2117
2187
  }
@@ -2120,7 +2190,7 @@ class AgenticChatController {
2120
2190
  if (!success) {
2121
2191
  return new server_interface_1.ResponseError(protocol_2.ErrorCodes.InternalError, sessionResult.error);
2122
2192
  }
2123
- session.modelId = modelId;
2193
+ this.#legacySetModelId(params.tabId, session);
2124
2194
  // Get the saved pair programming mode from the database or default to true if not found
2125
2195
  const savedPairProgrammingMode = this.#chatHistoryDb.getPairProgrammingMode();
2126
2196
  session.pairProgrammingMode = savedPairProgrammingMode !== undefined ? savedPairProgrammingMode : true;
@@ -2486,8 +2556,8 @@ class AgenticChatController {
2486
2556
  const timeoutPromise = new Promise((_, reject) => {
2487
2557
  timeoutId = setTimeout(() => {
2488
2558
  abortController.abort();
2489
- reject(new errors_2.AgenticChatError(`${constants_2.responseTimeoutPartialMsg} ${constants_2.responseTimeoutMs}ms`, 'ResponseProcessingTimeout'));
2490
- }, constants_2.responseTimeoutMs);
2559
+ reject(new errors_2.AgenticChatError(`${constants_2.RESPONSE_TIMEOUT_PARTIAL_MSG} ${constants_2.RESPONSE_TIMEOUT_MS}ms`, 'ResponseProcessingTimeout'));
2560
+ }, constants_2.RESPONSE_TIMEOUT_MS);
2491
2561
  });
2492
2562
  const streamWriter = chatResultStream.getResultStreamWriter();
2493
2563
  const processResponsePromise = this.#processAgenticChatResponse(response, metric, chatResultStream, streamWriter, session, contextList, abortController.signal);
@@ -2622,6 +2692,10 @@ class AgenticChatController {
2622
2692
  * nothing is happening.
2623
2693
  */
2624
2694
  async #showLoadingIfRequired(toolUseEvent, streamWriter, toolUseStartTimes, toolUseLoadingTimeouts) {
2695
+ const canWrite = new Set(this.#features.agent.getBuiltInWriteToolNames());
2696
+ if (toolUseEvent.name && canWrite.has(toolUseEvent.name)) {
2697
+ return;
2698
+ }
2625
2699
  const toolUseId = toolUseEvent.toolUseId;
2626
2700
  if (!toolUseEvent.stop && toolUseId) {
2627
2701
  if (!toolUseStartTimes[toolUseId]) {
@@ -2632,9 +2706,9 @@ class AgenticChatController {
2632
2706
  }
2633
2707
  this.#debug(`ToolUseEvent ${toolUseId} started`);
2634
2708
  toolUseLoadingTimeouts[toolUseId] = setTimeout(async () => {
2635
- this.#debug(`ToolUseEvent ${toolUseId} is taking longer than ${constants_2.loadingThresholdMs}ms, showing loading indicator`);
2709
+ this.#debug(`ToolUseEvent ${toolUseId} is taking longer than ${constants_2.LOADING_THRESHOLD_MS}ms, showing loading indicator`);
2636
2710
  await streamWriter.write({ ...constants_1.loadingMessage, messageId: `loading-${toolUseId}` });
2637
- }, constants_2.loadingThresholdMs);
2711
+ }, constants_2.LOADING_THRESHOLD_MS);
2638
2712
  }
2639
2713
  }
2640
2714
  else if (toolUseEvent.stop && toolUseId) {