@codingame/monaco-vscode-chat-cloud-service-override 0.0.0-stage → 38.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common.d.ts +2 -0
- package/common.js +29 -0
- package/index.d.ts +3 -0
- package/index.js +9 -0
- package/package.json +52 -3
- package/session.d.ts +3 -0
- package/session.js +11 -0
- package/vscode/src/vs/sessions/contrib/chat/browser/newSession.d.ts +9 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/cloudAutomationStore.d.ts +67 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/cloudAutomationStore.js +695 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/cloudSandboxSessionConfig.d.ts +4 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/cloudSandboxSessionConfig.js +39 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessions.contribution.d.ts +1 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessions.contribution.js +59 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsActions.d.ts +1 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsActions.js +83 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsChangesets.d.ts +87 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsChangesets.js +176 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsProvider.d.ts +422 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/copilotChatSessionsProvider.js +2444 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/githubCloudAutomationStore.d.ts +91 -0
- package/vscode/src/vs/sessions/contrib/providers/copilotChatSessions/browser/githubCloudAutomationStore.js +620 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxAgentHost.contribution.d.ts +1 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxAgentHost.contribution.js +5 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxAgentHostContribution.d.ts +46 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxAgentHostContribution.js +321 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxSessionsProvider.d.ts +104 -0
- package/vscode/src/vs/sessions/contrib/providers/remoteAgentHost/browser/cloudSandboxSessionsProvider.js +345 -0
- package/README.md +0 -3
|
@@ -0,0 +1,2444 @@
|
|
|
1
|
+
|
|
2
|
+
import { __decorate, __param } from '@codingame/monaco-vscode-api/external/tslib/tslib.es6';
|
|
3
|
+
import { Emitter, Event } from '@codingame/monaco-vscode-api/vscode/vs/base/common/event';
|
|
4
|
+
import { raceCancellationError, raceTimeout } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
|
|
5
|
+
import { Codicon } from '@codingame/monaco-vscode-api/vscode/vs/base/common/codicons';
|
|
6
|
+
import { CancellationError, isCancellationError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
|
|
7
|
+
import { markdownStringEqual, MarkdownString } from '@codingame/monaco-vscode-api/vscode/vs/base/common/htmlContent';
|
|
8
|
+
import { Disposable, MutableDisposable, toDisposable, DisposableMap, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
|
|
9
|
+
import { Schemas } from '@codingame/monaco-vscode-api/vscode/vs/base/common/network';
|
|
10
|
+
import { deepClone } from '@codingame/monaco-vscode-api/vscode/vs/base/common/objects';
|
|
11
|
+
import { isWeb } from '@codingame/monaco-vscode-api/vscode/vs/base/common/platform';
|
|
12
|
+
import '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/index';
|
|
13
|
+
import { URI } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uri';
|
|
14
|
+
import { ICommandService } from '@codingame/monaco-vscode-api/vscode/vs/platform/commands/common/commands.service';
|
|
15
|
+
import { IInstantiationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/instantiation/common/instantiation';
|
|
16
|
+
import { AgentSession } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/agent';
|
|
17
|
+
import { parseGitHubIssueUrl, getGitHubRepositoryId } from '@codingame/monaco-vscode-api/vscode/vs/platform/github/common/githubUrls';
|
|
18
|
+
import { getAgentSessionPullRequestUri } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsModel';
|
|
19
|
+
import { getRepositoryName } from '@codingame/monaco-vscode-katex-common/vscode/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsViewer';
|
|
20
|
+
import { IAgentSessionsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsService.service';
|
|
21
|
+
import { AgentSessionProviders } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/agentSessions/agentSessions';
|
|
22
|
+
import { IChatService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatService/chatService.service';
|
|
23
|
+
import { ChatSessionStatus, SessionType } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatSessionsService';
|
|
24
|
+
import { IChatSessionsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/chatSessionsService.service';
|
|
25
|
+
import { assertAutomationSessionTemplate } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/automations/automation';
|
|
26
|
+
import { AutomationModelConfiguration } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/automations/browser/automationModelConfiguration';
|
|
27
|
+
import { SessionTypeAuthRequirement, ChatInteractivity, SessionStatus, sessionFileChangesEqual, toSessionId, GITHUB_REMOTE_FILE_SCHEME, sessionWorkspaceEqual, gitHubInfoEqual, SessionArtifactKind, SESSION_WORKSPACE_GROUP_GITHUB, SESSION_WORKSPACE_GROUP_LOCAL, ChatModelSource } from '@codingame/monaco-vscode-api/vscode/vs/sessions/services/sessions/common/session';
|
|
28
|
+
import { linkKey } from '@codingame/monaco-vscode-api/vscode/vs/sessions/common/sessionLinks';
|
|
29
|
+
import { getSessionApplication } from '@codingame/monaco-vscode-api/vscode/vs/sessions/common/sessionApplication';
|
|
30
|
+
import { ChatConfiguration, isChatPermissionLevel, ChatPermissionLevel, ChatModeKind, ChatAgentLocation } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/constants';
|
|
31
|
+
import { isEqual, basename, dirname } from '@codingame/monaco-vscode-api/vscode/vs/base/common/resources';
|
|
32
|
+
import { UNIFIED_WORKSPACE_PICKER_SETTING } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/chat/common/constants';
|
|
33
|
+
import { cancelOnDispose, CancellationTokenSource, CancellationToken } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
|
|
34
|
+
import { generateUuid } from '@codingame/monaco-vscode-api/vscode/vs/base/common/uuid';
|
|
35
|
+
import { COPILOT_VENDOR_ID } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModels';
|
|
36
|
+
import { ILanguageModelsService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/languageModels.service';
|
|
37
|
+
import { resolveModelIdentifier, getRegisteredLanguageModels, resolveModelIdentifierFromLanguageModels } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/common/modelSelection';
|
|
38
|
+
import { ContextKeyExpr } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey';
|
|
39
|
+
import { IContextKeyService } from '@codingame/monaco-vscode-api/vscode/vs/platform/contextkey/common/contextkey.service';
|
|
40
|
+
import { ExtensionIdentifier } from '@codingame/monaco-vscode-api/vscode/vs/platform/extensions/common/extensions';
|
|
41
|
+
import { localize } from '@codingame/monaco-vscode-api/vscode/vs/nls';
|
|
42
|
+
import { IConfigurationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/configuration/common/configuration.service';
|
|
43
|
+
import { ILabelService } from '@codingame/monaco-vscode-api/vscode/vs/platform/label/common/label.service';
|
|
44
|
+
import { ILogService } from '@codingame/monaco-vscode-api/vscode/vs/platform/log/common/log.service';
|
|
45
|
+
import { INotificationService } from '@codingame/monaco-vscode-api/vscode/vs/platform/notification/common/notification.service';
|
|
46
|
+
import { SessionConfigKey } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/sessionConfigKeys';
|
|
47
|
+
import { SESSION_META_WORKSPACELESS_KEY } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/sessionState';
|
|
48
|
+
import { StorageScope, StorageTarget } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage';
|
|
49
|
+
import { IStorageService } from '@codingame/monaco-vscode-api/vscode/vs/platform/storage/common/storage.service';
|
|
50
|
+
import { IGitHubService } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/github/browser/githubService.service';
|
|
51
|
+
import { GitHubPullRequestState } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/github/common/types';
|
|
52
|
+
import { computePullRequestRefPresentation } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/github/browser/pullRequestIconStatus';
|
|
53
|
+
import { IPullRequestIconCache } from '@codingame/monaco-vscode-api/vscode/vs/sessions/contrib/github/browser/pullRequestIconCache.service';
|
|
54
|
+
import { arrayEquals, structuralEquals } from '@codingame/monaco-vscode-api/vscode/vs/base/common/equals';
|
|
55
|
+
import { createChangesets } from './copilotChatSessionsChangesets.js';
|
|
56
|
+
import { IUriIdentityService } from '@codingame/monaco-vscode-api/vscode/vs/platform/uriIdentity/common/uriIdentity.service';
|
|
57
|
+
import { isCloudSandboxEnabled, CloudSandboxEnabledSettingId } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/cloudSandboxAgentHost';
|
|
58
|
+
import { RemoteAgentHostsEnabledSettingId } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/remoteAgentHostService';
|
|
59
|
+
import { getWorkbenchContribution } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/contributions';
|
|
60
|
+
import { CLOUD_SANDBOX_CREATION_PROVIDER_ID, CloudSandboxAgentHostContribution } from '../../remoteAgentHost/browser/cloudSandboxAgentHostContribution.js';
|
|
61
|
+
import { IFileService } from '@codingame/monaco-vscode-api/vscode/vs/platform/files/common/files.service';
|
|
62
|
+
import { resolveGitRepositoryFromGitConfig } from '@codingame/monaco-vscode-api/vscode/vs/sessions/services/sessions/browser/gitHubRepositoryResolver';
|
|
63
|
+
import '@codingame/monaco-vscode-api/vscode/vs/workbench/services/path/common/pathService';
|
|
64
|
+
import { RepositoryPicker } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/agentSessions/repositoryPicker';
|
|
65
|
+
import { ChatAIDisabledSettingId } from '@codingame/monaco-vscode-api/vscode/vs/platform/chat/common/chatSettings';
|
|
66
|
+
import { CloudSandboxModels } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/chat/browser/remoteAgentHost/cloudSandboxModels';
|
|
67
|
+
import { validateSessionConfigWrite } from '@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/sessionConfigProperties';
|
|
68
|
+
import { createCloudSandboxSessionConfig } from './cloudSandboxSessionConfig.js';
|
|
69
|
+
import { CloudAutomationStore } from './cloudAutomationStore.js';
|
|
70
|
+
import { observableValue } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/observableValue';
|
|
71
|
+
import { constObservable } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/constObservable';
|
|
72
|
+
import { transaction } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/transaction';
|
|
73
|
+
import { IPathService } from '@codingame/monaco-vscode-api/vscode/vs/platform/path/common/pathService.service';
|
|
74
|
+
import { observableValueOpts } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/observableValueOpts';
|
|
75
|
+
import { derived } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/observables/derived';
|
|
76
|
+
import { computePullRequestIcon } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/chatPullRequest';
|
|
77
|
+
import { observableFromPromise } from '@codingame/monaco-vscode-api/vscode/vs/base/common/observableInternal/utils/utils';
|
|
78
|
+
|
|
79
|
+
var CopilotChatSessionsProvider_1;
|
|
80
|
+
const CopilotCloudSessionType = {
|
|
81
|
+
id: "copilot-cloud-agent",
|
|
82
|
+
label: ( localize(5066, "Cloud")),
|
|
83
|
+
icon: Codicon.cloud,
|
|
84
|
+
authRequirement: SessionTypeAuthRequirement.GitHub
|
|
85
|
+
};
|
|
86
|
+
const CopilotSandboxSessionType = {
|
|
87
|
+
id: "copilot-cloud-sandbox",
|
|
88
|
+
label: ( localize(5067, "Copilot")),
|
|
89
|
+
icon: Codicon.copilot,
|
|
90
|
+
authRequirement: SessionTypeAuthRequirement.GitHub
|
|
91
|
+
};
|
|
92
|
+
const STORAGE_KEY_CREATED_BY_SESSIONS = "sessions.copilotChat.createdBySessions";
|
|
93
|
+
const OPEN_REPO_COMMAND = "github.copilot.chat.cloudSessions.openRepository";
|
|
94
|
+
const OPEN_ISSUE_COMMAND = "github.copilot.chat.cloudSessions.openIssue";
|
|
95
|
+
const OPEN_PULL_REQUEST_COMMAND = "github.copilot.chat.cloudSessions.openPullRequest";
|
|
96
|
+
const COPILOT_PROVIDER_ID = "default-copilot";
|
|
97
|
+
function isChangesSummary(changes) {
|
|
98
|
+
return !!changes && !Array.isArray(changes);
|
|
99
|
+
}
|
|
100
|
+
function buildChatFromSession(chat) {
|
|
101
|
+
return {
|
|
102
|
+
resource: chat.resource,
|
|
103
|
+
createdAt: chat.createdAt,
|
|
104
|
+
workspace: chat.workspace,
|
|
105
|
+
title: chat.title,
|
|
106
|
+
updatedAt: chat.updatedAt,
|
|
107
|
+
status: chat.status,
|
|
108
|
+
changes: chat.changes,
|
|
109
|
+
changesets: constObservable(undefined),
|
|
110
|
+
checkpoints: chat.checkpoints,
|
|
111
|
+
modelId: chat.modelId,
|
|
112
|
+
modelSource: chat.modelSource,
|
|
113
|
+
mode: chat.mode,
|
|
114
|
+
isArchived: chat.isArchived,
|
|
115
|
+
isRead: chat.isRead,
|
|
116
|
+
interactivity: constObservable(ChatInteractivity.Full),
|
|
117
|
+
description: chat.description,
|
|
118
|
+
lastTurnEnd: chat.lastTurnEnd
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function setIfChanged(observable, value, tx, equals = Object.is) {
|
|
122
|
+
if (equals(observable.get(), value)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
observable.set(value, tx, undefined);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
function dateEquals(a, b) {
|
|
129
|
+
return a?.getTime() === b?.getTime();
|
|
130
|
+
}
|
|
131
|
+
function markdownStringEquals(a, b) {
|
|
132
|
+
return a === b || !!a && !!b && markdownStringEqual(a, b);
|
|
133
|
+
}
|
|
134
|
+
function sessionArtifactsEqual(a, b) {
|
|
135
|
+
return arrayEquals(
|
|
136
|
+
a,
|
|
137
|
+
b,
|
|
138
|
+
(left, right) => left.id === right.id && left.kind === right.kind && left.label === right.label && left.isArtifact === right.isArtifact && isEqual(left.link, right.link) && isEqual(left.uri, right.uri) && left.commitHash === right.commitHash && left.isGitHub === right.isGitHub
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
function isModelOptionGroup(group) {
|
|
142
|
+
if (group.id === "models") {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
const nameLower = group.name.toLowerCase();
|
|
146
|
+
return nameLower === "model" || nameLower === "models";
|
|
147
|
+
}
|
|
148
|
+
function isRepositoriesOptionGroup(group) {
|
|
149
|
+
return group.id === "repositories";
|
|
150
|
+
}
|
|
151
|
+
let RemoteNewSession = class RemoteNewSession extends Disposable {
|
|
152
|
+
get project() {
|
|
153
|
+
return this._project;
|
|
154
|
+
}
|
|
155
|
+
get selectedModelId() {
|
|
156
|
+
return this._modelId;
|
|
157
|
+
}
|
|
158
|
+
get repoNwo() {
|
|
159
|
+
return this._repoUri ? githubRemoteRepoLabel(this._repoUri) : undefined;
|
|
160
|
+
}
|
|
161
|
+
get query() {
|
|
162
|
+
return this._query;
|
|
163
|
+
}
|
|
164
|
+
get attachedContext() {
|
|
165
|
+
return this._attachedContext;
|
|
166
|
+
}
|
|
167
|
+
setCreatedBySession(reference) {
|
|
168
|
+
this.createdBySession.set(reference, undefined);
|
|
169
|
+
}
|
|
170
|
+
get disabled() {
|
|
171
|
+
return !this.isQuickChat.get() && !this._repoUri && !( this.selectedOptions.has("repositories"));
|
|
172
|
+
}
|
|
173
|
+
constructor(
|
|
174
|
+
resource,
|
|
175
|
+
sessionWorkspace,
|
|
176
|
+
target,
|
|
177
|
+
providerId,
|
|
178
|
+
initialAutomationSessionConfiguration,
|
|
179
|
+
isAutomationDraft,
|
|
180
|
+
chatSessionsService,
|
|
181
|
+
contextKeyService,
|
|
182
|
+
languageModelsService
|
|
183
|
+
) {
|
|
184
|
+
super();
|
|
185
|
+
this.resource = resource;
|
|
186
|
+
this.sessionWorkspace = sessionWorkspace;
|
|
187
|
+
this.target = target;
|
|
188
|
+
this.initialAutomationSessionConfiguration = initialAutomationSessionConfiguration;
|
|
189
|
+
this.isAutomationDraft = isAutomationDraft;
|
|
190
|
+
this.chatSessionsService = chatSessionsService;
|
|
191
|
+
this.contextKeyService = contextKeyService;
|
|
192
|
+
this.application = constObservable(getSessionApplication("vscode"));
|
|
193
|
+
this.lifetimeToken = cancelOnDispose(this._store);
|
|
194
|
+
this._title = observableValue(this, "");
|
|
195
|
+
this.title = this._title;
|
|
196
|
+
this._updatedAt = observableValue(this, ( new Date()));
|
|
197
|
+
this.updatedAt = this._updatedAt;
|
|
198
|
+
this._status = observableValue(this, SessionStatus.Untitled);
|
|
199
|
+
this.status = this._status;
|
|
200
|
+
this._workspaceData = observableValue(this, undefined);
|
|
201
|
+
this.workspace = this._workspaceData;
|
|
202
|
+
this.changes = observableValueOpts({
|
|
203
|
+
owner: this,
|
|
204
|
+
equalsFn: sessionFileChangesEqual
|
|
205
|
+
}, []);
|
|
206
|
+
this.checkpoints = constObservable(undefined);
|
|
207
|
+
this._modelIdObservable = observableValue(this, undefined);
|
|
208
|
+
this.modelId = this._modelIdObservable;
|
|
209
|
+
this._modelSourceObservable = observableValue(this, undefined);
|
|
210
|
+
this.modelSource = this._modelSourceObservable;
|
|
211
|
+
this.mode = observableValue(this, undefined);
|
|
212
|
+
this.loading = observableValue(this, false);
|
|
213
|
+
this.preparationProgress = observableValue(this, undefined);
|
|
214
|
+
this.isNewSessionRequestInProgress = this.preparationProgress.map(progress => !!progress);
|
|
215
|
+
this._preparationCts = this._register(( new MutableDisposable()));
|
|
216
|
+
this._preparationActivities = 0;
|
|
217
|
+
this._isArchived = observableValue(this, false);
|
|
218
|
+
this.isArchived = this._isArchived;
|
|
219
|
+
this.isRead = observableValue(this, true);
|
|
220
|
+
this.description = constObservable(undefined);
|
|
221
|
+
this.lastTurnEnd = constObservable(undefined);
|
|
222
|
+
this.gitHubInfo = constObservable(undefined);
|
|
223
|
+
this._onDidChangeOptionGroups = this._register(( new Emitter()));
|
|
224
|
+
this.onDidChangeOptionGroups = this._onDidChangeOptionGroups.event;
|
|
225
|
+
this.selectedOptions = ( new Map());
|
|
226
|
+
this.createdBySession = observableValue(this, undefined);
|
|
227
|
+
this._whenClauseKeys = ( new Set());
|
|
228
|
+
this.modelConfiguration = this._register(( new AutomationModelConfiguration(
|
|
229
|
+
languageModelsService,
|
|
230
|
+
initialAutomationSessionConfiguration?.sessionTemplate
|
|
231
|
+
)));
|
|
232
|
+
this.sessionId = toSessionId(providerId, resource);
|
|
233
|
+
this.providerId = providerId;
|
|
234
|
+
this.sessionType = target;
|
|
235
|
+
this.isQuickChat = constObservable(sessionWorkspace === undefined);
|
|
236
|
+
this.icon = target === CopilotSandboxSessionType.id ? CopilotSandboxSessionType.icon : CopilotCloudSessionType.icon;
|
|
237
|
+
this.createdAt = ( new Date());
|
|
238
|
+
this._updateWhenClauseKeys();
|
|
239
|
+
this._register(this.chatSessionsService.onDidChangeOptionGroups(() => {
|
|
240
|
+
this._updateWhenClauseKeys();
|
|
241
|
+
this._onDidChangeOptionGroups.fire();
|
|
242
|
+
}));
|
|
243
|
+
this._register(this.contextKeyService.onDidChangeContext(e => {
|
|
244
|
+
if (this._whenClauseKeys.size > 0 && e.affectsSome(this._whenClauseKeys)) {
|
|
245
|
+
this._onDidChangeOptionGroups.fire();
|
|
246
|
+
}
|
|
247
|
+
}));
|
|
248
|
+
this._workspaceData.set(sessionWorkspace, undefined);
|
|
249
|
+
this._repoUri = sessionWorkspace?.folders[0]?.root;
|
|
250
|
+
if (this._repoUri) {
|
|
251
|
+
const id = this._repoUri.path.substring(1);
|
|
252
|
+
this.setOption("repositories", {
|
|
253
|
+
id,
|
|
254
|
+
name: id
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
this.mainChat = observableValue(this, buildChatFromSession(this));
|
|
258
|
+
}
|
|
259
|
+
setModelId(modelId, source) {
|
|
260
|
+
this._modelId = modelId;
|
|
261
|
+
transaction(tx => {
|
|
262
|
+
this._modelSourceObservable.set(modelId ? source : undefined, tx);
|
|
263
|
+
this._modelIdObservable.set(modelId, tx);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
setTitle(title) {
|
|
267
|
+
this._title.set(title, undefined);
|
|
268
|
+
}
|
|
269
|
+
setStatus(status) {
|
|
270
|
+
this._status.set(status, undefined);
|
|
271
|
+
}
|
|
272
|
+
startPreparation() {
|
|
273
|
+
if (!this._preparationCts.value) {
|
|
274
|
+
this._preparationCts.value = ( new CancellationTokenSource(this.lifetimeToken));
|
|
275
|
+
this.reportPreparationProgress(( localize(5068, "Setting up cloud container")));
|
|
276
|
+
}
|
|
277
|
+
this._preparationActivities++;
|
|
278
|
+
const token = this._preparationCts.value.token;
|
|
279
|
+
const activity = toDisposable(() => {
|
|
280
|
+
if (--this._preparationActivities === 0) {
|
|
281
|
+
this.clearPreparation();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
object: token,
|
|
286
|
+
dispose: () => activity.dispose()
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
reportPreparationProgress(message) {
|
|
290
|
+
const source = this._preparationCts.value;
|
|
291
|
+
if (source && !source.token.isCancellationRequested && this.preparationProgress.get()?.message !== message) {
|
|
292
|
+
this.preparationProgress.set({
|
|
293
|
+
message,
|
|
294
|
+
cancel: () => source.cancel()
|
|
295
|
+
}, undefined);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
clearPreparation() {
|
|
299
|
+
this.preparationProgress.set(undefined, undefined);
|
|
300
|
+
this._preparationCts.clear();
|
|
301
|
+
}
|
|
302
|
+
setArchived(archived) {
|
|
303
|
+
this._isArchived.set(archived, undefined);
|
|
304
|
+
}
|
|
305
|
+
setOption(optionId, value) {
|
|
306
|
+
if (typeof value !== "string") {
|
|
307
|
+
this.selectedOptions.set(optionId, value);
|
|
308
|
+
}
|
|
309
|
+
this.chatSessionsService.setSessionOption(this.resource, optionId, value);
|
|
310
|
+
}
|
|
311
|
+
getModelOptionsSnapshot() {
|
|
312
|
+
const groups = this._getOptionGroups();
|
|
313
|
+
if (!groups) {
|
|
314
|
+
return {
|
|
315
|
+
modelOption: undefined,
|
|
316
|
+
isResolved: false
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
const group = groups.find(g => isModelOptionGroup(g));
|
|
320
|
+
if (!group) {
|
|
321
|
+
return {
|
|
322
|
+
modelOption: undefined,
|
|
323
|
+
isResolved: true
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
modelOption: {
|
|
328
|
+
group,
|
|
329
|
+
value: this._getValueForGroup(group)
|
|
330
|
+
},
|
|
331
|
+
isResolved: true
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
getOtherOptionGroups() {
|
|
335
|
+
const groups = this._getOptionGroups();
|
|
336
|
+
if (!groups) {
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
return groups.filter(
|
|
340
|
+
g => !isModelOptionGroup(g) && !isRepositoriesOptionGroup(g) && this._isOptionGroupVisible(g)
|
|
341
|
+
).map(g => ({
|
|
342
|
+
group: g,
|
|
343
|
+
value: this._getValueForGroup(g)
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
346
|
+
getOptionValue(groupId) {
|
|
347
|
+
return this.selectedOptions.get(groupId);
|
|
348
|
+
}
|
|
349
|
+
setOptionValue(groupId, value) {
|
|
350
|
+
this.setOption(groupId, value);
|
|
351
|
+
}
|
|
352
|
+
_getOptionGroups() {
|
|
353
|
+
return this.chatSessionsService.getOptionGroupsForSessionType(this.target);
|
|
354
|
+
}
|
|
355
|
+
_isOptionGroupVisible(group) {
|
|
356
|
+
if (!group.when) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
const expr = ContextKeyExpr.deserialize(group.when);
|
|
360
|
+
return !expr || this.contextKeyService.contextMatchesRules(expr);
|
|
361
|
+
}
|
|
362
|
+
_updateWhenClauseKeys() {
|
|
363
|
+
this._whenClauseKeys.clear();
|
|
364
|
+
const groups = this._getOptionGroups();
|
|
365
|
+
if (!groups) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
for (const group of groups) {
|
|
369
|
+
if (group.when) {
|
|
370
|
+
const expr = ContextKeyExpr.deserialize(group.when);
|
|
371
|
+
if (expr) {
|
|
372
|
+
for (const key of ( expr.keys())) {
|
|
373
|
+
this._whenClauseKeys.add(key);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
_getValueForGroup(group) {
|
|
380
|
+
const selected = this.selectedOptions.get(group.id);
|
|
381
|
+
if (selected) {
|
|
382
|
+
return selected;
|
|
383
|
+
}
|
|
384
|
+
const sessionOption = this.chatSessionsService.getSessionOption(this.resource, group.id);
|
|
385
|
+
if (sessionOption && typeof sessionOption !== "string") {
|
|
386
|
+
return sessionOption;
|
|
387
|
+
}
|
|
388
|
+
if (typeof sessionOption === "string") {
|
|
389
|
+
const item = group.items.find(i => i.id === sessionOption.trim());
|
|
390
|
+
if (item) {
|
|
391
|
+
return item;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return group.items.find(i => i.default === true) ?? group.items[0];
|
|
395
|
+
}
|
|
396
|
+
update(_session) {}
|
|
397
|
+
};
|
|
398
|
+
RemoteNewSession = ( __decorate([( __param(6, IChatSessionsService)), ( __param(7, IContextKeyService)), ( __param(8, ILanguageModelsService))], RemoteNewSession));
|
|
399
|
+
function toSessionStatus(status) {
|
|
400
|
+
switch (status) {
|
|
401
|
+
case ChatSessionStatus.InProgress:
|
|
402
|
+
return SessionStatus.InProgress;
|
|
403
|
+
case ChatSessionStatus.NeedsInput:
|
|
404
|
+
return SessionStatus.NeedsInput;
|
|
405
|
+
case ChatSessionStatus.Completed:
|
|
406
|
+
return SessionStatus.Completed;
|
|
407
|
+
case ChatSessionStatus.Failed:
|
|
408
|
+
return SessionStatus.Error;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function githubRemoteRepoLabel(uri) {
|
|
412
|
+
if (uri.scheme !== GITHUB_REMOTE_FILE_SCHEME) {
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
const parts = uri.path.replace(/^\//, "").split("/");
|
|
416
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : undefined;
|
|
417
|
+
}
|
|
418
|
+
function resolveGitHubRepositoryId(folder) {
|
|
419
|
+
const gitHubInfo = folder.gitRepository?.gitHubInfo.get();
|
|
420
|
+
if (gitHubInfo) {
|
|
421
|
+
return `${gitHubInfo.owner}/${gitHubInfo.repo}`;
|
|
422
|
+
}
|
|
423
|
+
return githubRemoteRepoLabel(folder.root);
|
|
424
|
+
}
|
|
425
|
+
class AgentSessionAdapter {
|
|
426
|
+
constructor(session, providerId, _gitHubService, _pullRequestIconCache, _logService) {
|
|
427
|
+
this._gitHubService = _gitHubService;
|
|
428
|
+
this._pullRequestIconCache = _pullRequestIconCache;
|
|
429
|
+
this._logService = _logService;
|
|
430
|
+
this._modelSource = observableValue("agentSessionModelSource", undefined);
|
|
431
|
+
this.modelSource = this._modelSource;
|
|
432
|
+
this._pullRequestNumberCache = ( new Map());
|
|
433
|
+
this.sessionId = toSessionId(providerId, session.resource);
|
|
434
|
+
this.resource = session.resource;
|
|
435
|
+
this.providerId = providerId;
|
|
436
|
+
this.sessionType = session.providerType;
|
|
437
|
+
this.application = observableValueOpts({
|
|
438
|
+
owner: this,
|
|
439
|
+
equalsFn: structuralEquals
|
|
440
|
+
}, getSessionApplication(
|
|
441
|
+
typeof session.metadata?.event_type === "string" && session.metadata.event_type ? session.metadata.event_type : this._extractIsExternal(session) ? "github/autopilot" : "vscode"
|
|
442
|
+
));
|
|
443
|
+
this.icon = CopilotCloudSessionType.icon;
|
|
444
|
+
this.createdAt = ( new Date(session.timing.created));
|
|
445
|
+
const artifacts = this._extractIssueArtifacts(session);
|
|
446
|
+
this._artifacts = observableValueOpts({
|
|
447
|
+
owner: this,
|
|
448
|
+
equalsFn: sessionArtifactsEqual
|
|
449
|
+
}, artifacts);
|
|
450
|
+
this.artifacts = this._artifacts;
|
|
451
|
+
this._baseGitHubInfo = observableValue(this, this._extractGitHubInfo(session, artifacts));
|
|
452
|
+
this._pullRequestBranch = observableValue(this, this._extractPullRequestBranch(session));
|
|
453
|
+
this._pullRequestNumberFromBranch = derived(this, reader => {
|
|
454
|
+
const base = this._baseGitHubInfo.read(reader);
|
|
455
|
+
const branch = this._pullRequestBranch.read(reader);
|
|
456
|
+
if (base?.pullRequest || !base || !branch) {
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
459
|
+
return this._pullRequestNumberForBranch(base.owner, base.repo, branch);
|
|
460
|
+
});
|
|
461
|
+
this.gitHubInfo = derived(this, reader => {
|
|
462
|
+
let info = this._baseGitHubInfo.read(reader);
|
|
463
|
+
if (!info) {
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
if (!info.pullRequest) {
|
|
467
|
+
const pullRequestNumber = this._pullRequestNumberFromBranch.read(reader)?.read(reader).value;
|
|
468
|
+
if (pullRequestNumber === undefined) {
|
|
469
|
+
return info;
|
|
470
|
+
}
|
|
471
|
+
info = {
|
|
472
|
+
...info,
|
|
473
|
+
pullRequest: {
|
|
474
|
+
number: pullRequestNumber,
|
|
475
|
+
uri: ( URI.parse(`https://github.com/${info.owner}/${info.repo}/pull/${pullRequestNumber}`))
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
const pullRequest = info.pullRequest;
|
|
480
|
+
if (!pullRequest) {
|
|
481
|
+
return info;
|
|
482
|
+
}
|
|
483
|
+
if (pullRequest.uri.authority.toLowerCase() !== "github.com") {
|
|
484
|
+
return info;
|
|
485
|
+
}
|
|
486
|
+
const presentation = computePullRequestRefPresentation(reader, this._gitHubService, this._pullRequestIconCache, {
|
|
487
|
+
owner: info.owner,
|
|
488
|
+
repo: info.repo,
|
|
489
|
+
number: pullRequest.number,
|
|
490
|
+
uri: pullRequest.uri,
|
|
491
|
+
icon: pullRequest.icon,
|
|
492
|
+
title: pullRequest.title
|
|
493
|
+
}, computePullRequestIcon(GitHubPullRequestState.Open));
|
|
494
|
+
return {
|
|
495
|
+
...info,
|
|
496
|
+
pullRequest: {
|
|
497
|
+
...pullRequest,
|
|
498
|
+
...presentation
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
this._workspace = observableValue(this, this._buildWorkspace(session));
|
|
503
|
+
this.workspace = this._workspace;
|
|
504
|
+
this._title = observableValue(this, session.label);
|
|
505
|
+
this.title = this._title;
|
|
506
|
+
const updatedTime = session.timing.lastRequestEnded ?? session.timing.lastRequestStarted ?? session.timing.created;
|
|
507
|
+
this._updatedAt = observableValue(this, ( new Date(updatedTime)));
|
|
508
|
+
this.updatedAt = this._updatedAt;
|
|
509
|
+
this._status = observableValue(this, toSessionStatus(session.status));
|
|
510
|
+
this.status = this._status;
|
|
511
|
+
this._changes = observableValueOpts({
|
|
512
|
+
owner: this,
|
|
513
|
+
equalsFn: sessionFileChangesEqual
|
|
514
|
+
}, this._extractChanges(session));
|
|
515
|
+
this.changes = this._changes;
|
|
516
|
+
this._changesSummary = observableValueOpts({
|
|
517
|
+
owner: this,
|
|
518
|
+
equalsFn: structuralEquals
|
|
519
|
+
}, this._extractChangesSummary(session));
|
|
520
|
+
this.changesSummary = this._changesSummary;
|
|
521
|
+
this._checkpoints = observableValueOpts({
|
|
522
|
+
owner: this,
|
|
523
|
+
equalsFn: structuralEquals
|
|
524
|
+
}, this._extractCheckpoints(session));
|
|
525
|
+
this.checkpoints = this._checkpoints;
|
|
526
|
+
this._modelId = observableValue(this, undefined);
|
|
527
|
+
this.modelId = this._modelId;
|
|
528
|
+
this.mode = observableValue(this, undefined);
|
|
529
|
+
this.loading = observableValue(this, false);
|
|
530
|
+
this._isArchived = observableValue(this, session.isArchived());
|
|
531
|
+
this.isArchived = this._isArchived;
|
|
532
|
+
this._isRead = observableValue(this, session.isRead());
|
|
533
|
+
this.isRead = this._isRead;
|
|
534
|
+
this._isExternal = observableValue(this, this._extractIsExternal(session));
|
|
535
|
+
this.isExternal = this._isExternal;
|
|
536
|
+
this._description = observableValue(this, this._extractDescription(session));
|
|
537
|
+
this.description = this._description;
|
|
538
|
+
this._lastTurnEnd = observableValue(this, session.timing.lastRequestEnded ? ( new Date(session.timing.lastRequestEnded)) : undefined);
|
|
539
|
+
this.lastTurnEnd = this._lastTurnEnd;
|
|
540
|
+
this.mainChat = observableValue(this, buildChatFromSession(this));
|
|
541
|
+
}
|
|
542
|
+
setModelId(modelId, source) {
|
|
543
|
+
transaction(tx => {
|
|
544
|
+
this._modelSource.set(modelId ? source : undefined, tx);
|
|
545
|
+
this._modelId.set(modelId, tx);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
update(session) {
|
|
549
|
+
let changed = false;
|
|
550
|
+
transaction(tx => {
|
|
551
|
+
const artifacts = this._extractIssueArtifacts(session);
|
|
552
|
+
const gitHubInfo = this._extractGitHubInfo(session, artifacts);
|
|
553
|
+
const pullRequestBranch = this._extractPullRequestBranch(session);
|
|
554
|
+
changed = setIfChanged(this._title, session.label, tx) || changed;
|
|
555
|
+
changed = setIfChanged(this._workspace, this._buildWorkspace(session), tx, sessionWorkspaceEqual) || changed;
|
|
556
|
+
const updatedTime = session.timing.lastRequestEnded ?? session.timing.lastRequestStarted ?? session.timing.created;
|
|
557
|
+
changed = setIfChanged(this._updatedAt, ( new Date(updatedTime)), tx, dateEquals) || changed;
|
|
558
|
+
changed = setIfChanged(this._status, toSessionStatus(session.status), tx) || changed;
|
|
559
|
+
changed = setIfChanged(this._changes, this._extractChanges(session), tx, sessionFileChangesEqual) || changed;
|
|
560
|
+
changed = setIfChanged(
|
|
561
|
+
this._changesSummary,
|
|
562
|
+
this._extractChangesSummary(session),
|
|
563
|
+
tx,
|
|
564
|
+
structuralEquals
|
|
565
|
+
) || changed;
|
|
566
|
+
changed = setIfChanged(this._checkpoints, this._extractCheckpoints(session), tx, structuralEquals) || changed;
|
|
567
|
+
changed = setIfChanged(this._isArchived, session.isArchived(), tx) || changed;
|
|
568
|
+
changed = setIfChanged(this._isRead, session.isRead(), tx) || changed;
|
|
569
|
+
changed = setIfChanged(this._isExternal, this._extractIsExternal(session), tx) || changed;
|
|
570
|
+
if (typeof session.metadata?.event_type === "string" && session.metadata.event_type) {
|
|
571
|
+
changed = setIfChanged(
|
|
572
|
+
this.application,
|
|
573
|
+
getSessionApplication(session.metadata.event_type),
|
|
574
|
+
tx,
|
|
575
|
+
structuralEquals
|
|
576
|
+
) || changed;
|
|
577
|
+
}
|
|
578
|
+
changed = setIfChanged(
|
|
579
|
+
this._description,
|
|
580
|
+
this._extractDescription(session),
|
|
581
|
+
tx,
|
|
582
|
+
markdownStringEquals
|
|
583
|
+
) || changed;
|
|
584
|
+
changed = setIfChanged(this._lastTurnEnd, session.timing.lastRequestEnded ? ( new Date(session.timing.lastRequestEnded)) : undefined, tx, dateEquals) || changed;
|
|
585
|
+
changed = setIfChanged(this._baseGitHubInfo, gitHubInfo, tx, gitHubInfoEqual) || changed;
|
|
586
|
+
changed = setIfChanged(this._artifacts, artifacts, tx, sessionArtifactsEqual) || changed;
|
|
587
|
+
changed = setIfChanged(this._pullRequestBranch, pullRequestBranch, tx) || changed;
|
|
588
|
+
});
|
|
589
|
+
return changed;
|
|
590
|
+
}
|
|
591
|
+
_pullRequestNumberForBranch(owner, repo, branch) {
|
|
592
|
+
const key = `${owner}/${repo}@${branch}`;
|
|
593
|
+
const cached = this._pullRequestNumberCache.get(key);
|
|
594
|
+
if (cached) {
|
|
595
|
+
return cached;
|
|
596
|
+
}
|
|
597
|
+
const lookup = this._gitHubService.findPullRequestNumberByHeadBranch(owner, repo, branch);
|
|
598
|
+
const observable = observableFromPromise(lookup);
|
|
599
|
+
this._pullRequestNumberCache.set(key, observable);
|
|
600
|
+
lookup.then(pullRequestNumber => {
|
|
601
|
+
if (pullRequestNumber === undefined && this._pullRequestNumberCache.get(key) === observable) {
|
|
602
|
+
this._pullRequestNumberCache.delete(key);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
return observable;
|
|
606
|
+
}
|
|
607
|
+
_extractDescription(session) {
|
|
608
|
+
if (!session.description) {
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
return typeof session.description === "string" ? ( new MarkdownString(session.description)) : session.description;
|
|
612
|
+
}
|
|
613
|
+
_extractIsExternal(session) {
|
|
614
|
+
return session.providerType === AgentSessionProviders.Cloud && session.metadata?.external === true;
|
|
615
|
+
}
|
|
616
|
+
_extractIssueArtifacts(session) {
|
|
617
|
+
const linkedIssues = session.metadata?.linkedIssues;
|
|
618
|
+
if (linkedIssues === undefined) {
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
if (!Array.isArray(linkedIssues)) {
|
|
622
|
+
this._logService.warn("Ignoring invalid linked issues metadata for a cloud session.");
|
|
623
|
+
return [];
|
|
624
|
+
}
|
|
625
|
+
const artifacts = [];
|
|
626
|
+
const seen = ( new Set());
|
|
627
|
+
const issues = linkedIssues;
|
|
628
|
+
for (const issue of issues) {
|
|
629
|
+
if (!issue || typeof issue !== "object" || typeof issue.url !== "string" || typeof issue.title !== "string") {
|
|
630
|
+
this._logService.warn("Ignoring invalid linked issue metadata for a cloud session.");
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
let link;
|
|
634
|
+
try {
|
|
635
|
+
link = ( URI.parse(issue.url, true));
|
|
636
|
+
} catch (error) {
|
|
637
|
+
this._logService.warn("Ignoring an invalid linked issue URL for a cloud session.", error);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (link.scheme !== Schemas.https || !link.authority || !/^\/[\w.-]+\/[\w.-]+\/issues\/[1-9]\d*\/?$/.test(link.path)) {
|
|
641
|
+
this._logService.warn("Ignoring an invalid linked issue URL for a cloud session.");
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const key = linkKey(issue.url);
|
|
645
|
+
if (( seen.has(key))) {
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
seen.add(key);
|
|
649
|
+
artifacts.push({
|
|
650
|
+
id: `linked-issue:${key}`,
|
|
651
|
+
kind: SessionArtifactKind.Issue,
|
|
652
|
+
label: issue.title || issue.url,
|
|
653
|
+
isArtifact: true,
|
|
654
|
+
link,
|
|
655
|
+
isGitHub: true
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return artifacts;
|
|
659
|
+
}
|
|
660
|
+
_extractGitHubInfo(session, artifacts) {
|
|
661
|
+
const metadata = session.metadata;
|
|
662
|
+
if (!metadata) {
|
|
663
|
+
return undefined;
|
|
664
|
+
}
|
|
665
|
+
const pullRequestUri = this._extractPullRequestUri(session);
|
|
666
|
+
const pullRequestIdentity = pullRequestUri ? this._extractPullRequestIdentity(pullRequestUri) : undefined;
|
|
667
|
+
const {
|
|
668
|
+
owner,
|
|
669
|
+
repo
|
|
670
|
+
} = pullRequestIdentity ?? this._extractOwnerRepo(session);
|
|
671
|
+
if (!owner || !repo) {
|
|
672
|
+
return undefined;
|
|
673
|
+
}
|
|
674
|
+
const issues = [];
|
|
675
|
+
for (const artifact of artifacts) {
|
|
676
|
+
const issue = artifact.link && parseGitHubIssueUrl(( artifact.link.toString(true)));
|
|
677
|
+
if (issue && artifact.link) {
|
|
678
|
+
issues.push({
|
|
679
|
+
...issue,
|
|
680
|
+
uri: artifact.link,
|
|
681
|
+
title: artifact.label
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
const issueInfo = issues.length ? {
|
|
686
|
+
issues
|
|
687
|
+
} : {};
|
|
688
|
+
if (!pullRequestUri || !pullRequestIdentity) {
|
|
689
|
+
return {
|
|
690
|
+
owner,
|
|
691
|
+
repo,
|
|
692
|
+
...issueInfo
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
const icon = this._extractPullRequestStateIcon(session);
|
|
696
|
+
const baseRefOid = typeof metadata.baseRefOid === "string" ? metadata.baseRefOid : undefined;
|
|
697
|
+
const headRefOid = typeof metadata.headRefOid === "string" ? metadata.headRefOid : undefined;
|
|
698
|
+
return {
|
|
699
|
+
owner,
|
|
700
|
+
repo,
|
|
701
|
+
...issueInfo,
|
|
702
|
+
pullRequest: {
|
|
703
|
+
number: pullRequestIdentity.number,
|
|
704
|
+
uri: pullRequestUri,
|
|
705
|
+
icon,
|
|
706
|
+
baseRefOid,
|
|
707
|
+
headRefOid
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
_extractPullRequestBranch(session) {
|
|
712
|
+
if (typeof session.metadata?.host === "string" && session.metadata.host.toLowerCase() !== "github.com") {
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
715
|
+
return typeof session.metadata?.branch === "string" ? session.metadata.branch : undefined;
|
|
716
|
+
}
|
|
717
|
+
_extractPullRequestIdentity(pullRequestUri) {
|
|
718
|
+
const match = /^\/(?<owner>[^/]+)\/(?<repo>[^/]+)\/pull\/(?<number>\d+)\/?$/.exec(pullRequestUri.path);
|
|
719
|
+
if (!match?.groups) {
|
|
720
|
+
return undefined;
|
|
721
|
+
}
|
|
722
|
+
return {
|
|
723
|
+
owner: decodeURIComponent(match.groups.owner),
|
|
724
|
+
repo: decodeURIComponent(match.groups.repo),
|
|
725
|
+
number: parseInt(match.groups.number, 10)
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
_extractOwnerRepo(session) {
|
|
729
|
+
const metadata = session.metadata;
|
|
730
|
+
if (!metadata) {
|
|
731
|
+
return {
|
|
732
|
+
owner: undefined,
|
|
733
|
+
repo: undefined
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
if (typeof metadata.owner === "string" && typeof metadata.name === "string") {
|
|
737
|
+
return {
|
|
738
|
+
owner: metadata.owner,
|
|
739
|
+
repo: metadata.name
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
if (typeof metadata.repositoryNwo === "string") {
|
|
743
|
+
const parts = metadata.repositoryNwo.split("/");
|
|
744
|
+
if (parts.length === 2) {
|
|
745
|
+
return {
|
|
746
|
+
owner: parts[0],
|
|
747
|
+
repo: parts[1]
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
owner: undefined,
|
|
753
|
+
repo: undefined
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
_extractPullRequestStateIcon(session) {
|
|
757
|
+
const metadata = session.metadata;
|
|
758
|
+
const state = metadata?.pullRequestState;
|
|
759
|
+
if (typeof state === "string") {
|
|
760
|
+
return computePullRequestIcon(state);
|
|
761
|
+
}
|
|
762
|
+
return undefined;
|
|
763
|
+
}
|
|
764
|
+
_extractPullRequestUri(session) {
|
|
765
|
+
return getAgentSessionPullRequestUri(session);
|
|
766
|
+
}
|
|
767
|
+
_extractChanges(session) {
|
|
768
|
+
return session.changes && !isChangesSummary(session.changes) ? session.changes : [];
|
|
769
|
+
}
|
|
770
|
+
_extractChangesSummary(session) {
|
|
771
|
+
if (!isChangesSummary(session.changes)) {
|
|
772
|
+
return undefined;
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
files: session.changes.files,
|
|
776
|
+
additions: session.changes.insertions,
|
|
777
|
+
deletions: session.changes.deletions
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
_extractCheckpoints(session) {
|
|
781
|
+
const metadata = session.metadata;
|
|
782
|
+
if (typeof metadata?.firstCheckpointRef !== "string" || typeof metadata?.lastCheckpointRef !== "string") {
|
|
783
|
+
return undefined;
|
|
784
|
+
}
|
|
785
|
+
return {
|
|
786
|
+
firstCheckpointRef: metadata.firstCheckpointRef,
|
|
787
|
+
lastCheckpointRef: metadata.lastCheckpointRef
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
_buildWorkspace(session) {
|
|
791
|
+
const repoUri = this._extractRepositoryUri(session);
|
|
792
|
+
const repoUriResolved = repoUri ?? ( URI.parse("unknown:///"));
|
|
793
|
+
const gitRepository = {
|
|
794
|
+
uri: repoUriResolved,
|
|
795
|
+
workTreeUri: undefined,
|
|
796
|
+
isRepository: constObservable(repoUri !== undefined),
|
|
797
|
+
baseBranchName: undefined,
|
|
798
|
+
gitHubInfo: this.gitHubInfo
|
|
799
|
+
};
|
|
800
|
+
const folder = {
|
|
801
|
+
root: repoUriResolved,
|
|
802
|
+
workingDirectory: repoUriResolved,
|
|
803
|
+
name: basename(repoUriResolved),
|
|
804
|
+
description: undefined,
|
|
805
|
+
gitRepository
|
|
806
|
+
};
|
|
807
|
+
return {
|
|
808
|
+
uri: repoUriResolved,
|
|
809
|
+
label: githubRemoteRepoLabel(repoUriResolved) ?? getRepositoryName(session) ?? basename(repoUriResolved),
|
|
810
|
+
icon: repoUri ? Codicon.repo : Codicon.folder,
|
|
811
|
+
group: repoUri ? SESSION_WORKSPACE_GROUP_GITHUB : SESSION_WORKSPACE_GROUP_LOCAL,
|
|
812
|
+
folders: [folder],
|
|
813
|
+
requiresWorkspaceTrust: false,
|
|
814
|
+
isVirtualWorkspace: true
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
_extractRepositoryUri(session) {
|
|
818
|
+
const metadata = session.metadata;
|
|
819
|
+
if (typeof metadata?.owner !== "string" || typeof metadata.name !== "string") {
|
|
820
|
+
return undefined;
|
|
821
|
+
}
|
|
822
|
+
const branch = typeof metadata.branch === "string" ? metadata.branch : "HEAD";
|
|
823
|
+
return ( URI.from({
|
|
824
|
+
scheme: GITHUB_REMOTE_FILE_SCHEME,
|
|
825
|
+
authority: "github",
|
|
826
|
+
path: `/${metadata.owner}/${metadata.name}/${encodeURIComponent(branch)}`
|
|
827
|
+
}));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
let CopilotChatSessionsProvider = class CopilotChatSessionsProvider extends Disposable {
|
|
831
|
+
static {
|
|
832
|
+
CopilotChatSessionsProvider_1 = this;
|
|
833
|
+
}
|
|
834
|
+
static {
|
|
835
|
+
this.SANDBOX_MODEL_WAIT_MS = 30_000;
|
|
836
|
+
}
|
|
837
|
+
get id() {
|
|
838
|
+
return this.providerMode === "sandbox" ? CLOUD_SANDBOX_CREATION_PROVIDER_ID : COPILOT_PROVIDER_ID;
|
|
839
|
+
}
|
|
840
|
+
get label() {
|
|
841
|
+
return this.providerMode === "sandbox" ? ( localize(5069, "GitHub Sandboxes")) : ( localize(5070, "Copilot Chat"));
|
|
842
|
+
}
|
|
843
|
+
get sessionTypes() {
|
|
844
|
+
return this.providerMode === "sandbox" ? [CopilotSandboxSessionType] : [CopilotCloudSessionType];
|
|
845
|
+
}
|
|
846
|
+
get supportsLocalWorkspaces() {
|
|
847
|
+
return this.providerMode !== "sandbox";
|
|
848
|
+
}
|
|
849
|
+
get supportsAutomationSessionConfiguration() {
|
|
850
|
+
return this.providerMode === "default" && this.automations?.enabled.get() === true;
|
|
851
|
+
}
|
|
852
|
+
get supportsQuickChats() {
|
|
853
|
+
return isCloudSandboxEnabled(this.configurationService) && !this.configurationService.getValue(ChatAIDisabledSettingId);
|
|
854
|
+
}
|
|
855
|
+
constructor(
|
|
856
|
+
providerMode,
|
|
857
|
+
agentSessionsService,
|
|
858
|
+
chatService,
|
|
859
|
+
chatSessionsService,
|
|
860
|
+
commandService,
|
|
861
|
+
instantiationService,
|
|
862
|
+
languageModelsService,
|
|
863
|
+
configurationService,
|
|
864
|
+
logService,
|
|
865
|
+
notificationService,
|
|
866
|
+
gitHubService,
|
|
867
|
+
pullRequestIconCache,
|
|
868
|
+
labelService,
|
|
869
|
+
uriIdentityService,
|
|
870
|
+
fileService,
|
|
871
|
+
pathService,
|
|
872
|
+
storageService
|
|
873
|
+
) {
|
|
874
|
+
super();
|
|
875
|
+
this.providerMode = providerMode;
|
|
876
|
+
this.agentSessionsService = agentSessionsService;
|
|
877
|
+
this.chatService = chatService;
|
|
878
|
+
this.chatSessionsService = chatSessionsService;
|
|
879
|
+
this.commandService = commandService;
|
|
880
|
+
this.instantiationService = instantiationService;
|
|
881
|
+
this.languageModelsService = languageModelsService;
|
|
882
|
+
this.configurationService = configurationService;
|
|
883
|
+
this.logService = logService;
|
|
884
|
+
this.notificationService = notificationService;
|
|
885
|
+
this.gitHubService = gitHubService;
|
|
886
|
+
this.pullRequestIconCache = pullRequestIconCache;
|
|
887
|
+
this.labelService = labelService;
|
|
888
|
+
this.uriIdentityService = uriIdentityService;
|
|
889
|
+
this.fileService = fileService;
|
|
890
|
+
this.pathService = pathService;
|
|
891
|
+
this.storageService = storageService;
|
|
892
|
+
this.environment = {
|
|
893
|
+
id: "cloud",
|
|
894
|
+
label: ( localize(5071, "Cloud"))
|
|
895
|
+
};
|
|
896
|
+
this.icon = Codicon.copilot;
|
|
897
|
+
this.order = 0;
|
|
898
|
+
this._onDidChangeSessionTypes = this._register(( new Emitter()));
|
|
899
|
+
this.onDidChangeSessionTypes = this._onDidChangeSessionTypes.event;
|
|
900
|
+
this._onDidChangeCapabilities = this._register(( new Emitter()));
|
|
901
|
+
this.onDidChangeCapabilities = this._onDidChangeCapabilities.event;
|
|
902
|
+
this._onDidChangeSessions = this._register(( new Emitter()));
|
|
903
|
+
this.onDidChangeSessions = this._onDidChangeSessions.event;
|
|
904
|
+
this._onDidReplaceSession = this._register(( new Emitter()));
|
|
905
|
+
this.onDidReplaceSession = this._onDidReplaceSession.event;
|
|
906
|
+
this._sessionCache = ( new Map());
|
|
907
|
+
this._inFlightCommits = ( new Set());
|
|
908
|
+
this._sandboxSends = ( new Set());
|
|
909
|
+
this._repositoryPicker = this._register(( new MutableDisposable()));
|
|
910
|
+
this._sandboxCatalog = this._register(( new MutableDisposable()));
|
|
911
|
+
this._onDidChangeSandboxModels = this._register(( new Emitter()));
|
|
912
|
+
this._sandboxConfigs = ( new Map());
|
|
913
|
+
this._onDidChangeSessionConfig = this._register(( new Emitter()));
|
|
914
|
+
this.onDidChangeSessionConfig = this._onDidChangeSessionConfig.event;
|
|
915
|
+
this.sessionConfig = this;
|
|
916
|
+
this._sessionWrapperCache = ( new Map());
|
|
917
|
+
this._localGitRepositoryState = ( new Map());
|
|
918
|
+
this._localGitRepositoryResolutionStarted = ( new Set());
|
|
919
|
+
this._newSessions = this._register(( new DisposableMap()));
|
|
920
|
+
this._createdBySessions = ( new Map());
|
|
921
|
+
this._storedCreatedBySessions = ( new Map());
|
|
922
|
+
this._loadCreatedBySessions();
|
|
923
|
+
if (providerMode === "default") {
|
|
924
|
+
this.automations = this._register(
|
|
925
|
+
this.instantiationService.createInstance(CloudAutomationStore, this.id, CopilotCloudSessionType.id, async uri => {
|
|
926
|
+
if (uri.scheme === GITHUB_REMOTE_FILE_SCHEME) {
|
|
927
|
+
return uri;
|
|
928
|
+
}
|
|
929
|
+
if (uri.scheme !== Schemas.file) {
|
|
930
|
+
return undefined;
|
|
931
|
+
}
|
|
932
|
+
const repository = await resolveGitRepositoryFromGitConfig(this.fileService, uri, ["github.com"]);
|
|
933
|
+
return repository?.gitHub ? ( URI.from({
|
|
934
|
+
scheme: GITHUB_REMOTE_FILE_SCHEME,
|
|
935
|
+
authority: "github",
|
|
936
|
+
path: `/${repository.gitHub.owner}/${repository.gitHub.repo}/HEAD`
|
|
937
|
+
})) : undefined;
|
|
938
|
+
})
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
this._register(Event.filter(
|
|
942
|
+
this.configurationService.onDidChangeConfiguration,
|
|
943
|
+
event => event.affectsConfiguration(UNIFIED_WORKSPACE_PICKER_SETTING)
|
|
944
|
+
)(() => this._onDidChangeSessionTypes.fire()));
|
|
945
|
+
this._register(this.configurationService.onDidChangeConfiguration(event => {
|
|
946
|
+
const sandboxChanged = event.affectsConfiguration(CloudSandboxEnabledSettingId) || event.affectsConfiguration(RemoteAgentHostsEnabledSettingId);
|
|
947
|
+
if (sandboxChanged || event.affectsConfiguration(ChatAIDisabledSettingId)) {
|
|
948
|
+
this._onDidChangeSessionTypes.fire();
|
|
949
|
+
this._onDidChangeCapabilities.fire();
|
|
950
|
+
}
|
|
951
|
+
if (sandboxChanged) {
|
|
952
|
+
if (this._newSessions.size > 0 && this._usesSandbox()) {
|
|
953
|
+
this._getSandboxCatalog().load();
|
|
954
|
+
}
|
|
955
|
+
for (const sessionId of ( this._newSessions.keys())) {
|
|
956
|
+
this._onDidChangeSessionConfig.fire(sessionId);
|
|
957
|
+
}
|
|
958
|
+
this._onDidChangeSandboxModels.fire();
|
|
959
|
+
}
|
|
960
|
+
if (event.affectsConfiguration(ChatConfiguration.DefaultConfiguration) || event.affectsConfiguration(ChatConfiguration.GlobalAutoApprove)) {
|
|
961
|
+
for (const [sessionId, config] of this._sandboxConfigs) {
|
|
962
|
+
const refreshed = createCloudSandboxSessionConfig(this.configurationService);
|
|
963
|
+
for (const [key, value] of Object.entries(config.values)) {
|
|
964
|
+
if (refreshed.schema.properties[key]?.enum?.some(candidate => candidate === value)) {
|
|
965
|
+
refreshed.values[key] = value;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
this._sandboxConfigs.set(sessionId, refreshed);
|
|
969
|
+
this._onDidChangeSessionConfig.fire(sessionId);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}));
|
|
973
|
+
this._register(this.agentSessionsService.model.onDidChangeSessions(() => {
|
|
974
|
+
this._refreshSessionCache();
|
|
975
|
+
}));
|
|
976
|
+
this._ensureSessionCache();
|
|
977
|
+
}
|
|
978
|
+
get browseActions() {
|
|
979
|
+
const useConsolidatedRemoteWorkspaces = this.configurationService.getValue(UNIFIED_WORKSPACE_PICKER_SETTING);
|
|
980
|
+
const isSandbox = this.providerMode === "sandbox";
|
|
981
|
+
const repositoryAction = {
|
|
982
|
+
label: isSandbox ? ( localize(5072, "Choose Repository...")) : useConsolidatedRemoteWorkspaces ? ( localize(5073, "Work in Repository...")) : ( localize(5074, "Repository...")),
|
|
983
|
+
group: SESSION_WORKSPACE_GROUP_GITHUB,
|
|
984
|
+
icon: isSandbox || useConsolidatedRemoteWorkspaces ? Codicon.github : Codicon.library,
|
|
985
|
+
providerId: this.id,
|
|
986
|
+
attachesContext: false,
|
|
987
|
+
supportsContextAttachment: !isSandbox,
|
|
988
|
+
run: () => this._browseForRepository()
|
|
989
|
+
};
|
|
990
|
+
if (isSandbox) {
|
|
991
|
+
return [repositoryAction];
|
|
992
|
+
}
|
|
993
|
+
return [repositoryAction, {
|
|
994
|
+
label: ( localize(5075, "Issue...")),
|
|
995
|
+
group: SESSION_WORKSPACE_GROUP_GITHUB,
|
|
996
|
+
icon: Codicon.issues,
|
|
997
|
+
providerId: this.id,
|
|
998
|
+
attachesContext: true,
|
|
999
|
+
run: workspace => this._browseForGitHubContext(OPEN_ISSUE_COMMAND, Codicon.issues, workspace)
|
|
1000
|
+
}, {
|
|
1001
|
+
label: ( localize(5076, "Pull Request...")),
|
|
1002
|
+
group: SESSION_WORKSPACE_GROUP_GITHUB,
|
|
1003
|
+
icon: useConsolidatedRemoteWorkspaces ? Codicon.github : Codicon.gitPullRequest,
|
|
1004
|
+
providerId: this.id,
|
|
1005
|
+
attachesContext: true,
|
|
1006
|
+
run: workspace => this._browseForGitHubContext(
|
|
1007
|
+
OPEN_PULL_REQUEST_COMMAND,
|
|
1008
|
+
useConsolidatedRemoteWorkspaces ? Codicon.github : Codicon.gitPullRequest,
|
|
1009
|
+
workspace
|
|
1010
|
+
)
|
|
1011
|
+
}];
|
|
1012
|
+
}
|
|
1013
|
+
getSessionTypes(workspaceUri) {
|
|
1014
|
+
if (this.providerMode === "sandbox") {
|
|
1015
|
+
return this.resolveWorkspace(workspaceUri) ? [CopilotSandboxSessionType] : [];
|
|
1016
|
+
}
|
|
1017
|
+
if (workspaceUri.scheme === GITHUB_REMOTE_FILE_SCHEME || workspaceUri.scheme === SessionType.CopilotCloud) {
|
|
1018
|
+
return [CopilotCloudSessionType];
|
|
1019
|
+
}
|
|
1020
|
+
if (this.configurationService.getValue(UNIFIED_WORKSPACE_PICKER_SETTING) && workspaceUri.scheme === Schemas.file) {
|
|
1021
|
+
const gitRepository = this._getLocalGitRepository(workspaceUri);
|
|
1022
|
+
gitRepository.resolveGitHubInfo?.();
|
|
1023
|
+
if (gitRepository.gitHubInfo.get()) {
|
|
1024
|
+
return [CopilotCloudSessionType];
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return [];
|
|
1028
|
+
}
|
|
1029
|
+
getSessions() {
|
|
1030
|
+
this._ensureSessionCache();
|
|
1031
|
+
return Array.from(( this._sessionCache.values()), chat => this._chatToSession(chat));
|
|
1032
|
+
}
|
|
1033
|
+
_createdBySession(resource) {
|
|
1034
|
+
const key = ( resource.toString());
|
|
1035
|
+
let createdBySession = this._createdBySessions.get(key);
|
|
1036
|
+
if (!createdBySession) {
|
|
1037
|
+
createdBySession = observableValue(this, this._storedCreatedBySessions.get(key));
|
|
1038
|
+
this._createdBySessions.set(key, createdBySession);
|
|
1039
|
+
}
|
|
1040
|
+
return createdBySession;
|
|
1041
|
+
}
|
|
1042
|
+
_setCreatedBySession(resource, reference) {
|
|
1043
|
+
const key = ( resource.toString());
|
|
1044
|
+
this._createdBySession(resource).set(reference, undefined);
|
|
1045
|
+
this._storedCreatedBySessions.set(key, reference);
|
|
1046
|
+
this._saveCreatedBySessions();
|
|
1047
|
+
}
|
|
1048
|
+
_deleteCreatedBySession(resource) {
|
|
1049
|
+
const key = ( resource.toString());
|
|
1050
|
+
this._createdBySessions.delete(key);
|
|
1051
|
+
if (this._storedCreatedBySessions.delete(key)) {
|
|
1052
|
+
this._saveCreatedBySessions();
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
_loadCreatedBySessions() {
|
|
1056
|
+
const raw = this.storageService.get(STORAGE_KEY_CREATED_BY_SESSIONS, StorageScope.PROFILE);
|
|
1057
|
+
if (!raw) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
try {
|
|
1061
|
+
const stored = JSON.parse(raw);
|
|
1062
|
+
for (const [resource, reference] of Object.entries(stored)) {
|
|
1063
|
+
this._storedCreatedBySessions.set(resource, {
|
|
1064
|
+
session: ( URI.parse(reference.session)),
|
|
1065
|
+
chat: reference.chat ? ( URI.parse(reference.chat)) : undefined,
|
|
1066
|
+
turnId: reference.turnId
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
this.logService.error(
|
|
1071
|
+
"[CopilotChatSessionsProvider] Failed to restore session creation references.",
|
|
1072
|
+
error
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
_saveCreatedBySessions() {
|
|
1077
|
+
const stored = {};
|
|
1078
|
+
for (const [resource, reference] of this._storedCreatedBySessions) {
|
|
1079
|
+
stored[resource] = {
|
|
1080
|
+
session: ( reference.session.toString()),
|
|
1081
|
+
chat: reference.chat?.toString(),
|
|
1082
|
+
turnId: reference.turnId
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
this.storageService.store(
|
|
1086
|
+
STORAGE_KEY_CREATED_BY_SESSIONS,
|
|
1087
|
+
JSON.stringify(stored),
|
|
1088
|
+
StorageScope.PROFILE,
|
|
1089
|
+
StorageTarget.MACHINE
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
_clearCurrentNewSessionIfMatch(session, leak) {
|
|
1093
|
+
if (this._newSessions.get(session.sessionId) === session) {
|
|
1094
|
+
this._sandboxConfigs.delete(session.sessionId);
|
|
1095
|
+
if (leak) {
|
|
1096
|
+
this._newSessions.deleteAndLeak(session.sessionId);
|
|
1097
|
+
} else {
|
|
1098
|
+
this._newSessions.deleteAndDispose(session.sessionId);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
deleteNewSession(sessionId) {
|
|
1103
|
+
this._sandboxConfigs.delete(sessionId);
|
|
1104
|
+
if (( this._newSessions.has(sessionId))) {
|
|
1105
|
+
this._newSessions.deleteAndDispose(sessionId);
|
|
1106
|
+
this._sessionWrapperCache.delete(sessionId);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
getSession(sessionId) {
|
|
1110
|
+
const newSession = this._newSessions.get(sessionId);
|
|
1111
|
+
if (newSession) {
|
|
1112
|
+
return newSession;
|
|
1113
|
+
}
|
|
1114
|
+
return this._findChatSession(sessionId);
|
|
1115
|
+
}
|
|
1116
|
+
createNewSession(workspaceUri, sessionTypeId, options) {
|
|
1117
|
+
return this._createDraftSession(workspaceUri, sessionTypeId, options);
|
|
1118
|
+
}
|
|
1119
|
+
_createDraftSession(workspaceUri, sessionTypeId, options) {
|
|
1120
|
+
if (this.providerMode === "sandbox") {
|
|
1121
|
+
if (!isCloudSandboxEnabled(this.configurationService) || this.configurationService.getValue(ChatAIDisabledSettingId)) {
|
|
1122
|
+
throw ( new Error(( localize(5077, "GitHub sandbox sessions are not enabled."))));
|
|
1123
|
+
}
|
|
1124
|
+
if (sessionTypeId !== CopilotSandboxSessionType.id || options?.automationConfiguration || options?.isAutomationDraft) {
|
|
1125
|
+
throw ( new Error(( localize(
|
|
1126
|
+
5078,
|
|
1127
|
+
"This configuration is not supported for a new GitHub sandbox session."
|
|
1128
|
+
))));
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
const workspace = workspaceUri ? this.resolveWorkspace(workspaceUri) : undefined;
|
|
1132
|
+
if (workspaceUri && !workspace) {
|
|
1133
|
+
throw ( new Error(`Cannot resolve workspace for URI: ${( workspaceUri.toString())}`));
|
|
1134
|
+
}
|
|
1135
|
+
const automationConfiguration = options?.automationConfiguration;
|
|
1136
|
+
assertAutomationSessionTemplate(automationConfiguration?.sessionTemplate);
|
|
1137
|
+
if (this.providerMode !== "sandbox" && sessionTypeId !== CopilotCloudSessionType.id) {
|
|
1138
|
+
throw ( new Error(`Unsupported session type '${sessionTypeId}'`));
|
|
1139
|
+
}
|
|
1140
|
+
const cloudWorkspace = !workspace || workspaceUri?.scheme === GITHUB_REMOTE_FILE_SCHEME ? workspace : this._getCloudWorkspaceForLocalRepository(workspace);
|
|
1141
|
+
if (workspace && !cloudWorkspace) {
|
|
1142
|
+
throw ( new Error("Copilot Cloud sessions require a local workspace with a GitHub remote"));
|
|
1143
|
+
}
|
|
1144
|
+
const target = this.providerMode === "sandbox" ? CopilotSandboxSessionType.id : AgentSessionProviders.Cloud;
|
|
1145
|
+
const resource = ( URI.from({
|
|
1146
|
+
scheme: target,
|
|
1147
|
+
path: `/untitled-${generateUuid()}`
|
|
1148
|
+
}));
|
|
1149
|
+
const session = this.instantiationService.createInstance(
|
|
1150
|
+
RemoteNewSession,
|
|
1151
|
+
resource,
|
|
1152
|
+
cloudWorkspace,
|
|
1153
|
+
target,
|
|
1154
|
+
this.id,
|
|
1155
|
+
automationConfiguration,
|
|
1156
|
+
options?.isAutomationDraft === true
|
|
1157
|
+
);
|
|
1158
|
+
session.setCreatedBySession(options?.createdBySession);
|
|
1159
|
+
this._newSessions.set(session.sessionId, session);
|
|
1160
|
+
if (this._usesSandbox(session)) {
|
|
1161
|
+
this._getSandboxCatalog().load();
|
|
1162
|
+
}
|
|
1163
|
+
this._onDidChangeSessionConfig.fire(session.sessionId);
|
|
1164
|
+
this._onDidChangeSandboxModels.fire();
|
|
1165
|
+
try {
|
|
1166
|
+
this._applyAutomationSessionConfiguration(session, automationConfiguration);
|
|
1167
|
+
return this._chatToSession(session);
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
this._newSessions.deleteAndDispose(session.sessionId);
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
_getCloudWorkspaceForLocalRepository(workspace) {
|
|
1174
|
+
const gitHubInfo = workspace.folders.map(folder => folder.gitRepository?.gitHubInfo.get()).find(info => info !== undefined);
|
|
1175
|
+
if (!gitHubInfo) {
|
|
1176
|
+
return undefined;
|
|
1177
|
+
}
|
|
1178
|
+
const root = ( URI.from({
|
|
1179
|
+
scheme: GITHUB_REMOTE_FILE_SCHEME,
|
|
1180
|
+
authority: "github",
|
|
1181
|
+
path: `/${gitHubInfo.owner}/${gitHubInfo.repo}/HEAD`
|
|
1182
|
+
}));
|
|
1183
|
+
return this.resolveWorkspace(root);
|
|
1184
|
+
}
|
|
1185
|
+
getAutomationModelConfiguration(sessionId) {
|
|
1186
|
+
return this._newSessions.get(sessionId)?.modelConfiguration;
|
|
1187
|
+
}
|
|
1188
|
+
async getAutomationSessionConfiguration(sessionId) {
|
|
1189
|
+
const session = this._newSessions.get(sessionId);
|
|
1190
|
+
if (!session) {
|
|
1191
|
+
return undefined;
|
|
1192
|
+
}
|
|
1193
|
+
const modelId = session.modelId.get();
|
|
1194
|
+
const modelConfiguration = session.modelConfiguration.captureModelConfiguration(modelId);
|
|
1195
|
+
const initialConfiguration = session.initialAutomationSessionConfiguration;
|
|
1196
|
+
const initialTemplate = initialConfiguration?.sessionTemplate;
|
|
1197
|
+
if (this.automations?.enabled.get()) {
|
|
1198
|
+
if (modelConfiguration !== undefined || initialConfiguration?.mode !== undefined || initialConfiguration?.permissionLevel !== undefined) {
|
|
1199
|
+
throw ( new Error(( localize(
|
|
1200
|
+
5079,
|
|
1201
|
+
"Cloud automations do not support local mode, approval, or model-specific settings. Remove those settings before saving."
|
|
1202
|
+
))));
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
sessionTemplate: {
|
|
1206
|
+
...(modelId !== undefined ? {
|
|
1207
|
+
modelId
|
|
1208
|
+
} : {}),
|
|
1209
|
+
...(initialTemplate?.config !== undefined ? {
|
|
1210
|
+
config: initialTemplate.config
|
|
1211
|
+
} : {})
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
const initialMode = initialConfiguration?.mode ?? initialTemplate?.config?.[SessionConfigKey.Mode];
|
|
1216
|
+
const mode = typeof initialMode === "string" ? initialMode : undefined;
|
|
1217
|
+
const initialPermissionLevel = initialConfiguration?.permissionLevel ?? initialTemplate?.config?.[SessionConfigKey.AutoApprove];
|
|
1218
|
+
const permissionLevel = isChatPermissionLevel(initialPermissionLevel) ? initialPermissionLevel : ChatPermissionLevel.Default;
|
|
1219
|
+
const config = {
|
|
1220
|
+
...initialTemplate?.config
|
|
1221
|
+
};
|
|
1222
|
+
if (mode) {
|
|
1223
|
+
config[SessionConfigKey.Mode] = mode;
|
|
1224
|
+
} else {
|
|
1225
|
+
delete config[SessionConfigKey.Mode];
|
|
1226
|
+
}
|
|
1227
|
+
config[SessionConfigKey.AutoApprove] = permissionLevel;
|
|
1228
|
+
const sessionTemplate = {
|
|
1229
|
+
...(modelId ? {
|
|
1230
|
+
modelId
|
|
1231
|
+
} : {}),
|
|
1232
|
+
...(modelConfiguration !== undefined ? {
|
|
1233
|
+
modelConfiguration
|
|
1234
|
+
} : {}),
|
|
1235
|
+
...(( Object.keys(config)).length > 0 ? {
|
|
1236
|
+
config
|
|
1237
|
+
} : {})
|
|
1238
|
+
};
|
|
1239
|
+
return {
|
|
1240
|
+
sessionTemplate,
|
|
1241
|
+
modelId,
|
|
1242
|
+
mode,
|
|
1243
|
+
permissionLevel
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
createQuickChat(sessionTypeId, options) {
|
|
1247
|
+
if (!this.supportsQuickChats) {
|
|
1248
|
+
throw ( new Error(( localize(5077, "GitHub sandbox sessions are not enabled."))));
|
|
1249
|
+
}
|
|
1250
|
+
return this._createDraftSession(undefined, sessionTypeId, options);
|
|
1251
|
+
}
|
|
1252
|
+
_applyAutomationSessionConfiguration(session, configuration) {
|
|
1253
|
+
if (!configuration) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
const template = configuration.sessionTemplate;
|
|
1257
|
+
if (template?.agent) {
|
|
1258
|
+
throw ( new Error(( localize(
|
|
1259
|
+
5080,
|
|
1260
|
+
"This provider does not support custom agents in Automation session templates."
|
|
1261
|
+
))));
|
|
1262
|
+
}
|
|
1263
|
+
const modelId = template?.modelId ?? configuration.modelId;
|
|
1264
|
+
if (modelId) {
|
|
1265
|
+
session.setModelId(modelId, ChatModelSource.Chosen);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
get onDidChangeModels() {
|
|
1269
|
+
return Event.signal(Event.any(
|
|
1270
|
+
this._onDidChangeSandboxModels.event,
|
|
1271
|
+
this.languageModelsService.onDidChangeLanguageModels,
|
|
1272
|
+
this.chatSessionsService.onDidChangeOptionGroups
|
|
1273
|
+
));
|
|
1274
|
+
}
|
|
1275
|
+
getModelsSnapshot(sessionId, desiredModelId) {
|
|
1276
|
+
const draft = this._newSessions.get(sessionId);
|
|
1277
|
+
if (draft && this._usesSandbox(draft)) {
|
|
1278
|
+
return this._sandboxModelsSnapshot(desiredModelId);
|
|
1279
|
+
}
|
|
1280
|
+
const session = this.getSession(sessionId);
|
|
1281
|
+
if (session instanceof RemoteNewSession) {
|
|
1282
|
+
const {
|
|
1283
|
+
modelOption,
|
|
1284
|
+
isResolved
|
|
1285
|
+
} = session.getModelOptionsSnapshot();
|
|
1286
|
+
const models = modelOption?.group.items.map(item => this._toSyntheticModel(item)) ?? [];
|
|
1287
|
+
return {
|
|
1288
|
+
models,
|
|
1289
|
+
desiredModelResolution: resolveModelIdentifier(models, desiredModelId, isResolved),
|
|
1290
|
+
modelTarget: session.sessionType
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
const sessionType = session?.sessionType;
|
|
1294
|
+
if (!sessionType) {
|
|
1295
|
+
return {
|
|
1296
|
+
models: [],
|
|
1297
|
+
desiredModelResolution: resolveModelIdentifier([], desiredModelId, false),
|
|
1298
|
+
modelTarget: undefined
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
const allModels = getRegisteredLanguageModels(this.languageModelsService);
|
|
1302
|
+
const models = allModels.filter(model => model.metadata.targetChatSessionType === sessionType);
|
|
1303
|
+
return {
|
|
1304
|
+
models,
|
|
1305
|
+
desiredModelResolution: resolveModelIdentifierFromLanguageModels(models, desiredModelId, this.languageModelsService, allModels),
|
|
1306
|
+
modelTarget: sessionType
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
getModelsSnapshotForCreation(_workspaceUri, sessionTypeId, desiredModelId) {
|
|
1310
|
+
if (this.providerMode !== "sandbox" && sessionTypeId !== CopilotCloudSessionType.id) {
|
|
1311
|
+
return {
|
|
1312
|
+
models: [],
|
|
1313
|
+
desiredModelResolution: resolveModelIdentifier([], desiredModelId, true),
|
|
1314
|
+
modelTarget: undefined
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
if (this._usesSandbox()) {
|
|
1318
|
+
return this._sandboxModelsSnapshot(desiredModelId);
|
|
1319
|
+
}
|
|
1320
|
+
const group = this.chatSessionsService.getOptionGroupsForSessionType(AgentSessionProviders.Cloud)?.find(candidate => isModelOptionGroup(candidate));
|
|
1321
|
+
const models = group?.items.map(item => this._toSyntheticModel(item)) ?? [];
|
|
1322
|
+
return {
|
|
1323
|
+
models,
|
|
1324
|
+
desiredModelResolution: resolveModelIdentifier(models, desiredModelId, group !== undefined),
|
|
1325
|
+
modelTarget: AgentSessionProviders.Cloud
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
getModelPickerOptions(sessionId) {
|
|
1329
|
+
const draft = this._newSessions.get(sessionId);
|
|
1330
|
+
if (draft && this._usesSandbox(draft)) {
|
|
1331
|
+
return {
|
|
1332
|
+
showUnavailableFeatured: false,
|
|
1333
|
+
showManageModelsAction: false,
|
|
1334
|
+
showAutoModel: false
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
const sessionType = this.getSession(sessionId)?.sessionType;
|
|
1338
|
+
const showAutoModel = !sessionType || this.chatSessionsService.supportsAutoModelForSessionType(sessionType);
|
|
1339
|
+
return {
|
|
1340
|
+
showUnavailableFeatured: false,
|
|
1341
|
+
showManageModelsAction: false,
|
|
1342
|
+
showAutoModel
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
_usesSandbox(session) {
|
|
1346
|
+
return !session?.isAutomationDraft && (session?.isQuickChat.get() === true || this.providerMode === "sandbox" || isCloudSandboxEnabled(this.configurationService));
|
|
1347
|
+
}
|
|
1348
|
+
_getSandboxCatalog() {
|
|
1349
|
+
if (!this._sandboxCatalog.value) {
|
|
1350
|
+
const catalog = this.instantiationService.createInstance(
|
|
1351
|
+
CloudSandboxModels,
|
|
1352
|
+
CopilotSandboxSessionType.id,
|
|
1353
|
+
`${this.id}-sandbox-models`,
|
|
1354
|
+
undefined
|
|
1355
|
+
);
|
|
1356
|
+
this._sandboxCatalog.value = catalog;
|
|
1357
|
+
this._register(catalog.onDidChange(() => this._onDidChangeSandboxModels.fire()));
|
|
1358
|
+
}
|
|
1359
|
+
return this._sandboxCatalog.value;
|
|
1360
|
+
}
|
|
1361
|
+
_sandboxModelsSnapshot(desiredModelId) {
|
|
1362
|
+
const catalog = this._getSandboxCatalog();
|
|
1363
|
+
catalog.load();
|
|
1364
|
+
return {
|
|
1365
|
+
models: catalog.models,
|
|
1366
|
+
desiredModelResolution: resolveModelIdentifier(catalog.models, desiredModelId, catalog.ready),
|
|
1367
|
+
modelTarget: CopilotSandboxSessionType.id
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
getSessionConfig(sessionId) {
|
|
1371
|
+
const session = this._newSessions.get(sessionId);
|
|
1372
|
+
if (!session || !this._usesSandbox(session)) {
|
|
1373
|
+
return undefined;
|
|
1374
|
+
}
|
|
1375
|
+
let config = this._sandboxConfigs.get(sessionId);
|
|
1376
|
+
if (!config) {
|
|
1377
|
+
config = createCloudSandboxSessionConfig(this.configurationService);
|
|
1378
|
+
this._sandboxConfigs.set(sessionId, config);
|
|
1379
|
+
}
|
|
1380
|
+
return config;
|
|
1381
|
+
}
|
|
1382
|
+
getCreateSessionConfig(sessionId) {
|
|
1383
|
+
return this.getSessionConfig(sessionId)?.values;
|
|
1384
|
+
}
|
|
1385
|
+
isSessionConfigResolving(_sessionId) {
|
|
1386
|
+
return constObservable(false);
|
|
1387
|
+
}
|
|
1388
|
+
async setSessionConfigValue(sessionId, property, value) {
|
|
1389
|
+
const config = this.getSessionConfig(sessionId);
|
|
1390
|
+
if (!config) {
|
|
1391
|
+
throw ( new Error("Cloud sandbox draft configuration is unavailable."));
|
|
1392
|
+
}
|
|
1393
|
+
validateSessionConfigWrite(config.schema, config.values, property, value, true);
|
|
1394
|
+
this._sandboxConfigs.set(sessionId, {
|
|
1395
|
+
...config,
|
|
1396
|
+
values: {
|
|
1397
|
+
...config.values,
|
|
1398
|
+
[property]: value
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
this._onDidChangeSessionConfig.fire(sessionId);
|
|
1402
|
+
}
|
|
1403
|
+
_toSyntheticModel(item) {
|
|
1404
|
+
const modelMetadata = item.modelMetadata;
|
|
1405
|
+
return {
|
|
1406
|
+
identifier: item.id,
|
|
1407
|
+
metadata: {
|
|
1408
|
+
extension: ( new ExtensionIdentifier("")),
|
|
1409
|
+
name: modelMetadata?.name ?? item.name,
|
|
1410
|
+
id: modelMetadata?.id ?? item.id,
|
|
1411
|
+
vendor: COPILOT_VENDOR_ID,
|
|
1412
|
+
version: modelMetadata?.version ?? "",
|
|
1413
|
+
family: modelMetadata?.family ?? "",
|
|
1414
|
+
tooltip: modelMetadata?.tooltip ?? item.tooltip,
|
|
1415
|
+
pricing: modelMetadata?.pricing,
|
|
1416
|
+
multiplierNumeric: modelMetadata?.multiplierNumeric,
|
|
1417
|
+
inputCost: modelMetadata?.inputCost,
|
|
1418
|
+
outputCost: modelMetadata?.outputCost,
|
|
1419
|
+
cacheCost: modelMetadata?.cacheCost,
|
|
1420
|
+
cacheWriteCost: modelMetadata?.cacheWriteCost,
|
|
1421
|
+
longContextInputCost: modelMetadata?.longContextInputCost,
|
|
1422
|
+
longContextOutputCost: modelMetadata?.longContextOutputCost,
|
|
1423
|
+
longContextCacheCost: modelMetadata?.longContextCacheCost,
|
|
1424
|
+
longContextCacheWriteCost: modelMetadata?.longContextCacheWriteCost,
|
|
1425
|
+
priceCategory: modelMetadata?.priceCategory,
|
|
1426
|
+
promo: modelMetadata?.promo,
|
|
1427
|
+
maxInputTokens: modelMetadata?.maxInputTokens ?? 0,
|
|
1428
|
+
maxOutputTokens: modelMetadata?.maxOutputTokens ?? 0,
|
|
1429
|
+
maxContextWindowTokens: modelMetadata?.maxContextWindowTokens,
|
|
1430
|
+
capabilities: modelMetadata?.capabilities ? {
|
|
1431
|
+
vision: modelMetadata.capabilities.vision,
|
|
1432
|
+
toolCalling: modelMetadata.capabilities.toolCalling
|
|
1433
|
+
} : undefined,
|
|
1434
|
+
isUserSelectable: true,
|
|
1435
|
+
isDefaultForLocation: {}
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
setModel(sessionId, chatResource, modelId, source) {
|
|
1440
|
+
const newSession = this._newSessions.get(sessionId);
|
|
1441
|
+
if (newSession) {
|
|
1442
|
+
const previousModelId = newSession.modelId.get();
|
|
1443
|
+
if (previousModelId && previousModelId !== modelId) {
|
|
1444
|
+
const resolution = this.getModelsSnapshot(sessionId, previousModelId).desiredModelResolution;
|
|
1445
|
+
if (resolution.kind === "available" && resolution.model.identifier === modelId) {
|
|
1446
|
+
newSession.modelConfiguration.rebindModelConfiguration(previousModelId, modelId);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
newSession.setModelId(modelId, source);
|
|
1450
|
+
const {
|
|
1451
|
+
modelOption
|
|
1452
|
+
} = newSession.getModelOptionsSnapshot();
|
|
1453
|
+
const item = modelOption?.group.items.find(i => i.id === modelId);
|
|
1454
|
+
if (item) {
|
|
1455
|
+
newSession.setOptionValue(modelOption.group.id, item);
|
|
1456
|
+
}
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
this._ensureSessionCache();
|
|
1460
|
+
const chatSession = this._sessionCache.get(( chatResource.toString())) ?? this._findChatSession(sessionId);
|
|
1461
|
+
chatSession?.setModelId(modelId, source);
|
|
1462
|
+
}
|
|
1463
|
+
async getNewSessionConfig(sessionId) {
|
|
1464
|
+
const session = this._newSessions.get(sessionId);
|
|
1465
|
+
if (!session) {
|
|
1466
|
+
return undefined;
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
providerConfig: deepClone(
|
|
1470
|
+
Object.fromEntries([...session.selectedOptions].map(([key, value]) => [key, value.id]))
|
|
1471
|
+
)
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
async archiveSession(sessionId) {
|
|
1475
|
+
const chatSession = this._findChatSession(sessionId);
|
|
1476
|
+
if (chatSession instanceof RemoteNewSession) {
|
|
1477
|
+
chatSession.setArchived(true);
|
|
1478
|
+
this._onDidChangeSessions.fire({
|
|
1479
|
+
added: [],
|
|
1480
|
+
removed: [],
|
|
1481
|
+
changed: [this._chatToSession(chatSession)]
|
|
1482
|
+
});
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
const agentSession = this._findAgentSession(sessionId);
|
|
1486
|
+
if (agentSession) {
|
|
1487
|
+
agentSession.setArchived(true);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
async unarchiveSession(sessionId) {
|
|
1491
|
+
const chatSession = this._findChatSession(sessionId);
|
|
1492
|
+
if (chatSession instanceof RemoteNewSession) {
|
|
1493
|
+
chatSession.setArchived(false);
|
|
1494
|
+
this._onDidChangeSessions.fire({
|
|
1495
|
+
added: [],
|
|
1496
|
+
removed: [],
|
|
1497
|
+
changed: [this._chatToSession(chatSession)]
|
|
1498
|
+
});
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const agentSession = this._findAgentSession(sessionId);
|
|
1502
|
+
if (agentSession) {
|
|
1503
|
+
agentSession.setArchived(false);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
async setSessionReadState(sessionId, isRead) {
|
|
1507
|
+
const agentSession = this._findAgentSession(sessionId);
|
|
1508
|
+
if (agentSession && agentSession.isRead() !== isRead) {
|
|
1509
|
+
agentSession.setRead(isRead);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
async deleteSession(sessionId) {
|
|
1513
|
+
const agentSession = this._findAgentSession(sessionId);
|
|
1514
|
+
if (!agentSession) {
|
|
1515
|
+
this._cleanupTempSession(sessionId);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
await this.chatService.removeHistoryEntry(agentSession.resource);
|
|
1519
|
+
this._deleteCreatedBySession(agentSession.resource);
|
|
1520
|
+
this._sessionWrapperCache.delete(sessionId);
|
|
1521
|
+
this._refreshSessionCache();
|
|
1522
|
+
}
|
|
1523
|
+
async deleteSessions(sessionIds) {
|
|
1524
|
+
for (const sessionId of sessionIds) {
|
|
1525
|
+
await this.deleteSession(sessionId);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
async renameChat(_sessionId, _chatUri, _title) {
|
|
1529
|
+
throw ( new Error("Renaming is not supported for Copilot Cloud sessions"));
|
|
1530
|
+
}
|
|
1531
|
+
async renameSession(_sessionId, _title) {
|
|
1532
|
+
throw ( new Error("Renaming is not supported for Copilot Cloud sessions"));
|
|
1533
|
+
}
|
|
1534
|
+
async deleteChat(_sessionId, _chatUri, _options) {
|
|
1535
|
+
throw ( new Error("Deleting individual chats is not supported for Copilot Cloud sessions"));
|
|
1536
|
+
}
|
|
1537
|
+
async forkChat(sessionId, _sourceChat, _turnId) {
|
|
1538
|
+
throw ( new Error(`Session '${sessionId}' does not support forking into a chat`));
|
|
1539
|
+
}
|
|
1540
|
+
async createSideChat(sessionId, _sourceChat, _turnId, _selection) {
|
|
1541
|
+
throw ( new Error(`Session '${sessionId}' does not support side chats`));
|
|
1542
|
+
}
|
|
1543
|
+
startNewSessionRequest(sessionId) {
|
|
1544
|
+
const session = this._newSessions.get(sessionId);
|
|
1545
|
+
if (!session || !this._usesSandbox(session)) {
|
|
1546
|
+
return undefined;
|
|
1547
|
+
}
|
|
1548
|
+
return session.startPreparation();
|
|
1549
|
+
}
|
|
1550
|
+
async createNewChat(sessionId, _prompt) {
|
|
1551
|
+
const session = this._newSessions.get(sessionId);
|
|
1552
|
+
if (!session) {
|
|
1553
|
+
throw ( new Error(
|
|
1554
|
+
`[CopilotChatSessionsProvider] Session '${sessionId}' does not support multiple chats`
|
|
1555
|
+
));
|
|
1556
|
+
}
|
|
1557
|
+
if (!this._usesSandbox(session)) {
|
|
1558
|
+
(await this._createChatSession(session.resource, session)).dispose();
|
|
1559
|
+
}
|
|
1560
|
+
const newChat = this._withChangesets(buildChatFromSession(session), session.workspace);
|
|
1561
|
+
session.mainChat.set(newChat, undefined);
|
|
1562
|
+
return newChat;
|
|
1563
|
+
}
|
|
1564
|
+
_getCloudSandboxContribution() {
|
|
1565
|
+
return getWorkbenchContribution(CloudSandboxAgentHostContribution.ID);
|
|
1566
|
+
}
|
|
1567
|
+
get _sandboxModelWaitMs() {
|
|
1568
|
+
return CopilotChatSessionsProvider_1.SANDBOX_MODEL_WAIT_MS;
|
|
1569
|
+
}
|
|
1570
|
+
async _sendFirstChatToSandbox(session, repoNwo, options) {
|
|
1571
|
+
this._sandboxSends.add(session.sessionId);
|
|
1572
|
+
const preparation = session.startPreparation();
|
|
1573
|
+
const token = preparation.object;
|
|
1574
|
+
session.setTitle(
|
|
1575
|
+
(options.title || options.query.split("\n")[0]).trim().substring(0, 100) || ( localize(5081, "New Session"))
|
|
1576
|
+
);
|
|
1577
|
+
session.setStatus(SessionStatus.InProgress);
|
|
1578
|
+
this._sessionCache.set(( session.resource.toString()), session);
|
|
1579
|
+
const placeholder = this._chatToSession(session);
|
|
1580
|
+
this._onDidChangeSessions.fire({
|
|
1581
|
+
added: [placeholder],
|
|
1582
|
+
removed: [],
|
|
1583
|
+
changed: []
|
|
1584
|
+
});
|
|
1585
|
+
let provisioned;
|
|
1586
|
+
const selectedModel = this._selectedCloudModel(session);
|
|
1587
|
+
const config = this.getCreateSessionConfig(session.sessionId);
|
|
1588
|
+
const store = ( new DisposableStore());
|
|
1589
|
+
store.add(preparation);
|
|
1590
|
+
store.add(token.onCancellationRequested(() => store.dispose()));
|
|
1591
|
+
const progress = {
|
|
1592
|
+
report: message => {
|
|
1593
|
+
if (!store.isDisposed) {
|
|
1594
|
+
session.reportPreparationProgress(message);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
try {
|
|
1599
|
+
const contribution = this._getCloudSandboxContribution();
|
|
1600
|
+
provisioned = await raceCancellationError(contribution.provisionSession({
|
|
1601
|
+
...(repoNwo ? {
|
|
1602
|
+
repoNwo
|
|
1603
|
+
} : {}),
|
|
1604
|
+
prompt: options.query
|
|
1605
|
+
}, token, progress), token);
|
|
1606
|
+
if (token.isCancellationRequested) {
|
|
1607
|
+
throw ( new CancellationError());
|
|
1608
|
+
}
|
|
1609
|
+
if (repoNwo) {
|
|
1610
|
+
store.add(
|
|
1611
|
+
contribution.trackSessionCreationProgress(provisioned.environmentId, repoNwo, progress)
|
|
1612
|
+
);
|
|
1613
|
+
await raceCancellationError(
|
|
1614
|
+
contribution.prepareSession(provisioned.environmentId, repoNwo, token),
|
|
1615
|
+
token
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
progress.report(( localize(5082, "Starting Copilot agent")));
|
|
1619
|
+
const chat = provisioned.session.mainChat.get();
|
|
1620
|
+
if (session.isQuickChat.get()) {
|
|
1621
|
+
const canResolve = await raceCancellationError(
|
|
1622
|
+
this.chatSessionsService.canResolveChatSession(chat.resource.scheme),
|
|
1623
|
+
token
|
|
1624
|
+
);
|
|
1625
|
+
if (!canResolve || !this.chatSessionsService.updateChatSessionMetadata(chat.resource, {
|
|
1626
|
+
[SESSION_META_WORKSPACELESS_KEY]: true
|
|
1627
|
+
})) {
|
|
1628
|
+
throw ( new Error(( localize(
|
|
1629
|
+
5083,
|
|
1630
|
+
"The sandbox could not start a chat without a workspace. Your prompt was not sent."
|
|
1631
|
+
))));
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
const sessionConfig = config ? await provisioned.provider.resolveInitialSessionConfig(provisioned.session.sessionId, config, token) : undefined;
|
|
1635
|
+
await raceCancellationError(
|
|
1636
|
+
this._carryModelToSandbox(provisioned, chat.resource, selectedModel),
|
|
1637
|
+
token
|
|
1638
|
+
);
|
|
1639
|
+
await raceCancellationError(
|
|
1640
|
+
provisioned.provider.setInitialSessionTitle(provisioned.session.sessionId, session.title.get()),
|
|
1641
|
+
token
|
|
1642
|
+
);
|
|
1643
|
+
const committed = await provisioned.provider.sendRequest(provisioned.session.sessionId, chat.resource, {
|
|
1644
|
+
...options,
|
|
1645
|
+
sessionConfig
|
|
1646
|
+
});
|
|
1647
|
+
this._publishSandboxSession(provisioned, {
|
|
1648
|
+
announce: false
|
|
1649
|
+
});
|
|
1650
|
+
this._retirePlaceholder(session, placeholder, committed);
|
|
1651
|
+
return committed;
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
this.logService.error(
|
|
1654
|
+
`[CopilotChatSessionsProvider] Failed to start cloud sandbox session ${session.sessionId}:`,
|
|
1655
|
+
error
|
|
1656
|
+
);
|
|
1657
|
+
if (provisioned) {
|
|
1658
|
+
this._publishSandboxSession(provisioned);
|
|
1659
|
+
}
|
|
1660
|
+
this._sessionCache.delete(( session.resource.toString()));
|
|
1661
|
+
this._sessionWrapperCache.delete(session.sessionId);
|
|
1662
|
+
this._clearCurrentNewSessionIfMatch(session, true);
|
|
1663
|
+
this._onDidChangeSessions.fire({
|
|
1664
|
+
added: [],
|
|
1665
|
+
removed: [placeholder],
|
|
1666
|
+
changed: []
|
|
1667
|
+
});
|
|
1668
|
+
session.dispose();
|
|
1669
|
+
throw error;
|
|
1670
|
+
} finally {
|
|
1671
|
+
store.dispose();
|
|
1672
|
+
this._sandboxSends.delete(session.sessionId);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
_publishSandboxSession(provisioned, options) {
|
|
1676
|
+
provisioned.provider.publishWithheldSession(AgentSession.id(provisioned.session.resource), options);
|
|
1677
|
+
}
|
|
1678
|
+
_selectedCloudModel(session) {
|
|
1679
|
+
const selectedModelId = session.selectedModelId;
|
|
1680
|
+
if (!selectedModelId) {
|
|
1681
|
+
return undefined;
|
|
1682
|
+
}
|
|
1683
|
+
const sandboxModel = this._sandboxCatalog.value?.models.find(model => model.identifier === selectedModelId);
|
|
1684
|
+
if (sandboxModel) {
|
|
1685
|
+
return {
|
|
1686
|
+
rawModelId: sandboxModel.metadata.id,
|
|
1687
|
+
label: sandboxModel.metadata.name,
|
|
1688
|
+
config: session.modelConfiguration.captureModelConfiguration(selectedModelId),
|
|
1689
|
+
fromCloudCatalog: true
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
const {
|
|
1693
|
+
modelOption
|
|
1694
|
+
} = session.getModelOptionsSnapshot();
|
|
1695
|
+
const item = modelOption?.group.items.find(i => i.id === selectedModelId);
|
|
1696
|
+
const rawModelId = item?.modelMetadata?.id ?? item?.id ?? selectedModelId;
|
|
1697
|
+
return {
|
|
1698
|
+
rawModelId,
|
|
1699
|
+
label: item?.modelMetadata?.name ?? item?.name ?? rawModelId
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
async _carryModelToSandbox(provisioned, chatResource, selected) {
|
|
1703
|
+
if (!selected) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
const {
|
|
1707
|
+
rawModelId,
|
|
1708
|
+
label
|
|
1709
|
+
} = selected;
|
|
1710
|
+
const sessionId = provisioned.session.sessionId;
|
|
1711
|
+
const provider = provisioned.provider;
|
|
1712
|
+
const modelTarget = provider.getModelsSnapshot(sessionId).modelTarget;
|
|
1713
|
+
if (!modelTarget) {
|
|
1714
|
+
this.logService.info(
|
|
1715
|
+
`[CopilotChatSessionsProvider] Sandbox session ${sessionId} reported no model target; letting the agent host choose.`
|
|
1716
|
+
);
|
|
1717
|
+
this._notifySandboxModelNotApplied(label);
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const desiredModelId = `${modelTarget}:${rawModelId}`;
|
|
1721
|
+
const store = ( new DisposableStore());
|
|
1722
|
+
try {
|
|
1723
|
+
const deadline = Date.now() + this._sandboxModelWaitMs;
|
|
1724
|
+
for (; ; ) {
|
|
1725
|
+
const resolution = provider.getModelsSnapshot(sessionId, desiredModelId).desiredModelResolution;
|
|
1726
|
+
if (resolution.kind === "available") {
|
|
1727
|
+
if (selected.config && ( Object.keys(selected.config)).length) {
|
|
1728
|
+
const schema = resolution.model.metadata.configurationSchema;
|
|
1729
|
+
for (const [key, value] of Object.entries(selected.config)) {
|
|
1730
|
+
const property = schema?.properties?.[key];
|
|
1731
|
+
if (!property || property.readOnly || (property.enum && !property.enum.includes(value))) {
|
|
1732
|
+
throw ( new Error(( localize(5084, "The sandbox does not support the selected {0} for {1}.", key, label))));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
const configuration = provider.getAutomationModelConfiguration(sessionId);
|
|
1736
|
+
if (!configuration) {
|
|
1737
|
+
throw ( new Error("The sandbox model configuration is unavailable."));
|
|
1738
|
+
}
|
|
1739
|
+
await configuration.setModelConfiguration(resolution.model.identifier, selected.config);
|
|
1740
|
+
}
|
|
1741
|
+
provider.setModel(
|
|
1742
|
+
sessionId,
|
|
1743
|
+
chatResource,
|
|
1744
|
+
resolution.model.identifier,
|
|
1745
|
+
ChatModelSource.CarriedOver
|
|
1746
|
+
);
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
if (resolution.kind !== "pending" && !selected.fromCloudCatalog) {
|
|
1750
|
+
this.logService.info(
|
|
1751
|
+
`[CopilotChatSessionsProvider] Sandbox session ${sessionId} does not advertise model '${rawModelId}'; letting the agent host choose.`
|
|
1752
|
+
);
|
|
1753
|
+
this._notifySandboxModelNotApplied(label);
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
const remaining = deadline - Date.now();
|
|
1757
|
+
const published = remaining > 0 ? await raceTimeout(
|
|
1758
|
+
Event.toPromise(provider.onDidChangeModels, store).then(() => true),
|
|
1759
|
+
remaining
|
|
1760
|
+
) : undefined;
|
|
1761
|
+
if (!published) {
|
|
1762
|
+
this.logService.warn(
|
|
1763
|
+
`[CopilotChatSessionsProvider] Sandbox session ${sessionId} had not published model '${rawModelId}' in time; letting the agent host choose.`
|
|
1764
|
+
);
|
|
1765
|
+
this._notifySandboxModelNotApplied(label);
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
} finally {
|
|
1770
|
+
store.dispose();
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
_notifySandboxModelNotApplied(label) {
|
|
1774
|
+
this.notificationService.warn(( localize(
|
|
1775
|
+
5085,
|
|
1776
|
+
"Couldn't use {0} for this session. The agent's default model will be used instead.",
|
|
1777
|
+
label
|
|
1778
|
+
)));
|
|
1779
|
+
}
|
|
1780
|
+
_retirePlaceholder(session, placeholder, committed) {
|
|
1781
|
+
this._sessionCache.delete(( session.resource.toString()));
|
|
1782
|
+
this._sessionWrapperCache.delete(session.sessionId);
|
|
1783
|
+
this._clearCurrentNewSessionIfMatch(session);
|
|
1784
|
+
this._onDidReplaceSession.fire({
|
|
1785
|
+
from: placeholder,
|
|
1786
|
+
to: committed
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
async sendRequest(sessionId, chatResource, options) {
|
|
1790
|
+
if (( this._sandboxSends.has(sessionId))) {
|
|
1791
|
+
throw ( new Error(( localize(
|
|
1792
|
+
5086,
|
|
1793
|
+
"A GitHub sandbox session is already being started. Wait for it to finish before sending another message."
|
|
1794
|
+
))));
|
|
1795
|
+
}
|
|
1796
|
+
const newSession = this._newSessions.get(sessionId);
|
|
1797
|
+
if (newSession) {
|
|
1798
|
+
if (!this.uriIdentityService.extUri.isEqual(newSession.mainChat.get().resource, chatResource)) {
|
|
1799
|
+
throw ( new Error("Chat resource does not match the main chat of the current new session"));
|
|
1800
|
+
}
|
|
1801
|
+
if (this._usesSandbox(newSession)) {
|
|
1802
|
+
if (!this.supportsQuickChats) {
|
|
1803
|
+
throw ( new Error(( localize(
|
|
1804
|
+
5087,
|
|
1805
|
+
"GitHub sandbox creation is no longer available. Enable the feature to try again."
|
|
1806
|
+
))));
|
|
1807
|
+
}
|
|
1808
|
+
if (!newSession.isQuickChat.get() && !newSession.repoNwo) {
|
|
1809
|
+
throw ( new Error(( localize(
|
|
1810
|
+
5088,
|
|
1811
|
+
"GitHub sandbox creation requires a repository for this session. Please choose a repository to try again."
|
|
1812
|
+
))));
|
|
1813
|
+
}
|
|
1814
|
+
return this._sendFirstChatToSandbox(newSession, newSession.repoNwo, options);
|
|
1815
|
+
}
|
|
1816
|
+
return this._sendFirstChat(newSession, chatResource, options);
|
|
1817
|
+
}
|
|
1818
|
+
if (!this._findChatSession(sessionId)) {
|
|
1819
|
+
throw ( new Error(`Session '${sessionId}' not found`));
|
|
1820
|
+
}
|
|
1821
|
+
throw ( new Error("Multiple chats per session is not supported"));
|
|
1822
|
+
}
|
|
1823
|
+
async _sendFirstChat(session, chatResource, options) {
|
|
1824
|
+
const {
|
|
1825
|
+
query,
|
|
1826
|
+
attachedContext
|
|
1827
|
+
} = options;
|
|
1828
|
+
session.setTitle(
|
|
1829
|
+
(options.title || query.split("\n")[0]).substring(0, 100) || ( localize(5081, "New Session"))
|
|
1830
|
+
);
|
|
1831
|
+
session.setStatus(SessionStatus.InProgress);
|
|
1832
|
+
this._sessionCache.set(( session.resource.toString()), session);
|
|
1833
|
+
const newSession = this._chatToSession(session);
|
|
1834
|
+
this._onDidChangeSessions.fire({
|
|
1835
|
+
added: [newSession],
|
|
1836
|
+
removed: [],
|
|
1837
|
+
changed: []
|
|
1838
|
+
});
|
|
1839
|
+
const contribution = this.chatSessionsService.getChatSessionContribution(session.target);
|
|
1840
|
+
const permissionLevel = ChatPermissionLevel.Default;
|
|
1841
|
+
const sendOptions = {
|
|
1842
|
+
location: ChatAgentLocation.Chat,
|
|
1843
|
+
userSelectedModelId: session.selectedModelId,
|
|
1844
|
+
userSelectedModelConfiguration: session.modelConfiguration.getModelConfigurationForRequest(session.selectedModelId),
|
|
1845
|
+
modeInfo: {
|
|
1846
|
+
kind: ChatModeKind.Agent,
|
|
1847
|
+
isBuiltin: true,
|
|
1848
|
+
modeInstructions: undefined,
|
|
1849
|
+
telemetryModeId: ChatModeKind.Agent,
|
|
1850
|
+
applyCodeBlockSuggestionId: undefined,
|
|
1851
|
+
permissionLevel
|
|
1852
|
+
},
|
|
1853
|
+
agentIdSilent: contribution?.type,
|
|
1854
|
+
attachedContext,
|
|
1855
|
+
hideFromTranscript: options.hideFromTranscript,
|
|
1856
|
+
onDidCreateResponse: options.onDidCreateResponse
|
|
1857
|
+
};
|
|
1858
|
+
const ref = await this._updateChatSessionState(chatResource, session, permissionLevel);
|
|
1859
|
+
this.logService.debug(
|
|
1860
|
+
`[CopilotChatSessionsProvider] Sending first chat for session ${session.sessionId} with options:`,
|
|
1861
|
+
{
|
|
1862
|
+
userSelectedModelId: sendOptions.userSelectedModelId
|
|
1863
|
+
}
|
|
1864
|
+
);
|
|
1865
|
+
try {
|
|
1866
|
+
const result = await this.chatService.sendRequest(chatResource, query, sendOptions);
|
|
1867
|
+
if (result.kind === "rejected") {
|
|
1868
|
+
this._sessionCache.delete(( session.resource.toString()));
|
|
1869
|
+
this._sessionWrapperCache.delete(session.sessionId);
|
|
1870
|
+
this._clearCurrentNewSessionIfMatch(session, true);
|
|
1871
|
+
this._onDidChangeSessions.fire({
|
|
1872
|
+
added: [],
|
|
1873
|
+
removed: [newSession],
|
|
1874
|
+
changed: []
|
|
1875
|
+
});
|
|
1876
|
+
session.dispose();
|
|
1877
|
+
throw ( new Error(`[DefaultCopilotProvider] sendRequest rejected: ${result.reason}`));
|
|
1878
|
+
}
|
|
1879
|
+
const cts = ( new CancellationTokenSource());
|
|
1880
|
+
const responseCreatedPromise = result.kind === "sent" ? result.data.responseCreatedPromise : undefined;
|
|
1881
|
+
responseCreatedPromise?.then(r => {
|
|
1882
|
+
if (r?.isCanceled) {
|
|
1883
|
+
cts.cancel();
|
|
1884
|
+
}
|
|
1885
|
+
});
|
|
1886
|
+
try {
|
|
1887
|
+
const committedResource = await this._waitForCommittedSession(session.resource, responseCreatedPromise);
|
|
1888
|
+
this._inFlightCommits.add(( committedResource.toString()));
|
|
1889
|
+
try {
|
|
1890
|
+
const createdBySession = session.createdBySession.get();
|
|
1891
|
+
if (createdBySession) {
|
|
1892
|
+
this._setCreatedBySession(committedResource, createdBySession);
|
|
1893
|
+
}
|
|
1894
|
+
const committedChat = await this._waitForSessionInCache(committedResource, cts.token);
|
|
1895
|
+
this._sessionCache.delete(( session.resource.toString()));
|
|
1896
|
+
this._clearCurrentNewSessionIfMatch(session);
|
|
1897
|
+
const committedSession = this._chatToSession(committedChat);
|
|
1898
|
+
this._sessionWrapperCache.delete(session.sessionId);
|
|
1899
|
+
this._onDidReplaceSession.fire({
|
|
1900
|
+
from: newSession,
|
|
1901
|
+
to: committedSession
|
|
1902
|
+
});
|
|
1903
|
+
return committedSession;
|
|
1904
|
+
} finally {
|
|
1905
|
+
this._inFlightCommits.delete(( committedResource.toString()));
|
|
1906
|
+
}
|
|
1907
|
+
} catch (error) {
|
|
1908
|
+
this._clearCurrentNewSessionIfMatch(session, true);
|
|
1909
|
+
if (error instanceof CancellationError) {
|
|
1910
|
+
session.setStatus(SessionStatus.Completed);
|
|
1911
|
+
this._onDidChangeSessions.fire({
|
|
1912
|
+
added: [],
|
|
1913
|
+
removed: [],
|
|
1914
|
+
changed: [newSession]
|
|
1915
|
+
});
|
|
1916
|
+
return newSession;
|
|
1917
|
+
}
|
|
1918
|
+
this._sessionCache.delete(( session.resource.toString()));
|
|
1919
|
+
this._sessionWrapperCache.delete(session.sessionId);
|
|
1920
|
+
this._onDidChangeSessions.fire({
|
|
1921
|
+
added: [],
|
|
1922
|
+
removed: [this._chatToSession(session)],
|
|
1923
|
+
changed: []
|
|
1924
|
+
});
|
|
1925
|
+
session.dispose();
|
|
1926
|
+
throw error;
|
|
1927
|
+
} finally {
|
|
1928
|
+
cts.dispose();
|
|
1929
|
+
}
|
|
1930
|
+
} catch (error) {
|
|
1931
|
+
this.logService.error(
|
|
1932
|
+
`[CopilotChatSessionsProvider] Failed to send first chat for session ${session.sessionId}:`,
|
|
1933
|
+
error
|
|
1934
|
+
);
|
|
1935
|
+
throw error;
|
|
1936
|
+
} finally {
|
|
1937
|
+
ref?.dispose();
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
async _createChatSession(resource, session) {
|
|
1941
|
+
await this.chatSessionsService.getOrCreateChatSession(resource, CancellationToken.None);
|
|
1942
|
+
return this._updateChatSessionState(resource, session);
|
|
1943
|
+
}
|
|
1944
|
+
async _updateChatSessionState(resource, session, permissionLevel) {
|
|
1945
|
+
const modelRef = await this.chatService.acquireOrLoadSession(resource, ChatAgentLocation.Chat, CancellationToken.None);
|
|
1946
|
+
if (!modelRef) {
|
|
1947
|
+
return Disposable.None;
|
|
1948
|
+
}
|
|
1949
|
+
const model = modelRef.object;
|
|
1950
|
+
if (session.selectedModelId) {
|
|
1951
|
+
const languageModel = this.languageModelsService.lookupLanguageModel(session.selectedModelId);
|
|
1952
|
+
if (languageModel) {
|
|
1953
|
+
model.inputModel.setState({
|
|
1954
|
+
selectedModel: {
|
|
1955
|
+
identifier: session.selectedModelId,
|
|
1956
|
+
metadata: languageModel
|
|
1957
|
+
}
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
if (session.selectedOptions.size > 0) {
|
|
1962
|
+
this.chatSessionsService.updateSessionOptions(resource, session.selectedOptions);
|
|
1963
|
+
}
|
|
1964
|
+
if (permissionLevel) {
|
|
1965
|
+
model.inputModel.setState({
|
|
1966
|
+
permissionLevel
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
return modelRef;
|
|
1970
|
+
}
|
|
1971
|
+
async _waitForCommittedSession(untitledResource, responseCreatedPromise) {
|
|
1972
|
+
const timeoutMs = 5 * 60_000;
|
|
1973
|
+
const disposables = ( new DisposableStore());
|
|
1974
|
+
try {
|
|
1975
|
+
const commitPromise = ( new Promise(resolve => {
|
|
1976
|
+
disposables.add(this.chatSessionsService.onDidCommitSession(e => {
|
|
1977
|
+
if (isEqual(e.original, untitledResource)) {
|
|
1978
|
+
resolve(e.committed);
|
|
1979
|
+
}
|
|
1980
|
+
}));
|
|
1981
|
+
}));
|
|
1982
|
+
const candidates = [raceTimeout(commitPromise, timeoutMs).then(uri => uri ? {
|
|
1983
|
+
kind: "commit",
|
|
1984
|
+
uri
|
|
1985
|
+
} : {
|
|
1986
|
+
kind: "timeout"
|
|
1987
|
+
})];
|
|
1988
|
+
if (responseCreatedPromise) {
|
|
1989
|
+
candidates.push(responseCreatedPromise.then(r => r?.isCanceled ? {
|
|
1990
|
+
kind: "cancelled"
|
|
1991
|
+
} : ( new Promise(() => {}))));
|
|
1992
|
+
}
|
|
1993
|
+
const outcome = await Promise.race(candidates);
|
|
1994
|
+
if (outcome.kind === "commit") {
|
|
1995
|
+
return outcome.uri;
|
|
1996
|
+
}
|
|
1997
|
+
if (outcome.kind === "cancelled") {
|
|
1998
|
+
throw ( new CancellationError());
|
|
1999
|
+
}
|
|
2000
|
+
const response = responseCreatedPromise ? await responseCreatedPromise : undefined;
|
|
2001
|
+
if (response?.isCanceled) {
|
|
2002
|
+
throw ( new CancellationError());
|
|
2003
|
+
}
|
|
2004
|
+
throw ( new Error("Timed out waiting for session commit"));
|
|
2005
|
+
} finally {
|
|
2006
|
+
disposables.dispose();
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
async _waitForSessionInCache(resource, token) {
|
|
2010
|
+
const key = ( resource.toString());
|
|
2011
|
+
const existing = this._sessionCache.get(key);
|
|
2012
|
+
if (existing instanceof AgentSessionAdapter) {
|
|
2013
|
+
return existing;
|
|
2014
|
+
}
|
|
2015
|
+
const disposables = ( new DisposableStore());
|
|
2016
|
+
try {
|
|
2017
|
+
const sessionPromise = ( new Promise(resolve => {
|
|
2018
|
+
disposables.add(this.onDidChangeSessions(e => {
|
|
2019
|
+
const cached = this._sessionCache.get(key);
|
|
2020
|
+
if (cached instanceof AgentSessionAdapter) {
|
|
2021
|
+
resolve(cached);
|
|
2022
|
+
}
|
|
2023
|
+
}));
|
|
2024
|
+
}));
|
|
2025
|
+
const result = await raceTimeout(
|
|
2026
|
+
token ? raceCancellationError(sessionPromise, token) : sessionPromise,
|
|
2027
|
+
30_000
|
|
2028
|
+
);
|
|
2029
|
+
if (!result) {
|
|
2030
|
+
throw ( new Error("Timed out waiting for committed session in cache"));
|
|
2031
|
+
}
|
|
2032
|
+
return result;
|
|
2033
|
+
} finally {
|
|
2034
|
+
disposables.dispose();
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
async _pickRepository(allowRepositoryUrl = false) {
|
|
2038
|
+
if (isWeb) {
|
|
2039
|
+
const store = ( new DisposableStore());
|
|
2040
|
+
this._repositoryPicker.value = store;
|
|
2041
|
+
const token = cancelOnDispose(store);
|
|
2042
|
+
const checkHost = () => {
|
|
2043
|
+
if (this.gitHubService.enterpriseHost !== undefined) {
|
|
2044
|
+
throw ( new Error(( localize(
|
|
2045
|
+
5089,
|
|
2046
|
+
"This picker supports github.com repositories only. Switch to a github.com account, then try again."
|
|
2047
|
+
))));
|
|
2048
|
+
}
|
|
2049
|
+
};
|
|
2050
|
+
try {
|
|
2051
|
+
checkHost();
|
|
2052
|
+
await raceCancellationError(this.gitHubService.authenticateForRepositoryAccess(token), token);
|
|
2053
|
+
if (token.isCancellationRequested) {
|
|
2054
|
+
return undefined;
|
|
2055
|
+
}
|
|
2056
|
+
checkHost();
|
|
2057
|
+
const picker = store.add(this.instantiationService.createInstance(RepositoryPicker));
|
|
2058
|
+
const selection = await picker.pickRepository(async (query, requestToken) => {
|
|
2059
|
+
checkHost();
|
|
2060
|
+
const repositories = await this.gitHubService.getRepositories(getGitHubRepositoryId(query.trim()) ?? query, requestToken);
|
|
2061
|
+
checkHost();
|
|
2062
|
+
return repositories.map(repository => repository.fullName);
|
|
2063
|
+
}, undefined, token);
|
|
2064
|
+
if (selection) {
|
|
2065
|
+
checkHost();
|
|
2066
|
+
}
|
|
2067
|
+
return selection?.repository;
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
if (!isCancellationError(error) && !token.isCancellationRequested) {
|
|
2070
|
+
this.notificationService.error(error);
|
|
2071
|
+
}
|
|
2072
|
+
return undefined;
|
|
2073
|
+
} finally {
|
|
2074
|
+
store.dispose();
|
|
2075
|
+
if (this._repositoryPicker.value === store) {
|
|
2076
|
+
this._repositoryPicker.clear();
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
return this.commandService.executeCommand(OPEN_REPO_COMMAND, undefined, {
|
|
2081
|
+
allowRepositoryUrl
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
async _browseForRepository() {
|
|
2085
|
+
const allowRepositoryUrl = this._supportsLocalRepositoryActions();
|
|
2086
|
+
const repository = await this._pickRepository(allowRepositoryUrl);
|
|
2087
|
+
if (!repository) {
|
|
2088
|
+
return undefined;
|
|
2089
|
+
}
|
|
2090
|
+
const repoId = getGitHubRepositoryId(repository);
|
|
2091
|
+
if (!repoId) {
|
|
2092
|
+
return allowRepositoryUrl ? this._cloneRepository(repository) : undefined;
|
|
2093
|
+
}
|
|
2094
|
+
const uri = ( URI.from({
|
|
2095
|
+
scheme: GITHUB_REMOTE_FILE_SCHEME,
|
|
2096
|
+
authority: "github",
|
|
2097
|
+
path: `/${repoId}/HEAD`
|
|
2098
|
+
}));
|
|
2099
|
+
const folder = {
|
|
2100
|
+
root: uri,
|
|
2101
|
+
workingDirectory: uri,
|
|
2102
|
+
name: basename(uri),
|
|
2103
|
+
description: undefined,
|
|
2104
|
+
gitRepository: undefined
|
|
2105
|
+
};
|
|
2106
|
+
return {
|
|
2107
|
+
uri: ( URI.parse(`https://github.com/${repoId}`)),
|
|
2108
|
+
label: this._labelFromUri(uri),
|
|
2109
|
+
icon: this._iconFromUri(uri),
|
|
2110
|
+
group: SESSION_WORKSPACE_GROUP_GITHUB,
|
|
2111
|
+
folders: [folder],
|
|
2112
|
+
requiresWorkspaceTrust: false,
|
|
2113
|
+
isVirtualWorkspace: true
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
_supportsLocalRepositoryActions() {
|
|
2117
|
+
return this.supportsLocalWorkspaces && !isWeb && (this.pathService.defaultUriScheme === Schemas.file || this.pathService.defaultUriScheme === GITHUB_REMOTE_FILE_SCHEME || this.pathService.defaultUriScheme === SessionType.CopilotCloud);
|
|
2118
|
+
}
|
|
2119
|
+
async _cloneRepository(url) {
|
|
2120
|
+
try {
|
|
2121
|
+
const repositoryPath = await this.commandService.executeCommand("git.clone", url, undefined, {
|
|
2122
|
+
postCloneAction: "none",
|
|
2123
|
+
returnRepositoryPath: true
|
|
2124
|
+
});
|
|
2125
|
+
if (repositoryPath?.endsWith(".code-workspace")) {
|
|
2126
|
+
this.notificationService.error(( localize(
|
|
2127
|
+
5090,
|
|
2128
|
+
"The selected clone is a workspace file. Choose the repository again to select a repository folder."
|
|
2129
|
+
)));
|
|
2130
|
+
return undefined;
|
|
2131
|
+
}
|
|
2132
|
+
return repositoryPath ? this.resolveWorkspace(URI.file(repositoryPath)) : undefined;
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
if (!isCancellationError(error)) {
|
|
2135
|
+
this.notificationService.error(error);
|
|
2136
|
+
}
|
|
2137
|
+
return undefined;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
async _browseForGitHubContext(commandId, icon, currentWorkspace) {
|
|
2141
|
+
const repositoryIds = ( new Set());
|
|
2142
|
+
for (const folder of currentWorkspace?.folders ?? []) {
|
|
2143
|
+
const repositoryId = resolveGitHubRepositoryId(folder);
|
|
2144
|
+
if (repositoryId) {
|
|
2145
|
+
repositoryIds.add(repositoryId);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
const repository = repositoryIds.size === 1 ? ( repositoryIds.values()).next().value : currentWorkspace?.folders.length === 1 && currentWorkspace.folders[0].root.scheme === Schemas.file ? currentWorkspace.folders[0].root : await this._pickRepository();
|
|
2149
|
+
if (!repository) {
|
|
2150
|
+
return undefined;
|
|
2151
|
+
}
|
|
2152
|
+
const selection = await this.commandService.executeCommand(commandId, repository);
|
|
2153
|
+
if (!selection) {
|
|
2154
|
+
return undefined;
|
|
2155
|
+
}
|
|
2156
|
+
const root = ( URI.from({
|
|
2157
|
+
scheme: GITHUB_REMOTE_FILE_SCHEME,
|
|
2158
|
+
authority: "github",
|
|
2159
|
+
path: `/${selection.repoId}/HEAD`
|
|
2160
|
+
}));
|
|
2161
|
+
return {
|
|
2162
|
+
uri: ( URI.parse(selection.url)),
|
|
2163
|
+
label: selection.label,
|
|
2164
|
+
icon,
|
|
2165
|
+
group: SESSION_WORKSPACE_GROUP_GITHUB,
|
|
2166
|
+
folders: [{
|
|
2167
|
+
root,
|
|
2168
|
+
workingDirectory: root,
|
|
2169
|
+
name: basename(root),
|
|
2170
|
+
description: undefined,
|
|
2171
|
+
gitRepository: undefined
|
|
2172
|
+
}],
|
|
2173
|
+
requiresWorkspaceTrust: false,
|
|
2174
|
+
isVirtualWorkspace: true
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
resolveWorkspace(uri) {
|
|
2178
|
+
if (this.providerMode === "sandbox" && (uri.scheme !== GITHUB_REMOTE_FILE_SCHEME || uri.authority !== "github" || !/^\/[^/]+\/[^/]+\/HEAD$/.test(uri.path) || uri.query || uri.fragment)) {
|
|
2179
|
+
return undefined;
|
|
2180
|
+
}
|
|
2181
|
+
if (uri.scheme !== Schemas.file && uri.scheme !== GITHUB_REMOTE_FILE_SCHEME) {
|
|
2182
|
+
return undefined;
|
|
2183
|
+
}
|
|
2184
|
+
const folder = {
|
|
2185
|
+
root: uri,
|
|
2186
|
+
workingDirectory: uri,
|
|
2187
|
+
name: basename(uri),
|
|
2188
|
+
description: undefined,
|
|
2189
|
+
gitRepository: uri.scheme === Schemas.file ? this._getLocalGitRepository(uri) : undefined
|
|
2190
|
+
};
|
|
2191
|
+
return {
|
|
2192
|
+
uri: uri,
|
|
2193
|
+
label: this._labelFromUri(uri),
|
|
2194
|
+
description: this._descriptionFromUri(uri),
|
|
2195
|
+
group: uri.scheme === GITHUB_REMOTE_FILE_SCHEME ? SESSION_WORKSPACE_GROUP_GITHUB : SESSION_WORKSPACE_GROUP_LOCAL,
|
|
2196
|
+
icon: this._iconFromUri(uri),
|
|
2197
|
+
folders: [folder],
|
|
2198
|
+
requiresWorkspaceTrust: uri.scheme !== GITHUB_REMOTE_FILE_SCHEME,
|
|
2199
|
+
isVirtualWorkspace: uri.scheme === GITHUB_REMOTE_FILE_SCHEME
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
_getLocalGitRepository(uri) {
|
|
2203
|
+
const state = this._getLocalGitRepositoryState(uri);
|
|
2204
|
+
const resolveRepository = () => this._resolveLocalGitRepository(uri, state);
|
|
2205
|
+
return {
|
|
2206
|
+
uri,
|
|
2207
|
+
workTreeUri: uri,
|
|
2208
|
+
baseBranchName: undefined,
|
|
2209
|
+
isRepository: state.isRepository,
|
|
2210
|
+
gitHubInfo: state.gitHubInfo,
|
|
2211
|
+
resolveRepository,
|
|
2212
|
+
resolveGitHubInfo: resolveRepository
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
_getLocalGitRepositoryState(uri) {
|
|
2216
|
+
const key = this.uriIdentityService.extUri.getComparisonKey(uri);
|
|
2217
|
+
let state = this._localGitRepositoryState.get(key);
|
|
2218
|
+
if (state) {
|
|
2219
|
+
return state;
|
|
2220
|
+
}
|
|
2221
|
+
if (this._localGitRepositoryState.size >= 50) {
|
|
2222
|
+
const oldestKey = ( this._localGitRepositoryState.keys()).next().value;
|
|
2223
|
+
if (oldestKey !== undefined) {
|
|
2224
|
+
this._localGitRepositoryState.delete(oldestKey);
|
|
2225
|
+
this._localGitRepositoryResolutionStarted.delete(oldestKey);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
state = {
|
|
2229
|
+
isRepository: observableValue(this, false),
|
|
2230
|
+
gitHubInfo: observableValue(this, undefined)
|
|
2231
|
+
};
|
|
2232
|
+
this._localGitRepositoryState.set(key, state);
|
|
2233
|
+
return state;
|
|
2234
|
+
}
|
|
2235
|
+
_resolveLocalGitRepository(uri, state) {
|
|
2236
|
+
const key = this.uriIdentityService.extUri.getComparisonKey(uri);
|
|
2237
|
+
if (( this._localGitRepositoryResolutionStarted.has(key))) {
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
this._localGitRepositoryResolutionStarted.add(key);
|
|
2241
|
+
void resolveGitRepositoryFromGitConfig(this.fileService, uri).then(repositoryInfo => {
|
|
2242
|
+
if (this._localGitRepositoryState.get(key) !== state) {
|
|
2243
|
+
this._localGitRepositoryResolutionStarted.delete(key);
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
if (!repositoryInfo) {
|
|
2247
|
+
this._localGitRepositoryResolutionStarted.delete(key);
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
const nextGitHubInfo = repositoryInfo.gitHub ? {
|
|
2251
|
+
owner: repositoryInfo.gitHub.owner,
|
|
2252
|
+
repo: repositoryInfo.gitHub.repo
|
|
2253
|
+
} : undefined;
|
|
2254
|
+
if (!state.isRepository.get() || !gitHubInfoEqual(state.gitHubInfo.get(), nextGitHubInfo)) {
|
|
2255
|
+
transaction(tx => {
|
|
2256
|
+
state.isRepository.set(true, tx);
|
|
2257
|
+
state.gitHubInfo.set(nextGitHubInfo, tx);
|
|
2258
|
+
});
|
|
2259
|
+
this._onDidChangeSessionTypes.fire();
|
|
2260
|
+
}
|
|
2261
|
+
if (!repositoryInfo.gitHub) {
|
|
2262
|
+
this._localGitRepositoryResolutionStarted.delete(key);
|
|
2263
|
+
}
|
|
2264
|
+
}, error => {
|
|
2265
|
+
this._localGitRepositoryResolutionStarted.delete(key);
|
|
2266
|
+
this.logService.warn(`Failed to resolve Git repository metadata for '${( uri.toString())}'.`, error);
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
_labelFromUri(uri) {
|
|
2270
|
+
return githubRemoteRepoLabel(uri) ?? basename(uri);
|
|
2271
|
+
}
|
|
2272
|
+
_descriptionFromUri(uri) {
|
|
2273
|
+
if (uri.scheme === GITHUB_REMOTE_FILE_SCHEME) {
|
|
2274
|
+
const parts = uri.path.substring(1).split("/");
|
|
2275
|
+
return parts.length >= 2 ? parts[0] : undefined;
|
|
2276
|
+
}
|
|
2277
|
+
return this.labelService.getUriLabel(dirname(uri), {
|
|
2278
|
+
relative: false
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
_iconFromUri(uri) {
|
|
2282
|
+
if (uri.scheme === GITHUB_REMOTE_FILE_SCHEME) {
|
|
2283
|
+
return Codicon.repo;
|
|
2284
|
+
}
|
|
2285
|
+
return Codicon.folder;
|
|
2286
|
+
}
|
|
2287
|
+
_ensureSessionCache() {
|
|
2288
|
+
if (this._sessionCache.size > 0) {
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
this._refreshSessionCache();
|
|
2292
|
+
}
|
|
2293
|
+
_cleanupTempSession(sessionId) {
|
|
2294
|
+
const chatSession = this._findChatSession(sessionId);
|
|
2295
|
+
if (!chatSession) {
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
this._sessionCache.delete(( chatSession.resource.toString()));
|
|
2299
|
+
this._deleteCreatedBySession(chatSession.resource);
|
|
2300
|
+
if (( this._newSessions.has(chatSession.sessionId))) {
|
|
2301
|
+
this._newSessions.deleteAndLeak(chatSession.sessionId);
|
|
2302
|
+
}
|
|
2303
|
+
const removedSession = this._chatToSession(chatSession);
|
|
2304
|
+
this._sessionWrapperCache.delete(chatSession.sessionId);
|
|
2305
|
+
this._onDidChangeSessions.fire({
|
|
2306
|
+
added: [],
|
|
2307
|
+
removed: [removedSession],
|
|
2308
|
+
changed: []
|
|
2309
|
+
});
|
|
2310
|
+
if (chatSession instanceof RemoteNewSession) {
|
|
2311
|
+
chatSession.dispose();
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
_refreshSessionCache() {
|
|
2315
|
+
if (this.providerMode === "sandbox") {
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
const currentKeys = ( new Set());
|
|
2319
|
+
const addedData = [];
|
|
2320
|
+
const changedData = [];
|
|
2321
|
+
const sessionsToMarkUnread = [];
|
|
2322
|
+
for (const session of this.agentSessionsService.model.sessions) {
|
|
2323
|
+
if (session.providerType !== AgentSessionProviders.Cloud) {
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2326
|
+
const key = ( session.resource.toString());
|
|
2327
|
+
currentKeys.add(key);
|
|
2328
|
+
const existing = this._sessionCache.get(key);
|
|
2329
|
+
if (existing) {
|
|
2330
|
+
const previousStatus = existing.status.get();
|
|
2331
|
+
if (existing.update(session)) {
|
|
2332
|
+
changedData.push(existing);
|
|
2333
|
+
}
|
|
2334
|
+
const currentStatus = existing.status.get();
|
|
2335
|
+
if (previousStatus === SessionStatus.InProgress && currentStatus !== SessionStatus.InProgress && currentStatus !== SessionStatus.Untitled && existing.isRead.get()) {
|
|
2336
|
+
sessionsToMarkUnread.push(session);
|
|
2337
|
+
}
|
|
2338
|
+
} else {
|
|
2339
|
+
const adapter = ( new AgentSessionAdapter(
|
|
2340
|
+
session,
|
|
2341
|
+
this.id,
|
|
2342
|
+
this.gitHubService,
|
|
2343
|
+
this.pullRequestIconCache,
|
|
2344
|
+
this.logService
|
|
2345
|
+
));
|
|
2346
|
+
this._sessionCache.set(key, adapter);
|
|
2347
|
+
addedData.push(adapter);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
const removedData = [];
|
|
2351
|
+
for (const [key, adapter] of this._sessionCache) {
|
|
2352
|
+
if (!( currentKeys.has(key)) && adapter instanceof AgentSessionAdapter && !( this._inFlightCommits.has(key))) {
|
|
2353
|
+
removedData.push(adapter);
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
for (const removed of removedData) {
|
|
2357
|
+
this._sessionCache.delete(( removed.resource.toString()));
|
|
2358
|
+
}
|
|
2359
|
+
if (addedData.length > 0 || removedData.length > 0 || changedData.length > 0) {
|
|
2360
|
+
this._onDidChangeSessions.fire({
|
|
2361
|
+
added: addedData.map(d => this._chatToSession(d)),
|
|
2362
|
+
removed: removedData.map(d => {
|
|
2363
|
+
const session = this._chatToSession(d);
|
|
2364
|
+
this._sessionWrapperCache.delete(d.sessionId);
|
|
2365
|
+
return session;
|
|
2366
|
+
}),
|
|
2367
|
+
changed: changedData.map(d => this._chatToSession(d))
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
for (const session of sessionsToMarkUnread) {
|
|
2371
|
+
session.setRead(false);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
_findChatSession(sessionId) {
|
|
2375
|
+
return this._sessionCache.get(this._localIdFromSessionId(sessionId));
|
|
2376
|
+
}
|
|
2377
|
+
_findAgentSession(sessionId) {
|
|
2378
|
+
const adapter = this._findChatSession(sessionId);
|
|
2379
|
+
if (!adapter) {
|
|
2380
|
+
return undefined;
|
|
2381
|
+
}
|
|
2382
|
+
return this.agentSessionsService.getSession(adapter.resource);
|
|
2383
|
+
}
|
|
2384
|
+
_localIdFromSessionId(sessionId) {
|
|
2385
|
+
const prefix = `${this.id}:`;
|
|
2386
|
+
return sessionId.startsWith(prefix) ? sessionId.substring(prefix.length) : sessionId;
|
|
2387
|
+
}
|
|
2388
|
+
_chatToSession(chat) {
|
|
2389
|
+
const cached = this._sessionWrapperCache.get(chat.sessionId);
|
|
2390
|
+
if (cached) {
|
|
2391
|
+
return cached;
|
|
2392
|
+
}
|
|
2393
|
+
const mainChat = chat.mainChat.map(mainChat => this._withChangesets(mainChat, chat.workspace));
|
|
2394
|
+
const chatsObs = mainChat.map(c => [c]);
|
|
2395
|
+
const session = {
|
|
2396
|
+
sessionId: chat.sessionId,
|
|
2397
|
+
resource: chat.resource,
|
|
2398
|
+
providerId: chat.providerId,
|
|
2399
|
+
sessionType: chat.sessionType,
|
|
2400
|
+
harness: "copilot",
|
|
2401
|
+
environment: this.environment.id,
|
|
2402
|
+
application: chat.application,
|
|
2403
|
+
icon: chat.icon,
|
|
2404
|
+
createdAt: chat.createdAt,
|
|
2405
|
+
workspace: chat.workspace,
|
|
2406
|
+
isQuickChat: chat.isQuickChat,
|
|
2407
|
+
title: chat.title,
|
|
2408
|
+
updatedAt: chat.updatedAt,
|
|
2409
|
+
status: chat.status,
|
|
2410
|
+
changesSummary: chat.changesSummary,
|
|
2411
|
+
artifacts: chat.artifacts,
|
|
2412
|
+
modelId: chat.modelId,
|
|
2413
|
+
mode: chat.mode,
|
|
2414
|
+
loading: chat.loading,
|
|
2415
|
+
preparationProgress: chat.preparationProgress,
|
|
2416
|
+
isNewSessionRequestInProgress: chat.isNewSessionRequestInProgress,
|
|
2417
|
+
isArchived: chat.isArchived,
|
|
2418
|
+
isRead: chat.isRead,
|
|
2419
|
+
description: chat.description,
|
|
2420
|
+
lastTurnEnd: chat.lastTurnEnd,
|
|
2421
|
+
chats: chatsObs,
|
|
2422
|
+
mainChat,
|
|
2423
|
+
createdBySession: chat.createdBySession ?? this._createdBySession(chat.resource),
|
|
2424
|
+
isExternal: chat.isExternal,
|
|
2425
|
+
capabilities: constObservable({
|
|
2426
|
+
supportsMultipleChats: false,
|
|
2427
|
+
supportsRename: false,
|
|
2428
|
+
supportsDelete: false,
|
|
2429
|
+
runsWorktreeCreatedTasks: chat.sessionType === CopilotCloudSessionType.id
|
|
2430
|
+
})
|
|
2431
|
+
};
|
|
2432
|
+
this._sessionWrapperCache.set(chat.sessionId, session);
|
|
2433
|
+
return session;
|
|
2434
|
+
}
|
|
2435
|
+
_withChangesets(chat, workspace) {
|
|
2436
|
+
return {
|
|
2437
|
+
...chat,
|
|
2438
|
+
changesets: createChangesets(workspace, constObservable([chat]), this.instantiationService)
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
CopilotChatSessionsProvider = CopilotChatSessionsProvider_1 = ( __decorate([( __param(1, IAgentSessionsService)), ( __param(2, IChatService)), ( __param(3, IChatSessionsService)), ( __param(4, ICommandService)), ( __param(5, IInstantiationService)), ( __param(6, ILanguageModelsService)), ( __param(7, IConfigurationService)), ( __param(8, ILogService)), ( __param(9, INotificationService)), ( __param(10, IGitHubService)), ( __param(11, IPullRequestIconCache)), ( __param(12, ILabelService)), ( __param(13, IUriIdentityService)), ( __param(14, IFileService)), ( __param(15, IPathService)), ( __param(16, IStorageService))], CopilotChatSessionsProvider));
|
|
2443
|
+
|
|
2444
|
+
export { COPILOT_PROVIDER_ID, CopilotChatSessionsProvider, CopilotCloudSessionType, CopilotSandboxSessionType, RemoteNewSession };
|