Skip to content

Commit 06268cf

Browse files
authored
add inline confirmation (microsoft/vscode#260228) (#7934)
1 parent ca1c605 commit 06268cf

File tree

1 file changed

+57
-27
lines changed

1 file changed

+57
-27
lines changed

src/github/copilotRemoteAgent.ts

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const CONTINUE_WITHOUT_PUSHING = vscode.l10n.t('Ignore changes');
4242
const CONTINUE_AND_DO_NOT_ASK_AGAIN = vscode.l10n.t('Continue and don\'t ask again');
4343

4444
const CONTINUE_TRUNCATION = vscode.l10n.t('Continue with truncation');
45+
const DELEGATE_MODAL_DETAILS = vscode.l10n.t('The agent will work asynchronously to create a pull request with your requested changes.');
4546

4647
const COPILOT = '@copilot';
4748

@@ -72,23 +73,25 @@ export namespace SessionIdForPr {
7273

7374
export class CopilotRemoteAgentManager extends Disposable {
7475
async chatParticipantImpl(request: vscode.ChatRequest, context: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) {
75-
const startSession = async (prompt: string, history: ReadonlyArray<vscode.ChatRequestTurn | vscode.ChatResponseTurn>, source: string, chatSummary?: { prompt?: string; history?: string }) => {
76+
const startSession = async (source: string) => {
7677
/* __GDPR__
7778
"copilot.remoteagent.editor.invoke" : {
7879
"promptLength" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
7980
"historyLength" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
80-
"hasPromptSummary" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
81-
"hasHistorySummary" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
81+
"promptSummaryLength" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
82+
"historySummaryLength" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
8283
"source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
8384
}
8485
*/
85-
const promptSummary = chatSummary?.prompt;
86-
const historySummary = chatSummary?.history;
86+
const prompt = request.prompt;
87+
const history = context.history;
88+
const promptSummary = context.chatSummary?.prompt;
89+
const historySummary = context.chatSummary?.history;
8790
this.telemetry.sendTelemetryEvent('copilot.remoteagent.editor.invoke', {
8891
promptLength: prompt.length.toString(),
8992
historyLength: history?.length.toString(),
90-
hasPromptSummary: String(!!promptSummary),
91-
hasHistorySummary: String(!!historySummary),
93+
promptSummaryLength: promptSummary?.length.toString() || '0',
94+
historySummaryLength: historySummary?.length.toString() || '0',
9295
source,
9396
});
9497
stream.progress(vscode.l10n.t('Delegating to coding agent'));
@@ -109,9 +112,48 @@ export class CopilotRemoteAgentManager extends Disposable {
109112
return result.number;
110113
};
111114

115+
const handleConfirmationData = async () => {
116+
const results: Array<{ step: string; accepted: boolean }> = [];
117+
results.push(...(request.acceptedConfirmationData?.map(data => ({ step: data.step, accepted: true })) ?? []));
118+
results.push(...((request.rejectedConfirmationData ?? []).filter(data => !results.some(r => r.step === data.step)).map(data => ({ step: data.step, accepted: false }))));
119+
for (const data of results) {
120+
switch (data.step) {
121+
case 'create':
122+
if (!data.accepted) {
123+
stream.markdown(vscode.l10n.t('Coding agent request cancelled.'));
124+
return {};
125+
}
126+
const number = await startSession('chat');
127+
if (!number) {
128+
return {};
129+
}
130+
const pullRequest = await this.findPullRequestById(number, true);
131+
if (!pullRequest) {
132+
stream.warning(vscode.l10n.t('Could not find the associated pull request {0} for this chat session.', number));
133+
return {};
134+
}
135+
const uri = await toOpenPullRequestWebviewUri({ owner: pullRequest.remote.owner, repo: pullRequest.remote.repositoryName, pullRequestNumber: pullRequest.number });
136+
const plaintextBody = marked.parse(pullRequest.body, { renderer: new PlainTextRenderer(true), smartypants: true }).trim();
137+
const card = new vscode.ChatResponsePullRequestPart(uri, pullRequest.title, plaintextBody, pullRequest.author.specialDisplayName ?? pullRequest.author.login, `#${pullRequest.number}`);
138+
stream.push(card);
139+
stream.markdown(vscode.l10n.t('GitHub Copilot coding agent has begun working on your request. Follow its progress in the associated chat and pull request.'));
140+
vscode.window.showChatSession(COPILOT_SWE_AGENT, String(number), { viewColumn: vscode.ViewColumn.Active });
141+
break;
142+
default:
143+
stream.warning(`Unknown confirmation step: ${data.step}\n\n`);
144+
break;
145+
}
146+
}
147+
return {};
148+
};
149+
150+
if (request.acceptedConfirmationData || request.rejectedConfirmationData) {
151+
return await handleConfirmationData();
152+
}
153+
112154
if (context.chatSessionContext?.isUntitled) {
113155
/* Generate new coding agent session from an 'untitled' session */
114-
const number = await startSession(request.prompt, context.history, 'untitledChatSession');
156+
const number = await startSession('untitledChatSession');
115157
if (!number) {
116158
return {};
117159
}
@@ -175,25 +217,13 @@ export class CopilotRemoteAgentManager extends Disposable {
175217
} else {
176218
/* @copilot invoked from a 'normal' chat */
177219

178-
// TODO(jospicer): Use confirmations to guide users
179-
180-
const number = await startSession(request.prompt, context.history, 'chat', context.chatSummary); // TODO(jospicer): 'All of the chat messages so far in the current chat session. Currently, only chat messages for the current participant are included'
181-
if (!number) {
182-
return {};
183-
}
184-
const pullRequest = await this.findPullRequestById(number, true);
185-
if (!pullRequest) {
186-
stream.warning(vscode.l10n.t('Could not find the associated pull request {0} for this chat session.', number));
187-
return {};
188-
}
189-
190-
const uri = await toOpenPullRequestWebviewUri({ owner: pullRequest.remote.owner, repo: pullRequest.remote.repositoryName, pullRequestNumber: pullRequest.number });
191-
const plaintextBody = marked.parse(pullRequest.body, { renderer: new PlainTextRenderer(true), smartypants: true }).trim();
220+
stream.confirmation(
221+
vscode.l10n.t('Delegate to coding agent'),
222+
DELEGATE_MODAL_DETAILS,
223+
{ step: 'create' },
224+
['Delegate', 'Cancel']
225+
);
192226

193-
const card = new vscode.ChatResponsePullRequestPart(uri, pullRequest.title, plaintextBody, pullRequest.author.specialDisplayName ?? pullRequest.author.login, `#${pullRequest.number}`);
194-
stream.push(card);
195-
stream.markdown(vscode.l10n.t('GitHub Copilot coding agent has begun working on your request. Follow its progress in the associated chat and pull request.'));
196-
vscode.window.showChatSession(COPILOT_SWE_AGENT, String(number), { viewColumn: vscode.ViewColumn.Active });
197227
}
198228
}
199229

@@ -549,7 +579,7 @@ export class CopilotRemoteAgentManager extends Disposable {
549579

550580
let autoPushAndCommit = false;
551581
const message = vscode.l10n.t('Copilot coding agent will continue your work in \'{0}\'.', repoName);
552-
const detail = vscode.l10n.t('Your chat context will be used to continue work in a new pull request.');
582+
const detail = DELEGATE_MODAL_DETAILS;
553583
if (source !== 'prompt' && hasChanges && CopilotRemoteAgentConfig.getAutoCommitAndPushEnabled()) {
554584
// Pending changes modal
555585
const modalResult = await vscode.window.showInformationMessage(

0 commit comments

Comments
 (0)