Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/common/agentHostSessionsProvider.ts
13389 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 { Event } from '../../base/common/event.js';
7
import { IObservable } from '../../base/common/observable.js';
8
import { equals } from '../../base/common/objects.js';
9
import { RemoteAgentHostConnectionStatus } from '../../platform/agentHost/common/remoteAgentHostService.js';
10
import { ResolveSessionConfigResult, SessionConfigValueItem } from '../../platform/agentHost/common/state/protocol/commands.js';
11
import { RootConfigState } from '../../platform/agentHost/common/state/protocol/state.js';
12
import { ISessionsProvider } from '../services/sessions/common/sessionsProvider.js';
13
14
/**
15
* Extended sessions provider for agent host providers (local and remote).
16
* Adds remote connection properties and dynamic session configuration.
17
*/
18
export interface IAgentHostSessionsProvider extends ISessionsProvider {
19
// -- Remote Connection (optional, used by remote agent host providers) --
20
/** Connection status observable, present on remote providers. */
21
readonly connectionStatus?: IObservable<RemoteAgentHostConnectionStatus>;
22
/** Remote address string, present on remote providers. */
23
readonly remoteAddress?: string;
24
/** Output channel ID for remote provider logs. */
25
outputChannelId?: string;
26
/**
27
* Establish (or re-establish) the connection for this host on demand.
28
* Tears down any existing connection first. Present on remote providers
29
* that manage their own transport (e.g. tunnel relay); providers that
30
* use the generic {@link IRemoteAgentHostService} reconnect flow may
31
* leave this undefined.
32
*/
33
connect?(): Promise<void>;
34
/**
35
* Tear down the active connection for this host without forgetting the
36
* entry. A subsequent {@link connect} call should be able to re-establish
37
* it. Present on remote providers that manage their own transport.
38
*/
39
disconnect?(): Promise<void>;
40
41
// -- Dynamic Session Config --
42
43
/** Fires when dynamic configuration for a session changes. */
44
readonly onDidChangeSessionConfig: Event<string>;
45
/** Returns the last resolved dynamic configuration for a session. */
46
getSessionConfig(sessionId: string): ResolveSessionConfigResult | undefined;
47
/** Sets one dynamic configuration property and re-resolves the schema. */
48
setSessionConfigValue(sessionId: string, property: string, value: unknown): Promise<void>;
49
/**
50
* Replaces the full set of running-session config values atomically.
51
*
52
* Dispatches a single `session/configChanged` action with replace
53
* semantics. Only user-editable properties (`sessionMutable: true` and
54
* not `readOnly`) are actually replaced from the caller-supplied values —
55
* for every other property the current value is carried through, so
56
* non-mutable / read-only properties (e.g. `isolation`, `branch`) can
57
* never be altered through this API even if included in the input.
58
* Unknown keys (no schema entry) are ignored.
59
*
60
* No-op for pre-creation (new) sessions — use {@link setSessionConfigValue}
61
* there since the schema is still being resolved.
62
*/
63
replaceSessionConfig(sessionId: string, values: Record<string, unknown>): Promise<void>;
64
/** Returns dynamic completions for a configuration property. */
65
getSessionConfigCompletions(sessionId: string, property: string, query?: string): Promise<readonly SessionConfigValueItem[]>;
66
/** Returns the resolved config that should be sent to createSession. */
67
getCreateSessionConfig(sessionId: string): Record<string, unknown> | undefined;
68
/** Clears dynamic configuration state for an abandoned new session. */
69
clearSessionConfig(sessionId: string): void;
70
71
// -- Root (agent host) Config --
72
73
/** Fires when the root (agent host) configuration schema or values change. */
74
readonly onDidChangeRootConfig: Event<void>;
75
/** Returns the last-known root (agent host) configuration, or `undefined` if the host has not published any. */
76
getRootConfig(): RootConfigState | undefined;
77
/**
78
* Sets one root configuration property.
79
*
80
* Optimistically updates local state and dispatches a
81
* `root/configChanged` action (non-replace) to the agent host.
82
*/
83
setRootConfigValue(property: string, value: unknown): Promise<void>;
84
/**
85
* Replaces the full set of root configuration values atomically.
86
*
87
* Dispatches a single `root/configChanged` action with replace semantics.
88
* Unknown keys (no schema entry) are ignored.
89
*/
90
replaceRootConfig(values: Record<string, unknown>): Promise<void>;
91
}
92
93
export const LOCAL_AGENT_HOST_PROVIDER_ID = 'local-agent-host';
94
export const REMOTE_AGENT_HOST_PROVIDER_PREFIX = 'agenthost-';
95
export const REMOTE_AGENT_HOST_PROVIDER_RE = /^agenthost-/;
96
export const ANY_AGENT_HOST_PROVIDER_RE = /^(local-agent-host|agenthost-)/;
97
98
/**
99
* Checks whether a provider is an agent host provider based on its
100
* reserved provider ID (`local-agent-host` or `agenthost-*` prefix).
101
*/
102
export function isAgentHostProvider(provider: ISessionsProvider): provider is IAgentHostSessionsProvider {
103
return provider.id === LOCAL_AGENT_HOST_PROVIDER_ID || provider.id.startsWith(REMOTE_AGENT_HOST_PROVIDER_PREFIX);
104
}
105
106
/**
107
* Structural equality for resolved session configs. Returns true when both
108
* inputs have the same value-key set with deep-equal values and the same set
109
* of schema property keys with identical (by-identity) property objects.
110
* Schema property objects are compared by identity since they originate from
111
* the same protocol snapshot in the providers that use this helper. Values
112
* are deep-compared via {@link equals} so non-string entries (e.g. permission
113
* objects) compare correctly.
114
*/
115
export function resolvedConfigsEqual(a: ResolveSessionConfigResult, b: ResolveSessionConfigResult): boolean {
116
const aValueKeys = Object.keys(a.values);
117
const bValueKeys = Object.keys(b.values);
118
if (aValueKeys.length !== bValueKeys.length) {
119
return false;
120
}
121
for (const key of aValueKeys) {
122
if (!equals(a.values[key], b.values[key])) {
123
return false;
124
}
125
}
126
const aPropKeys = Object.keys(a.schema.properties);
127
const bPropKeys = Object.keys(b.schema.properties);
128
if (aPropKeys.length !== bPropKeys.length) {
129
return false;
130
}
131
for (const key of aPropKeys) {
132
if (a.schema.properties[key] !== b.schema.properties[key]) {
133
return false;
134
}
135
}
136
return true;
137
}
138
139
/** Known auto-approve config values. */
140
const AUTO_APPROVE_ENUM = ['default', 'autoApprove', 'autopilot'];
141
142
type MutableConfigSchemaItem =
143
| { type: 'string'; title: string; sessionMutable: true; enum: string[] }
144
| { type: 'number'; title: string; sessionMutable: true }
145
| { type: 'boolean'; title: string; sessionMutable: true }
146
| { type: 'array'; title: string; sessionMutable: true }
147
| { type: 'object'; title: string; sessionMutable: true };
148
149
function buildMutableConfigSchemaItem(key: string, value: unknown): MutableConfigSchemaItem | undefined {
150
if (typeof value === 'string') {
151
return {
152
type: 'string',
153
title: key,
154
sessionMutable: true,
155
enum: key === 'autoApprove' ? AUTO_APPROVE_ENUM : [value],
156
};
157
}
158
if (typeof value === 'number') {
159
return { type: 'number', title: key, sessionMutable: true };
160
}
161
if (typeof value === 'boolean') {
162
return { type: 'boolean', title: key, sessionMutable: true };
163
}
164
if (Array.isArray(value)) {
165
return { type: 'array', title: key, sessionMutable: true };
166
}
167
if (value && typeof value === 'object') {
168
return { type: 'object', title: key, sessionMutable: true };
169
}
170
return undefined;
171
}
172
173
/**
174
* Builds a minimal session-mutable config schema from changed values.
175
* Used when a restored session receives a ConfigChanged action before
176
* the full schema has been hydrated. Properties whose value type isn't
177
* representable in the config schema (e.g. `null`, `undefined`) are
178
* omitted.
179
*/
180
export function buildMutableConfigSchema(config: Record<string, unknown>): Record<string, MutableConfigSchemaItem> {
181
const properties: Record<string, MutableConfigSchemaItem> = {};
182
for (const key of Object.keys(config)) {
183
const property = buildMutableConfigSchemaItem(key, config[key]);
184
if (property) {
185
properties[key] = property;
186
}
187
}
188
return properties;
189
}
190
191