@aws/lsp-codewhisperer 0.0.66 → 0.0.67

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 (79) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +5 -0
  3. package/out/language-server/agenticChat/agenticChatController.d.ts +2 -2
  4. package/out/language-server/agenticChat/agenticChatController.js +109 -34
  5. package/out/language-server/agenticChat/agenticChatController.js.map +1 -1
  6. package/out/language-server/agenticChat/constants/constants.d.ts +5 -0
  7. package/out/language-server/agenticChat/constants/constants.js +7 -1
  8. package/out/language-server/agenticChat/constants/constants.js.map +1 -1
  9. package/out/language-server/agenticChat/context/additionalContextProvider.d.ts +9 -1
  10. package/out/language-server/agenticChat/context/additionalContextProvider.js +55 -32
  11. package/out/language-server/agenticChat/context/additionalContextProvider.js.map +1 -1
  12. package/out/language-server/agenticChat/context/agenticChatTriggerContext.js +4 -0
  13. package/out/language-server/agenticChat/context/agenticChatTriggerContext.js.map +1 -1
  14. package/out/language-server/agenticChat/qAgenticChatServer.d.ts +2 -0
  15. package/out/language-server/agenticChat/qAgenticChatServer.js +18 -2
  16. package/out/language-server/agenticChat/qAgenticChatServer.js.map +1 -1
  17. package/out/language-server/agenticChat/tools/chatDb/chatDb.js +14 -2
  18. package/out/language-server/agenticChat/tools/chatDb/chatDb.js.map +1 -1
  19. package/out/language-server/agenticChat/tools/chatDb/util.d.ts +11 -1
  20. package/out/language-server/agenticChat/tools/chatDb/util.js +17 -0
  21. package/out/language-server/agenticChat/tools/chatDb/util.js.map +1 -1
  22. package/out/language-server/agenticChat/tools/executeBash.d.ts +0 -5
  23. package/out/language-server/agenticChat/tools/executeBash.js +11 -14
  24. package/out/language-server/agenticChat/tools/executeBash.js.map +1 -1
  25. package/out/language-server/agenticChat/tools/grepSearch.js +3 -1
  26. package/out/language-server/agenticChat/tools/grepSearch.js.map +1 -1
  27. package/out/language-server/agenticChat/tools/mcp/mcpEventHandler.js +208 -170
  28. package/out/language-server/agenticChat/tools/mcp/mcpEventHandler.js.map +1 -1
  29. package/out/language-server/agenticChat/tools/mcp/mcpManager.d.ts +12 -18
  30. package/out/language-server/agenticChat/tools/mcp/mcpManager.js +353 -216
  31. package/out/language-server/agenticChat/tools/mcp/mcpManager.js.map +1 -1
  32. package/out/language-server/agenticChat/tools/mcp/mcpTypes.d.ts +29 -0
  33. package/out/language-server/agenticChat/tools/mcp/mcpTypes.js +60 -1
  34. package/out/language-server/agenticChat/tools/mcp/mcpTypes.js.map +1 -1
  35. package/out/language-server/agenticChat/tools/mcp/mcpUtils.d.ts +27 -4
  36. package/out/language-server/agenticChat/tools/mcp/mcpUtils.js +464 -2
  37. package/out/language-server/agenticChat/tools/mcp/mcpUtils.js.map +1 -1
  38. package/out/language-server/agenticChat/tools/toolServer.js +8 -10
  39. package/out/language-server/agenticChat/tools/toolServer.js.map +1 -1
  40. package/out/language-server/agenticChat/tools/toolShared.js +6 -2
  41. package/out/language-server/agenticChat/tools/toolShared.js.map +1 -1
  42. package/out/language-server/chat/chatController.d.ts +1 -1
  43. package/out/language-server/chat/chatController.js.map +1 -1
  44. package/out/language-server/chat/contexts/triggerContext.js +11 -2
  45. package/out/language-server/chat/contexts/triggerContext.js.map +1 -1
  46. package/out/language-server/configuration/qConfigurationServer.d.ts +2 -0
  47. package/out/language-server/configuration/qConfigurationServer.js.map +1 -1
  48. package/out/language-server/inline-completion/auto-trigger/autoTrigger.d.ts +1 -0
  49. package/out/language-server/inline-completion/auto-trigger/autoTrigger.js +36 -0
  50. package/out/language-server/inline-completion/auto-trigger/autoTrigger.js.map +1 -1
  51. package/out/language-server/inline-completion/codeWhispererServer.js +25 -36
  52. package/out/language-server/inline-completion/codeWhispererServer.js.map +1 -1
  53. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.d.ts +4 -1
  54. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js +36 -2
  55. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js.map +1 -1
  56. package/out/language-server/workspaceContext/dependency/dependencyEventBundler.d.ts +11 -5
  57. package/out/language-server/workspaceContext/dependency/dependencyEventBundler.js +37 -10
  58. package/out/language-server/workspaceContext/dependency/dependencyEventBundler.js.map +1 -1
  59. package/out/language-server/workspaceContext/dependency/dependencyHandler/JSTSDependencyHandler.d.ts +1 -1
  60. package/out/language-server/workspaceContext/dependency/dependencyHandler/JSTSDependencyHandler.js +8 -3
  61. package/out/language-server/workspaceContext/dependency/dependencyHandler/JSTSDependencyHandler.js.map +1 -1
  62. package/out/language-server/workspaceContext/dependency/dependencyHandler/JavaDependencyHandler.js +3 -4
  63. package/out/language-server/workspaceContext/dependency/dependencyHandler/JavaDependencyHandler.js.map +1 -1
  64. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.d.ts +4 -3
  65. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js +5 -9
  66. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js.map +1 -1
  67. package/out/language-server/workspaceContext/dependency/dependencyHandler/PythonDependencyHandler.js +3 -4
  68. package/out/language-server/workspaceContext/dependency/dependencyHandler/PythonDependencyHandler.js.map +1 -1
  69. package/out/language-server/workspaceContext/workspaceContextServer.js +12 -8
  70. package/out/language-server/workspaceContext/workspaceContextServer.js.map +1 -1
  71. package/out/shared/amazonQServiceManager/configurationUtils.d.ts +4 -0
  72. package/out/shared/amazonQServiceManager/configurationUtils.js +6 -0
  73. package/out/shared/amazonQServiceManager/configurationUtils.js.map +1 -1
  74. package/out/shared/streamingClientService.js +12 -1
  75. package/out/shared/streamingClientService.js.map +1 -1
  76. package/out/shared/utils.d.ts +1 -7
  77. package/out/shared/utils.js +39 -36
  78. package/out/shared/utils.js.map +1 -1
  79. package/package.json +2 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.67](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.66...lsp-codewhisperer/v0.0.67) (2025-07-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * adding extra context as a workspace config for inline chat ([#1942](https://github.com/aws/language-servers/issues/1942)) ([1b402bb](https://github.com/aws/language-servers/commit/1b402bb8b083c5505a4e13ecf7e097a43388d10b))
9
+ * **chat-client:** add auto-approve (trust mode) for built-in tools ([#1949](https://github.com/aws/language-servers/issues/1949)) ([f17b631](https://github.com/aws/language-servers/commit/f17b631d9e06371a11ef8e9cb1413762fb51a143))
10
+ * **chat-client:** add shortcut for stop/reject/run commands ([#1932](https://github.com/aws/language-servers/issues/1932)) ([087f338](https://github.com/aws/language-servers/commit/087f3387ba736e92d014274e195f7ef76e377f1e))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **amazonq:** add image context to chat history ([#1859](https://github.com/aws/language-servers/issues/1859)) ([788920b](https://github.com/aws/language-servers/commit/788920bdd2de0448fd335734b62ac80aba9cff82))
16
+ * **amazonq:** avoid workspace context server missing historical dependency events ([#1946](https://github.com/aws/language-servers/issues/1946)) ([3362956](https://github.com/aws/language-servers/commit/3362956ded75d77296fa98abb172bd87d66e5d5e))
17
+ * **amazonq:** continueous edits trigger returns earlier as first session is already closed ([#1907](https://github.com/aws/language-servers/issues/1907)) ([a2dc5a8](https://github.com/aws/language-servers/commit/a2dc5a87e488e523c12270b98749c1f835b55e87))
18
+ * **amazonq:** fix for mcp server unnecessary refresh from file watchers ([#1933](https://github.com/aws/language-servers/issues/1933)) ([208909b](https://github.com/aws/language-servers/commit/208909b55ecda40ff8d412b2b3be890eccee70bc))
19
+ * **amazonq:** make JSTSDependencyHandler process scoped packages correctly ([#1910](https://github.com/aws/language-servers/issues/1910)) ([3034494](https://github.com/aws/language-servers/commit/303449454254987047649c49b7a377d45ad284b6))
20
+ * **amazonq:** update mcp and persona config to agent config ([#1897](https://github.com/aws/language-servers/issues/1897)) ([530977f](https://github.com/aws/language-servers/commit/530977f8c73c7946a0205f02014248d71b4b1fe0))
21
+ * bug for credential refresh in StreamingClientServiceIAM ([#1944](https://github.com/aws/language-servers/issues/1944)) ([a69ec0c](https://github.com/aws/language-servers/commit/a69ec0c63423187c96bdd2b03d14da8a723c192e))
22
+ * fix blocking regex calls being made before indexing ([#1916](https://github.com/aws/language-servers/issues/1916)) ([3c0592f](https://github.com/aws/language-servers/commit/3c0592fec53922b0493f51b7e88313971cb54e93))
23
+ * fix to remove config from agent file for failed initialization ([#1948](https://github.com/aws/language-servers/issues/1948)) ([45645c2](https://github.com/aws/language-servers/commit/45645c2cd7c241c54ddfebced6f377f38e077957))
24
+ * Make the classifier of auto trigger output the same score as the IDE auto trigger classifier ([#1930](https://github.com/aws/language-servers/issues/1930)) ([be3231f](https://github.com/aws/language-servers/commit/be3231f27d545daf137df149e5f9fd23042c82a9))
25
+ * put compaction feature behind a feature flag ([#1945](https://github.com/aws/language-servers/issues/1945)) ([51f4161](https://github.com/aws/language-servers/commit/51f4161571679408d6b11b61d70d8027097a6ef6))
26
+ * remove hardcoded EDITS predictionTypes for trigger on acceptance ([#1937](https://github.com/aws/language-servers/issues/1937)) ([8ef7986](https://github.com/aws/language-servers/commit/8ef7986424dc4ced8e7414c1378dfca872150fb4))
27
+ * replace cancel with stop ([#1935](https://github.com/aws/language-servers/issues/1935)) ([2f51923](https://github.com/aws/language-servers/commit/2f51923f9d3497469c70162235482b569e2d796e))
28
+ * update ChatHandlers before adding new types dependency ([#1925](https://github.com/aws/language-servers/issues/1925)) ([e94e581](https://github.com/aws/language-servers/commit/e94e581a00fb99d862527ee7b91bf37ef47f4013))
29
+
3
30
  ## [0.0.66](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.65...lsp-codewhisperer/v0.0.66) (2025-07-17)
4
31
 
5
32
 
package/README.md CHANGED
@@ -102,6 +102,8 @@ The server supports the following [workspace configurations](https://github.com/
102
102
  - This flag controls whether to opt-in or opt-out to telemetry.
103
103
  - `aws.q.inlineSuggestions.extraContext` (type: `string | undefined`, default: `undefined`)
104
104
  - The extra context to be included for suggestions, an empty string will be interpreted as undefined. See [below](#extra-context-for-q-inline-suggestions) for more context.
105
+ - `aws.q.inlineChat.extraContext` (type: `string | undefined`, default: `undefined`)
106
+ - The extra context to be included for inline chat, an empty string will be interpreted as undefined. See [below](#extra-context-for-q-inline-chat) for more context.
105
107
  - `aws.codeWhisperer.includeSuggestionsWithCodeReferences`: (type: `boolean`, default: `false`)
106
108
  - This flag controls whether to include references with code suggestions.
107
109
  - `aws.codeWhisperer.shareCodeWhispererContentWithAWS`: (type: `boolean`, default: `false`)
@@ -111,3 +113,6 @@ The client can signal updates to the workspace configuration with the `DidChange
111
113
 
112
114
  #### Extra context for Q Inline Suggestions
113
115
  In cases when the client runs in a specific environment that requires customized suggestions, the server supports a `aws.q.inlineSuggestions.extraContext` workspace configuration. This extra context will be passed to the left file content of the request in the beginning of the file.
116
+
117
+ #### Extra context for Q Inline Chat
118
+ In cases when the client runs in a specific environment that requires customized inline chat responses, the server supports a `aws.q.inlineChat.extraContext` workspace configuration. This extra context will be prepended to the document text of the request, similar to how inline suggestions work.
@@ -17,7 +17,7 @@ import { AgenticChatResultStream } from './agenticChatResultStream';
17
17
  import { AdditionalContentEntryAddition } from './context/agenticChatTriggerContext';
18
18
  import { PaidTierMode } from '../paidTier/paidTier';
19
19
  import { UserContext } from '../../client/token/codewhispererbearertokenclient';
20
- type ChatHandlers = Omit<LspHandlers<Chat>, 'openTab' | 'sendChatUpdate' | 'sendContextCommands' | 'onListConversations' | 'onConversationClick' | 'onListMcpServers' | 'onMcpServerClick' | 'onTabBarAction' | 'getSerializedChat' | 'chatOptionsUpdate' | 'onListRules' | 'sendPinnedContext' | 'onActiveEditorChanged' | 'onPinnedContextAdd' | 'onPinnedContextRemove' | 'onOpenFileDialog' | 'onListAvailableModels'>;
20
+ type ChatHandlers = Omit<LspHandlers<Chat>, 'openTab' | 'sendChatUpdate' | 'sendContextCommands' | 'onListConversations' | 'onConversationClick' | 'onListMcpServers' | 'onMcpServerClick' | 'onTabBarAction' | 'getSerializedChat' | 'chatOptionsUpdate' | 'onListRules' | 'sendPinnedContext' | 'onActiveEditorChanged' | 'onPinnedContextAdd' | 'onPinnedContextRemove' | 'onOpenFileDialog' | 'onListAvailableModels' | 'sendSubscriptionDetails' | 'onSubscriptionUpgrade'>;
21
21
  export declare class AgenticChatController implements ChatHandlers {
22
22
  #private;
23
23
  /**
@@ -55,7 +55,7 @@ export declare class AgenticChatController implements ChatHandlers {
55
55
  * Returns the remaining character budget for chat history.
56
56
  * @param request
57
57
  */
58
- truncateRequest(request: ChatCommandInput, pinnedContext?: AdditionalContentEntryAddition[]): number;
58
+ truncateRequest(request: ChatCommandInput, additionalContext?: AdditionalContentEntryAddition[]): number;
59
59
  /**
60
60
  * Creates a promise that does not resolve until the user accepts or rejects the tool usage.
61
61
  * @param toolUseId
@@ -64,6 +64,7 @@ const imageVerification_1 = require("../../shared/imageVerification");
64
64
  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
+ const qAgenticChatServer_1 = require("./qAgenticChatServer");
67
68
  class AgenticChatController {
68
69
  #features;
69
70
  #chatSessionManagementService;
@@ -540,8 +541,6 @@ class AgenticChatController {
540
541
  const contextItems = [...additionalContext, ...activeFile];
541
542
  triggerContext.documentReference = this.#additionalContextProvider.getFileListFromContext(contextItems);
542
543
  const customContext = await this.#additionalContextProvider.getImageBlocksFromContext(params.context, params.tabId);
543
- // Add image context to triggerContext.documentReference for transparency
544
- await this.#additionalContextProvider.appendCustomContextToTriggerContext(triggerContext, params.context, params.tabId);
545
544
  let finalResult;
546
545
  if (params.prompt.command === quickActions_1.QuickAction.Compact) {
547
546
  // Get the compaction request input
@@ -559,7 +558,7 @@ class AgenticChatController {
559
558
  const promptId = crypto.randomUUID();
560
559
  session.setCurrentPromptId(promptId);
561
560
  // Start the agent loop
562
- finalResult = await this.#runAgentLoop(initialRequestInput, session, metric, chatResultStream, params.tabId, promptId, session.conversationId, token, triggerContext.documentReference, additionalContext.filter(item => item.pinned));
561
+ finalResult = await this.#runAgentLoop(initialRequestInput, session, metric, chatResultStream, params.tabId, promptId, session.conversationId, token, triggerContext.documentReference, additionalContext);
563
562
  }
564
563
  // Result Handling - This happens only once
565
564
  return await this.#handleFinalResult(finalResult, session, params.tabId, metric, triggerContext, isNewConversation, chatResultStream);
@@ -594,11 +593,11 @@ class AgenticChatController {
594
593
  /**
595
594
  * Prepares the initial request input for the chat prompt
596
595
  */
597
- async #prepareRequestInput(params, session, triggerContext, additionalContext, chatResultStream, customContext) {
596
+ async #prepareRequestInput(params, session, triggerContext, additionalContext, chatResultStream, images) {
598
597
  this.#debug('Preparing request input');
599
598
  // Get profileArn from the service manager if available
600
599
  const profileArn = this.#serviceManager?.getActiveProfileArn();
601
- const requestInput = await this.#triggerContext.getChatParamsFromTrigger(params, triggerContext, codewhisperer_streaming_1.ChatTriggerType.MANUAL, this.#customizationArn, chatResultStream, profileArn, this.#getTools(session), additionalContext, session.modelId, this.#origin, customContext);
600
+ const requestInput = await this.#triggerContext.getChatParamsFromTrigger(params, triggerContext, codewhisperer_streaming_1.ChatTriggerType.MANUAL, this.#customizationArn, chatResultStream, profileArn, this.#getTools(session), additionalContext, session.modelId, this.#origin, images);
602
601
  return requestInput;
603
602
  }
604
603
  /**
@@ -616,7 +615,7 @@ class AgenticChatController {
616
615
  */
617
616
  #shouldCompact(currentRequestCount) {
618
617
  // 80% of 570K limit
619
- if (currentRequestCount > 456_000) {
618
+ if ((0, qAgenticChatServer_1.enabledCompaction)(this.#features.lsp.getClientInitializeParams()) && currentRequestCount > 456_000) {
620
619
  this.#debug(`Current request total character count is: ${currentRequestCount}, prompting user to compact`);
621
620
  return true;
622
621
  }
@@ -726,12 +725,13 @@ class AgenticChatController {
726
725
  /**
727
726
  * Runs the agent loop, making requests and processing tool uses until completion
728
727
  */
729
- async #runAgentLoop(initialRequestInput, session, metric, chatResultStream, tabId, promptId, conversationIdentifier, token, documentReference, pinnedContext) {
728
+ async #runAgentLoop(initialRequestInput, session, metric, chatResultStream, tabId, promptId, conversationIdentifier, token, documentReference, additionalContext) {
730
729
  let currentRequestInput = { ...initialRequestInput };
731
730
  let finalResult = null;
732
731
  let iterationCount = 0;
733
732
  let shouldDisplayMessage = true;
734
733
  let currentRequestCount = 0;
734
+ const pinnedContext = additionalContext?.filter(item => item.pinned);
735
735
  metric.recordStart();
736
736
  this.logSystemInformation();
737
737
  while (true) {
@@ -745,7 +745,7 @@ class AgenticChatController {
745
745
  this.#debug('Stopping agent loop - cancelled by user');
746
746
  throw new lsp_core_1.CancellationError('user');
747
747
  }
748
- this.truncateRequest(currentRequestInput, pinnedContext);
748
+ this.truncateRequest(currentRequestInput, additionalContext);
749
749
  const currentMessage = currentRequestInput.conversationState?.currentMessage;
750
750
  const conversationId = conversationIdentifier ?? '';
751
751
  if (!currentMessage || !conversationId) {
@@ -807,6 +807,7 @@ class AgenticChatController {
807
807
  shouldDisplayMessage: shouldDisplayMessage &&
808
808
  !currentMessage.userInputMessage?.content?.startsWith('You are Amazon Q'),
809
809
  timestamp: new Date(),
810
+ images: currentMessage.userInputMessage?.images,
810
811
  });
811
812
  }
812
813
  }
@@ -959,7 +960,7 @@ class AgenticChatController {
959
960
  * Returns the remaining character budget for chat history.
960
961
  * @param request
961
962
  */
962
- truncateRequest(request, pinnedContext) {
963
+ truncateRequest(request, additionalContext) {
963
964
  // TODO: Confirm if this limit applies to SendMessage and rename this constant
964
965
  let remainingCharacterBudget = constants_2.GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT;
965
966
  if (!request?.conversationState?.currentMessage?.userInputMessage) {
@@ -979,20 +980,63 @@ class AgenticChatController {
979
980
  remainingCharacterBudget = remainingCharacterBudget - message.length;
980
981
  }
981
982
  }
982
- // 2. try to fit @context into budget
983
- let truncatedRelevantDocuments = [];
984
- if (request.conversationState.currentMessage.userInputMessage.userInputMessageContext?.editorState
985
- ?.relevantDocuments) {
986
- for (const relevantDoc of request.conversationState.currentMessage.userInputMessage.userInputMessageContext
987
- ?.editorState?.relevantDocuments) {
988
- const docLength = relevantDoc?.text?.length || 0;
989
- if (remainingCharacterBudget > docLength) {
990
- truncatedRelevantDocuments.push(relevantDoc);
991
- remainingCharacterBudget = remainingCharacterBudget - docLength;
983
+ // 2. try to fit @context and images into budget together
984
+ const docs = request.conversationState.currentMessage.userInputMessage.userInputMessageContext?.editorState
985
+ ?.relevantDocuments ?? [];
986
+ const images = request.conversationState.currentMessage.userInputMessage.images ?? [];
987
+ // Combine docs and images, preserving the order from additionalContext
988
+ let combined;
989
+ if (additionalContext && additionalContext.length > 0) {
990
+ let docIdx = 0;
991
+ let imageIdx = 0;
992
+ combined = additionalContext
993
+ .map(entry => {
994
+ if (entry.type === 'image') {
995
+ return { type: 'image', value: images[imageIdx++] };
996
+ }
997
+ else {
998
+ return { type: 'doc', value: docs[docIdx++] };
999
+ }
1000
+ })
1001
+ .filter(item => item.value !== undefined);
1002
+ }
1003
+ else {
1004
+ combined = [
1005
+ ...docs.map(d => ({ type: 'doc', value: d })),
1006
+ ...images.map(i => ({ type: 'image', value: i })),
1007
+ ];
1008
+ }
1009
+ const truncatedDocs = [];
1010
+ const truncatedImages = [];
1011
+ for (const item of combined) {
1012
+ let itemLength = 0;
1013
+ if (item.type === 'doc') {
1014
+ itemLength = item.value?.text?.length || 0;
1015
+ if (remainingCharacterBudget >= itemLength) {
1016
+ truncatedDocs.push(item.value);
1017
+ remainingCharacterBudget -= itemLength;
1018
+ }
1019
+ }
1020
+ else if (item.type === 'image') {
1021
+ // Type guard: only call on ImageBlock
1022
+ if (item.value && typeof item.value === 'object' && 'format' in item.value && 'source' in item.value) {
1023
+ itemLength = (0, util_1.estimateCharacterCountFromImageBlock)(item.value);
1024
+ if (remainingCharacterBudget >= itemLength) {
1025
+ truncatedImages.push(item.value);
1026
+ remainingCharacterBudget -= itemLength;
1027
+ }
992
1028
  }
993
1029
  }
1030
+ }
1031
+ // Assign truncated lists back to request
1032
+ if (request.conversationState.currentMessage.userInputMessage.userInputMessageContext?.editorState
1033
+ ?.relevantDocuments) {
994
1034
  request.conversationState.currentMessage.userInputMessage.userInputMessageContext.editorState.relevantDocuments =
995
- truncatedRelevantDocuments;
1035
+ truncatedDocs;
1036
+ }
1037
+ if (request.conversationState.currentMessage.userInputMessage.images !== undefined &&
1038
+ request.conversationState.currentMessage.userInputMessage.images.length > 0) {
1039
+ request.conversationState.currentMessage.userInputMessage.images = truncatedImages;
996
1040
  }
997
1041
  // 3. try to fit current file context
998
1042
  let truncatedCurrentDocument = undefined;
@@ -1008,6 +1052,7 @@ class AgenticChatController {
1008
1052
  request.conversationState.currentMessage.userInputMessage.userInputMessageContext.editorState.document =
1009
1053
  truncatedCurrentDocument;
1010
1054
  }
1055
+ const pinnedContext = additionalContext?.filter(item => item.pinned);
1011
1056
  // 4. try to fit pinned context into budget
1012
1057
  if (pinnedContext && pinnedContext.length > 0) {
1013
1058
  remainingCharacterBudget = this.truncatePinnedContext(remainingCharacterBudget, pinnedContext);
@@ -1096,24 +1141,35 @@ class AgenticChatController {
1096
1141
  const { Tool } = toolMap[toolUse.name];
1097
1142
  const tool = new Tool(this.#features);
1098
1143
  // For MCP tools, get the permission from McpManager
1099
- // const permission = McpManager.instance.getToolPerm('Built-in', toolUse.name)
1144
+ const permission = mcpManager_1.McpManager.instance.getToolPerm('Built-in', toolUse.name);
1100
1145
  // If permission is 'alwaysAllow', we don't need to ask for acceptance
1101
- // const builtInPermission = permission !== 'alwaysAllow'
1146
+ const builtInPermission = permission !== 'alwaysAllow';
1102
1147
  // Get the approved paths from the session
1103
1148
  const approvedPaths = session.approvedPaths;
1104
1149
  // Pass the approved paths to the tool's requiresAcceptance method
1105
1150
  const { requiresAcceptance, warning, commandCategory } = await tool.requiresAcceptance(toolUse.input, approvedPaths);
1151
+ const isExecuteBash = toolUse.name === toolConstants_1.EXECUTE_BASH;
1152
+ // check if tool execution's path is out of workspace
1153
+ const isOutOfWorkSpace = warning === constants_2.OUT_OF_WORKSPACE_WARNING_MSG;
1154
+ // check if tool involved secured files
1155
+ const isSecuredFilesInvoled = warning === constants_2.BINARY_FILE_WARNING_MSG || warning === constants_2.CREDENTIAL_FILE_WARNING_MSG;
1106
1156
  // Honor built-in permission if available, otherwise use tool's requiresAcceptance
1107
- // const requiresAcceptance = builtInPermission || toolRequiresAcceptance
1108
- if (requiresAcceptance || toolUse.name === toolConstants_1.EXECUTE_BASH) {
1157
+ let toolRequiresAcceptance = (builtInPermission || isOutOfWorkSpace || isSecuredFilesInvoled) ?? requiresAcceptance;
1158
+ // if the command is read-only and in-workspace --> flip back to no approval needed
1159
+ if (isExecuteBash &&
1160
+ commandCategory === executeBash_2.CommandCategory.ReadOnly &&
1161
+ !isOutOfWorkSpace &&
1162
+ !requiresAcceptance) {
1163
+ toolRequiresAcceptance = false;
1164
+ }
1165
+ if (toolRequiresAcceptance || isExecuteBash) {
1109
1166
  // for executeBash, we till send the confirmation message without action buttons
1110
- const confirmationResult = this.#processToolConfirmation(toolUse, requiresAcceptance, warning, commandCategory);
1167
+ const confirmationResult = this.#processToolConfirmation(toolUse, toolRequiresAcceptance, warning, commandCategory, toolUse.name, builtInPermission);
1111
1168
  cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult);
1112
- const isExecuteBash = toolUse.name === toolConstants_1.EXECUTE_BASH;
1113
1169
  if (isExecuteBash) {
1114
1170
  this.#telemetryController.emitInteractWithAgenticChat('GeneratedCommand', tabId, session.pairProgrammingMode, session.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
1115
1171
  }
1116
- if (requiresAcceptance) {
1172
+ if (toolRequiresAcceptance) {
1117
1173
  await this.waitForToolApproval(toolUse, chatResultStream, cachedButtonBlockId, session, toolUse.name);
1118
1174
  }
1119
1175
  if (isExecuteBash) {
@@ -1551,7 +1607,7 @@ class AgenticChatController {
1551
1607
  let headerEmitted = false;
1552
1608
  const initialHeader = {
1553
1609
  body: 'shell',
1554
- buttons: [{ id: toolConstants_1.BUTTON_STOP_SHELL_COMMAND, text: 'Cancel', icon: 'stop' }],
1610
+ buttons: [this.#renderStopShellCommandButton()],
1555
1611
  };
1556
1612
  const completedHeader = {
1557
1613
  body: 'shell',
@@ -1615,7 +1671,7 @@ class AgenticChatController {
1615
1671
  text: 'Rejected',
1616
1672
  },
1617
1673
  }),
1618
- buttons: isAccept ? [{ id: toolConstants_1.BUTTON_STOP_SHELL_COMMAND, text: 'Cancel', icon: 'stop' }] : [],
1674
+ buttons: isAccept ? [this.#renderStopShellCommandButton()] : [],
1619
1675
  },
1620
1676
  };
1621
1677
  }
@@ -1703,7 +1759,7 @@ class AgenticChatController {
1703
1759
  status: {
1704
1760
  status: 'error',
1705
1761
  icon: 'stop',
1706
- text: 'Canceled',
1762
+ text: 'Stopped',
1707
1763
  },
1708
1764
  buttons: [],
1709
1765
  },
@@ -1768,8 +1824,8 @@ class AgenticChatController {
1768
1824
  #renderStopShellCommandButton() {
1769
1825
  const stopKey = this.#getKeyBinding('aws.amazonq.stopCmdExecution');
1770
1826
  return {
1771
- id: 'stop-shell-command',
1772
- text: 'Cancel',
1827
+ id: toolConstants_1.BUTTON_STOP_SHELL_COMMAND,
1828
+ text: 'Stop',
1773
1829
  icon: 'stop',
1774
1830
  ...(stopKey ? { description: `Stop: ${stopKey}` } : {}),
1775
1831
  };
@@ -1812,14 +1868,25 @@ class AgenticChatController {
1812
1868
  switch (toolName) {
1813
1869
  case toolConstants_1.EXECUTE_BASH: {
1814
1870
  const commandString = toolUse.input.command;
1871
+ // get feature flag
1872
+ const shortcut = this.#features.lsp.getClientInitializeParams()?.initializationOptions?.aws?.awsClientCapabilities?.q
1873
+ ?.shortcut;
1874
+ const runKey = this.#getKeyBinding('aws.amazonq.runCmdExecution');
1875
+ const rejectKey = this.#getKeyBinding('aws.amazonq.rejectCmdExecution');
1815
1876
  buttons = requiresAcceptance
1816
1877
  ? [
1817
- { id: toolConstants_1.BUTTON_RUN_SHELL_COMMAND, text: 'Run', icon: 'play' },
1878
+ {
1879
+ id: toolConstants_1.BUTTON_RUN_SHELL_COMMAND,
1880
+ text: 'Run',
1881
+ icon: 'play',
1882
+ ...(runKey ? { description: `Run: ${runKey}` } : {}),
1883
+ },
1818
1884
  {
1819
1885
  id: toolConstants_1.BUTTON_REJECT_SHELL_COMMAND,
1820
1886
  status: 'dimmed-clear',
1821
1887
  text: 'Reject',
1822
1888
  icon: 'cancel',
1889
+ ...(rejectKey ? { description: `Reject: ${rejectKey}` } : {}),
1823
1890
  },
1824
1891
  ]
1825
1892
  : [];
@@ -1908,7 +1975,7 @@ class AgenticChatController {
1908
1975
  ? `I need permission to read files.\n${formattedPaths.join('\n')}`
1909
1976
  : `I need permission to read files outside the workspace.\n${formattedPaths.join('\n')}`;
1910
1977
  }
1911
- else {
1978
+ else if (toolName === 'listDirectory') {
1912
1979
  const readFilePath = toolUse.input.path;
1913
1980
  // Validate the path using our synchronous utility
1914
1981
  (0, pathValidation_1.validatePathExists)(readFilePath);
@@ -1917,6 +1984,12 @@ class AgenticChatController {
1917
1984
  ? `I need permission to list directories.\n\`${readFilePath}\``
1918
1985
  : `I need permission to list directories outside the workspace.\n\`${readFilePath}\``;
1919
1986
  }
1987
+ else {
1988
+ const readFilePath = toolUse.input.path;
1989
+ body = builtInPermission
1990
+ ? `I need permission to search files.\n\`${readFilePath}\``
1991
+ : `I need permission to search files outside the workspace.\n\`${readFilePath}\``;
1992
+ }
1920
1993
  break;
1921
1994
  }
1922
1995
  default: {
@@ -2143,6 +2216,8 @@ class AgenticChatController {
2143
2216
  cursorState: undefined,
2144
2217
  useRelevantDocuments: false,
2145
2218
  };
2219
+ // Clear images to avoid passing them again in follow-up toolUse/toolResult loops, as it is may confuse the model
2220
+ updatedRequestInput.conversationState.currentMessage.userInputMessage.images = [];
2146
2221
  for (const toolResult of toolResults) {
2147
2222
  this.#debug(`ToolResult: ${JSON.stringify(toolResult)}`);
2148
2223
  updatedRequestInput.conversationState.currentMessage.userInputMessage.userInputMessageContext.toolResults.push({