mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-10 08:45:56 +01:00
Fix chat persistence issue on session restart in Agents Window (#324456)
Agent Host changes for agents/agents-window-restart-chat-bug
This commit is contained in:
committed by
GitHub
parent
2fe88e4617
commit
d2fa20bf00
@@ -472,6 +472,9 @@ export class SessionsService extends Disposable implements ISessionsService {
|
||||
// no slot remains); drive the open flow below so the fallback is fully
|
||||
// opened.
|
||||
if (e.removed.length) {
|
||||
for (const session of e.removed) {
|
||||
this._sessionStates.delete(session.resource);
|
||||
}
|
||||
this._visibility.removeMany(e.removed.map(r => r.sessionId));
|
||||
}
|
||||
|
||||
@@ -886,6 +889,26 @@ export class SessionsService extends Disposable implements ISessionsService {
|
||||
|
||||
private _saveSessionStates(): void {
|
||||
const entries = this._snapshotVisibleSessionStates();
|
||||
|
||||
// Also persist the per-session state (closed chats, last active chat) of
|
||||
// sessions that are not currently visible, so a session switched out of
|
||||
// the grid keeps its closed-chat set across a reload. Grid-placement
|
||||
// fields are stripped so they are not restored into the grid.
|
||||
const visible = new ResourceMap<true>();
|
||||
for (const entry of entries) {
|
||||
visible.set(URI.parse(entry.sessionResource), true);
|
||||
}
|
||||
for (const [resource, state] of this._sessionStates) {
|
||||
if (visible.has(resource)) {
|
||||
continue;
|
||||
}
|
||||
entries.push({
|
||||
sessionResource: state.sessionResource,
|
||||
activeChatResource: state.activeChatResource,
|
||||
closedChatResources: state.closedChatResources,
|
||||
});
|
||||
}
|
||||
|
||||
this.storageService.store(ACTIVE_SESSION_STATES_KEY, JSON.stringify(entries), StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1404,6 +1404,62 @@ suite('SessionsManagementService', () => {
|
||||
await second.restoreVisibleSessions();
|
||||
assert.deepStrictEqual((second.activeSession.get()?.closedChats.get() ?? []).map(c => c.title.get()), ['b']);
|
||||
});
|
||||
|
||||
test('a chat closed in a non-active session stays closed across a restart', async () => {
|
||||
const mainA = chat('mainA');
|
||||
const chatA2 = chat('a2');
|
||||
const sessionA = stubSession({
|
||||
sessionId: 'A', providerId: 'test',
|
||||
status: constObservable(SessionStatus.Completed),
|
||||
chats: constObservable([mainA, chatA2]),
|
||||
mainChat: constObservable(mainA),
|
||||
capabilities: constObservable({ supportsMultipleChats: true }),
|
||||
});
|
||||
const mainB = chat('mainB');
|
||||
const chatB2 = chat('b2');
|
||||
const sessionB = stubSession({
|
||||
sessionId: 'B', providerId: 'test',
|
||||
status: constObservable(SessionStatus.Completed),
|
||||
chats: constObservable([mainB, chatB2]),
|
||||
mainChat: constObservable(mainB),
|
||||
capabilities: constObservable({ supportsMultipleChats: true }),
|
||||
});
|
||||
const storage = disposables.add(new InMemoryStorageService());
|
||||
const provider = new class extends TestSessionsProvider {
|
||||
constructor() { super(sessionA); }
|
||||
override getSessions(): ISession[] { return [sessionA, sessionB]; }
|
||||
};
|
||||
const makeView = () => {
|
||||
const instantiationService = disposables.add(new TestInstantiationService());
|
||||
instantiationService.stub(IStorageService, storage);
|
||||
instantiationService.stub(ILogService, new NullLogService());
|
||||
instantiationService.stub(IContextKeyService, disposables.add(new MockContextKeyService()));
|
||||
instantiationService.stub(ISessionsProvidersService, new TestSessionsProvidersService([provider]));
|
||||
instantiationService.stub(IUriIdentityService, { extUri: extUriBiasedIgnorePathCase });
|
||||
instantiationService.stub(IChatWidgetService, new TestChatWidgetService());
|
||||
instantiationService.stub(IProgressService, new TestProgressService());
|
||||
instantiationService.stub(IChatService, new class extends mock<IChatService>() {
|
||||
override readonly onDidSubmitRequest = Event.None;
|
||||
});
|
||||
const service = disposables.add(instantiationService.createInstance(SessionsManagementService));
|
||||
return createView(instantiationService, service, disposables);
|
||||
};
|
||||
|
||||
// First window: close a chat in each session, end on session A so B is
|
||||
// no longer visible, then simulate shutdown (flush storage).
|
||||
const first = makeView();
|
||||
await first.openSession(sessionB.resource);
|
||||
await first.closeChat(first.activeSession.get()!, chatB2);
|
||||
await first.openSession(sessionA.resource);
|
||||
await first.closeChat(first.activeSession.get()!, chatA2);
|
||||
await storage.flush();
|
||||
|
||||
// Second window: restore, then switch to B and confirm its chat is still closed.
|
||||
const second = makeView();
|
||||
await second.restoreVisibleSessions();
|
||||
await second.openSession(sessionB.resource);
|
||||
assert.deepStrictEqual((second.activeSession.get()?.closedChats.get() ?? []).map(c => c.title.get()), ['b2']);
|
||||
});
|
||||
});
|
||||
|
||||
suite('createQuickChat', () => {
|
||||
|
||||
Reference in New Issue
Block a user