Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsOpener.ts
5343 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 { IDisposable } from '../../../../../base/common/lifecycle.js';
7
import { IAgentSession, isLocalAgentSessionItem } from './agentSessionsModel.js';
8
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
9
import { IChatEditorOptions } from '../widgetHosts/editor/chatEditor.js';
10
import { ChatViewPaneTarget, IChatWidget, IChatWidgetService } from '../chat.js';
11
import { ACTIVE_GROUP, SIDE_GROUP } from '../../../../services/editor/common/editorService.js';
12
import { IEditorOptions } from '../../../../../platform/editor/common/editor.js';
13
import { IChatSessionsService } from '../../common/chatSessionsService.js';
14
import { Schemas } from '../../../../../base/common/network.js';
15
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
16
import { INotificationService } from '../../../../../platform/notification/common/notification.js';
17
import { localize } from '../../../../../nls.js';
18
import { toErrorMessage } from '../../../../../base/common/errorMessage.js';
19
import { ILogService } from '../../../../../platform/log/common/log.js';
20
21
//#region Session Opener Registry
22
23
export interface ISessionOpenerParticipant {
24
handleOpenSession(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<boolean>;
25
}
26
27
export interface ISessionOpenOptions {
28
readonly sideBySide?: boolean;
29
readonly editorOptions?: IEditorOptions;
30
}
31
32
class SessionOpenerRegistry {
33
34
private readonly participants = new Set<ISessionOpenerParticipant>();
35
36
registerParticipant(participant: ISessionOpenerParticipant): IDisposable {
37
this.participants.add(participant);
38
39
return {
40
dispose: () => {
41
this.participants.delete(participant);
42
}
43
};
44
}
45
46
getParticipants(): readonly ISessionOpenerParticipant[] {
47
return Array.from(this.participants);
48
}
49
}
50
51
export const sessionOpenerRegistry = new SessionOpenerRegistry();
52
53
//#endregion
54
55
export async function openSession(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<IChatWidget | undefined> {
56
const instantiationService = accessor.get(IInstantiationService);
57
const logService = accessor.get(ILogService);
58
59
// First, give registered participants a chance to handle the session
60
for (const participant of sessionOpenerRegistry.getParticipants()) {
61
try {
62
const handled = await instantiationService.invokeFunction(accessor => participant.handleOpenSession(accessor, session, openOptions));
63
if (handled) {
64
return undefined; // Participant handled the session, skip default opening
65
}
66
} catch (error) {
67
logService.error(error); // log error but continue to support opening from default logic
68
}
69
}
70
71
// Default session opening logic
72
return instantiationService.invokeFunction(accessor => openSessionDefault(accessor, session, openOptions));
73
}
74
75
async function openSessionDefault(accessor: ServicesAccessor, session: IAgentSession, openOptions?: ISessionOpenOptions): Promise<IChatWidget | undefined> {
76
const chatSessionsService = accessor.get(IChatSessionsService);
77
const chatWidgetService = accessor.get(IChatWidgetService);
78
const notificationService = accessor.get(INotificationService);
79
80
try {
81
session.setRead(true); // mark as read when opened
82
83
let sessionOptions: IChatEditorOptions;
84
if (isLocalAgentSessionItem(session)) {
85
sessionOptions = {};
86
} else {
87
sessionOptions = { title: { preferred: session.label } };
88
}
89
90
let options: IChatEditorOptions = {
91
...sessionOptions,
92
...openOptions?.editorOptions,
93
revealIfOpened: true, // always try to reveal if already opened
94
};
95
96
await chatSessionsService.activateChatSessionItemProvider(session.providerType); // ensure provider is activated before trying to open
97
98
let target: typeof SIDE_GROUP | typeof ACTIVE_GROUP | typeof ChatViewPaneTarget | undefined;
99
if (openOptions?.sideBySide) {
100
target = ACTIVE_GROUP;
101
} else {
102
target = ChatViewPaneTarget;
103
}
104
105
const isLocalChatSession = session.resource.scheme === Schemas.vscodeChatEditor || session.resource.scheme === Schemas.vscodeLocalChatSession;
106
if (!isLocalChatSession && !(await chatSessionsService.canResolveChatSession(session.resource))) {
107
target = openOptions?.sideBySide ? SIDE_GROUP : ACTIVE_GROUP; // force to open in editor if session cannot be resolved in panel
108
options = { ...options, revealIfOpened: true };
109
}
110
111
return await chatWidgetService.openSession(session.resource, target, options);
112
} catch (error) {
113
notificationService.error(localize('chat.openSessionFailed', "Failed to open chat session: {0}", toErrorMessage(error)));
114
return undefined;
115
}
116
}
117
118