@aws/lsp-codewhisperer 0.0.63 → 0.0.65

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 (75) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/out/client/token/bearer-token-service.json +1 -1
  3. package/out/language-server/agenticChat/agenticChatController.d.ts +6 -0
  4. package/out/language-server/agenticChat/agenticChatController.js +137 -12
  5. package/out/language-server/agenticChat/agenticChatController.js.map +1 -1
  6. package/out/language-server/agenticChat/context/additionalContextProvider.d.ts +1 -1
  7. package/out/language-server/agenticChat/context/additionalContextProvider.js +8 -3
  8. package/out/language-server/agenticChat/context/additionalContextProvider.js.map +1 -1
  9. package/out/language-server/agenticChat/qAgenticChatServer.js +5 -1
  10. package/out/language-server/agenticChat/qAgenticChatServer.js.map +1 -1
  11. package/out/language-server/agenticChat/tools/executeBash.d.ts +16 -0
  12. package/out/language-server/agenticChat/tools/executeBash.js +95 -3
  13. package/out/language-server/agenticChat/tools/executeBash.js.map +1 -1
  14. package/out/language-server/agenticChat/tools/fsWrite.js +7 -0
  15. package/out/language-server/agenticChat/tools/fsWrite.js.map +1 -1
  16. package/out/language-server/agenticChat/tools/mcp/mcpManager.js +1 -1
  17. package/out/language-server/agenticChat/tools/mcp/mcpManager.js.map +1 -1
  18. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReview.d.ts +211 -0
  19. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReview.js +630 -0
  20. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReview.js.map +1 -0
  21. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewConstants.d.ts +34 -0
  22. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewConstants.js +200 -0
  23. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewConstants.js.map +1 -0
  24. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewErrors.d.ts +12 -0
  25. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewErrors.js +32 -0
  26. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewErrors.js.map +1 -0
  27. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewSchemas.d.ts +289 -0
  28. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewSchemas.js +140 -0
  29. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewSchemas.js.map +1 -0
  30. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewTypes.d.ts +58 -0
  31. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewTypes.js +3 -0
  32. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewTypes.js.map +1 -0
  33. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewUtils.d.ts +156 -0
  34. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewUtils.js +363 -0
  35. package/out/language-server/agenticChat/tools/qCodeAnalysis/qCodeReviewUtils.js.map +1 -0
  36. package/out/language-server/agenticChat/tools/toolServer.d.ts +1 -0
  37. package/out/language-server/agenticChat/tools/toolServer.js +90 -39
  38. package/out/language-server/agenticChat/tools/toolServer.js.map +1 -1
  39. package/out/language-server/chat/telemetry/chatTelemetryController.d.ts +3 -3
  40. package/out/language-server/chat/telemetry/chatTelemetryController.js +13 -3
  41. package/out/language-server/chat/telemetry/chatTelemetryController.js.map +1 -1
  42. package/out/language-server/configuration/qConfigurationServer.d.ts +1 -0
  43. package/out/language-server/configuration/qConfigurationServer.js.map +1 -1
  44. package/out/language-server/inline-completion/codeWhispererServer.js +58 -41
  45. package/out/language-server/inline-completion/codeWhispererServer.js.map +1 -1
  46. package/out/language-server/workspaceContext/artifactManager.d.ts +4 -1
  47. package/out/language-server/workspaceContext/artifactManager.js +16 -1
  48. package/out/language-server/workspaceContext/artifactManager.js.map +1 -1
  49. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.d.ts +2 -1
  50. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js +9 -6
  51. package/out/language-server/workspaceContext/dependency/dependencyDiscoverer.js.map +1 -1
  52. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.d.ts +7 -2
  53. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js +20 -7
  54. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandler.js.map +1 -1
  55. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandlerFactory.d.ts +2 -2
  56. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandlerFactory.js +4 -4
  57. package/out/language-server/workspaceContext/dependency/dependencyHandler/LanguageDependencyHandlerFactory.js.map +1 -1
  58. package/out/language-server/workspaceContext/fileUploadJobManager.js +3 -1
  59. package/out/language-server/workspaceContext/fileUploadJobManager.js.map +1 -1
  60. package/out/language-server/workspaceContext/workspaceContextServer.js +32 -19
  61. package/out/language-server/workspaceContext/workspaceContextServer.js.map +1 -1
  62. package/out/language-server/workspaceContext/workspaceFolderManager.d.ts +5 -3
  63. package/out/language-server/workspaceContext/workspaceFolderManager.js +80 -59
  64. package/out/language-server/workspaceContext/workspaceFolderManager.js.map +1 -1
  65. package/out/shared/amazonQServiceManager/configurationUtils.js +6 -0
  66. package/out/shared/amazonQServiceManager/configurationUtils.js.map +1 -1
  67. package/out/shared/telemetry/telemetryService.d.ts +2 -0
  68. package/out/shared/telemetry/telemetryService.js +4 -1
  69. package/out/shared/telemetry/telemetryService.js.map +1 -1
  70. package/out/shared/telemetry/types.d.ts +2 -0
  71. package/out/shared/telemetry/types.js.map +1 -1
  72. package/out/shared/testUtils.d.ts +9 -0
  73. package/out/shared/testUtils.js +12 -1
  74. package/out/shared/testUtils.js.map +1 -1
  75. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.65](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.64...lsp-codewhisperer/v0.0.65) (2025-07-15)
4
+
5
+
6
+ ### Features
7
+
8
+ * **amazonq:** add a/b testing info into agenticChat toolkit metrics ([#1898](https://github.com/aws/language-servers/issues/1898)) ([6ab9b2c](https://github.com/aws/language-servers/commit/6ab9b2cef0125846c2f20fd8554f591808b59cd0))
9
+ * **amazonq:** added full system information to the logs ([#1875](https://github.com/aws/language-servers/issues/1875)) ([7795c6b](https://github.com/aws/language-servers/commit/7795c6b43274211731aa9bb295b41ec89db41a6d))
10
+ * **amazonq:** Adding QCodeReview tool to amazonQ ([#1882](https://github.com/aws/language-servers/issues/1882)) ([07e343b](https://github.com/aws/language-servers/commit/07e343b9fcef319bdbec80c48388e44b4b19269a))
11
+ * **amazonq:** allow opt-out for workspace context server ([#1867](https://github.com/aws/language-servers/issues/1867)) ([72b6d76](https://github.com/aws/language-servers/commit/72b6d76c5ed8e240aad6be80f65eab3497caaacf))
12
+ * **chat-client:** add built-in tool permission and enable auto-approve ([#1890](https://github.com/aws/language-servers/issues/1890)) ([03b59c8](https://github.com/aws/language-servers/commit/03b59c8fba58db0f6b6c387cf5d53227c3f54673))
13
+ * **chat-client:** handle keyboard shortcut for run/reject/stop shell commands and tooltips ([#1885](https://github.com/aws/language-servers/issues/1885)) ([f8e9461](https://github.com/aws/language-servers/commit/f8e94615b5ce8a3f4bf8837627fa4816a09cbef2))
14
+ * update UserTriggerDecisionEventStreakLengthInteger min value ([#1878](https://github.com/aws/language-servers/issues/1878)) ([e06f180](https://github.com/aws/language-servers/commit/e06f18017864ea33e316059a708cb87aa6d8c562))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * **amazonq:** additional checks for binary and credential files ([#1866](https://github.com/aws/language-servers/issues/1866)) ([76656c9](https://github.com/aws/language-servers/commit/76656c9b2bb5080f64f581bb3b39cd55a3015bdf))
20
+ * **amazonq:** catch mcp initialization errors ([#1873](https://github.com/aws/language-servers/issues/1873)) ([afdd6a4](https://github.com/aws/language-servers/commit/afdd6a4bd1db7c3990a7a279ebbbfbe0640e27c3))
21
+ * **chat-client:** revert for add built-in tool permission and enable auto-approve ([#1890](https://github.com/aws/language-servers/issues/1890)) ([#1900](https://github.com/aws/language-servers/issues/1900)) ([34b41b8](https://github.com/aws/language-servers/commit/34b41b8f87c21d2ee6b98643339dbdfa71efcb77))
22
+ * **chat-client:** revert for amazon q keyboard shortcuts feature ([#1901](https://github.com/aws/language-servers/issues/1901)) ([522f8de](https://github.com/aws/language-servers/commit/522f8de6dba8dfa9b4363934cd7fcea905add1ce))
23
+ * Disable Concurrent inline completion handler ([#1880](https://github.com/aws/language-servers/issues/1880)) ([61eeb8c](https://github.com/aws/language-servers/commit/61eeb8c93b5454c5a99ebb79b5593007d08007e5))
24
+ * Forward slash shown in rules list in multi-root workspaces on windows ([#1855](https://github.com/aws/language-servers/issues/1855)) ([061caa6](https://github.com/aws/language-servers/commit/061caa6450946e20cd1630b92f9b6dada8058edd))
25
+
26
+
27
+ ### Reverts
28
+
29
+ * adding streakLength back for UserTriggerDecisionEvent ([#1877](https://github.com/aws/language-servers/issues/1877)) ([b199100](https://github.com/aws/language-servers/commit/b199100153aa0629890c49e12a56efbb9c627154))
30
+
31
+ ## [0.0.64](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.63...lsp-codewhisperer/v0.0.64) (2025-07-11)
32
+
33
+
34
+ ### Bug Fixes
35
+
36
+ * **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))
37
+ * **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))
38
+ * use absolute file path for shell ([#1871](https://github.com/aws/language-servers/issues/1871)) ([f863735](https://github.com/aws/language-servers/commit/f863735c8dc734a1af4b26fbe8b9c436a32c21ca))
39
+
40
+
41
+ ### Reverts
42
+
43
+ * 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))
44
+ * 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))
45
+
3
46
  ## [0.0.63](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.62...lsp-codewhisperer/v0.0.63) (2025-07-08)
4
47
 
5
48
 
@@ -6453,7 +6453,7 @@
6453
6453
  },
6454
6454
  "UserTriggerDecisionEventStreakLengthInteger": {
6455
6455
  "type": "integer",
6456
- "min": 0
6456
+ "min": -1
6457
6457
  },
6458
6458
  "ValidationException": {
6459
6459
  "type": "structure",
@@ -16,9 +16,14 @@ 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
+ import { UserContext } from '../../client/token/codewhispererbearertokenclient';
19
20
  type ChatHandlers = Omit<LspHandlers<Chat>, 'openTab' | 'sendChatUpdate' | 'sendContextCommands' | 'onListConversations' | 'onConversationClick' | 'onListMcpServers' | 'onMcpServerClick' | 'onTabBarAction' | 'getSerializedChat' | 'chatOptionsUpdate' | 'onListRules' | 'sendPinnedContext' | 'onActiveEditorChanged' | 'onPinnedContextAdd' | 'onPinnedContextRemove' | 'onOpenFileDialog' | 'onListAvailableModels'>;
20
21
  export declare class AgenticChatController implements ChatHandlers {
21
22
  #private;
23
+ /**
24
+ * Logs system information that can be helpful for debugging customer issues
25
+ */
26
+ private logSystemInformation;
22
27
  constructor(chatSessionManagementService: ChatSessionManagementService, features: Features, telemetryService: TelemetryService, serviceManager?: AmazonQBaseServiceManager);
23
28
  onExecuteCommand(params: ExecuteCommandParams, _token: CancellationToken): Promise<any>;
24
29
  onButtonClick(params: ButtonClickParams): Promise<ButtonClickResult>;
@@ -143,5 +148,6 @@ export declare class AgenticChatController implements ChatHandlers {
143
148
  onPromptInputOptionChange(params: PromptInputOptionChangeParams): void;
144
149
  updateConfiguration: (newConfig: AmazonQWorkspaceConfig) => void;
145
150
  restorePreviousChats(): Promise<void>;
151
+ scheduleABTestingFetching(userContext: UserContext | undefined): void;
146
152
  }
147
153
  export {};
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.AgenticChatController = void 0;
8
8
  const crypto = require("crypto");
9
9
  const path = require("path");
10
+ const os = require("os");
10
11
  const codewhisperer_streaming_1 = require("@amzn/codewhisperer-streaming");
11
12
  const protocol_1 = require("@aws/language-server-runtimes/protocol");
12
13
  const protocol_2 = require("@aws/language-server-runtimes/protocol");
@@ -49,6 +50,8 @@ const errors_2 = require("./errors");
49
50
  const vscode_uri_1 = require("vscode-uri");
50
51
  const executeBash_2 = require("./tools/executeBash");
51
52
  const userWrittenCodeTracker_1 = require("../../shared/userWrittenCodeTracker");
53
+ const qCodeReview_1 = require("./tools/qCodeAnalysis/qCodeReview");
54
+ const qCodeReviewConstants_1 = require("./tools/qCodeAnalysis/qCodeReviewConstants");
52
55
  const mcpEventHandler_1 = require("./tools/mcp/mcpEventHandler");
53
56
  const mcpUtils_1 = require("./tools/mcp/mcpUtils");
54
57
  const mcpManager_1 = require("./tools/mcp/mcpManager");
@@ -85,6 +88,9 @@ class AgenticChatController {
85
88
  #timeToFirstChunk = -1;
86
89
  #timeBetweenChunks = [];
87
90
  #lastChunkTime = 0;
91
+ // A/B testing allocation
92
+ #abTestingFetchingTimeout;
93
+ #abTestingAllocation;
88
94
  /**
89
95
  * Determines the appropriate message ID for a tool use based on tool type and name
90
96
  * @param toolType The type of tool being used
@@ -96,6 +102,23 @@ class AgenticChatController {
96
102
  // Return plain toolUseId for executeBash, add "_permission" suffix for all other tools
97
103
  return toolUse.name === 'executeBash' || toolType === 'executeBash' ? toolUseId : `${toolUseId}_permission`;
98
104
  }
105
+ /**
106
+ * Logs system information that can be helpful for debugging customer issues
107
+ */
108
+ logSystemInformation() {
109
+ const clientInfo = this.#features.lsp.getClientInitializeParams()?.clientInfo;
110
+ const systemInfo = {
111
+ languageServerVersion: this.#features.runtime.serverInfo.version ?? 'unknown',
112
+ clientName: clientInfo?.name ?? 'unknown',
113
+ clientVersion: clientInfo?.version ?? 'unknown',
114
+ OS: os.platform(),
115
+ OSVersion: os.release(),
116
+ ComputeEnv: process.env.COMPUTE_ENV ?? 'unknown',
117
+ extensionVersion: this.#features.lsp.getClientInitializeParams()?.initializationOptions?.aws?.clientInfo?.extension
118
+ ?.version,
119
+ };
120
+ this.#features.logging.info(`System Information: ${JSON.stringify(systemInfo)}`);
121
+ }
99
122
  constructor(chatSessionManagementService, features, telemetryService, serviceManager) {
100
123
  this.#features = features;
101
124
  this.#chatSessionManagementService = chatSessionManagementService;
@@ -162,7 +185,7 @@ class AgenticChatController {
162
185
  try {
163
186
  await this.#undoFileChange(toolUseId, session.data);
164
187
  this.#updateUndoButtonAfterClick(params.tabId, toolUseId, session.data);
165
- this.#telemetryController.emitInteractWithAgenticChat('RejectDiff', params.tabId, session.data?.pairProgrammingMode, session.data?.getConversationType());
188
+ this.#telemetryController.emitInteractWithAgenticChat('RejectDiff', params.tabId, session.data?.pairProgrammingMode, session.data?.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
166
189
  }
167
190
  catch (err) {
168
191
  return { success: false, failureReason: err.message };
@@ -207,6 +230,10 @@ class AgenticChatController {
207
230
  }
208
231
  else {
209
232
  await this.#features.workspace.fs.rm(input.path);
233
+ void localProjectContextController_1.LocalProjectContextController.getInstance().then(controller => {
234
+ const filePath = vscode_uri_1.URI.file(input.path).fsPath;
235
+ return controller.updateIndexAndContextCommand([filePath], false);
236
+ });
210
237
  }
211
238
  }
212
239
  #updateUndoButtonAfterClick(tabId, toolUseId, session) {
@@ -367,6 +394,7 @@ class AgenticChatController {
367
394
  this.#contextCommandsProvider?.dispose();
368
395
  this.#userWrittenCodeTracker?.dispose();
369
396
  this.#mcpEventHandler.dispose();
397
+ clearInterval(this.#abTestingFetchingTimeout);
370
398
  }
371
399
  async onListConversations(params) {
372
400
  return this.#tabBarController.onListConversations(params);
@@ -433,6 +461,8 @@ class AgenticChatController {
433
461
  await this.#invalidateAllShellCommands(params.tabId, session);
434
462
  const metric = new metric_1.Metric({
435
463
  cwsprChatConversationType: 'AgenticChat',
464
+ experimentName: this.#abTestingAllocation?.experimentName,
465
+ userVariation: this.#abTestingAllocation?.userVariation,
436
466
  });
437
467
  try {
438
468
  const triggerContext = await this.#getTriggerContext(params, metric);
@@ -458,7 +488,7 @@ class AgenticChatController {
458
488
  await this.#showUndoAllIfRequired(chatResultStream, session);
459
489
  await chatResultStream.updateOngoingProgressResult('Canceled');
460
490
  // Finally, send telemetry/metrics
461
- this.#telemetryController.emitInteractWithAgenticChat('StopChat', params.tabId, session.pairProgrammingMode, session.getConversationType());
491
+ this.#telemetryController.emitInteractWithAgenticChat('StopChat', params.tabId, session.pairProgrammingMode, session.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
462
492
  metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version);
463
493
  metric.setDimension('codewhispererCustomizationArn', this.#customizationArn);
464
494
  metric.setDimension('enabled', session.pairProgrammingMode);
@@ -466,8 +496,11 @@ class AgenticChatController {
466
496
  });
467
497
  session.setConversationType('AgenticChat');
468
498
  const additionalContext = await this.#additionalContextProvider.getAdditionalContext(triggerContext, params.tabId, params.context);
469
- // Add active file to context list if it exists
470
- const activeFile = triggerContext.text && triggerContext.relativeFilePath && triggerContext.activeFilePath
499
+ // Add active file to context list if it's not already there
500
+ const activeFile = triggerContext.text &&
501
+ triggerContext.relativeFilePath &&
502
+ triggerContext.activeFilePath &&
503
+ !additionalContext.some(item => item.path === triggerContext.activeFilePath)
471
504
  ? [
472
505
  {
473
506
  name: path.basename(triggerContext.relativeFilePath),
@@ -542,6 +575,7 @@ class AgenticChatController {
542
575
  let iterationCount = 0;
543
576
  let shouldDisplayMessage = true;
544
577
  metric.recordStart();
578
+ this.logSystemInformation();
545
579
  while (true) {
546
580
  iterationCount++;
547
581
  this.#debug(`Agent loop iteration ${iterationCount} for conversation id:`, conversationIdentifier || '');
@@ -679,7 +713,7 @@ class AgenticChatController {
679
713
  if (pendingToolUses.length === 0) {
680
714
  this.recordChunk('agent_loop_done');
681
715
  // No more tool uses, we're done
682
- 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);
716
+ 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);
683
717
  finalResult = result;
684
718
  break;
685
719
  }
@@ -700,7 +734,7 @@ class AgenticChatController {
700
734
  metric.setDimension('requestIds', metric.metric.requestIds);
701
735
  const toolNames = this.#toolUseLatencies.map(item => item.toolName);
702
736
  const toolUseIds = this.#toolUseLatencies.map(item => item.toolUseId);
703
- 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);
737
+ 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, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
704
738
  }
705
739
  else {
706
740
  // Send an error card to UI?
@@ -709,7 +743,7 @@ class AgenticChatController {
709
743
  status: codewhisperer_streaming_1.ToolResultStatus.ERROR,
710
744
  content: [{ text: result.error }],
711
745
  }));
712
- 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);
746
+ 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, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
713
747
  if (result.error.startsWith('ToolUse input is invalid JSON:')) {
714
748
  content =
715
749
  '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.';
@@ -905,17 +939,20 @@ class AgenticChatController {
905
939
  cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult);
906
940
  const isExecuteBash = toolUse.name === 'executeBash';
907
941
  if (isExecuteBash) {
908
- this.#telemetryController.emitInteractWithAgenticChat('GeneratedCommand', tabId, session.pairProgrammingMode, session.getConversationType());
942
+ this.#telemetryController.emitInteractWithAgenticChat('GeneratedCommand', tabId, session.pairProgrammingMode, session.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
909
943
  }
910
944
  if (requiresAcceptance) {
911
945
  await this.waitForToolApproval(toolUse, chatResultStream, cachedButtonBlockId, session, toolUse.name);
912
946
  }
913
947
  if (isExecuteBash) {
914
- this.#telemetryController.emitInteractWithAgenticChat('RunCommand', tabId, session.pairProgrammingMode, session.getConversationType());
948
+ this.#telemetryController.emitInteractWithAgenticChat('RunCommand', tabId, session.pairProgrammingMode, session.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
915
949
  }
916
950
  }
917
951
  break;
918
952
  }
953
+ case qCodeReview_1.QCodeReview.toolName:
954
+ // no need to write tool message for code review
955
+ break;
919
956
  // — DEFAULT ⇒ Only MCP tools, but can also handle generic tool execution messages
920
957
  default:
921
958
  // Get original server and tool names from the mapping
@@ -965,6 +1002,22 @@ class AgenticChatController {
965
1002
  fileChange: { before: document?.getText() },
966
1003
  });
967
1004
  }
1005
+ if (toolUse.name === qCodeReview_1.QCodeReview.toolName) {
1006
+ try {
1007
+ let initialInput = JSON.parse(JSON.stringify(toolUse.input));
1008
+ let ruleArtifacts = await this.#additionalContextProvider.collectWorkspaceRules(tabId);
1009
+ if (ruleArtifacts !== undefined || ruleArtifacts !== null) {
1010
+ this.#features.logging.info(`RuleArtifacts: ${JSON.stringify(ruleArtifacts)}`);
1011
+ let pathsToRulesMap = ruleArtifacts.map(ruleArtifact => ({ path: ruleArtifact.id }));
1012
+ this.#features.logging.info(`PathsToRules: ${JSON.stringify(pathsToRulesMap)}`);
1013
+ initialInput['ruleArtifacts'] = pathsToRulesMap;
1014
+ }
1015
+ toolUse.input = initialInput;
1016
+ }
1017
+ catch (e) {
1018
+ this.#features.logging.warn(`could not parse QCodeReview tool input: ${e}`);
1019
+ }
1020
+ }
968
1021
  // After approval, add the path to the approved paths in the session
969
1022
  const inputPath = toolUse.input?.path || toolUse.input?.cwd;
970
1023
  if (inputPath) {
@@ -1029,9 +1082,23 @@ class AgenticChatController {
1029
1082
  fileChange: { ...cachedToolUse.fileChange, after: doc?.getText() },
1030
1083
  });
1031
1084
  }
1032
- this.#telemetryController.emitInteractWithAgenticChat('GeneratedDiff', tabId, session.pairProgrammingMode, session.getConversationType());
1085
+ this.#telemetryController.emitInteractWithAgenticChat('GeneratedDiff', tabId, session.pairProgrammingMode, session.getConversationType(), this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
1033
1086
  await chatResultStream.writeResultBlock(chatResult);
1034
1087
  break;
1088
+ case qCodeReview_1.QCodeReview.toolName:
1089
+ // no need to write tool result for code review, this is handled by model via chat
1090
+ // Push result in message so that it is picked by IDE plugin to show in issues panel
1091
+ const qCodeReviewResult = result;
1092
+ if (qCodeReviewResult?.output?.kind === 'json' &&
1093
+ qCodeReviewResult.output.success &&
1094
+ qCodeReviewResult.output.content?.findingsByFile) {
1095
+ await chatResultStream.writeResultBlock({
1096
+ type: 'tool',
1097
+ messageId: toolUse.toolUseId + qCodeReviewConstants_1.FINDINGS_MESSAGE_SUFFIX,
1098
+ body: qCodeReviewResult.output.content.findingsByFile,
1099
+ });
1100
+ }
1101
+ break;
1035
1102
  // — DEFAULT ⇒ MCP tools
1036
1103
  default:
1037
1104
  await this.#handleMcpToolResult(toolUse, result, session, chatResultStream);
@@ -1052,7 +1119,7 @@ class AgenticChatController {
1052
1119
  });
1053
1120
  }
1054
1121
  }
1055
- this.#telemetryController.emitToolUseSuggested(toolUse, session.conversationId ?? '', this.#features.runtime.serverInfo.version ?? '', latency, session.pairProgrammingMode);
1122
+ this.#telemetryController.emitToolUseSuggested(toolUse, session.conversationId ?? '', this.#features.runtime.serverInfo.version ?? '', latency, session.pairProgrammingMode, this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation);
1056
1123
  }
1057
1124
  }
1058
1125
  catch (err) {
@@ -1279,7 +1346,31 @@ class AgenticChatController {
1279
1346
  return undefined;
1280
1347
  }
1281
1348
  }
1349
+ #getToolOverWritableStream(chatResultStream, toolUse) {
1350
+ const toolMsgId = toolUse.toolUseId;
1351
+ return new WritableStream({
1352
+ write: async (chunk) => {
1353
+ if (this.#stoppedToolUses.has(toolMsgId))
1354
+ return;
1355
+ await chatResultStream.removeResultBlockAndUpdateUI(toolMsgId);
1356
+ await chatResultStream.writeResultBlock({
1357
+ type: 'tool',
1358
+ messageId: toolMsgId,
1359
+ body: chunk,
1360
+ });
1361
+ },
1362
+ close: async () => {
1363
+ if (this.#stoppedToolUses.has(toolMsgId))
1364
+ return;
1365
+ await chatResultStream.removeResultBlockAndUpdateUI(toolMsgId);
1366
+ this.#stoppedToolUses.add(toolMsgId);
1367
+ },
1368
+ });
1369
+ }
1282
1370
  #getWritableStream(chatResultStream, toolUse) {
1371
+ if (toolUse.name === qCodeReview_1.QCodeReview.toolName) {
1372
+ return this.#getToolOverWritableStream(chatResultStream, toolUse);
1373
+ }
1283
1374
  if (toolUse.name !== 'executeBash') {
1284
1375
  return;
1285
1376
  }
@@ -1774,7 +1865,7 @@ class AgenticChatController {
1774
1865
  */
1775
1866
  #updateRequestInputWithToolResults(requestInput, toolResults, content) {
1776
1867
  // Create a deep copy of the request input
1777
- const updatedRequestInput = JSON.parse(JSON.stringify(requestInput));
1868
+ const updatedRequestInput = structuredClone(requestInput);
1778
1869
  // Add tool results to the request
1779
1870
  updatedRequestInput.conversationState.currentMessage.userInputMessage.userInputMessageContext.toolResults =
1780
1871
  [];
@@ -2896,6 +2987,40 @@ class AgenticChatController {
2896
2987
  body: (0, textFormatting_1.toolResultMessage)(toolUse, result),
2897
2988
  });
2898
2989
  }
2990
+ scheduleABTestingFetching(userContext) {
2991
+ if (!userContext) {
2992
+ return;
2993
+ }
2994
+ this.#abTestingFetchingTimeout = setInterval(() => {
2995
+ let codeWhispererServiceToken;
2996
+ try {
2997
+ codeWhispererServiceToken = AmazonQTokenServiceManager_1.AmazonQTokenServiceManager.getInstance().getCodewhispererService();
2998
+ }
2999
+ catch (error) {
3000
+ // getCodewhispererService only returns the cwspr client if the service manager was initialized
3001
+ // i.e. profile was selected otherwise it throws an error
3002
+ // we will not evaluate a/b status until profile is selected and service manager is fully initialized
3003
+ return;
3004
+ }
3005
+ // Clear interval once we have the CodewhispererService
3006
+ clearInterval(this.#abTestingFetchingTimeout);
3007
+ this.#abTestingFetchingTimeout = undefined;
3008
+ codeWhispererServiceToken
3009
+ .listFeatureEvaluations({ userContext })
3010
+ .then(result => {
3011
+ const feature = result.featureEvaluations?.find(feature => feature.feature === 'MaestroWorkspaceContext');
3012
+ if (feature) {
3013
+ this.#abTestingAllocation = {
3014
+ experimentName: feature.feature,
3015
+ userVariation: feature.variation,
3016
+ };
3017
+ }
3018
+ })
3019
+ .catch(error => {
3020
+ this.#features.logging.debug(`Error fetching AB testing result: ${error}`);
3021
+ });
3022
+ }, 5000);
3023
+ }
2899
3024
  #log(...messages) {
2900
3025
  this.#features.logging.log(messages.join(' '));
2901
3026
  }