Skip to content
This repository was archived by the owner on May 20, 2026. It is now read-only.

Commit 0fe0d96

Browse files
Use a single session id mapping variable (#4296)
* Background - use the worktree branch name in the picker when locked * Use a single session id mapping variable * Fix tests --------- Co-authored-by: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com>
1 parent fd53376 commit 0fe0d96

2 files changed

Lines changed: 16 additions & 17 deletions

File tree

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

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,6 @@ const MAX_MRU_ENTRIES = 10;
6262
const _sessionBranch: Map<string, string | undefined> = new Map();
6363
const _sessionIsolation: Map<string, string | undefined> = new Map();
6464

65-
// When we start an untitled CLI session, the id of the session is `untitled:xyz`
66-
// As soon as we create a CLI session we have the real session id, lets say `cli-1234`
67-
// Once the session completes, this untitled session `untitled:xyz` will get swapped with the real session id `cli-1234`
68-
// However if the session items provider is called while the session is still running, we need to return the same old `untitled:xyz` session id back to core.
69-
// There's an issue in core (about holding onto ref of the Chat Model).
70-
// As a temporary solution, return the same untitled session id back to core until the session is completed.
71-
const _untitledSessionIdMap = new Map<string, string>();
7265
const _invalidCopilotCLISessionIdsWithErrorMessage = new Map<string, string>();
7366

7467
namespace SessionIdForCLI {
@@ -100,6 +93,13 @@ function escapeXml(text: string): string {
10093
}
10194

10295
export class CopilotCLIChatSessionItemProvider extends Disposable implements vscode.ChatSessionItemProvider {
96+
// When we start an untitled CLI session, the id of the session is `untitled:xyz`
97+
// As soon as we create a CLI session we have the real session id, lets say `cli-1234`
98+
// Once the session completes, this untitled session `untitled:xyz` will get swapped with the real session id `cli-1234`
99+
// However if the session items provider is called while the session is still running, we need to return the same old `untitled:xyz` session id back to core.
100+
// There's an issue in core (about holding onto ref of the Chat Model).
101+
// As a temporary solution, return the same untitled session id back to core until the session is completed.
102+
public readonly untitledSessionIdMapping = new Map<string, string>();
103103
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
104104
public readonly onDidChangeChatSessionItems: Event<void> = this._onDidChangeChatSessionItems.event;
105105

@@ -210,7 +210,7 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
210210
}
211211

212212
private async _toChatSessionItem(session: ICopilotCLISessionItem): Promise<vscode.ChatSessionItem> {
213-
const resource = SessionIdForCLI.getResource(_untitledSessionIdMap.get(session.id) ?? session.id);
213+
const resource = SessionIdForCLI.getResource(this.untitledSessionIdMapping.get(session.id) ?? session.id);
214214
const worktreeProperties = await this.worktreeManager.getWorktreeProperties(session.id);
215215
const workingDirectory = worktreeProperties?.worktreePath ? vscode.Uri.file(worktreeProperties.worktreePath)
216216
: session.workingDirectory;
@@ -876,7 +876,6 @@ function toWorkspaceFolderOptionItem(workspaceFolderUri: URI, name: string): Cha
876876
}
877877

878878
export class CopilotCLIChatSessionParticipant extends Disposable {
879-
private readonly untitledSessionIdMapping = new Map<string, string>();
880879
constructor(
881880
private readonly contentProvider: CopilotCLIChatSessionContentProvider,
882881
private readonly promptResolver: CopilotCLIPromptResolver,
@@ -1061,8 +1060,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
10611060

10621061
this.copilotCLIAgents.trackSessionAgent(session.object.sessionId, agent?.name);
10631062
if (isUntitled) {
1064-
_untitledSessionIdMap.set(session.object.sessionId, id);
1065-
disposables.add(toDisposable(() => _untitledSessionIdMap.delete(session.object.sessionId)));
1063+
disposables.add(toDisposable(() => this.sessionItemProvider.untitledSessionIdMapping.delete(session.object.sessionId)));
10661064
}
10671065

10681066
// Lock the repo option with more accurate information.
@@ -1100,8 +1098,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
11001098
// Delete old information stored for untitled session id.
11011099
_sessionBranch.delete(id);
11021100
_sessionIsolation.delete(id);
1103-
this.untitledSessionIdMapping.delete(id);
1104-
_untitledSessionIdMap.delete(session.object.sessionId);
1101+
this.sessionItemProvider.untitledSessionIdMapping.delete(id);
1102+
this.sessionItemProvider.untitledSessionIdMapping.delete(session.object.sessionId);
11051103
this.folderRepositoryManager.deleteUntitledSessionFolder(id);
11061104
this.sessionItemProvider.swap(chatSessionContext.chatSessionItem, { resource: SessionIdForCLI.getResource(session.object.sessionId), label: request.prompt });
11071105
}
@@ -1129,7 +1127,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
11291127
// If we have a real session id that was mapped to this untitled session, then use that.
11301128
// This way we can get the latest information associated with the real session.
11311129
const parsedId = SessionIdForCLI.parse(resource);
1132-
const id = this.untitledSessionIdMapping.get(parsedId) ?? parsedId;
1130+
const id = this.sessionItemProvider.untitledSessionIdMapping.get(parsedId) ?? parsedId;
11331131
const folderInfo = await this.folderRepositoryManager.getFolderRepository(id, undefined, token);
11341132
if (folderInfo.folder) {
11351133
const folderName = basename(folderInfo.folder);
@@ -1254,7 +1252,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
12541252

12551253
private async getOrCreateSession(request: vscode.ChatRequest, chatSessionContext: vscode.ChatSessionContext, model: string | undefined, agent: SweCustomAgent | undefined, stream: vscode.ChatResponseStream, disposables: DisposableStore, token: vscode.CancellationToken): Promise<{ session: IReference<ICopilotCLISession> | undefined; trusted: boolean }> {
12561254
const { resource } = chatSessionContext.chatSessionItem;
1257-
const existingSessionId = this.untitledSessionIdMapping.get(SessionIdForCLI.parse(resource));
1255+
const existingSessionId = this.sessionItemProvider.untitledSessionIdMapping.get(SessionIdForCLI.parse(resource));
12581256
const id = existingSessionId ?? SessionIdForCLI.parse(resource);
12591257
const isNewSession = chatSessionContext.isUntitled && !existingSessionId;
12601258

@@ -1276,7 +1274,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
12761274
}
12771275
this.logService.info(`Using Copilot CLI session: ${session.object.sessionId} (isNewSession: ${isNewSession}, isolationEnabled: ${isIsolationEnabled(workspaceInfo)}, workingDirectory: ${workingDirectory}, worktreePath: ${worktreeProperties?.worktreePath})`);
12781276
if (isNewSession) {
1279-
this.untitledSessionIdMapping.set(id, session.object.sessionId);
1277+
this.sessionItemProvider.untitledSessionIdMapping.set(id, session.object.sessionId);
12801278
if (worktreeProperties) {
12811279
void this.copilotCLIWorktreeManagerService.setWorktreeProperties(session.object.sessionId, worktreeProperties);
12821280
}
@@ -1336,7 +1334,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
13361334
}> {
13371335
let folderInfo: FolderRepositoryInfo;
13381336
if (chatSessionContext) {
1339-
const existingSessionId = this.untitledSessionIdMapping.get(SessionIdForCLI.parse(chatSessionContext.chatSessionItem.resource));
1337+
const existingSessionId = this.sessionItemProvider.untitledSessionIdMapping.get(SessionIdForCLI.parse(chatSessionContext.chatSessionItem.resource));
13401338
const id = existingSessionId ?? SessionIdForCLI.parse(chatSessionContext.chatSessionItem.resource);
13411339
const isNewSession = chatSessionContext.isUntitled && !existingSessionId;
13421340

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
259259
itemProvider = new class extends mock<CopilotCLIChatSessionItemProvider>() {
260260
override swap = vi.fn();
261261
override notifySessionsChange = vi.fn();
262+
override untitledSessionIdMapping = new Map<string, string>();
262263
}();
263264
cloudProvider = new FakeCloudProvider();
264265
summarizer = new class extends mock<ChatSummarizerProvider>() {

0 commit comments

Comments
 (0)