Skip to content

Commit 49e2cb6

Browse files
Improvements to the fix for microsoft/vscode#275641 (#1843)
fixes microsoft/vscode#275641 This includes confirmation handling in chat and also prevents some random modals from poping up when they shouldn't. I should clean up the auth upgrade service next week to handle metadata better... but this works for the release to keep the change small.
1 parent d9f49e5 commit 49e2cb6

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

src/extension/chatSessions/vscode-node/copilotCloudSessionsProvider.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { Disposable, toDisposable } from '../../../util/vs/base/common/lifecycle
1616
import { body_suffix, CONTINUE_TRUNCATION, extractTitle, formatBodyPlaceholder, getAuthorDisplayName, getRepoId, JOBS_API_VERSION, RemoteAgentResult, SessionIdForPr, toOpenPullRequestWebviewUri, truncatePrompt } from '../vscode/copilotCodingAgentUtils';
1717
import { ChatSessionContentBuilder } from './copilotCloudSessionContentBuilder';
1818
import { IPullRequestFileChangesService } from './pullRequestFileChangesService';
19+
import { IAuthenticationChatUpgradeService } from '../../../platform/authentication/common/authenticationUpgrade';
20+
import { IAuthenticationService } from '../../../platform/authentication/common/authentication';
1921

2022
export type ConfirmationResult = { step: string; accepted: boolean; metadata?: ConfirmationMetadata };
2123

@@ -80,11 +82,17 @@ export class CopilotCloudSessionsProvider extends Disposable implements vscode.C
8082
@ILogService private readonly logService: ILogService,
8183
@IGitExtensionService private readonly _gitExtensionService: IGitExtensionService,
8284
@IPullRequestFileChangesService private readonly _prFileChangesService: IPullRequestFileChangesService,
85+
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
86+
@IAuthenticationChatUpgradeService private readonly _authenticationUpgradeService: IAuthenticationChatUpgradeService,
8387
) {
8488
super();
8589
const interval = setInterval(async () => {
8690
const repoId = await getRepoId(this._gitService);
8791
if (repoId) {
92+
// TODO: handle no auth token case more gracefully
93+
if (!this._authenticationService.permissiveGitHubSession) {
94+
return;
95+
}
8896
const sessions = await this._octoKitService.getAllOpenSessions(`${repoId.org}/${repoId.repo}`);
8997
if (this.cachedSessionsSize !== sessions.length) {
9098
this.refresh();
@@ -104,6 +112,10 @@ export class CopilotCloudSessionsProvider extends Disposable implements vscode.C
104112
return { optionGroups: [] };
105113
}
106114

115+
// TODO: handle no auth token case more gracefully
116+
if (!this._authenticationService.permissiveGitHubSession) {
117+
return { optionGroups: [] };
118+
}
107119
try {
108120
const customAgents = await this._octoKitService.getCustomAgents(repoId.org, repoId.repo);
109121
const agentItems: vscode.ChatSessionProviderOptionItem[] = [
@@ -153,6 +165,10 @@ export class CopilotCloudSessionsProvider extends Disposable implements vscode.C
153165
return [];
154166
}
155167

168+
// TODO: handle no auth token case more gracefully
169+
if (!this._authenticationService.permissiveGitHubSession) {
170+
return [];
171+
}
156172
const sessions = await this._octoKitService.getAllOpenSessions(`${repoId.org}/${repoId.repo}`);
157173
this.cachedSessionsSize = sessions.length;
158174

@@ -430,9 +446,9 @@ export class CopilotCloudSessionsProvider extends Disposable implements vscode.C
430446
}
431447

432448

433-
private async handleConfirmationData(request: vscode.ChatRequest, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) {
449+
private async handleConfirmationData(request: vscode.ChatRequest, stream: vscode.ChatResponseStream, context: vscode.ChatContext, token: vscode.CancellationToken) {
434450
const results: ConfirmationResult[] = [];
435-
results.push(...(request.acceptedConfirmationData?.map(data => ({ step: data.step, accepted: true, metadata: data?.metadata })) ?? []));
451+
results.push(...(request.acceptedConfirmationData?.filter(data => !data?.authPermissionPrompted).map(data => ({ step: data.step, accepted: true, metadata: data?.metadata })) ?? []));
436452
results.push(...((request.rejectedConfirmationData ?? []).filter(data => !results.some(r => r.step === data.step)).map(data => ({ step: data.step, accepted: false, metadata: data?.metadata }))));
437453
for (const data of results) {
438454
switch (data.step) {
@@ -576,7 +592,26 @@ export class CopilotCloudSessionsProvider extends Disposable implements vscode.C
576592

577593
private async chatParticipantImpl(request: vscode.ChatRequest, context: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) {
578594
if (request.acceptedConfirmationData || request.rejectedConfirmationData) {
579-
return await this.handleConfirmationData(request, stream, token);
595+
const findConfirmRequest = request.acceptedConfirmationData?.find(ref => ref?.authPermissionPrompted);
596+
if (findConfirmRequest) {
597+
const result = await this._authenticationUpgradeService.handleConfirmationRequestWithContext(stream, request, context.history);
598+
request = result.request;
599+
context = result.context ?? context;
600+
} else {
601+
return await this.handleConfirmationData(request, stream, context, token);
602+
}
603+
}
604+
605+
const accessToken = this._authenticationService.permissiveGitHubSession;
606+
if (!accessToken) {
607+
// Otherwise, show the permissive session upgrade prompt because it's required
608+
this._authenticationUpgradeService.showPermissiveSessionUpgradeInChat(
609+
stream,
610+
request,
611+
vscode.l10n.t('GitHub Copilot Cloud Agent requires access to your repositories on GitHub for handling requests.'),
612+
context
613+
);
614+
return {};
580615
}
581616

582617
/* __GDPR__

src/platform/authentication/common/authenticationUpgrade.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export interface IAuthenticationChatUpgradeService {
3333
* @param data - The initial chat request data for context.
3434
* @param detail - Optional detail overriding
3535
*/
36-
showPermissiveSessionUpgradeInChat(stream: ChatResponseStream, data: ChatRequest, detail?: string): void;
36+
showPermissiveSessionUpgradeInChat(stream: ChatResponseStream, data: ChatRequest, detail?: string, context?: ChatContext): void;
3737

3838
/**
3939
* Manages the user's input regarding the confirmation request for a session upgrade.
@@ -42,4 +42,13 @@ export interface IAuthenticationChatUpgradeService {
4242
* was passed in if we don't detect that the confirmation was presented.
4343
*/
4444
handleConfirmationRequest(stream: ChatResponseStream, request: ChatRequest, history: ChatContext['history']): Promise<ChatRequest>;
45+
46+
/**
47+
* TODO: Fold this into one API with the above
48+
* Manages the user's input regarding the confirmation request for a session upgrade.
49+
* @param request - The chat request object containing details necessary for the upgrade flow.
50+
* @returns Promise<ChatRequest> - The ChatRequest that was originally presented the confirmation, or the request that
51+
* was passed in if we don't detect that the confirmation was presented.
52+
*/
53+
handleConfirmationRequestWithContext(stream: ChatResponseStream, request: ChatRequest, history: ChatContext['history']): Promise<{ request: ChatRequest; context?: ChatContext }>;
4554
}

src/platform/authentication/common/authenticationUpgradeService.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ export class AuthenticationChatUpgradeService extends Disposable implements IAut
109109
showPermissiveSessionUpgradeInChat(
110110
stream: ChatResponseStream,
111111
data: ChatRequest,
112-
detail?: string
112+
detail?: string,
113+
context?: ChatContext
113114
): void {
114115
this.logService.trace('Requesting permissive session upgrade in chat');
115116
this.hasRequestedPermissiveSessionUpgrade = true;
116117
stream.confirmation(
117118
this._permissionRequest,
118119
detail || l10n.t('To get more relevant Chat results, we need permission to read the contents of your repository on GitHub.'),
119-
{ authPermissionPrompted: true, ...data },
120+
// TODO: Change this shape to include request via a dedicated field
121+
{ authPermissionPrompted: true, ...data, context },
120122
[
121123
this._permissionRequestGrant,
122124
this._permissionRequestNotNow,
@@ -125,6 +127,17 @@ export class AuthenticationChatUpgradeService extends Disposable implements IAut
125127
);
126128
}
127129

130+
async handleConfirmationRequestWithContext(stream: ChatResponseStream, request: ChatRequest, history: ChatContext['history']): Promise<{ request: ChatRequest; context?: ChatContext }> {
131+
const findConfirmationRequested: (ChatRequest & { context?: ChatContext }) | undefined = request.acceptedConfirmationData?.find(ref => ref?.authPermissionPrompted);
132+
if (!findConfirmationRequested) {
133+
return { request, context: undefined };
134+
}
135+
const context = findConfirmationRequested.context;
136+
137+
const updatedRequest = await this.handleConfirmationRequest(stream, request, history);
138+
return { request: updatedRequest, context };
139+
}
140+
128141
async handleConfirmationRequest(stream: ChatResponseStream, request: ChatRequest, history: ChatContext['history']): Promise<ChatRequest> {
129142
const findConfirmationRequested: ChatRequest | undefined = request.acceptedConfirmationData?.find(ref => ref?.authPermissionPrompted);
130143
if (!findConfirmationRequested) {

0 commit comments

Comments
 (0)