diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts index 81bf66493ede3..53aa03a8f8b21 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatExecuteActions.ts @@ -17,7 +17,7 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { IChatAgentService } from '../../common/chatAgents.js'; import { ChatContextKeyExprs, ChatContextKeys } from '../../common/chatContextKeys.js'; -import { IChatEditingService, IChatEditingSession, WorkingSetEntryState } from '../../common/chatEditingService.js'; +import { WorkingSetEntryState } from '../../common/chatEditingService.js'; import { chatVariableLeader } from '../../common/chatParserTypes.js'; import { IChatService } from '../../common/chatService.js'; import { ChatAgentLocation, ChatConfiguration, ChatMode } from '../../common/constants.js'; @@ -492,8 +492,14 @@ class SendToChatEditingAction extends Action2 { const viewsService = accessor.get(IViewsService); const dialogService = accessor.get(IDialogService); - const chatEditingService = accessor.get(IChatEditingService); - const currentEditingSession: IChatEditingSession | undefined = chatEditingService.editingSessionsObs.get().at(0); + const { widget: editingWidget } = await viewsService.openView(EditsViewId) as ChatViewPane; + if (!editingWidget.viewModel?.sessionId) { + return; + } + const currentEditingSession = editingWidget.viewModel.model.editingSession; + if (!currentEditingSession) { + return; + } const currentEditCount = currentEditingSession?.entries.get().length; if (currentEditCount) { @@ -510,17 +516,10 @@ class SendToChatEditingAction extends Action2 { return; } - await currentEditingSession?.stop(); + await currentEditingSession.stop(true); + editingWidget.clear(); } - const { widget: editingWidget } = await viewsService.openView(EditsViewId) as ChatViewPane; - if (!editingWidget.viewModel?.sessionId) { - return; - } - const chatEditingSession = editingWidget.viewModel.model.editingSession; - if (!chatEditingSession) { - return; - } for (const attachment of widget.attachmentModel.attachments) { editingWidget.attachmentModel.addContext(attachment); } diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index 10764ef387445..8e72f998abf6a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -604,11 +604,6 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio } }); })); - - if (this._state.get() !== ChatEditingSessionState.Disposed) { - // session got disposed while we were closing editors and clearing state - this.dispose(); - } } override dispose() { diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index dfae127242800..c393e9a849b9b 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -21,7 +21,6 @@ import { IOffsetRange, OffsetRange } from '../../../../editor/common/core/offset import { IRange } from '../../../../editor/common/core/range.js'; import { Location, SymbolKind, TextEdit } from '../../../../editor/common/languages.js'; import { localize } from '../../../../nls.js'; -import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { IMarker, MarkerSeverity } from '../../../../platform/markers/common/markers.js'; import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommon.js'; @@ -30,7 +29,7 @@ import { IChatEditingService, IChatEditingSession } from './chatEditingService.j import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js'; import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatNotebookEdit, IChatProgress, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js'; import { IChatRequestVariableValue } from './chatVariables.js'; -import { ChatAgentLocation, ChatConfiguration } from './constants.js'; +import { ChatAgentLocation } from './constants.js'; export interface IBaseChatRequestVariableEntry { id: string; @@ -1317,8 +1316,7 @@ export class ChatModel extends Disposable implements IChatModel { private readonly _initialLocation: ChatAgentLocation, @ILogService private readonly logService: ILogService, @IChatAgentService private readonly chatAgentService: IChatAgentService, - @IChatEditingService chatEditingService: IChatEditingService, - @IConfigurationService configurationService: IConfigurationService, + @IChatEditingService private readonly chatEditingService: IChatEditingService, ) { super(); @@ -1336,11 +1334,14 @@ export class ChatModel extends Disposable implements IChatModel { this._initialRequesterAvatarIconUri = initialData?.requesterAvatarIconUri && URI.revive(initialData.requesterAvatarIconUri); this._initialResponderAvatarIconUri = isUriComponents(initialData?.responderAvatarIconUri) ? URI.revive(initialData.responderAvatarIconUri) : initialData?.responderAvatarIconUri; + } - if (this._initialLocation === ChatAgentLocation.EditingSession || (configurationService.getValue(ChatConfiguration.UnifiedChatView) && this._initialLocation === ChatAgentLocation.Panel)) { - this._editingSession = new ObservablePromise(chatEditingService.startOrContinueGlobalEditingSession(this)); - this._editingSession.promise.then(editingSession => this._register(editingSession)); - } + startEditingSession(isGlobalEditingSession?: boolean): void { + const editingSessionPromise = isGlobalEditingSession ? + this.chatEditingService.startOrContinueGlobalEditingSession(this) : + this.chatEditingService.createEditingSession(this); + this._editingSession = new ObservablePromise(editingSessionPromise); + this._editingSession.promise.then(editingSession => this._store.isDisposed ? editingSession.dispose() : this._register(editingSession)); } private _deserialize(obj: IExportableChatData): ChatRequestModel[] { diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 6af959f768ebd..4ba63bfd57ea1 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -491,7 +491,7 @@ export interface IChatService { isEnabled(location: ChatAgentLocation): boolean; hasSessions(): boolean; - startSession(location: ChatAgentLocation, token: CancellationToken): ChatModel; + startSession(location: ChatAgentLocation, token: CancellationToken, isGlobalEditingSession?: boolean): ChatModel; getSession(sessionId: string): IChatModel | undefined; getOrRestoreSession(sessionId: string): Promise; isPersistedSessionEmpty(sessionId: string): boolean; diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index e07e484c600de..5a734d53c2560 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -469,13 +469,17 @@ export class ChatService extends Disposable implements IChatService { this.saveState(); } - startSession(location: ChatAgentLocation, token: CancellationToken): ChatModel { + startSession(location: ChatAgentLocation, token: CancellationToken, isGlobalEditingSession: boolean = true): ChatModel { this.trace('startSession'); - return this._startSession(undefined, location, token); + return this._startSession(undefined, location, isGlobalEditingSession, token); } - private _startSession(someSessionHistory: IExportableChatData | ISerializableChatData | undefined, location: ChatAgentLocation, token: CancellationToken): ChatModel { + private _startSession(someSessionHistory: IExportableChatData | ISerializableChatData | undefined, location: ChatAgentLocation, isGlobalEditingSession: boolean, token: CancellationToken): ChatModel { const model = this.instantiationService.createInstance(ChatModel, someSessionHistory, location); + if (location === ChatAgentLocation.EditingSession || (this.unifiedViewEnabled && location === ChatAgentLocation.Panel)) { + model.startEditingSession(isGlobalEditingSession); + } + this._sessionModels.set(model.sessionId, model); this.initializeSession(model, token); return model; @@ -528,7 +532,7 @@ export class ChatService extends Disposable implements IChatService { return undefined; } - const session = this._startSession(sessionData, sessionData.initialLocation ?? ChatAgentLocation.Panel, CancellationToken.None); + const session = this._startSession(sessionData, sessionData.initialLocation ?? ChatAgentLocation.Panel, true, CancellationToken.None); const isTransferred = this.transferredSessionData?.sessionId === sessionId; if (isTransferred) { @@ -553,7 +557,7 @@ export class ChatService extends Disposable implements IChatService { } loadSessionFromContent(data: IExportableChatData | ISerializableChatData): IChatModel | undefined { - return this._startSession(data, data.initialLocation ?? ChatAgentLocation.Panel, CancellationToken.None); + return this._startSession(data, data.initialLocation ?? ChatAgentLocation.Panel, true, CancellationToken.None); } async resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions): Promise { diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts index 682d72460b142..f7612029ae71c 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingService.test.ts @@ -136,7 +136,10 @@ suite('ChatEditingService', function () { const uri = URI.from({ scheme: 'test', path: 'HelloWorld' }); const model = chatService.startSession(ChatAgentLocation.EditingSession, CancellationToken.None); - const session = await editingService.createEditingSession(model, true); + const session = await model.editingSessionObs?.promise; + if (!session) { + assert.fail('session not created'); + } const chatRequest = model?.addRequest({ text: '', parts: [] }, { variables: [] }, 0); assertType(chatRequest.response); @@ -159,7 +162,6 @@ suite('ChatEditingService', function () { await entry.reject(undefined); - session.dispose(); model.dispose(); }); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index d56ff17b99677..25d1f30a4b415 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -1422,7 +1422,7 @@ export async function reviewEdits(accessor: ServicesAccessor, editor: ICodeEdito const chatEditingService = accessor.get(IChatEditingService); const uri = editor.getModel().uri; - const chatModel = chatService.startSession(ChatAgentLocation.Editor, token); + const chatModel = chatService.startSession(ChatAgentLocation.Editor, token, false); const editSession = await chatEditingService.createEditingSession(chatModel); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index 599195d2fcdd1..8e37a831c4908 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -5,11 +5,16 @@ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; +import { ResourceMap } from '../../../../base/common/map.js'; import { Schemas } from '../../../../base/common/network.js'; +import { autorun } from '../../../../base/common/observable.js'; +import { isEqual } from '../../../../base/common/resources.js'; +import { assertType } from '../../../../base/common/types.js'; import { URI } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; import { IActiveCodeEditor, ICodeEditor, isCodeEditor, isCompositeEditor, isDiffEditor } from '../../../../editor/browser/editorBrowser.js'; import { Range } from '../../../../editor/common/core/range.js'; +import { ILanguageService } from '../../../../editor/common/languages/language.js'; import { IValidEditOperation } from '../../../../editor/common/model.js'; import { createTextBufferFactoryFromSnapshot } from '../../../../editor/common/model/textModel.js'; import { IEditorWorkerService } from '../../../../editor/common/services/editorWorker.js'; @@ -20,22 +25,17 @@ import { IInstantiationService } from '../../../../platform/instantiation/common import { ILogService } from '../../../../platform/log/common/log.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { DEFAULT_EDITOR_ASSOCIATION } from '../../../common/editor.js'; +import { IEditorService } from '../../../services/editor/common/editorService.js'; +import { ITextFileService } from '../../../services/textfile/common/textfiles.js'; +import { UntitledTextEditorInput } from '../../../services/untitled/common/untitledTextEditorInput.js'; +import { IChatWidgetService } from '../../chat/browser/chat.js'; import { IChatAgentService } from '../../chat/common/chatAgents.js'; +import { WorkingSetEntryState } from '../../chat/common/chatEditingService.js'; import { IChatService } from '../../chat/common/chatService.js'; +import { ChatAgentLocation } from '../../chat/common/constants.js'; import { CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_AGENT2, CTX_INLINE_CHAT_POSSIBLE } from '../common/inlineChat.js'; -import { IEditorService } from '../../../services/editor/common/editorService.js'; -import { UntitledTextEditorInput } from '../../../services/untitled/common/untitledTextEditorInput.js'; import { HunkData, Session, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession.js'; import { IInlineChatSession2, IInlineChatSessionEndEvent, IInlineChatSessionEvent, IInlineChatSessionService, ISessionKeyComputer } from './inlineChatSessionService.js'; -import { isEqual } from '../../../../base/common/resources.js'; -import { ILanguageService } from '../../../../editor/common/languages/language.js'; -import { ITextFileService } from '../../../services/textfile/common/textfiles.js'; -import { IChatEditingService, WorkingSetEntryState } from '../../chat/common/chatEditingService.js'; -import { assertType } from '../../../../base/common/types.js'; -import { autorun } from '../../../../base/common/observable.js'; -import { ResourceMap } from '../../../../base/common/map.js'; -import { IChatWidgetService } from '../../chat/browser/chat.js'; -import { ChatAgentLocation } from '../../chat/common/constants.js'; type SessionData = { @@ -86,7 +86,6 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { @ILanguageService private readonly _languageService: ILanguageService, @IChatService private readonly _chatService: IChatService, @IChatAgentService private readonly _chatAgentService: IChatAgentService, - @IChatEditingService private readonly _chatEditingService: IChatEditingService, @IChatWidgetService private readonly _chatWidgetService: IChatWidgetService, ) { } @@ -338,9 +337,9 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { this._onWillStartSession.fire(editor as IActiveCodeEditor); - const chatModel = this._chatService.startSession(ChatAgentLocation.EditingSession, token); + const chatModel = this._chatService.startSession(ChatAgentLocation.EditingSession, token, false); - const editingSession = await this._chatEditingService.createEditingSession(chatModel); + const editingSession = await chatModel.editingSessionObs?.promise!; const widget = this._chatWidgetService.getWidgetBySessionId(chatModel.sessionId); widget?.attachmentModel.addFile(uri); @@ -351,7 +350,6 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { this._sessions2.delete(uri); this._onDidChangeSessions.fire(this); })); - store.add(editingSession); store.add(chatModel); store.add(autorun(r => {