Skip to content

Commit ad8e2db

Browse files
BlakeLazarinemkovelamsinghAwsblakelaz-amazon
authored
feat(amazonq): redirect /review, rename CodeReview tool, emit metrics, modify prompts (aws#1964)
* Emitting metrics for QCodeReview operations * fix(amazonq): add scope attribute in the metric data for Scan metrics * fix(amazonq): increase code review tool timeout * fix(amazonq): add metrics metadata to QAgenticReview tool * fix(amazonq): update metric metadata attribute names for QCodeReview tools * fix(amazonq): redirect /review to use agentic chat * fix(amazonq): rename QCodeReview tool to CodeReview * fix(amazonq): fix the casing of variables * fix(amazonq): emitting metrics based on definitions * fix(amazonq): update prompts for tool & /review * fix(amazonq): update prompts for tool * feat(amazonq): redirect commands to use the agentic reviewer * fix(amazonq): putting agentic review redirect behind feature flag * fix(amazonq): change the review reroute card text * fix(amazonq): when no active file is provided, ask the user for more input * fix(amazonq): remove summary suppressor in prompt * fix(amazonq): add programmingLanguages in telemetry * fix(amazonq): change genericCommandString back to original format * fix(amazonq): update codeReview unit tests --------- Co-authored-by: mkovelam <[email protected]> Co-authored-by: Nitish <[email protected]> Co-authored-by: Nitish Kumar Singh <[email protected]> Co-authored-by: Blake Lazarine <[email protected]>
1 parent 50b61a7 commit ad8e2db

File tree

20 files changed

+623
-532
lines changed

20 files changed

+623
-532
lines changed

chat-client/src/client/chat.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ export const createChat = (
294294
tabFactory.enableReroute()
295295
}
296296

297+
if ((params as any)?.codeReviewInChat) {
298+
tabFactory.enableCodeReviewInChat()
299+
}
300+
297301
if (params?.quickActions?.quickActionsCommandGroups) {
298302
const quickActionCommandGroups = params.quickActions.quickActionsCommandGroups.map(group => ({
299303
...group,

chat-client/src/client/mynahUi.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,10 @@ export const handleChatPrompt = (
196196
messager.onStopChatResponse(tabId)
197197
}
198198

199+
const commandsToReroute = ['/dev', '/test', '/doc', '/review']
200+
199201
const isReroutedCommand =
200-
agenticMode &&
201-
tabFactory?.isRerouteEnabled() &&
202-
prompt.command &&
203-
['/dev', '/test', '/doc'].includes(prompt.command)
202+
agenticMode && tabFactory?.isRerouteEnabled() && prompt.command && commandsToReroute.includes(prompt.command)
204203

205204
if (prompt.command && !isReroutedCommand && prompt.command !== '/compact') {
206205
// Send /compact quick action as normal regular chat prompt
@@ -227,7 +226,7 @@ export const handleChatPrompt = (
227226
} else {
228227
// Go agentic chat workflow when:
229228
// 1. Regular prompts without commands
230-
// 2. Rerouted commands (/dev, /test, /doc) when feature flag: reroute is enabled
229+
// 2. Rerouted commands (/dev, /test, /doc, /review) when feature flag: reroute is enabled
231230

232231
// Special handling for /doc command - always send fixed prompt for fixed response
233232
if (isReroutedCommand && prompt.command === '/doc') {
@@ -253,6 +252,9 @@ export const handleChatPrompt = (
253252
case '/doc':
254253
defaultPrompt = DEFAULT_DOC_PROMPT
255254
break
255+
case '/review':
256+
defaultPrompt = DEFAULT_REVIEW_PROMPT
257+
break
256258
}
257259

258260
// Send the updated prompt with default text to server
@@ -1421,15 +1423,25 @@ export const createMynahUi = (
14211423
tabId = createTabId()
14221424
if (!tabId) return
14231425
}
1424-
1425-
const body = [
1426-
params.genericCommand,
1427-
' the following part of my code:',
1428-
'\n~~~~\n',
1429-
params.selection,
1430-
'\n~~~~\n',
1431-
].join('')
1432-
const chatPrompt: ChatPrompt = { prompt: body, escapedPrompt: body }
1426+
let body = ''
1427+
let chatPrompt: ChatPrompt
1428+
const genericCommandString = params.genericCommand as string
1429+
if (genericCommandString.includes('Review')) {
1430+
chatPrompt = { command: '/review' }
1431+
if (!tabFactory?.isCodeReviewInChatEnabled()) {
1432+
customChatClientAdapter?.handleQuickAction(chatPrompt, tabId, '')
1433+
return
1434+
}
1435+
} else {
1436+
body = [
1437+
genericCommandString,
1438+
' the following part of my code:',
1439+
'\n~~~~\n',
1440+
params.selection,
1441+
'\n~~~~\n',
1442+
].join('')
1443+
chatPrompt = { prompt: body, escapedPrompt: body }
1444+
}
14331445

14341446
handleChatPrompt(mynahUi, tabId, chatPrompt, messager, params.triggerType, undefined, agenticMode, tabFactory)
14351447
}
@@ -1754,6 +1766,8 @@ const DEFAULT_TEST_PROMPT = `You are Amazon Q. Start with a warm greeting, then
17541766

17551767
const DEFAULT_DEV_PROMPT = `You are Amazon Q. Start with a warm greeting, then ask the user to specify what kind of help they need in code development. Present common questions asked (like Creating a new project, Adding a new feature, Modifying your files). Keep the question brief and friendly. Don't make assumptions about existing content or context. Wait for their response before providing specific guidance.`
17561768

1769+
const DEFAULT_REVIEW_PROMPT = `You are Amazon Q. Start with a warm greeting, then use code review tool to perform code analysis of the open file. If there is no open file, ask what the user would like to review.`
1770+
17571771
export const uiComponentsTexts = {
17581772
mainTitle: 'Amazon Q (Preview)',
17591773
copy: 'Copy',

chat-client/src/client/tabs/tabFactory.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class TabFactory {
2828
private mcp: boolean = false
2929
private modelSelectionEnabled: boolean = false
3030
private reroute: boolean = false
31+
private codeReviewInChat: boolean = false
3132
private showLogs: boolean = false
3233
initialTabId: string
3334

@@ -124,10 +125,18 @@ export class TabFactory {
124125
this.reroute = true
125126
}
126127

128+
public enableCodeReviewInChat() {
129+
this.codeReviewInChat = true
130+
}
131+
127132
public isRerouteEnabled(): boolean {
128133
return this.reroute
129134
}
130135

136+
public isCodeReviewInChatEnabled(): boolean {
137+
return this.codeReviewInChat
138+
}
139+
131140
public getDefaultTabData(): DefaultTabData {
132141
const tabData = {
133142
...this.defaultTabData,
@@ -143,7 +152,7 @@ export class TabFactory {
143152
icon: MynahIcons.INFO,
144153
title: 'Q Developer agentic capabilities',
145154
description:
146-
"You can now ask Q directly in the chat to generate code, documentation, and unit tests. You don't need to explicitly use /dev, /test, or /doc",
155+
"You can now ask Q directly in the chat to generate code, documentation, and unit tests. You don't need to explicitly use /dev, /test, /review or /doc",
147156
} as QuickActionCommandsHeader,
148157
}
149158
: {}),

chat-client/src/client/texts/pairProgramming.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ Ask me to do things like:
8080
3. Modify your files`,
8181
}
8282

83+
export const reviewRerouteCard: ChatItem = {
84+
type: ChatItemType.ANSWER,
85+
border: true,
86+
header: {
87+
padding: true,
88+
iconForegroundStatus: 'warning',
89+
icon: MynahIcons.INFO,
90+
body: 'You can now ask to run code reviews directly in the chat.',
91+
},
92+
body: `You don't need to explicitly use /review. We've redirected your request to chat.
93+
Ask me to do things like:
94+
• Perform a code review of uncommitted changes in my active file
95+
• Perform a code review of my active file`,
96+
}
97+
8398
export const createRerouteCard = (command: string): ChatItem => {
8499
switch (command) {
85100
case '/test':
@@ -88,6 +103,8 @@ export const createRerouteCard = (command: string): ChatItem => {
88103
return docRerouteCard
89104
case '/dev':
90105
return devRerouteCard
106+
case '/review':
107+
return reviewRerouteCard
91108
default:
92109
return devRerouteCard // Default fallback
93110
}

chat-client/src/client/withAdapter.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ describe('withAdapter', () => {
107107
// Set up tab factory
108108
tabFactory = {
109109
isRerouteEnabled: sinon.stub().returns(false),
110+
isCodeReviewInChatEnabled: sinon.stub().returns(false),
110111
} as unknown as TabFactory
111112

112113
// Create the enhanced props

chat-client/src/client/withAdapter.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,18 @@ export const withAdapter = (
7575
return
7676
}
7777

78-
// Only /review and /transform commands for chatClientAdapter handling
79-
// Let /dev, /test, /doc use default event handler routing(agentic chat)
78+
// Only /transform commands for chatClientAdapter handling
79+
// Let /dev, /test, /doc, /review use default event handler routing(agentic chat)
8080
if (prompt.command) {
81+
const quickActionCommands = ['/transform']
82+
83+
if (!tabFactory?.isCodeReviewInChatEnabled()) {
84+
quickActionCommands.push('/review')
85+
}
86+
8187
const shouldHandleQuickAction = !tabFactory.isRerouteEnabled()
8288
? chatClientAdapter.isSupportedQuickAction(prompt.command)
83-
: ['/review', '/transform'].includes(prompt.command)
89+
: quickActionCommands.includes(prompt.command)
8490

8591
if (shouldHandleQuickAction) {
8692
chatClientAdapter.handleQuickAction(prompt, tabId, eventId)

server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
GREP_SEARCH,
2525
FILE_SEARCH,
2626
EXECUTE_BASH,
27-
Q_CODE_REVIEW,
27+
CODE_REVIEW,
2828
BUTTON_RUN_SHELL_COMMAND,
2929
BUTTON_REJECT_SHELL_COMMAND,
3030
BUTTON_REJECT_MCP_TOOL,
@@ -197,8 +197,8 @@ import {
197197
import { URI } from 'vscode-uri'
198198
import { CommandCategory } from './tools/executeBash'
199199
import { UserWrittenCodeTracker } from '../../shared/userWrittenCodeTracker'
200-
import { QCodeReview } from './tools/qCodeAnalysis/qCodeReview'
201-
import { FINDINGS_MESSAGE_SUFFIX } from './tools/qCodeAnalysis/qCodeReviewConstants'
200+
import { CodeReview } from './tools/qCodeAnalysis/codeReview'
201+
import { FINDINGS_MESSAGE_SUFFIX } from './tools/qCodeAnalysis/codeReviewConstants'
202202
import { McpEventHandler } from './tools/mcp/mcpEventHandler'
203203
import { enabledMCP, createNamespacedToolName } from './tools/mcp/mcpUtils'
204204
import { McpManager } from './tools/mcp/mcpManager'
@@ -1750,7 +1750,7 @@ export class AgenticChatController implements ChatHandlers {
17501750
}
17511751
break
17521752
}
1753-
case QCodeReview.toolName:
1753+
case CodeReview.toolName:
17541754
// no need to write tool message for code review
17551755
break
17561756
// — DEFAULT ⇒ Only MCP tools, but can also handle generic tool execution messages
@@ -1825,7 +1825,7 @@ export class AgenticChatController implements ChatHandlers {
18251825
})
18261826
}
18271827

1828-
if (toolUse.name === QCodeReview.toolName) {
1828+
if (toolUse.name === CodeReview.toolName) {
18291829
try {
18301830
let initialInput = JSON.parse(JSON.stringify(toolUse.input))
18311831
let ruleArtifacts = await this.#additionalContextProvider.collectWorkspaceRules(tabId)
@@ -1837,7 +1837,7 @@ export class AgenticChatController implements ChatHandlers {
18371837
}
18381838
toolUse.input = initialInput
18391839
} catch (e) {
1840-
this.#features.logging.warn(`could not parse QCodeReview tool input: ${e}`)
1840+
this.#features.logging.warn(`could not parse CodeReview tool input: ${e}`)
18411841
}
18421842
}
18431843

@@ -1916,19 +1916,19 @@ export class AgenticChatController implements ChatHandlers {
19161916
)
19171917
await chatResultStream.writeResultBlock(chatResult)
19181918
break
1919-
case QCodeReview.toolName:
1919+
case CodeReview.toolName:
19201920
// no need to write tool result for code review, this is handled by model via chat
19211921
// Push result in message so that it is picked by IDE plugin to show in issues panel
1922-
const qCodeReviewResult = result as InvokeOutput
1922+
const codeReviewResult = result as InvokeOutput
19231923
if (
1924-
qCodeReviewResult?.output?.kind === 'json' &&
1925-
qCodeReviewResult.output.success &&
1926-
(qCodeReviewResult.output.content as any)?.findingsByFile
1924+
codeReviewResult?.output?.kind === 'json' &&
1925+
codeReviewResult.output.success &&
1926+
(codeReviewResult.output.content as any)?.findingsByFile
19271927
) {
19281928
await chatResultStream.writeResultBlock({
19291929
type: 'tool',
19301930
messageId: toolUse.toolUseId + FINDINGS_MESSAGE_SUFFIX,
1931-
body: (qCodeReviewResult.output.content as any).findingsByFile,
1931+
body: (codeReviewResult.output.content as any).findingsByFile,
19321932
})
19331933
}
19341934
break
@@ -2237,7 +2237,7 @@ export class AgenticChatController implements ChatHandlers {
22372237
}
22382238

22392239
#getWritableStream(chatResultStream: AgenticChatResultStream, toolUse: ToolUse): WritableStream | undefined {
2240-
if (toolUse.name === QCodeReview.toolName) {
2240+
if (toolUse.name === CodeReview.toolName) {
22412241
return this.#getToolOverWritableStream(chatResultStream, toolUse)
22422242
}
22432243
if (toolUse.name !== EXECUTE_BASH) {

server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/toolConstants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const FILE_SEARCH = 'fileSearch'
1919
export const EXECUTE_BASH = 'executeBash'
2020

2121
// Code analysis tools
22-
export const Q_CODE_REVIEW = 'qCodeReview'
22+
export const CODE_REVIEW = 'codeReview'
2323

2424
// Tool use button IDs
2525
export const BUTTON_RUN_SHELL_COMMAND = 'run-shell-command'

server/aws-lsp-codewhisperer/src/language-server/agenticChat/qAgenticChatServer.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ export function enabledReroute(params: InitializeParams | undefined): boolean {
2626
return qCapabilities?.reroute || false
2727
}
2828

29+
export function enabledCodeReviewInChat(params: InitializeParams | undefined): boolean {
30+
const qCapabilities = params?.initializationOptions?.aws?.awsClientCapabilities?.q as
31+
| QClientCapabilities
32+
| undefined
33+
return qCapabilities?.codeReviewInChat || false
34+
}
35+
2936
export function enabledCompaction(params: InitializeParams | undefined): boolean {
3037
const qCapabilities = params?.initializationOptions?.aws?.awsClientCapabilities?.q as
3138
| QClientCapabilities
@@ -54,6 +61,7 @@ export const QAgenticChatServer =
5461

5562
lsp.addInitializer((params: InitializeParams) => {
5663
const rerouteEnabled = enabledReroute(params)
64+
const codeReviewInChatEnabled = enabledCodeReviewInChat(params)
5765
const quickActions = [HELP_QUICK_ACTION, CLEAR_QUICK_ACTION]
5866
if (enabledCompaction(params)) {
5967
quickActions.push(COMPACT_QUICK_ACTION)
@@ -84,7 +92,8 @@ export const QAgenticChatServer =
8492
export: TabBarController.enableChatExport(params),
8593
shortcut: shortcutEnabled,
8694
showLogs: TabBarController.enableShowLogs(params),
87-
reroute: rerouteEnabled
95+
reroute: rerouteEnabled,
96+
codeReviewInChat: codeReviewInChatEnabled
8897
},
8998
},
9099
}

0 commit comments

Comments
 (0)