Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/contrib/chat/browser/branchChatSessionAction.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { localize2 } from '../../../../nls.js';
7
import { Action2, MenuId } from '../../../../platform/actions/common/actions.js';
8
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
9
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
10
import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js';
11
import { Codicon } from '../../../../base/common/codicons.js';
12
import { generateUuid } from '../../../../base/common/uuid.js';
13
import { ChatTreeItem, ChatViewPaneTarget, IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js';
14
import { ChatModel, ISerializableChatData } from '../../../../workbench/contrib/chat/common/model/chatModel.js';
15
import { isRequestVM, isResponseVM } from '../../../../workbench/contrib/chat/common/model/chatViewModel.js';
16
import { revive } from '../../../../base/common/marshalling.js';
17
import { IChatService } from '../../../../workbench/contrib/chat/common/chatService/chatService.js';
18
19
20
/**
21
* Action ID for branching chat session to a new local session.
22
*/
23
export const ACTION_ID_BRANCH_CHAT_SESSION = 'workbench.action.chat.branchChatSession';
24
25
/**
26
* Action that allows users to branch the current chat session from a specific checkpoint.
27
* This creates a copy of the conversation up to the selected checkpoint, allowing users
28
* to explore alternative paths from any point in the conversation.
29
*/
30
export class BranchChatSessionAction extends Action2 {
31
32
static readonly ID = ACTION_ID_BRANCH_CHAT_SESSION;
33
34
constructor() {
35
super({
36
id: BranchChatSessionAction.ID,
37
title: localize2('branchChatSession', "Branch Chat"),
38
tooltip: localize2('branchChatSessionTooltip', "Branch to new session"),
39
icon: Codicon.reply,
40
f1: false,
41
precondition: ContextKeyExpr.and(
42
ChatContextKeys.enabled,
43
ChatContextKeys.requestInProgress.negate(),
44
),
45
menu: [{
46
id: MenuId.ChatMessageCheckpoint,
47
group: 'navigation',
48
order: 3,
49
when: ContextKeyExpr.and(
50
ChatContextKeys.isRequest,
51
ChatContextKeys.lockedToCodingAgent.negate(),
52
),
53
}]
54
});
55
}
56
57
override async run(accessor: ServicesAccessor, ...args: unknown[]): Promise<void> {
58
const item = args[0] as ChatTreeItem | undefined;
59
const widgetService = accessor.get(IChatWidgetService);
60
const chatService = accessor.get(IChatService);
61
62
// Item must be a valid request or response from the checkpoint toolbar context
63
if (!item || (!isRequestVM(item) && !isResponseVM(item))) {
64
return;
65
}
66
67
const widget = widgetService.getWidgetBySessionResource(item.sessionResource);
68
if (!widget || !widget.viewModel) {
69
return;
70
}
71
72
// Get the current chat model
73
const chatModel = widget.viewModel.model as ChatModel;
74
if (!chatModel) {
75
return;
76
}
77
78
const checkpointRequestId = isRequestVM(item) ? item.id : item.requestId;
79
const serializedData = revive(structuredClone(chatModel.toJSON())) as ISerializableChatData;
80
serializedData.sessionId = generateUuid();
81
82
delete serializedData.customTitle;
83
84
const checkpointIndex = serializedData.requests.findIndex(r => r.requestId === checkpointRequestId);
85
if (checkpointIndex === -1) {
86
return;
87
}
88
89
serializedData.requests = serializedData.requests.slice(0, checkpointIndex);
90
91
// Clear shouldBeRemovedOnSend for all requests in the branched session
92
// This ensures all requests are visible in the new session
93
for (const request of serializedData.requests) {
94
delete request.shouldBeRemovedOnSend;
95
delete (request as { isHidden?: boolean }).isHidden;
96
}
97
98
// If there's no conversation history to branch, don't proceed
99
if (serializedData.requests.length === 0) {
100
return;
101
}
102
103
// Load the branched data into a new session model
104
const modelRef = chatService.loadSessionFromData(serializedData);
105
106
// Open the branched session in the chat view pane
107
await widgetService.openSession(modelRef.object.sessionResource, ChatViewPaneTarget);
108
}
109
}
110
111