Skip to content

Commit cc73b96

Browse files
committed
pair programming mode
1 parent 66da962 commit cc73b96

File tree

13 files changed

+112
-3
lines changed

13 files changed

+112
-3
lines changed

packages/core/src/amazonq/webview/ui/apps/baseConnector.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ export abstract class BaseConnector {
194194
})
195195
}
196196

197+
onPromptInputOptionChange = (tabId: string, optionsValues: Record<string, string>): void => {
198+
this.sendMessageToExtension({
199+
command: 'prompt-input-option-change',
200+
optionsValues,
201+
tabType: this.getTabType(),
202+
tabID: tabId,
203+
})
204+
}
205+
197206
requestGenerativeAIAnswer = (tabID: string, messageId: string, payload: ChatPayload): Promise<any> => {
198207
/**
199208
* When a user presses "enter" send an event that indicates

packages/core/src/amazonq/webview/ui/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type MessageCommand =
2525
| 'help'
2626
| 'chat-item-voted'
2727
| 'chat-item-feedback'
28+
| 'prompt-input-option-change'
2829
| 'link-was-clicked'
2930
| 'onboarding-page-interaction'
3031
| 'source-link-click'

packages/core/src/amazonq/webview/ui/connector.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface ConnectorProps {
9797
onUpdateAuthentication: (featureDevEnabled: boolean, authenticatingTabIDs: string[]) => void
9898
onNewTab: (tabType: TabType) => void
9999
onFileActionClick: (tabID: string, messageId: string, filePath: string, actionName: string) => void
100+
onPromptInputOptionChange: (tabId: string, optionsValues: Record<string, string>, eventId?: string) => void
100101
handleCommand: (chatPrompt: ChatPrompt, tabId: string) => void
101102
sendStaticMessages: (tabID: string, messages: ChatItem[]) => void
102103
onContextCommandDataReceived: (message: MynahUIDataModel['contextCommands']) => void
@@ -617,6 +618,14 @@ export class Connector {
617618
}
618619
}
619620

621+
onPromptInputOptionChange = (tabId: string, optionsValues: Record<string, string>): void => {
622+
switch (this.tabsStorage.getTab(tabId)?.type) {
623+
case 'cwc':
624+
this.cwChatConnector.onPromptInputOptionChange(tabId, optionsValues)
625+
break
626+
}
627+
}
628+
620629
sendFeedback = (tabId: string, feedbackPayload: FeedbackPayload): void | undefined => {
621630
switch (this.tabsStorage.getTab(tabId)?.type) {
622631
case 'featuredev':

packages/core/src/amazonq/webview/ui/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ export const createMynahUI = (
239239
}
240240
},
241241
onFileActionClick: (tabID: string, messageId: string, filePath: string, actionName: string): void => {},
242+
onPromptInputOptionChange: (tabId: string, optionsValues: Record<string, string>, eventId?: string): void => {},
242243
onQuickHandlerCommand: (tabID: string, command?: string, eventId?: string) => {
243244
tabsStorage.updateTabLastCommand(tabID, command)
244245
if (command === 'aws.awsq.transform') {
@@ -926,6 +927,9 @@ export const createMynahUI = (
926927
onFileActionClick: async (tabID: string, messageId: string, filePath: string, actionName: string) => {
927928
connector.onFileActionClick(tabID, messageId, filePath, actionName)
928929
},
930+
onPromptInputOptionChange: (tabId, optionsValues) => {
931+
connector.onPromptInputOptionChange(tabId, optionsValues)
932+
},
929933
onFileClick: connector.onFileClick,
930934
tabs: {
931935
'tab-1': {

packages/core/src/amazonq/webview/ui/tabs/generator.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ export class TabDataGenerator {
7272
},
7373
]
7474
: [],
75+
promptInputOptions: [
76+
{
77+
type: 'toggle',
78+
id: 'prompt-type',
79+
value: 'ask',
80+
options: [
81+
{
82+
value: 'pair-programming-on',
83+
icon: 'code-block', // TODO: correct icons
84+
},
85+
{
86+
value: 'pair-programming-off',
87+
icon: 'chat', // TODO: correct icons
88+
},
89+
],
90+
},
91+
],
7592
}
7693
return tabData
7794
}

packages/core/src/codewhispererChat/app.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
AcceptDiff,
2929
QuickCommandGroupActionClick,
3030
FileClick,
31+
PromptInputOptionChange,
3132
} from './controllers/chat/model'
3233
import { EditorContextCommand, registerCommands } from './commands/registerCommands'
3334
import { ContextSelectedMessage, CustomFormActionMessage } from './view/connector/connector'
@@ -56,6 +57,7 @@ export function init(appContext: AmazonQAppInitContext) {
5657
processCustomFormAction: new EventEmitter<CustomFormActionMessage>(),
5758
processContextSelected: new EventEmitter<ContextSelectedMessage>(),
5859
processFileClick: new EventEmitter<FileClick>(),
60+
processPromptInputOptionChange: new EventEmitter<PromptInputOptionChange>(),
5961
}
6062

6163
const cwChatControllerMessageListeners = {
@@ -117,6 +119,9 @@ export function init(appContext: AmazonQAppInitContext) {
117119
cwChatControllerEventEmitters.processContextSelected
118120
),
119121
processFileClick: new MessageListener<FileClick>(cwChatControllerEventEmitters.processFileClick),
122+
processPromptInputOptionChange: new MessageListener<PromptInputOptionChange>(
123+
cwChatControllerEventEmitters.processPromptInputOptionChange
124+
),
120125
}
121126

122127
const cwChatControllerMessagePublishers = {
@@ -180,6 +185,9 @@ export function init(appContext: AmazonQAppInitContext) {
180185
cwChatControllerEventEmitters.processContextSelected
181186
),
182187
processFileClick: new MessagePublisher<FileClick>(cwChatControllerEventEmitters.processFileClick),
188+
processPromptInputOptionChange: new MessagePublisher<PromptInputOptionChange>(
189+
cwChatControllerEventEmitters.processPromptInputOptionChange
190+
),
183191
}
184192

185193
new CwChatController(

packages/core/src/codewhispererChat/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ export const tools: Tool[] = Object.entries(toolsJson).map(([, toolSpec]) => ({
3030
inputSchema: { json: toolSpec.inputSchema },
3131
},
3232
}))
33+
34+
export const noWriteTools: Tool[] = tools.filter(
35+
(tool) => !['fsWrite', 'executeBash'].includes(tool.toolSpecification?.name || '')
36+
)
37+
3338
export const defaultContextLengths: ContextLengths = {
3439
additionalContextLengths: {
3540
fileContextLength: 0,

packages/core/src/codewhispererChat/controllers/chat/chatRequest/converter.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { ConversationState, CursorState, DocumentSymbol, SymbolType, TextDocument } from '@amzn/codewhisperer-streaming'
77
import { AdditionalContentEntryAddition, ChatTriggerType, RelevantTextDocumentAddition, TriggerPayload } from '../model'
88
import { undefinedIfEmpty } from '../../../../shared/utilities/textUtilities'
9-
import { tools } from '../../../constants'
109
import { getLogger } from '../../../../shared/logger/logger'
1110
import vscode from 'vscode'
1211

@@ -164,7 +163,7 @@ export function triggerPayloadToChatRequest(triggerPayload: TriggerPayload): { c
164163
workspaceFolders: vscode.workspace.workspaceFolders?.map(({ uri }) => uri.fsPath) ?? [],
165164
},
166165
additionalContext: triggerPayload.additionalContents,
167-
tools,
166+
tools: triggerPayload.tools,
168167
...(triggerPayload.toolResults !== undefined &&
169168
triggerPayload.toolResults !== null && { toolResults: triggerPayload.toolResults }),
170169
},

packages/core/src/codewhispererChat/controllers/chat/controller.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
DocumentReference,
3333
FileClick,
3434
RelevantTextDocumentAddition,
35+
PromptInputOptionChange,
3536
} from './model'
3637
import {
3738
AppToWebViewMessageDispatcher,
@@ -85,6 +86,7 @@ import {
8586
tools,
8687
workspaceChunkMaxSize,
8788
defaultContextLengths,
89+
noWriteTools,
8890
} from '../../constants'
8991
import { ChatSession } from '../../clients/chat/v0/chat'
9092
import { amazonQTabSuffix } from '../../../shared/constants'
@@ -118,6 +120,7 @@ export interface ChatControllerMessagePublishers {
118120
readonly processCustomFormAction: MessagePublisher<CustomFormActionMessage>
119121
readonly processContextSelected: MessagePublisher<ContextSelectedMessage>
120122
readonly processFileClick: MessagePublisher<FileClick>
123+
readonly processPromptInputOptionChange: MessagePublisher<PromptInputOptionChange>
121124
}
122125

123126
export interface ChatControllerMessageListeners {
@@ -143,6 +146,7 @@ export interface ChatControllerMessageListeners {
143146
readonly processCustomFormAction: MessageListener<CustomFormActionMessage>
144147
readonly processContextSelected: MessageListener<ContextSelectedMessage>
145148
readonly processFileClick: MessageListener<FileClick>
149+
readonly processPromptInputOptionChange: MessageListener<PromptInputOptionChange>
146150
}
147151

148152
export class ChatController {
@@ -278,6 +282,9 @@ export class ChatController {
278282
this.chatControllerMessageListeners.processFileClick.onMessage((data) => {
279283
return this.processFileClickMessage(data)
280284
})
285+
this.chatControllerMessageListeners.processPromptInputOptionChange.onMessage((data) => {
286+
return this.processPromptInputOptionChange(data)
287+
})
281288
}
282289

283290
private registerUserPromptsWatcher() {
@@ -760,6 +767,17 @@ export class ChatController {
760767
this.handlePromptCreate(message.tabID)
761768
}
762769
}
770+
771+
private async processPromptInputOptionChange(message: PromptInputOptionChange) {
772+
const promptTypeValue = message.optionsValues['prompt-type']
773+
// TODO: display message: You turned off pair programmer mode. Q will not include code diffs or run commands in the chat.
774+
if (promptTypeValue === 'pair-programming-on') {
775+
this.chatHistoryStorage.setTabAvailableTools(message.tabID, tools)
776+
} else {
777+
this.chatHistoryStorage.setTabAvailableTools(message.tabID, noWriteTools)
778+
}
779+
}
780+
763781
private async processFileClickMessage(message: FileClick) {
764782
const session = this.sessionStorage.getSession(message.tabID)
765783
// Check if user clicked on filePath in the contextList or in the fileListTree and perform the functionality accordingly.
@@ -1326,6 +1344,7 @@ export class ChatController {
13261344

13271345
triggerPayload.contextLengths.userInputContextLength = triggerPayload.message.length
13281346
triggerPayload.contextLengths.focusFileContextLength = triggerPayload.fileText.length
1347+
triggerPayload.tools = this.chatHistoryStorage.getTabAvailableTools(tabID)
13291348

13301349
const chatHistory = this.chatHistoryStorage.getTabHistory(tabID)
13311350
const newUserMessage = {
@@ -1334,7 +1353,7 @@ export class ChatController {
13341353
userIntent: triggerPayload.userIntent,
13351354
...(triggerPayload.origin && { origin: triggerPayload.origin }),
13361355
userInputMessageContext: {
1337-
tools: tools,
1356+
tools: triggerPayload.tools,
13381357
...(triggerPayload.toolResults && { toolResults: triggerPayload.toolResults }),
13391358
},
13401359
},

packages/core/src/codewhispererChat/controllers/chat/model.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ChatMessage,
1010
Origin,
1111
RelevantTextDocument,
12+
Tool,
1213
ToolResult,
1314
UserIntent,
1415
} from '@amzn/codewhisperer-streaming'
@@ -161,6 +162,13 @@ export interface FileClick {
161162
filePath: string
162163
}
163164

165+
export interface PromptInputOptionChange {
166+
command: string
167+
tabID: string
168+
messageId: string
169+
optionsValues: Record<string, string>
170+
}
171+
164172
export interface ChatItemVotedMessage {
165173
tabID: string
166174
command: string
@@ -206,6 +214,7 @@ export interface TriggerPayload {
206214
chatHistory?: ChatMessage[]
207215
toolResults?: ToolResult[]
208216
origin?: Origin
217+
tools?: Tool[]
209218
}
210219

211220
export type ContextLengths = {

0 commit comments

Comments
 (0)