Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/contrib/agentHost/browser/agentSessionSettingsFileSystemProvider.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { IJSONSchema } from '../../../../base/common/jsonSchema.js';
7
import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';
8
import { URI } from '../../../../base/common/uri.js';
9
import { localize } from '../../../../nls.js';
10
import { ILogService } from '../../../../platform/log/common/log.js';
11
import { ResolveSessionConfigResult } from '../../../../platform/agentHost/common/state/protocol/commands.js';
12
import { SessionConfigPropertySchema } from '../../../../platform/agentHost/common/state/protocol/state.js';
13
import { IAgentHostSessionsProvider } from '../../../common/agentHostSessionsProvider.js';
14
import { ISessionsProvidersService } from '../../../services/sessions/browser/sessionsProvidersService.js';
15
import { ISession, toSessionId } from '../../../services/sessions/common/session.js';
16
import {
17
AbstractAgentHostConfigFileSystemProvider,
18
AbstractAgentHostConfigSchemaRegistrar,
19
AgentHostConfigPropertyFilter,
20
buildAgentHostConfigJsonSchema,
21
IAgentHostConfigLike,
22
IAgentHostSettingsContext,
23
IAgentHostSettingsLocale,
24
serializeAgentHostConfigDocument,
25
} from './agentHostSettingsShared.js';
26
27
/** Scheme for the synthetic agent-host session settings files. */
28
export const AGENT_SESSION_SETTINGS_SCHEME = 'agent-session-settings';
29
30
/**
31
* Build the URI used to open the settings file for an agent-host session.
32
*
33
* URI shape: `agent-session-settings://{providerId}/{resourceScheme}{resourcePath}.jsonc`
34
*
35
* - `authority` = {@link ISession.providerId} (e.g. `local-agent-host`, `agenthost-<auth>`)
36
* - path encodes the session's resource scheme and path so the URI can be
37
* parsed back into an {@link ISession.sessionId} via {@link toSessionId}
38
* without having to look the session up on the provider.
39
*/
40
export function agentSessionSettingsUri(session: ISession): URI {
41
// `resource.path` already starts with `/`, so splice it between the scheme and the `.jsonc` suffix.
42
return URI.from({
43
scheme: AGENT_SESSION_SETTINGS_SCHEME,
44
authority: session.providerId,
45
path: `/${session.resource.scheme}${session.resource.path}.jsonc`,
46
});
47
}
48
49
interface ISessionSettingsContext extends IAgentHostSettingsContext {
50
/** Reconstructed {@link ISession.sessionId}. */
51
readonly sessionId: string;
52
}
53
54
function parseSessionSettingsUri(uri: URI): ISessionSettingsContext | undefined {
55
if (uri.scheme !== AGENT_SESSION_SETTINGS_SCHEME) {
56
return undefined;
57
}
58
const providerId = uri.authority;
59
if (!providerId) {
60
return undefined;
61
}
62
// Path: /{resourceScheme}/{rawId}.jsonc
63
const path = uri.path.startsWith('/') ? uri.path.substring(1) : uri.path;
64
const firstSlash = path.indexOf('/');
65
if (firstSlash <= 0) {
66
return undefined;
67
}
68
const resourceScheme = path.substring(0, firstSlash);
69
let rest = path.substring(firstSlash); // includes leading '/'
70
const lastDot = rest.lastIndexOf('.');
71
if (lastDot > 0) {
72
rest = rest.substring(0, lastDot);
73
}
74
if (!resourceScheme || rest === '/') {
75
return undefined;
76
}
77
const resource = URI.from({ scheme: resourceScheme, path: rest });
78
return { providerId, sessionId: toSessionId(providerId, resource) };
79
}
80
81
/**
82
* Property filter: only session-mutable, non-read-only properties are
83
* editable. Read-only / non-mutable properties (e.g. `isolation`, `branch`)
84
* are preserved in the underlying config and round-tripped on write — they
85
* just aren't surfaced for editing.
86
*/
87
const sessionSettingsPropertyFilter: AgentHostConfigPropertyFilter = (_key, schema) => {
88
const s = schema as SessionConfigPropertySchema;
89
return s.sessionMutable === true && s.readOnly !== true;
90
};
91
92
const sessionSettingsLocale: IAgentHostSettingsLocale = {
93
get header() { return localize('agentSessionSettings.header', "Session settings for this agent host session."); },
94
get saveHint() { return localize('agentSessionSettings.saveHint', "Edit values below and save to apply. Unknown or non-mutable properties are ignored."); },
95
get parseError() { return localize('agentSessionSettings.parseError', "Failed to parse agent session settings as JSON."); },
96
get notObject() { return localize('agentSessionSettings.notObject', "Agent session settings must be a JSON object."); },
97
};
98
99
/**
100
* Serialize the session-mutable config values for a session into a
101
* commented, pretty-printed JSON document.
102
*/
103
export function serializeSessionSettings(provider: IAgentHostSessionsProvider, sessionId: string): string {
104
return serializeAgentHostConfigDocument(provider.getSessionConfig(sessionId), sessionSettingsPropertyFilter, sessionSettingsLocale);
105
}
106
107
/**
108
* Build a JSON schema describing the editable session-mutable, non-readOnly
109
* properties of an agent-host session config. The filter mirrors the one
110
* used by {@link serializeSessionSettings} so validation matches the file
111
* contents produced by this provider.
112
*/
113
export function buildSessionSettingsJsonSchema(config: ResolveSessionConfigResult): IJSONSchema {
114
return buildAgentHostConfigJsonSchema(config, sessionSettingsPropertyFilter);
115
}
116
117
/**
118
* Filesystem provider serving synthetic JSONC documents that represent the
119
* session-mutable config values of agent-host sessions.
120
*/
121
export class AgentSessionSettingsFileSystemProvider extends AbstractAgentHostConfigFileSystemProvider<ISessionSettingsContext> {
122
123
protected readonly _schemeLabel = AGENT_SESSION_SETTINGS_SCHEME;
124
protected readonly _traceTag = 'AgentSessionSettings';
125
protected readonly _locale = sessionSettingsLocale;
126
127
constructor(
128
private readonly _schemaRegistrar: AgentSessionSettingsSchemaRegistrar,
129
@ISessionsProvidersService sessionsProvidersService: ISessionsProvidersService,
130
@ILogService logService: ILogService,
131
) {
132
super(sessionsProvidersService, logService);
133
}
134
135
protected _parseUri(resource: URI): ISessionSettingsContext | undefined {
136
return parseSessionSettingsUri(resource);
137
}
138
139
protected _serialize(provider: IAgentHostSessionsProvider, ctx: ISessionSettingsContext): string {
140
return serializeSessionSettings(provider, ctx.sessionId);
141
}
142
143
protected _watchChanges(provider: IAgentHostSessionsProvider, ctx: ISessionSettingsContext, fire: () => void): IDisposable {
144
return provider.onDidChangeSessionConfig(changedSessionId => {
145
if (changedSessionId === ctx.sessionId) {
146
fire();
147
}
148
});
149
}
150
151
protected _ensureSchemaRegistered(provider: IAgentHostSessionsProvider, ctx: ISessionSettingsContext): void {
152
const session = provider.getSessions().find(s => s.sessionId === ctx.sessionId);
153
if (session) {
154
this._schemaRegistrar.ensureRegistered(provider, session);
155
}
156
}
157
158
protected _hasConfig(provider: IAgentHostSessionsProvider, ctx: ISessionSettingsContext): boolean {
159
return provider.getSessionConfig(ctx.sessionId) !== undefined;
160
}
161
162
// The input is the user's full view of editable values. Dispatch as a
163
// replace — `replaceSessionConfig` guarantees non-editable properties
164
// (non-mutable or readOnly) are preserved regardless of what we send,
165
// and unknown keys are ignored.
166
protected _replaceConfig(provider: IAgentHostSessionsProvider, ctx: ISessionSettingsContext, values: Record<string, unknown>): Promise<void> {
167
return provider.replaceSessionConfig(ctx.sessionId, values);
168
}
169
170
protected _describeForTrace(ctx: ISessionSettingsContext): string {
171
return `session ${ctx.sessionId}`;
172
}
173
}
174
175
/**
176
* Keeps per-session JSON schemas registered so editors of the synthetic
177
* `agent-session-settings://…` files get completions, hover, and validation.
178
*/
179
export class AgentSessionSettingsSchemaRegistrar extends AbstractAgentHostConfigSchemaRegistrar<ISession> {
180
181
protected _propertyFilter(): AgentHostConfigPropertyFilter {
182
return sessionSettingsPropertyFilter;
183
}
184
185
protected _settingsUri(session: ISession): string {
186
return agentSessionSettingsUri(session).toString();
187
}
188
189
// Schema content is served via the `vscode://schemas/...` filesystem
190
// provider (see `SettingsFileSystemProvider`); the JSON language client
191
// only knows how to fetch schema content for that scheme. The
192
// settings-file URI is used as the fileMatch glob so the schema is
193
// applied to the actual editor document.
194
protected _schemaId(session: ISession): string {
195
return `vscode://schemas/agent-session-settings/${session.providerId}/${session.resource.scheme}/${session.resource.path}.jsonc`;
196
}
197
198
protected _getConfig(provider: IAgentHostSessionsProvider, session: ISession): IAgentHostConfigLike | undefined {
199
return provider.getSessionConfig(session.sessionId);
200
}
201
202
protected _targetsForProvider(provider: IAgentHostSessionsProvider): readonly ISession[] {
203
return provider.getSessions();
204
}
205
206
protected _observeProvider(
207
provider: IAgentHostSessionsProvider,
208
onChanged: (session: ISession) => void,
209
onRemoved: (session: ISession) => void,
210
): IDisposable {
211
const store = new DisposableStore();
212
store.add(provider.onDidChangeSessionConfig(sessionId => {
213
const session = provider.getSessions().find(s => s.sessionId === sessionId);
214
if (session) {
215
onChanged(session);
216
}
217
}));
218
store.add(provider.onDidChangeSessions(e => {
219
for (const removed of e.removed) {
220
onRemoved(removed);
221
}
222
}));
223
return store;
224
}
225
}
226
227