mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 08:15:56 +01:00
Try to reduce how often LocalAgentsSessionsController fires updates
`LocalAgentsSessionsController` is firing updates on every single response change. This PR tries to reduce this by doing a object equality check before firing the update. In a follow up I'll also see if we can debounce listening to so many request updates
This commit is contained in:
@@ -146,7 +146,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA
|
||||
}));
|
||||
|
||||
this._register(this._chatService.onDidDisposeSession(e => {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
this._proxy.$releaseSession(resource);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -7,16 +7,17 @@ import { coalesce } from '../../../../../base/common/arrays.js';
|
||||
import { CancellationToken } from '../../../../../base/common/cancellation.js';
|
||||
import { Codicon } from '../../../../../base/common/codicons.js';
|
||||
import { Emitter } from '../../../../../base/common/event.js';
|
||||
import { Disposable } from '../../../../../base/common/lifecycle.js';
|
||||
import { ResourceSet } from '../../../../../base/common/map.js';
|
||||
import { Schemas } from '../../../../../base/common/network.js';
|
||||
import { Disposable, DisposableResourceMap } from '../../../../../base/common/lifecycle.js';
|
||||
import { ResourceMap, ResourceSet } from '../../../../../base/common/map.js';
|
||||
import { equals } from '../../../../../base/common/objects.js';
|
||||
import { autorun, observableSignalFromEvent } from '../../../../../base/common/observable.js';
|
||||
import { isEqual } from '../../../../../base/common/resources.js';
|
||||
import { URI } from '../../../../../base/common/uri.js';
|
||||
import { ILogService } from '../../../../../platform/log/common/log.js';
|
||||
import { IWorkbenchContribution } from '../../../../common/contributions.js';
|
||||
import { convertLegacyChatSessionTiming, IChatDetail, IChatService, ResponseModelState } from '../../common/chatService/chatService.js';
|
||||
import { convertLegacyChatSessionTiming, IChatDetail, IChatService, IChatSessionTiming, ResponseModelState } from '../../common/chatService/chatService.js';
|
||||
import { chatModelToChatDetail } from '../../common/chatService/chatServiceImpl.js';
|
||||
import { ChatSessionStatus, IChatSessionItem, IChatSessionItemController, IChatSessionItemsDelta, IChatSessionsService, localChatSessionType } from '../../common/chatSessionsService.js';
|
||||
import { IChatModel } from '../../common/model/chatModel.js';
|
||||
import { ChatModel, IChatModel } from '../../common/model/chatModel.js';
|
||||
import { getChatSessionType } from '../../common/model/chatUri.js';
|
||||
import { getInProgressSessionDescription } from '../chatSessions/chatSessionDescription.js';
|
||||
|
||||
@@ -26,16 +27,14 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
|
||||
|
||||
readonly chatSessionType = localChatSessionType;
|
||||
|
||||
private readonly _onDidChange = this._register(new Emitter<void>());
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
readonly _onDidChangeChatSessionItems = this._register(new Emitter<IChatSessionItemsDelta>());
|
||||
readonly onDidChangeChatSessionItems = this._onDidChangeChatSessionItems.event;
|
||||
|
||||
private readonly _modelListeners = this._register(new DisposableResourceMap());
|
||||
|
||||
constructor(
|
||||
@IChatService private readonly chatService: IChatService,
|
||||
@IChatSessionsService private readonly chatSessionsService: IChatSessionsService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -44,44 +43,81 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private _items: IChatSessionItem[] = [];
|
||||
private _items = new ResourceMap<LocalChatSessionItem>();
|
||||
get items(): readonly IChatSessionItem[] {
|
||||
return this._items;
|
||||
return Array.from(this._items.values());
|
||||
}
|
||||
|
||||
async refresh(token: CancellationToken): Promise<void> {
|
||||
this._items = await this.provideChatSessionItems(token);
|
||||
const newItems = await this.provideChatSessionItems(token);
|
||||
|
||||
this._items.clear();
|
||||
for (const item of newItems) {
|
||||
this._items.set(item.resource, item);
|
||||
}
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.chatService.registerChatModelChangeListeners(Schemas.vscodeLocalChatSession, async sessionResource => {
|
||||
if (getChatSessionType(sessionResource) !== this.chatSessionType) {
|
||||
const tryAddModelListeners = async (model: IChatModel) => {
|
||||
if (getChatSessionType(model.sessionResource) !== this.chatSessionType) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: This gets fired too often
|
||||
await this.refresh(CancellationToken.None);
|
||||
const item = this.getItem(sessionResource);
|
||||
const onChange = () => {
|
||||
this.tryUpdateLiveSessionItem(model);
|
||||
};
|
||||
|
||||
if (item) {
|
||||
this._onDidChangeChatSessionItems.fire({ addedOrUpdated: [item] });
|
||||
}
|
||||
}));
|
||||
await this.refresh(CancellationToken.None);
|
||||
onChange();
|
||||
|
||||
const requestChangeListener = model.lastRequestObs.map(last => last?.response && observableSignalFromEvent('chatSessions.modelRequestChangeListener', last.response.onDidChange));
|
||||
const modelChangeListener = observableSignalFromEvent('chatSessions.modelChangeListener', model.onDidChange);
|
||||
this._modelListeners.set(model.sessionResource, autorun(reader => {
|
||||
requestChangeListener.read(reader)?.read(reader);
|
||||
modelChangeListener.read(reader);
|
||||
|
||||
onChange();
|
||||
}));
|
||||
};
|
||||
|
||||
this._register(this.chatService.onDidCreateModel(model => tryAddModelListeners(model)));
|
||||
for (const model of this.chatService.chatModels.get()) {
|
||||
tryAddModelListeners(model);
|
||||
}
|
||||
|
||||
this._register(this.chatService.onDidDisposeSession(e => {
|
||||
const removedSessionResources = e.sessionResource.filter(resource => getChatSessionType(resource) === this.chatSessionType);
|
||||
for (const sessionResource of e.sessionResources) {
|
||||
this._modelListeners.deleteAndDispose(sessionResource);
|
||||
}
|
||||
|
||||
const removedSessionResources = e.sessionResources.filter(resource => getChatSessionType(resource) === this.chatSessionType);
|
||||
if (removedSessionResources.length) {
|
||||
this._onDidChangeChatSessionItems.fire({ removed: removedSessionResources });
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private getItem(sessionResource: URI): IChatSessionItem | undefined {
|
||||
return this._items.find(item => isEqual(item.resource, sessionResource));
|
||||
private async tryUpdateLiveSessionItem(model: IChatModel): Promise<void> {
|
||||
if (!(model instanceof ChatModel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = this._items.get(model.sessionResource);
|
||||
if (!existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updated = new LocalChatSessionItem(await chatModelToChatDetail(model), model);
|
||||
if (existing.isEqual(updated)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._items.set(existing.resource, updated);
|
||||
this._onDidChangeChatSessionItems.fire({ addedOrUpdated: [updated] });
|
||||
}
|
||||
|
||||
private async provideChatSessionItems(token: CancellationToken): Promise<IChatSessionItem[]> {
|
||||
const sessions: IChatSessionItem[] = [];
|
||||
private async provideChatSessionItems(token: CancellationToken): Promise<LocalChatSessionItem[]> {
|
||||
const sessions: LocalChatSessionItem[] = [];
|
||||
const sessionsByResource = new ResourceSet();
|
||||
|
||||
for (const sessionDetail of await this.chatService.getLiveSessionItems()) {
|
||||
@@ -102,7 +138,7 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
|
||||
return sessions;
|
||||
}
|
||||
|
||||
private async getHistoryItems(): Promise<IChatSessionItem[]> {
|
||||
private async getHistoryItems(): Promise<LocalChatSessionItem[]> {
|
||||
try {
|
||||
const historyItems = await this.chatService.getHistorySessionItems();
|
||||
|
||||
@@ -112,72 +148,90 @@ export class LocalAgentsSessionsController extends Disposable implements IChatSe
|
||||
}
|
||||
}
|
||||
|
||||
private toChatSessionItem(chat: IChatDetail): IChatSessionItem | undefined {
|
||||
private toChatSessionItem(chat: IChatDetail): LocalChatSessionItem | undefined {
|
||||
const model = this.chatService.getSession(chat.sessionResource);
|
||||
|
||||
let description: string | undefined;
|
||||
if (model) {
|
||||
if (!model.hasRequests) {
|
||||
return undefined; // ignore sessions without requests
|
||||
}
|
||||
|
||||
description = getInProgressSessionDescription(model);
|
||||
} else if (chat.isActive) {
|
||||
// Sessions that are active but don't have a chat model are ultimately untitled with no requests
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
resource: chat.sessionResource,
|
||||
label: chat.title,
|
||||
description,
|
||||
status: model ? this.modelToStatus(model) : this.chatResponseStateToStatus(chat.lastResponseState),
|
||||
iconPath: Codicon.chatSparkle,
|
||||
timing: convertLegacyChatSessionTiming(chat.timing),
|
||||
changes: chat.stats ? {
|
||||
insertions: chat.stats.added,
|
||||
deletions: chat.stats.removed,
|
||||
files: chat.stats.fileCount,
|
||||
} : undefined
|
||||
};
|
||||
}
|
||||
|
||||
private modelToStatus(model: IChatModel): ChatSessionStatus | undefined {
|
||||
if (model.requestInProgress.get()) {
|
||||
this.logService.trace(`[agent sessions] Session ${model.sessionResource.toString()} request is in progress.`);
|
||||
return ChatSessionStatus.InProgress;
|
||||
}
|
||||
|
||||
const lastRequest = model.getRequests().at(-1);
|
||||
this.logService.trace(`[agent sessions] Session ${model.sessionResource.toString()} last request response: state ${lastRequest?.response?.state}, isComplete ${lastRequest?.response?.isComplete}, isCanceled ${lastRequest?.response?.isCanceled}, error: ${lastRequest?.response?.result?.errorDetails?.message}.`);
|
||||
if (lastRequest?.response) {
|
||||
if (lastRequest.response.state === ResponseModelState.NeedsInput) {
|
||||
return ChatSessionStatus.NeedsInput;
|
||||
} else if (lastRequest.response.isCanceled || lastRequest.response.result?.errorDetails?.code === 'canceled') {
|
||||
return ChatSessionStatus.Completed;
|
||||
} else if (lastRequest.response.result?.errorDetails) {
|
||||
return ChatSessionStatus.Failed;
|
||||
} else if (lastRequest.response.isComplete) {
|
||||
return ChatSessionStatus.Completed;
|
||||
} else {
|
||||
return ChatSessionStatus.InProgress;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private chatResponseStateToStatus(state: ResponseModelState): ChatSessionStatus {
|
||||
switch (state) {
|
||||
case ResponseModelState.Cancelled:
|
||||
case ResponseModelState.Complete:
|
||||
return ChatSessionStatus.Completed;
|
||||
case ResponseModelState.Failed:
|
||||
return ChatSessionStatus.Failed;
|
||||
case ResponseModelState.Pending:
|
||||
return ChatSessionStatus.InProgress;
|
||||
case ResponseModelState.NeedsInput:
|
||||
return ChatSessionStatus.NeedsInput;
|
||||
}
|
||||
return new LocalChatSessionItem(chat, model);
|
||||
}
|
||||
}
|
||||
|
||||
class LocalChatSessionItem implements IChatSessionItem {
|
||||
readonly resource: URI;
|
||||
readonly iconPath = Codicon.chatSparkle;
|
||||
|
||||
readonly label: string;
|
||||
readonly description: string | undefined;
|
||||
readonly status: ChatSessionStatus | undefined;
|
||||
readonly timing: IChatSessionTiming;
|
||||
readonly changes: IChatSessionItem['changes'];
|
||||
|
||||
constructor(chatDetail: IChatDetail, model: IChatModel | undefined) {
|
||||
this.resource = chatDetail.sessionResource;
|
||||
this.label = chatDetail.title;
|
||||
this.description = model ? getInProgressSessionDescription(model) : undefined;
|
||||
this.status = (model && getSessionStatusForModel(model)) ?? chatResponseStateToSessionStatus(chatDetail.lastResponseState);
|
||||
this.timing = convertLegacyChatSessionTiming(chatDetail.timing);
|
||||
this.changes = chatDetail.stats ? {
|
||||
insertions: chatDetail.stats.added,
|
||||
deletions: chatDetail.stats.removed,
|
||||
files: chatDetail.stats.fileCount,
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
isEqual(other: LocalChatSessionItem): boolean {
|
||||
return isEqual(this.resource, other.resource)
|
||||
&& this.label === other.label
|
||||
&& this.description === other.description
|
||||
&& this.status === other.status
|
||||
&& this.timing.created === other.timing.created
|
||||
&& this.timing.lastRequestStarted === other.timing.lastRequestStarted
|
||||
&& this.timing.lastRequestEnded === other.timing.lastRequestEnded
|
||||
&& equals(this.changes, other.changes);
|
||||
}
|
||||
}
|
||||
|
||||
function getSessionStatusForModel(model: IChatModel): ChatSessionStatus | undefined {
|
||||
if (model.requestInProgress.get()) {
|
||||
return ChatSessionStatus.InProgress;
|
||||
}
|
||||
|
||||
const lastRequest = model.getRequests().at(-1);
|
||||
if (lastRequest?.response) {
|
||||
if (lastRequest.response.state === ResponseModelState.NeedsInput) {
|
||||
return ChatSessionStatus.NeedsInput;
|
||||
} else if (lastRequest.response.isCanceled || lastRequest.response.result?.errorDetails?.code === 'canceled') {
|
||||
return ChatSessionStatus.Completed;
|
||||
} else if (lastRequest.response.result?.errorDetails) {
|
||||
return ChatSessionStatus.Failed;
|
||||
} else if (lastRequest.response.isComplete) {
|
||||
return ChatSessionStatus.Completed;
|
||||
} else {
|
||||
return ChatSessionStatus.InProgress;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function chatResponseStateToSessionStatus(state: ResponseModelState): ChatSessionStatus {
|
||||
switch (state) {
|
||||
case ResponseModelState.Cancelled:
|
||||
case ResponseModelState.Complete:
|
||||
return ChatSessionStatus.Completed;
|
||||
case ResponseModelState.Failed:
|
||||
return ChatSessionStatus.Failed;
|
||||
case ResponseModelState.Pending:
|
||||
return ChatSessionStatus.InProgress;
|
||||
case ResponseModelState.NeedsInput:
|
||||
return ChatSessionStatus.NeedsInput;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ export class ChatEditingService extends Disposable implements IChatEditingServic
|
||||
|
||||
this._register(this._chatService.onDidDisposeSession((e) => {
|
||||
if (e.reason === 'cleared') {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
this.getEditingSession(resource)?.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1525,7 +1525,7 @@ export interface IChatService {
|
||||
readonly onDidReceiveQuestionCarouselAnswer: Event<{ requestId: string; resolveId: string; answers: IChatQuestionAnswers | undefined }>;
|
||||
notifyQuestionCarouselAnswer(requestId: string, resolveId: string, answers: IChatQuestionAnswers | undefined): void;
|
||||
|
||||
readonly onDidDisposeSession: Event<{ readonly sessionResource: readonly URI[]; readonly reason: 'cleared' }>;
|
||||
readonly onDidDisposeSession: Event<{ readonly sessionResources: readonly URI[]; readonly reason: 'cleared' }>;
|
||||
|
||||
transferChatSession(transferredSessionResource: URI, toWorkspace: URI): Promise<void>;
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
private readonly _onDidReceiveQuestionCarouselAnswer = this._register(new Emitter<{ requestId: string; resolveId: string; answers: IChatQuestionAnswers | undefined }>());
|
||||
public readonly onDidReceiveQuestionCarouselAnswer = this._onDidReceiveQuestionCarouselAnswer.event;
|
||||
|
||||
private readonly _onDidDisposeSession = this._register(new Emitter<{ readonly sessionResource: URI[]; reason: 'cleared' }>());
|
||||
private readonly _onDidDisposeSession = this._register(new Emitter<{ readonly sessionResources: URI[]; reason: 'cleared' }>());
|
||||
public readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
||||
|
||||
private readonly _sessionFollowupCancelTokens = this._register(new DisposableResourceMap<CancellationTokenSource>());
|
||||
@@ -195,7 +195,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
this._register(this._sessionModels.onDidDisposeModel(model => {
|
||||
clearChatMarks(model.sessionResource);
|
||||
this.chatDebugService.endSession(model.sessionResource);
|
||||
this._onDidDisposeSession.fire({ sessionResource: [model.sessionResource], reason: 'cleared' });
|
||||
this._onDidDisposeSession.fire({ sessionResources: [model.sessionResource], reason: 'cleared' });
|
||||
}));
|
||||
|
||||
this._chatServiceTelemetry = this.instantiationService.createInstance(ChatServiceTelemetry);
|
||||
@@ -400,18 +400,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
async getLiveSessionItems(): Promise<IChatDetail[]> {
|
||||
return await Promise.all(Array.from(this._sessionModels.values())
|
||||
.filter(session => this.shouldBeInHistory(session))
|
||||
.map(async (session): Promise<IChatDetail> => {
|
||||
const title = session.title || localize('newChat', "New Chat");
|
||||
return {
|
||||
sessionResource: session.sessionResource,
|
||||
title,
|
||||
lastMessageDate: session.lastMessageDate,
|
||||
timing: session.timing,
|
||||
isActive: true,
|
||||
stats: await awaitStatsForSession(session),
|
||||
lastResponseState: session.lastRequest?.response?.state ?? ResponseModelState.Pending,
|
||||
};
|
||||
}));
|
||||
.map(chatModelToChatDetail));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,7 +441,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
|
||||
async removeHistoryEntry(sessionResource: URI): Promise<void> {
|
||||
await this._chatSessionStore.deleteSession(this.toLocalSessionId(sessionResource));
|
||||
this._onDidDisposeSession.fire({ sessionResource: [sessionResource], reason: 'cleared' });
|
||||
this._onDidDisposeSession.fire({ sessionResources: [sessionResource], reason: 'cleared' });
|
||||
}
|
||||
|
||||
async clearAllHistoryEntries(): Promise<void> {
|
||||
@@ -1881,3 +1870,16 @@ export class ChatService extends Disposable implements IChatService {
|
||||
return disposableStore;
|
||||
}
|
||||
}
|
||||
|
||||
export async function chatModelToChatDetail(model: ChatModel): Promise<IChatDetail> {
|
||||
const title = model.title || localize('newChat', "New Chat");
|
||||
return {
|
||||
sessionResource: model.sessionResource,
|
||||
title,
|
||||
lastMessageDate: model.lastMessageDate,
|
||||
timing: model.timing,
|
||||
isActive: true,
|
||||
stats: await awaitStatsForSession(model),
|
||||
lastResponseState: model.lastRequest?.response?.state ?? ResponseModelState.Pending,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export class ChatResponseResourceFileSystemProvider extends Disposable implement
|
||||
) {
|
||||
super();
|
||||
this._register(this.chatService.onDidDisposeSession(e => {
|
||||
for (const sessionResource of e.sessionResource) {
|
||||
for (const sessionResource of e.sessionResources) {
|
||||
const uris = this._sessionAssociations.get(sessionResource);
|
||||
if (uris) {
|
||||
for (const uri of uris) {
|
||||
|
||||
@@ -426,7 +426,7 @@ suite('ChatService', () => {
|
||||
|
||||
let disposed = false;
|
||||
testDisposables.add(testService.onDidDisposeSession(e => {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
if (resource.toString() === model.sessionResource.toString()) {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ export class MockChatService implements IChatService {
|
||||
private liveSessionItems: IChatDetail[] = [];
|
||||
private historySessionItems: IChatDetail[] = [];
|
||||
|
||||
private readonly _onDidDisposeSession = new Emitter<{ sessionResource: URI[]; reason: 'cleared' }>();
|
||||
private readonly _onDidDisposeSession = new Emitter<{ sessionResources: URI[]; reason: 'cleared' }>();
|
||||
readonly onDidDisposeSession = this._onDidDisposeSession.event;
|
||||
|
||||
fireDidDisposeSession(sessionResource: URI[]): void {
|
||||
this._onDidDisposeSession.fire({ sessionResource, reason: 'cleared' });
|
||||
fireDidDisposeSession(sessionResources: URI[]): void {
|
||||
this._onDidDisposeSession.fire({ sessionResources, reason: 'cleared' });
|
||||
}
|
||||
|
||||
setSaveModelsEnabled(enabled: boolean): void {
|
||||
|
||||
@@ -81,7 +81,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
|
||||
// Clear session auto-approve rules when chat sessions end
|
||||
this._register(this._chatService.onDidDisposeSession(e => {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
this._sessionAutoApproveRules.delete(resource);
|
||||
this._sessionAutoApprovalEnabled.delete(resource);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
}));
|
||||
|
||||
this._register(this._chatService.onDidDisposeSession(e => {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
if (LocalChatSessionUri.parseLocalSessionId(resource) === terminalToolSessionId) {
|
||||
this._terminalInstancesByToolSessionId.delete(terminalToolSessionId);
|
||||
this._toolSessionIdByTerminalInstance.delete(instance);
|
||||
|
||||
@@ -512,7 +512,7 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
|
||||
|
||||
// Listen for chat session disposal to clean up associated terminals
|
||||
this._register(this._chatService.onDidDisposeSession(e => {
|
||||
for (const resource of e.sessionResource) {
|
||||
for (const resource of e.sessionResources) {
|
||||
this._cleanupSessionTerminals(resource);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -75,7 +75,7 @@ suite('RunInTerminalTool', () => {
|
||||
let storageService: IStorageService;
|
||||
let workspaceContextService: TestContextService;
|
||||
let terminalServiceDisposeEmitter: Emitter<ITerminalInstance>;
|
||||
let chatServiceDisposeEmitter: Emitter<{ sessionResource: URI[]; reason: 'cleared' }>;
|
||||
let chatServiceDisposeEmitter: Emitter<{ sessionResources: URI[]; reason: 'cleared' }>;
|
||||
let chatSessionArchivedEmitter: Emitter<IAgentSession>;
|
||||
let sandboxEnabled: boolean;
|
||||
let terminalSandboxService: ITerminalSandboxService;
|
||||
@@ -95,7 +95,7 @@ suite('RunInTerminalTool', () => {
|
||||
setConfig(TerminalChatAgentToolsSettingId.BlockDetectedFileWrites, 'outsideWorkspace');
|
||||
sandboxEnabled = false;
|
||||
terminalServiceDisposeEmitter = new Emitter<ITerminalInstance>();
|
||||
chatServiceDisposeEmitter = new Emitter<{ sessionResource: URI[]; reason: 'cleared' }>();
|
||||
chatServiceDisposeEmitter = new Emitter<{ sessionResources: URI[]; reason: 'cleared' }>();
|
||||
chatSessionArchivedEmitter = new Emitter<IAgentSession>();
|
||||
|
||||
instantiationService = workbenchInstantiationService({
|
||||
@@ -1521,7 +1521,7 @@ suite('RunInTerminalTool', () => {
|
||||
});
|
||||
runInTerminalTool.sessionTerminalInstances.set(sessionResource, new Set([mockTerminal1, mockTerminal2]));
|
||||
|
||||
chatServiceDisposeEmitter.fire({ sessionResource: [sessionResource], reason: 'cleared' });
|
||||
chatServiceDisposeEmitter.fire({ sessionResources: [sessionResource], reason: 'cleared' });
|
||||
|
||||
strictEqual(terminal1Disposed, true, 'Terminal 1 should have been disposed');
|
||||
strictEqual(terminal2Disposed, true, 'Terminal 2 should have been disposed');
|
||||
@@ -1543,7 +1543,7 @@ suite('RunInTerminalTool', () => {
|
||||
|
||||
ok(runInTerminalTool.sessionTerminalAssociations.has(sessionResource), 'Terminal association should exist before disposal');
|
||||
|
||||
chatServiceDisposeEmitter.fire({ sessionResource: [sessionResource], reason: 'cleared' });
|
||||
chatServiceDisposeEmitter.fire({ sessionResources: [sessionResource], reason: 'cleared' });
|
||||
|
||||
strictEqual(terminalDisposed, true, 'Terminal should have been disposed');
|
||||
ok(!runInTerminalTool.sessionTerminalAssociations.has(sessionResource), 'Terminal association should be removed after disposal');
|
||||
@@ -1574,7 +1574,7 @@ suite('RunInTerminalTool', () => {
|
||||
ok(runInTerminalTool.sessionTerminalAssociations.has(sessionResource1), 'Session 1 terminal association should exist');
|
||||
ok(runInTerminalTool.sessionTerminalAssociations.has(sessionResource2), 'Session 2 terminal association should exist');
|
||||
|
||||
chatServiceDisposeEmitter.fire({ sessionResource: [sessionResource1], reason: 'cleared' });
|
||||
chatServiceDisposeEmitter.fire({ sessionResources: [sessionResource1], reason: 'cleared' });
|
||||
|
||||
strictEqual(terminal1Disposed, true, 'Terminal 1 should have been disposed');
|
||||
strictEqual(terminal2Disposed, false, 'Terminal 2 should NOT have been disposed');
|
||||
@@ -1584,7 +1584,7 @@ suite('RunInTerminalTool', () => {
|
||||
|
||||
test('should handle disposal of non-existent session gracefully', () => {
|
||||
strictEqual(runInTerminalTool.sessionTerminalAssociations.size, 0, 'No associations should exist initially');
|
||||
chatServiceDisposeEmitter.fire({ sessionResource: [LocalChatSessionUri.forSession('non-existent-session')], reason: 'cleared' });
|
||||
chatServiceDisposeEmitter.fire({ sessionResources: [LocalChatSessionUri.forSession('non-existent-session')], reason: 'cleared' });
|
||||
strictEqual(runInTerminalTool.sessionTerminalAssociations.size, 0, 'No associations should exist after handling non-existent session');
|
||||
});
|
||||
});
|
||||
@@ -1921,7 +1921,7 @@ suite('ChatAgentToolsContribution - tool registration refresh', () => {
|
||||
store.add(fileService.registerProvider(Schemas.file, fileSystemProvider));
|
||||
|
||||
const terminalServiceDisposeEmitter = store.add(new Emitter<ITerminalInstance>());
|
||||
const chatServiceDisposeEmitter = store.add(new Emitter<{ sessionResource: URI[]; reason: 'cleared' }>());
|
||||
const chatServiceDisposeEmitter = store.add(new Emitter<{ sessionResources: URI[]; reason: 'cleared' }>());
|
||||
const chatSessionArchivedEmitter = store.add(new Emitter<IAgentSession>());
|
||||
|
||||
instantiationService = workbenchInstantiationService({
|
||||
|
||||
Reference in New Issue
Block a user