diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 6eec236253a..fe252fca2d2 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -107,7 +107,7 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/c import { UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; -import { ExcludeSettingOptions, oldToNewTextSearchResult, TextSearchCompleteMessageType, TextSearchCompleteMessageTypeNew, TextSearchContextNew, TextSearchMatchNew } from 'vs/workbench/services/search/common/searchExtTypes'; +import { ExcludeSettingOptions, TextSearchCompleteMessageType, TextSearchCompleteMessageTypeNew, TextSearchContextNew, TextSearchMatchNew, oldToNewTextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes'; import type * as vscode from 'vscode'; export interface IExtensionRegistries { @@ -1818,6 +1818,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ChatResponseCommandButtonPart: extHostTypes.ChatResponseCommandButtonPart, ChatResponseDetectedParticipantPart: extHostTypes.ChatResponseDetectedParticipantPart, ChatResponseConfirmationPart: extHostTypes.ChatResponseConfirmationPart, + ChatResponseMovePart: extHostTypes.ChatResponseMovePart, ChatResponseReferencePartStatusKind: extHostTypes.ChatResponseReferencePartStatusKind, ChatRequestTurn: extHostTypes.ChatRequestTurn, ChatResponseTurn: extHostTypes.ChatResponseTurn, diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 357d7b4ea7a..4a1a50ae1ab 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -241,7 +241,8 @@ class ChatAgentResponseStream { part instanceof extHostTypes.ChatResponseDetectedParticipantPart || part instanceof extHostTypes.ChatResponseWarningPart || part instanceof extHostTypes.ChatResponseConfirmationPart || - part instanceof extHostTypes.ChatResponseCodeCitationPart + part instanceof extHostTypes.ChatResponseCodeCitationPart || + part instanceof extHostTypes.ChatResponseMovePart ) { checkProposedApiEnabled(that._extension, 'chatParticipantAdditions'); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 140fd24afbb..7c82c4a8d4c 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -40,7 +40,7 @@ import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from 'vs/workbench/common/edit import { IViewBadge } from 'vs/workbench/common/views'; import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatRequestVariableEntry } from 'vs/workbench/contrib/chat/common/chatModel'; -import { IChatAgentDetection, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatProgressMessage, IChatTaskDto, IChatTaskResult, IChatTextEdit, IChatTreeData, IChatUserActionEvent, IChatWarningMessage } from 'vs/workbench/contrib/chat/common/chatService'; +import { IChatAgentDetection, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatFollowup, IChatMarkdownContent, IChatMoveMessage, IChatProgressMessage, IChatTaskDto, IChatTaskResult, IChatTextEdit, IChatTreeData, IChatUserActionEvent, IChatWarningMessage } from 'vs/workbench/contrib/chat/common/chatService'; import { IToolData, IToolResult } from 'vs/workbench/contrib/chat/common/languageModelToolsService'; import * as chatProvider from 'vs/workbench/contrib/chat/common/languageModels'; import { DebugTreeItemCollapsibleState, IDebugVisualizationTreeItem } from 'vs/workbench/contrib/debug/common/debug'; @@ -2454,6 +2454,18 @@ export namespace ChatResponseWarningPart { } } +export namespace ChatResponseMovePart { + export function from(part: vscode.ChatResponseMovePart): Dto { + return { + kind: 'move', + uri: part.uri, + }; + } + export function to(part: Dto): vscode.ChatResponseMovePart { + return new types.ChatResponseMovePart(URI.revive(part.uri)); + } +} + export namespace ChatTask { export function from(part: vscode.ChatResponseProgressPart2): IChatTaskDto { return { @@ -2561,7 +2573,7 @@ export namespace ChatResponseCodeCitationPart { export namespace ChatResponsePart { - export function from(part: vscode.ChatResponsePart | vscode.ChatResponseTextEditPart | vscode.ChatResponseMarkdownWithVulnerabilitiesPart | vscode.ChatResponseDetectedParticipantPart | vscode.ChatResponseWarningPart | vscode.ChatResponseConfirmationPart | vscode.ChatResponseReferencePart2, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): extHostProtocol.IChatProgressDto { + export function from(part: vscode.ChatResponsePart | vscode.ChatResponseTextEditPart | vscode.ChatResponseMarkdownWithVulnerabilitiesPart | vscode.ChatResponseDetectedParticipantPart | vscode.ChatResponseWarningPart | vscode.ChatResponseConfirmationPart | vscode.ChatResponseReferencePart2 | vscode.ChatResponseMovePart, commandsConverter: CommandsConverter, commandDisposables: DisposableStore): extHostProtocol.IChatProgressDto { if (part instanceof types.ChatResponseMarkdownPart) { return ChatResponseMarkdownPart.from(part); } else if (part instanceof types.ChatResponseAnchorPart) { @@ -2586,6 +2598,8 @@ export namespace ChatResponsePart { return ChatResponseConfirmationPart.from(part); } else if (part instanceof types.ChatResponseCodeCitationPart) { return ChatResponseCodeCitationPart.from(part); + } else if (part instanceof types.ChatResponseMovePart) { + return ChatResponseMovePart.from(part); } return { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index b2693963f6f..de8a123e5f6 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4486,6 +4486,13 @@ export class ChatResponseCodeCitationPart { } } +export class ChatResponseMovePart { + constructor( + public readonly uri: vscode.Uri + ) { + } +} + export class ChatResponseTextEditPart { uri: vscode.Uri; edits: vscode.TextEdit[]; diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index d3aa7f35dd8..505c2680b44 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -592,7 +592,9 @@ export type IChatChangeEvent = | IChatInitEvent | IChatAddRequestEvent | IChatChangedRequestEvent | IChatRemoveRequestEvent | IChatAddResponseEvent - | IChatSetAgentEvent; + | IChatSetAgentEvent + | IChatMoveEvent + ; export interface IChatAddRequestEvent { kind: 'addRequest'; @@ -633,6 +635,11 @@ export interface IChatRemoveRequestEvent { reason: ChatRequestRemovalReason; } +export interface IChatMoveEvent { + kind: 'move'; + target: URI; +} + export interface IChatSetAgentEvent { kind: 'setAgent'; agent: IChatAgentData; @@ -949,6 +956,8 @@ export class ChatModel extends Disposable implements IChatModel { } } else if (progress.kind === 'codeCitation') { request.response.applyCodeCitation(progress); + } else if (progress.kind === 'move') { + this._onDidChange.fire({ kind: 'move', target: progress.uri }); } else { this.logService.error(`Couldn't handle progress: ${JSON.stringify(progress)}`); } diff --git a/src/vs/workbench/contrib/chat/common/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService.ts index 292c9a29cf7..830422c8496 100644 --- a/src/vs/workbench/contrib/chat/common/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService.ts @@ -164,6 +164,11 @@ export interface IChatCommandButton { kind: 'command'; } +export interface IChatMoveMessage { + uri: URI; + kind: 'move'; +} + export interface IChatTextEdit { uri: URI; edits: TextEdit[]; @@ -194,6 +199,7 @@ export type IChatProgress = | IChatCommandButton | IChatWarningMessage | IChatTextEdit + | IChatMoveMessage | IChatConfirmation; export interface IChatFollowup { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 39d083980dc..b34bf4a721c 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -5,23 +5,28 @@ import * as aria from 'vs/base/browser/ui/aria/aria'; import { Barrier, DeferredPromise, Queue } from 'vs/base/common/async'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Lazy } from 'vs/base/common/lazy'; import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { MovingAverage } from 'vs/base/common/numbers'; +import { isEqual } from 'vs/base/common/resources'; import { StopWatch } from 'vs/base/common/stopwatch'; import { assertType } from 'vs/base/common/types'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { TextEdit } from 'vs/editor/common/languages'; +import { IValidEditOperation } from 'vs/editor/common/model'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; +import { DefaultModelSHA1Computer } from 'vs/editor/common/services/modelService'; import { InlineCompletionsController } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController'; +import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; import { localize } from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -29,25 +34,21 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { showChatView } from 'vs/workbench/contrib/chat/browser/chat'; -import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; -import { IInlineChatSavingService } from './inlineChatSavingService'; -import { EmptyResponse, ErrorResponse, ReplyResponse, Session, SessionPrompt, StashedSession } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; -import { IInlineChatSessionService } from './inlineChatSessionService'; -import { EditModeStrategy, IEditObserver, LiveStrategy, PreviewStrategy, ProgressingEditsOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies'; -import { InlineChatZoneWidget } from './inlineChatZoneWidget'; -import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; -import { IValidEditOperation } from 'vs/editor/common/model'; -import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatContentWidget'; -import { MessageController } from 'vs/editor/contrib/message/browser/messageController'; -import { ChatModel, ChatRequestRemovalReason, IChatRequestModel, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from 'vs/workbench/contrib/chat/common/chatModel'; -import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl'; -import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; -import { DefaultModelSHA1Computer } from 'vs/editor/common/services/modelService'; -import { generateUuid } from 'vs/base/common/uuid'; -import { isEqual } from 'vs/base/common/resources'; -import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents'; -import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService'; import { IChatWidgetLocationOptions } from 'vs/workbench/contrib/chat/browser/chatWidget'; +import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { ChatModel, ChatRequestRemovalReason, IChatRequestModel, IChatTextEditGroup, IChatTextEditGroupState, IResponse } from 'vs/workbench/contrib/chat/common/chatModel'; +import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; +import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatContentWidget'; +import { EmptyResponse, ErrorResponse, ReplyResponse, Session, SessionPrompt, StashedSession } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; +import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl'; +import { EditModeStrategy, IEditObserver, LiveStrategy, PreviewStrategy, ProgressingEditsOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies'; +import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService'; +import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; +import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; +import { IInlineChatSavingService } from './inlineChatSavingService'; +import { IInlineChatSessionService } from './inlineChatSessionService'; +import { InlineChatZoneWidget } from './inlineChatZoneWidget'; export const enum State { CREATE_SESSION = 'CREATE_SESSION', @@ -142,6 +143,7 @@ export class InlineChatController implements IEditorContribution { @IDialogService private readonly _dialogService: IDialogService, @IContextKeyService contextKeyService: IContextKeyService, @IChatService private readonly _chatService: IChatService, + @IEditorService private readonly _editorService: IEditorService, @INotebookEditorService notebookEditorService: INotebookEditorService, ) { this._ctxVisible = CTX_INLINE_CHAT_VISIBLE.bindTo(contextKeyService); @@ -215,7 +217,7 @@ export class InlineChatController implements IEditorContribution { } })); - this._log('NEW controller'); + this._log(`NEW controller for ${this._editor.getId()}`); } dispose(): void { @@ -373,7 +375,7 @@ export class InlineChatController implements IEditorContribution { return State.INIT_UI; } - private async [State.INIT_UI](options: InlineChatRunOptions): Promise { + private async [State.INIT_UI](options: InlineChatRunOptions): Promise { assertType(this._session); assertType(this._strategy); @@ -456,6 +458,8 @@ export class InlineChatController implements IEditorContribution { } else if (options.isUnstashed) { delete options.isUnstashed; return State.SHOW_RESPONSE; + } else if (this._session.chatModel.hasRequests && this._session.chatModel.requestInProgress) { + return State.SHOW_REQUEST; } else { return State.SHOW_RESPONSE; } @@ -555,6 +559,7 @@ export class InlineChatController implements IEditorContribution { const progressiveEditsQueue = new Queue(); let next: State.SHOW_RESPONSE | State.SHOW_REQUEST | State.CANCEL | State.PAUSE | State.ACCEPT = State.SHOW_RESPONSE; + store.add(Event.once(this._messages.event)(message => { this._log('state=_makeRequest) message received', message); this._chatService.cancelCurrentRequestForSession(chatModel.sessionId); @@ -567,7 +572,7 @@ export class InlineChatController implements IEditorContribution { } })); - store.add(chatModel.onDidChange(e => { + store.add(chatModel.onDidChange(async e => { if (e.kind === 'removeRequest' && e.requestId === request.id) { progressiveEditsCts.cancel(); responsePromise.complete(); @@ -576,6 +581,38 @@ export class InlineChatController implements IEditorContribution { } else { next = State.CANCEL; } + return; + } + if (e.kind === 'move') { + this._log('state=_showRequest) request moved', e); + + const targetUri = e.target; + + // if there's already a tab open for targetUri, show it and move inline chat to that tab + // otherwise, open the tab to the side + const editorPane = await this._editorService.openEditor({ resource: targetUri }, SIDE_GROUP); + assertType(editorPane !== undefined, 'editor must be defined'); + + const newEditor = editorPane.getControl(); + assertType(newEditor !== undefined, 'control must be defined'); + + assertType(isCodeEditor(newEditor), 'control must be a code editor'); + + assertType(this._session !== undefined, 'session must be defined'); + + assertType(newEditor.hasModel()); + + const newSession = await this._inlineChatSessionService.createSession(newEditor, { + editMode: this._getMode(), + chatModel: this._session.chatModel, + }, CancellationToken.None); // FIXME@ulugbekna: add cancellation + + InlineChatController.get(newEditor)?.run({ existingSession: newSession }); + + next = State.CANCEL; + responsePromise.complete(); + + return; } })); @@ -610,6 +647,9 @@ export class InlineChatController implements IEditorContribution { const edits = localEditGroup.edits; const newEdits = edits.slice(lastLength); if (newEdits.length > 0) { + + this._log(`${this._session?.textModelN.uri.toString()} received ${newEdits.length} edits`); + // NEW changes lastLength = edits.length; progressiveEditsAvgDuration.update(progressiveEditsClock.elapsed()); @@ -658,7 +698,6 @@ export class InlineChatController implements IEditorContribution { if (response.isCanceled) { - // await this._session.undoChangesUntil(response.requestId); } @@ -677,8 +716,9 @@ export class InlineChatController implements IEditorContribution { assertType(this._session); assertType(this._strategy); - const { response } = this._session.lastExchange!; + const response = this._session.lastExchange?.response; // FIXME@ulugbekna + assertType(response, `State ${State.SHOW_RESPONSE} should only be reached if there is a response`); let newPosition: Position | undefined; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionService.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionService.ts index 6ab4ea5dbec..1e54dcb995d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionService.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionService.ts @@ -2,17 +2,17 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; -import { Event } from 'vs/base/common/event'; -import { EditMode } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; -import { IRange } from 'vs/editor/common/core/range'; -import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable } from 'vs/base/common/lifecycle'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { Session, StashedSession } from './inlineChatSession'; +import { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IRange } from 'vs/editor/common/core/range'; import { IValidEditOperation } from 'vs/editor/common/model'; -import { IChatResponseModel } from 'vs/workbench/contrib/chat/common/chatModel'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ChatModel, IChatResponseModel } from 'vs/workbench/contrib/chat/common/chatModel'; +import { EditMode } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { Session, StashedSession } from './inlineChatSession'; export type Recording = { @@ -44,7 +44,7 @@ export interface IInlineChatSessionService { onDidStashSession: Event; onDidEndSession: Event; - createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: IRange }, token: CancellationToken): Promise; + createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: IRange; chatModel?: ChatModel }, token: CancellationToken): Promise; moveSession(session: Session, newEditor: ICodeEditor): void; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index 44aecd6d917..1d04ac12aa6 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -16,18 +16,19 @@ import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/text import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker'; import { IModelService } from 'vs/editor/common/services/model'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor'; import { ChatAgentLocation, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents'; +import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel'; import { IChatService } from 'vs/workbench/contrib/chat/common/chatService'; import { CTX_INLINE_CHAT_HAS_AGENT, EditMode } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; import { EmptyResponse, ErrorResponse, HunkData, ReplyResponse, Session, SessionExchange, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession'; import { IInlineChatSessionEndEvent, IInlineChatSessionEvent, IInlineChatSessionService, ISessionKeyComputer, Recording } from './inlineChatSessionService'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; type SessionData = { @@ -86,7 +87,7 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { this._sessions.clear(); } - async createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: Range }, token: CancellationToken): Promise { + async createSession(editor: IActiveCodeEditor, options: { editMode: EditMode; wholeRange?: Range; chatModel?: ChatModel }, token: CancellationToken): Promise { const agent = this._chatAgentService.getDefaultAgent(ChatAgentLocation.Editor); @@ -104,15 +105,19 @@ export class InlineChatSessionServiceImpl implements IInlineChatSessionService { const store = new DisposableStore(); this._logService.trace(`[IE] creating NEW session for ${editor.getId()}, ${agent.extensionId}`); - const chatModel = this._chatService.startSession(ChatAgentLocation.Editor, token); + const chatModel = options.chatModel ?? this._chatService.startSession(ChatAgentLocation.Editor, token); if (!chatModel) { this._logService.trace('[IE] NO chatModel found'); return undefined; } store.add(toDisposable(() => { - this._chatService.clearSession(chatModel.sessionId); - chatModel.dispose(); + const doesOtherSessionUseChatModel = [...this._sessions.values()].some(data => data.session !== session && data.session.chatModel === chatModel); + + if (!doesOtherSessionUseChatModel) { + this._chatService.clearSession(chatModel.sessionId); + chatModel.dispose(); + } })); const lastResponseListener = store.add(new MutableDisposable()); diff --git a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts index 3c29ebef0a4..9cd2eb5f10d 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts @@ -70,7 +70,7 @@ declare module 'vscode' { constructor(value: Uri, license: string, snippet: string); } - export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseDetectedParticipantPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2; + export type ExtendedChatResponsePart = ChatResponsePart | ChatResponseTextEditPart | ChatResponseDetectedParticipantPart | ChatResponseConfirmationPart | ChatResponseCodeCitationPart | ChatResponseReferencePart2 | ChatResponseMovePart; export class ChatResponseWarningPart { value: MarkdownString; @@ -121,6 +121,13 @@ declare module 'vscode' { }, options?: { status?: { description: string; kind: ChatResponseReferencePartStatusKind } }); } + export class ChatResponseMovePart { + + readonly uri: Uri; + + constructor(uri: Uri); + } + export interface ChatResponseStream { /**