Skip to content

Commit e8b4191

Browse files
authored
refactor(copilotcli): enhance session handling with branch name generation (#308956)
1 parent eb62869 commit e8b4191

3 files changed

Lines changed: 29 additions & 10 deletions

File tree

extensions/copilot/src/extension/chatSessions/vscode-node/chatSessions.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { IChatSessionWorktreeService } from '../common/chatSessionWorktreeServic
4242
import { IChatFolderMruService, IFolderRepositoryManager } from '../common/folderRepositoryManager';
4343
import { ICustomSessionTitleService } from '../copilotcli/common/customSessionTitleService';
4444
import { ChatDelegationSummaryService, IChatDelegationSummaryService } from '../copilotcli/common/delegationSummaryService';
45+
import { SessionIdForCLI } from '../copilotcli/common/utils';
4546
import { CopilotCLIAgents, CopilotCLIModels, CopilotCLISDK, ICopilotCLIAgents, ICopilotCLIModels, ICopilotCLISDK } from '../copilotcli/node/copilotCli';
4647
import { CopilotCLIImageSupport, ICopilotCLIImageSupport } from '../copilotcli/node/copilotCLIImageSupport';
4748
import { CopilotCLIPromptResolver } from '../copilotcli/node/copilotcliPromptResolver';
@@ -57,16 +58,15 @@ import { GHPR_EXTENSION_ID } from '../vscode/chatSessionsUriHandler';
5758
import { AgentSessionsWorkspace } from './agentSessionsWorkspace';
5859
import { UserQuestionHandler } from './askUserQuestionHandler';
5960
import { ChatPromptFileService } from './chatPromptFileService';
60-
import { CopilotCLIChatSessionInitializer, ICopilotCLIChatSessionInitializer } from './copilotCLIChatSessionInitializer';
6161
import { ChatSessionMetadataStore } from './chatSessionMetadataStoreImpl';
6262
import { ChatSessionRepositoryTracker } from './chatSessionRepositoryTracker';
6363
import { ChatSessionWorkspaceFolderService } from './chatSessionWorkspaceFolderServiceImpl';
6464
import { ChatSessionWorktreeCheckpointService } from './chatSessionWorktreeCheckpointServiceImpl';
6565
import { ChatSessionWorktreeService } from './chatSessionWorktreeServiceImpl';
6666
import { ClaudeChatSessionContentProvider } from './claudeChatSessionContentProvider';
6767
import { ClaudeCustomizationProvider } from './claudeCustomizationProvider';
68+
import { CopilotCLIChatSessionInitializer, ICopilotCLIChatSessionInitializer } from './copilotCLIChatSessionInitializer';
6869
import { CopilotCLIChatSessionContentProvider, CopilotCLIChatSessionParticipant, registerCLIChatCommands } from './copilotCLIChatSessions';
69-
import { SessionIdForCLI } from '../copilotcli/common/utils';
7070
import { CopilotCLIChatSessionContentProvider as CopilotCLIChatSessionContentProviderV1, CopilotCLIChatSessionItemProvider as CopilotCLIChatSessionItemProviderV1, CopilotCLIChatSessionParticipant as CopilotCLIChatSessionParticipantV1, registerCLIChatCommands as registerCLIChatCommandsV1 } from './copilotCLIChatSessionsContribution';
7171
import { CopilotCLICustomizationProvider } from './copilotCLICustomizationProvider';
7272
import { CopilotCLITerminalIntegration, ICopilotCLITerminalIntegration } from './copilotCLITerminalIntegration';
@@ -75,8 +75,8 @@ import { ClaudeFolderRepositoryManager, CopilotCLIFolderRepositoryManager } from
7575
import { PRContentProvider } from './prContentProvider';
7676
import { IPullRequestDetectionService, PullRequestDetectionService } from './pullRequestDetectionService';
7777
import { IPullRequestFileChangesService, PullRequestFileChangesService } from './pullRequestFileChangesService';
78-
import { ISessionRequestLifecycle, SessionRequestLifecycle } from './sessionRequestLifecycle';
7978
import { ISessionOptionGroupBuilder, SessionOptionGroupBuilder } from './sessionOptionGroupBuilder';
79+
import { ISessionRequestLifecycle, SessionRequestLifecycle } from './sessionRequestLifecycle';
8080

8181

8282
// https://github.com/microsoft/vscode-pull-request-github/blob/8a5c9a145cd80ee364a3bed9cf616b2bd8ac74c2/src/github/copilotApi.ts#L56-L71
@@ -273,13 +273,18 @@ export class ChatSessionsContrib extends Disposable implements IExtensionContrib
273273
const gitService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitService));
274274
const gitExtensionService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitExtensionService));
275275
const toolsService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IToolsService));
276+
const aiGeneratedBranchNamesV1 = instantiationService.invokeFunction(accessor =>
277+
accessor.get(IConfigurationService).getConfig(ConfigKey.Advanced.CLIAIGenerateBranchNames)
278+
);
279+
const branchNameGeneratorV1 = aiGeneratedBranchNamesV1 ? copilotcliAgentInstaService.createInstance(GitBranchNameGenerator) : undefined;
276280

277281
const copilotcliChatSessionParticipant = this._register(copilotcliAgentInstaService.createInstance(
278282
CopilotCLIChatSessionParticipantV1,
279283
copilotcliChatSessionContentProvider,
280284
promptResolver,
281285
copilotcliSessionItemProvider,
282286
cloudSessionProvider,
287+
branchNameGeneratorV1,
283288
));
284289
const copilotCLISessionService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionService));
285290
const copilotCLIWorktreeManagerService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionWorktreeService));

extensions/copilot/src/extension/chatSessions/vscode-node/copilotCLIChatSessionsContribution.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import type { Attachment, SessionOptions, SweCustomAgent } from '@github/copilot/sdk';
77
import * as l10n from '@vscode/l10n';
88
import * as vscode from 'vscode';
9-
import { ChatExtendedRequestHandler, ChatSessionProviderOptionItem, Uri } from 'vscode';
9+
import { ChatExtendedRequestHandler, ChatRequestTurn2, ChatSessionProviderOptionItem, Uri } from 'vscode';
1010
import { IRunCommandExecutionService } from '../../../platform/commands/common/runCommandExecutionService';
1111
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
1212
import { INativeEnvService } from '../../../platform/env/common/envService';
@@ -33,6 +33,7 @@ import { StopWatch } from '../../../util/vs/base/common/stopwatch';
3333
import { URI } from '../../../util/vs/base/common/uri';
3434
import { EXTENSION_ID } from '../../common/constants';
3535
import { ChatVariablesCollection, extractDebugTargetSessionIds, isPromptFile } from '../../prompt/common/chatVariablesCollection';
36+
import { GitBranchNameGenerator } from '../../prompt/node/gitBranch';
3637
import { IToolsService } from '../../tools/common/toolsService';
3738
import { IChatSessionMetadataStore, RepositoryProperties, StoredModeInstructions } from '../common/chatSessionMetadataStore';
3839
import { IChatSessionWorkspaceFolderService } from '../common/chatSessionWorkspaceFolderService';
@@ -1097,6 +1098,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
10971098
private readonly promptResolver: CopilotCLIPromptResolver,
10981099
private readonly sessionItemProvider: CopilotCLIChatSessionItemProvider,
10991100
private readonly cloudSessionProvider: CopilotCloudSessionsProvider | undefined,
1101+
private readonly branchNameGenerator: GitBranchNameGenerator | undefined,
11001102
@IGitService private readonly gitService: IGitService,
11011103
@ICopilotCLIModels private readonly copilotCLIModels: ICopilotCLIModels,
11021104
@ICopilotCLIAgents private readonly copilotCLIAgents: ICopilotCLIAgents,
@@ -1311,7 +1313,14 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
13111313
this.getAgent(id, request, token),
13121314
]);
13131315

1314-
const sessionResult = await this.getOrCreateSession(request, chatSessionContext, stream, { model, agent }, disposables, token);
1316+
const requestTurn = new ChatRequestTurn2(request.prompt ?? '', request.command, [], '', [], [], undefined, undefined, undefined);
1317+
const fakeContext: vscode.ChatContext = {
1318+
history: [requestTurn],
1319+
yieldRequested: false,
1320+
};
1321+
const newBranch = (isUntitled && request.prompt && this.branchNameGenerator) ? this.branchNameGenerator.generateBranchName(fakeContext, token) : undefined;
1322+
1323+
const sessionResult = await this.getOrCreateSession(request, chatSessionContext, stream, { model, agent, newBranch }, disposables, token);
13151324
const session = sessionResult.session;
13161325
if (session) {
13171326
disposables.add(session);
@@ -1675,13 +1684,13 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
16751684
}
16761685
}
16771686

1678-
private async getOrCreateSession(request: vscode.ChatRequest, chatSessionContext: vscode.ChatSessionContext, stream: vscode.ChatResponseStream, options: { model: { model: string; reasoningEffort?: string } | undefined; agent: SweCustomAgent | undefined }, disposables: DisposableStore, token: vscode.CancellationToken): Promise<{ session: IReference<ICopilotCLISession> | undefined; trusted: boolean }> {
1687+
private async getOrCreateSession(request: vscode.ChatRequest, chatSessionContext: vscode.ChatSessionContext, stream: vscode.ChatResponseStream, options: { model: { model: string; reasoningEffort?: string } | undefined; agent: SweCustomAgent | undefined; newBranch?: Promise<string | undefined> }, disposables: DisposableStore, token: vscode.CancellationToken): Promise<{ session: IReference<ICopilotCLISession> | undefined; trusted: boolean }> {
16791688
const { resource } = chatSessionContext.chatSessionItem;
16801689
const existingSessionId = this.sessionItemProvider.untitledSessionIdMapping.get(SessionIdForCLI.parse(resource));
16811690
const id = existingSessionId ?? SessionIdForCLI.parse(resource);
16821691
const isNewSession = chatSessionContext.isUntitled && !existingSessionId;
16831692

1684-
const { workspaceInfo, cancelled, trusted } = await this.getOrInitializeWorkingDirectory(chatSessionContext, stream, request.toolInvocationToken, token);
1693+
const { workspaceInfo, cancelled, trusted } = await this.getOrInitializeWorkingDirectory(chatSessionContext, stream, request.toolInvocationToken, token, options.newBranch);
16851694
const workingDirectory = getWorkingDirectory(workspaceInfo);
16861695
const worktreeProperties = workspaceInfo.worktreeProperties;
16871696
if (cancelled || token.isCancellationRequested) {
@@ -1772,7 +1781,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
17721781
chatSessionContext: vscode.ChatSessionContext | undefined,
17731782
stream: vscode.ChatResponseStream,
17741783
toolInvocationToken: vscode.ChatParticipantToolToken,
1775-
token: vscode.CancellationToken
1784+
token: vscode.CancellationToken,
1785+
newBranch?: Promise<string | undefined>
17761786
): Promise<{
17771787
workspaceInfo: IWorkspaceInfo;
17781788
cancelled: boolean;
@@ -1788,7 +1798,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
17881798
// Use FolderRepositoryManager to initialize folder/repository with worktree creation
17891799
const branch = _sessionBranch.get(id);
17901800
const isolation = _sessionIsolation.get(id) ?? undefined;
1791-
folderInfo = await this.folderRepositoryManager.initializeFolderRepository(id, { stream, toolInvocationToken, branch: branch ?? undefined, isolation, folder: undefined }, token);
1801+
folderInfo = await this.folderRepositoryManager.initializeFolderRepository(id, { stream, toolInvocationToken, branch: branch ?? undefined, isolation, folder: undefined, newBranch }, token);
17921802
} else {
17931803
// Existing session - use getFolderRepository for resolution with trust check
17941804
folderInfo = await this.folderRepositoryManager.getFolderRepository(id, { promptForTrust: true, stream }, token);

extensions/copilot/src/extension/chatSessions/vscode-node/test/copilotCLIChatSessionParticipant.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { RepositoryProperties } from '../../common/chatSessionMetadataStore';
4242
import { IChatSessionWorkspaceFolderService } from '../../common/chatSessionWorkspaceFolderService';
4343
import { IChatSessionWorktreeCheckpointService } from '../../common/chatSessionWorktreeCheckpointService';
4444
import { IChatSessionWorktreeService, type ChatSessionWorktreeFile, type ChatSessionWorktreeProperties, type ChatSessionWorktreePropertiesV2 } from '../../common/chatSessionWorktreeService';
45+
import { IChatFolderMruService } from '../../common/folderRepositoryManager';
4546
import { MockChatSessionMetadataStore } from '../../common/test/mockChatSessionMetadataStore';
4647
import { getWorkingDirectory, IWorkspaceInfo } from '../../common/workspaceInfo';
4748
import { IChatDelegationSummaryService } from '../../copilotcli/common/delegationSummaryService';
@@ -55,7 +56,6 @@ import { IQuestion, IQuestionAnswer, IUserQuestionHandler } from '../../copilotc
5556
import { CustomSessionTitleService } from '../../copilotcli/vscode-node/customSessionTitleServiceImpl';
5657
import { MockChatPromptFileService } from '../../copilotcli/vscode-node/test/testHelpers';
5758
import { CopilotCLIChatSessionContentProvider, CopilotCLIChatSessionItemProvider, CopilotCLIChatSessionParticipant } from '../copilotCLIChatSessionsContribution';
58-
import { IChatFolderMruService } from '../../common/folderRepositoryManager';
5959
import { CopilotCloudSessionsProvider } from '../copilotCloudSessionsProvider';
6060
import { CopilotCLIFolderRepositoryManager } from '../folderRepositoryManagerImpl';
6161

@@ -413,6 +413,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
413413
promptResolver,
414414
itemProvider,
415415
cloudProvider,
416+
undefined,
416417
git,
417418
models as unknown as ICopilotCLIModels,
418419
new NullCopilotCLIAgents(),
@@ -761,6 +762,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
761762
promptResolver,
762763
itemProvider,
763764
cloudProvider,
765+
undefined,
764766
git,
765767
models as unknown as ICopilotCLIModels,
766768
new NullCopilotCLIAgents(),
@@ -1907,6 +1909,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
19071909
promptResolver,
19081910
itemProvider,
19091911
cloudProvider,
1912+
undefined,
19101913
git,
19111914
models as unknown as ICopilotCLIModels,
19121915
agents,
@@ -2039,6 +2042,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
20392042
promptResolver,
20402043
itemProvider,
20412044
cloudProvider,
2045+
undefined,
20422046
git,
20432047
models as unknown as ICopilotCLIModels,
20442048
new NullCopilotCLIAgents(),

0 commit comments

Comments
 (0)