Path: blob/main/src/vs/sessions/contrib/chat/browser/branchChatSessionAction.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize2 } from '../../../../nls.js';6import { Action2, MenuId } from '../../../../platform/actions/common/actions.js';7import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';8import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';9import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js';10import { Codicon } from '../../../../base/common/codicons.js';11import { generateUuid } from '../../../../base/common/uuid.js';12import { ChatTreeItem, ChatViewPaneTarget, IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js';13import { ChatModel, ISerializableChatData } from '../../../../workbench/contrib/chat/common/model/chatModel.js';14import { isRequestVM, isResponseVM } from '../../../../workbench/contrib/chat/common/model/chatViewModel.js';15import { revive } from '../../../../base/common/marshalling.js';16import { IChatService } from '../../../../workbench/contrib/chat/common/chatService/chatService.js';171819/**20* Action ID for branching chat session to a new local session.21*/22export const ACTION_ID_BRANCH_CHAT_SESSION = 'workbench.action.chat.branchChatSession';2324/**25* Action that allows users to branch the current chat session from a specific checkpoint.26* This creates a copy of the conversation up to the selected checkpoint, allowing users27* to explore alternative paths from any point in the conversation.28*/29export class BranchChatSessionAction extends Action2 {3031static readonly ID = ACTION_ID_BRANCH_CHAT_SESSION;3233constructor() {34super({35id: BranchChatSessionAction.ID,36title: localize2('branchChatSession', "Branch Chat"),37tooltip: localize2('branchChatSessionTooltip', "Branch to new session"),38icon: Codicon.reply,39f1: false,40precondition: ContextKeyExpr.and(41ChatContextKeys.enabled,42ChatContextKeys.requestInProgress.negate(),43),44menu: [{45id: MenuId.ChatMessageCheckpoint,46group: 'navigation',47order: 3,48when: ContextKeyExpr.and(49ChatContextKeys.isRequest,50ChatContextKeys.lockedToCodingAgent.negate(),51),52}]53});54}5556override async run(accessor: ServicesAccessor, ...args: unknown[]): Promise<void> {57const item = args[0] as ChatTreeItem | undefined;58const widgetService = accessor.get(IChatWidgetService);59const chatService = accessor.get(IChatService);6061// Item must be a valid request or response from the checkpoint toolbar context62if (!item || (!isRequestVM(item) && !isResponseVM(item))) {63return;64}6566const widget = widgetService.getWidgetBySessionResource(item.sessionResource);67if (!widget || !widget.viewModel) {68return;69}7071// Get the current chat model72const chatModel = widget.viewModel.model as ChatModel;73if (!chatModel) {74return;75}7677const checkpointRequestId = isRequestVM(item) ? item.id : item.requestId;78const serializedData = revive(structuredClone(chatModel.toJSON())) as ISerializableChatData;79serializedData.sessionId = generateUuid();8081delete serializedData.customTitle;8283const checkpointIndex = serializedData.requests.findIndex(r => r.requestId === checkpointRequestId);84if (checkpointIndex === -1) {85return;86}8788serializedData.requests = serializedData.requests.slice(0, checkpointIndex);8990// Clear shouldBeRemovedOnSend for all requests in the branched session91// This ensures all requests are visible in the new session92for (const request of serializedData.requests) {93delete request.shouldBeRemovedOnSend;94delete (request as { isHidden?: boolean }).isHidden;95}9697// If there's no conversation history to branch, don't proceed98if (serializedData.requests.length === 0) {99return;100}101102// Load the branched data into a new session model103const modelRef = chatService.loadSessionFromData(serializedData);104105// Open the branched session in the chat view pane106await widgetService.openSession(modelRef.object.sessionResource, ChatViewPaneTarget);107}108}109110111