Skip to content

Commit e137155

Browse files
authored
ensure fast new chat session swap (#1327)
* ensure fast new chat session swap * move pending session management to session service.
1 parent 4fa1197 commit e137155

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

src/extension/agents/copilotcli/node/copilotcliSessionService.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import type { Session, SessionManager } from '@github/copilot/sdk';
7-
import type { CancellationToken } from 'vscode';
7+
import type { CancellationToken, ChatContext, ChatRequest } from 'vscode';
88
import { IEnvService } from '../../../../platform/env/common/envService';
99
import { IVSCodeExtensionContext } from '../../../../platform/extContext/common/extensionContext';
1010
import { ILogService } from '../../../../platform/log/common/logService';
@@ -20,6 +20,8 @@ export interface ICopilotCLISession {
2020
readonly timestamp: Date;
2121
}
2222

23+
export type ExtendedChatRequest = ChatRequest & { prompt: string };
24+
2325
export interface ICopilotCLISessionService {
2426
readonly _serviceBrand: undefined;
2527

@@ -35,6 +37,11 @@ export interface ICopilotCLISessionService {
3537
// Session wrapper tracking
3638
trackSessionWrapper<T extends IDisposable>(sessionId: string, wrapper: T): void;
3739
findSessionWrapper<T extends IDisposable>(sessionId: string): T | undefined;
40+
41+
// Pending request tracking (for untitled sessions)
42+
setPendingRequest(sessionId: string, request: ExtendedChatRequest, context: ChatContext): void;
43+
getPendingRequest(sessionId: string): { request: ExtendedChatRequest; context: ChatContext } | undefined;
44+
clearPendingRequest(sessionId: string): void;
3845
}
3946

4047
export const ICopilotCLISessionService = createServiceIdentifier<ICopilotCLISessionService>('ICopilotCLISessionService');
@@ -45,6 +52,7 @@ export class CopilotCLISessionService implements ICopilotCLISessionService {
4552
private _sessionManager: SessionManager | undefined;
4653
private _sessionWrappers = new DisposableMap<string, IDisposable>();
4754
private _sessions = new Map<string, ICopilotCLISession>();
55+
private _pendingRequests = new Map<string, { request: any; context: any }>();
4856

4957
constructor(
5058
@ILogService private readonly logService: ILogService,
@@ -223,4 +231,16 @@ export class CopilotCLISessionService implements ICopilotCLISessionService {
223231
// Fallback to session ID
224232
return `Session ${sdkSession.sessionId.slice(0, 8)}`;
225233
}
234+
235+
public setPendingRequest(sessionId: string, request: ExtendedChatRequest, context: ChatContext): void {
236+
this._pendingRequests.set(sessionId, { request, context });
237+
}
238+
239+
public getPendingRequest(sessionId: string): { request: ExtendedChatRequest; context: ChatContext } | undefined {
240+
return this._pendingRequests.get(sessionId);
241+
}
242+
243+
public clearPendingRequest(sessionId: string): void {
244+
this._pendingRequests.delete(sessionId);
245+
}
226246
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ export class ChatSessionsContrib extends Disposable implements IExtensionContrib
5858
const copilotcliSessionItemProvider = this._register(copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionItemProvider));
5959
this._register(vscode.chat.registerChatSessionItemProvider(this.copilotcliSessionType, copilotcliSessionItemProvider));
6060
const copilotcliAgentManager = this._register(copilotcliAgentInstaService.createInstance(CopilotCLIAgentManager));
61-
const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProvider);
62-
const copilotcliChatSessionParticipant = new CopilotCLIChatSessionParticipant(this.copilotcliSessionType, copilotcliAgentManager, copilotcliSessionItemProvider);
61+
const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProvider, copilotcliAgentManager);
62+
const copilotcliChatSessionParticipant = new CopilotCLIChatSessionParticipant(this.copilotcliSessionType, copilotcliAgentManager, copilotCLISessionService, copilotcliSessionItemProvider);
6363
const copilotcliParticipant = vscode.chat.createChatParticipant(this.copilotcliSessionType, copilotcliChatSessionParticipant.createHandler());
6464
this._register(vscode.chat.registerChatSessionContentProvider(this.copilotcliSessionType, copilotcliChatSessionContentProvider, copilotcliParticipant));
6565
this._register(registerCLIChatCommands(copilotcliSessionItemProvider, copilotCLISessionService));

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

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import * as path from '../../../util/vs/base/common/path';
1717
import { URI } from '../../../util/vs/base/common/uri';
1818
import { localize } from '../../../util/vs/nls';
1919
import { CopilotCLIAgentManager } from '../../agents/copilotcli/node/copilotcliAgentManager';
20-
import { ICopilotCLISessionService } from '../../agents/copilotcli/node/copilotcliSessionService';
21-
import { buildChatHistoryFromEvents, parseChatMessagesToEvents } from '../../agents/copilotcli/node/copilotcliToolInvocationFormatter';
20+
import { ExtendedChatRequest, ICopilotCLISessionService } from '../../agents/copilotcli/node/copilotcliSessionService';
21+
import { buildChatHistoryFromEvents, parseChatMessagesToEvents, stripSystemReminders } from '../../agents/copilotcli/node/copilotcliToolInvocationFormatter';
2222

2323
export class CopilotCLIChatSessionItemProvider extends Disposable implements vscode.ChatSessionItemProvider {
2424
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
@@ -169,6 +169,7 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
169169
export class CopilotCLIChatSessionContentProvider implements vscode.ChatSessionContentProvider {
170170

171171
constructor(
172+
private readonly copilotcliAgentManager: CopilotCLIAgentManager,
172173
@ICopilotCLISessionService private readonly sessionService: ICopilotCLISessionService,
173174
) { }
174175

@@ -180,9 +181,39 @@ export class CopilotCLIChatSessionContentProvider implements vscode.ChatSessionC
180181

181182
const history = existingSession ? buildChatHistoryFromEvents(events) : [];
182183

184+
// Check if there's a pending request for this new session
185+
const pendingRequest = this.sessionService.getPendingRequest(copilotcliSessionId);
186+
187+
const activeResponseCallback = pendingRequest
188+
? async (stream: vscode.ChatResponseStream, token: vscode.CancellationToken) => {
189+
this.sessionService.clearPendingRequest(copilotcliSessionId);
190+
await this.copilotcliAgentManager.handleRequest(
191+
copilotcliSessionId,
192+
pendingRequest.request,
193+
pendingRequest.context,
194+
stream,
195+
token
196+
);
197+
}
198+
: undefined;
199+
200+
// If there's a pending request, add it to the history as the first request turn
201+
if (pendingRequest) {
202+
const request = pendingRequest.request;
203+
const requestTurn = new vscode.ChatRequestTurn2(
204+
stripSystemReminders(request.prompt),
205+
undefined,
206+
[...request.references],
207+
'',
208+
[],
209+
undefined
210+
);
211+
history.push(requestTurn);
212+
}
213+
183214
return {
184215
history,
185-
activeResponseCallback: undefined,
216+
activeResponseCallback,
186217
requestHandler: undefined,
187218
};
188219
}
@@ -192,6 +223,7 @@ export class CopilotCLIChatSessionParticipant {
192223
constructor(
193224
private readonly sessionType: string,
194225
private readonly copilotcliAgentManager: CopilotCLIAgentManager,
226+
private readonly sessionService: ICopilotCLISessionService,
195227
private readonly sessionItemProvider: CopilotCLIChatSessionItemProvider,
196228
) { }
197229

@@ -202,23 +234,24 @@ export class CopilotCLIChatSessionParticipant {
202234
private async handleRequest(request: vscode.ChatRequest, context: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken): Promise<vscode.ChatResult | void> {
203235
// Resolve the prompt with references before processing
204236
const resolvedPrompt = this.resolvePrompt(request);
205-
const processedRequest = { ...request, prompt: resolvedPrompt };
237+
const processedRequest: ExtendedChatRequest = { ...request, prompt: resolvedPrompt };
206238

207-
const create = async () => {
208-
const { copilotcliSessionId } = await this.copilotcliAgentManager.handleRequest(undefined, processedRequest, context, stream, token);
209-
if (!copilotcliSessionId) {
210-
stream.warning(localize('copilotcli.failedToCreateSession', "Failed to create a new CopilotCLI session."));
211-
return undefined;
212-
}
213-
return copilotcliSessionId;
214-
};
215239
const { chatSessionContext } = context;
216240
if (chatSessionContext) {
217241
if (chatSessionContext.isUntitled) {
218-
const copilotcliSessionId = await create();
219-
if (copilotcliSessionId) {
220-
this.sessionItemProvider.swap(chatSessionContext.chatSessionItem, { id: copilotcliSessionId, label: processedRequest.prompt ?? 'CopilotCLI' });
242+
// Create a new session (just get the session ID, don't run the request yet)
243+
const newSdkSession = await this.sessionService.getOrCreateSDKSession(undefined, processedRequest.prompt);
244+
const copilotcliSessionId = newSdkSession?.sessionId;
245+
if (!copilotcliSessionId) {
246+
stream.warning(localize('copilotcli.failedToCreateSession', "Failed to create a new CopilotCLI session."));
247+
return {};
221248
}
249+
250+
// Store the pending request that will be executed by activeResponseCallback
251+
this.sessionService.setPendingRequest(copilotcliSessionId, processedRequest, context);
252+
253+
// Immediately swap to the new session (this will trigger provideChatSessionContent)
254+
this.sessionItemProvider.swap(chatSessionContext.chatSessionItem, { id: copilotcliSessionId, label: processedRequest.prompt ?? 'CopilotCLI' });
222255
return {};
223256
}
224257

0 commit comments

Comments
 (0)