Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/extension/chatSessions/vscode-node/chatSessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ export class ChatSessionsContrib extends Disposable implements IExtensionContrib

const copilotcliSessionIsolationManager = copilotcliAgentInstaService.createInstance(CopilotCLISessionIsolationManager);
const copilotcliSessionItemProvider = this._register(copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionItemProvider));
this._register(vscode.chat.registerChatSessionItemProvider(this.copilotcliSessionType, copilotcliSessionItemProvider));
const imageSupport = copilotcliAgentInstaService.createInstance(CopilotCLIImageSupport);
const promptResolver = copilotcliAgentInstaService.createInstance(CopilotCLIPromptResolver, imageSupport);
const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProvider, copilotcliSessionIsolationManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ITelemetryService } from '../../../platform/telemetry/common/telemetry'
import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';
import { disposableTimeout, raceCancellation } from '../../../util/vs/base/common/async';
import { isCancellationError } from '../../../util/vs/base/common/errors';
import { Emitter, Event } from '../../../util/vs/base/common/event';
import { Emitter } from '../../../util/vs/base/common/event';
import { Disposable, DisposableStore, IDisposable, IReference, toDisposable } from '../../../util/vs/base/common/lifecycle';
import { autorun } from '../../../util/vs/base/common/observable';
import { extUri, isEqual } from '../../../util/vs/base/common/resources';
Expand Down Expand Up @@ -113,12 +113,8 @@ function escapeXml(text: string): string {
.replace(/'/g, ''');
}

export class CopilotCLIChatSessionItemProvider extends Disposable implements vscode.ChatSessionItemProvider {
private readonly _onDidChangeChatSessionItems = this._register(new Emitter<void>());
public readonly onDidChangeChatSessionItems: Event<void> = this._onDidChangeChatSessionItems.event;

private readonly _onDidCommitChatSessionItem = this._register(new Emitter<{ original: vscode.ChatSessionItem; modified: vscode.ChatSessionItem }>());
public readonly onDidCommitChatSessionItem: Event<{ original: vscode.ChatSessionItem; modified: vscode.ChatSessionItem }> = this._onDidCommitChatSessionItem.event;
export class CopilotCLIChatSessionItemProvider extends Disposable {
private readonly controller: vscode.ChatSessionItemController;

constructor(
@ICopilotCLISessionService private readonly copilotcliSessionService: ICopilotCLISessionService,
Expand All @@ -130,27 +126,45 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
) {
super();
this._register(this.terminalIntegration);

this.controller = this._register(vscode.chat.createChatSessionItemController(
'copilotcli',
() => this.refresh()
));

this._register(this.copilotcliSessionService.onDidChangeSessions(() => {
this.notifySessionsChange();
}));
}

public notifySessionsChange(): void {
this._onDidChangeChatSessionItems.fire();
void this.controller.refreshHandler();
}

public swap(original: vscode.ChatSessionItem, modified: vscode.ChatSessionItem): void {
this._onDidCommitChatSessionItem.fire({ original, modified });
this.controller.items.delete(original.resource);
this.controller.items.add(modified);
}

public async provideChatSessionItems(token: vscode.CancellationToken): Promise<vscode.ChatSessionItem[]> {
const sessions = await this.copilotcliSessionService.getAllSessions(this.shouldShowSession.bind(this), token);
const diskSessions = await Promise.all(sessions.map(async session => this._toChatSessionItem(session)));
private async refresh(): Promise<void> {
const ctx = new vscode.CancellationTokenSource();
try {
const sessions = await this.copilotcliSessionService.getAllSessions(this.shouldShowSession.bind(this), ctx.token);
const items: vscode.ChatSessionItem[] = [];

for (const session of sessions) {
const item = await this._toChatSessionItem(session);
items.push(item);
}

const count = diskSessions.length;
this.commandExecutionService.executeCommand('setContext', 'github.copilot.chat.cliSessionsEmpty', count === 0);
this.controller.items.replace(items);

return diskSessions;
const count = items.length;
this.commandExecutionService.executeCommand('setContext', 'github.copilot.chat.cliSessionsEmpty', count === 0);
}
finally {
ctx.dispose();
}
}

private shouldShowSession(sessionId: string): boolean | undefined {
Expand All @@ -177,27 +191,25 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc

const label = session.label;

const item = this.controller.createChatSessionItem(resource, label);

// Badge
let badge: vscode.MarkdownString | undefined;
if (worktreeProperties?.branchName) {
badge = new vscode.MarkdownString(`$(worktree) ${worktreeProperties.branchName}`);
const badge = new vscode.MarkdownString(`$(worktree) ${worktreeProperties.branchName}`);
badge.supportThemeIcons = true;
item.badge = badge;
}

// Statistics
const changes = await this.worktreeManager.getWorktreeChanges(session.id);
item.changes = await this.worktreeManager.getWorktreeChanges(session.id);

// Status
const status = session.status ?? vscode.ChatSessionStatus.Completed;
item.status = session.status ?? vscode.ChatSessionStatus.Completed;

return {
resource,
label,
badge,
timing: session.timing,
changes,
status
} satisfies vscode.ChatSessionItem;
// Timing
item.timing = session.timing;

return item;
}

public async createCopilotCLITerminal(): Promise<void> {
Expand Down