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 { URI } from '../../base/common/uri.js';
10
>
import { AuthenticateParams, AuthenticateResult, IAgentConnection } from '../../platform/agentHost/common/agentService.js';
11
>
import { RemoteAgentHostConnectionStatus } from '../../platform/agentHost/common/remoteAgentHostService.js';
12
>
import { ResolveSessionConfigResult, SessionConfigValueItem } from '../../platform/agentHost/common/state/protocol/commands.js';
13
>
import { AgentCustomization, Customization, McpServerStatus, RootConfigState, type McpServerState, type RootState } from '../../platform/agentHost/common/state/protocol/state.js';
14
>
import { ISessionsProvider } from '../services/sessions/common/sessionsProvider.js';
15
>
import { ISessionAgentRef } from '../services/sessions/common/session.js';
16
>
17
>
/**
18
>
* Progress emitted while an agent-host provider is establishing a connection.
19
>
*/
20
>
export interface IAgentHostConnectProgress {
21
>
readonly connectionKey: string;
22
>
readonly message: string;
23
>
}
24
>
25
>
/**
26
>
* A rich view of a single MCP server exposed by an agent host session.
27
>
* Encapsulates the dispatch plumbing so consumers can present and toggle
28
>
* servers without depending on the low-level protocol action surface.
29
>
*/
30
>
export interface IAgentHostMcpServer {
31
>
readonly id: string;
32
>
readonly name: string;
33
>
readonly enabled: boolean;
34
>
readonly status: McpServerStatus;
35
>
readonly state: McpServerState;
36
>
readonly logOutputChannelId?: string;
37
>
/** Starts or restarts the server. Providers that cannot control lifecycle may no-op. */
38
>
start(): Promise<void>;
39
>
/** Stops the server. Providers that cannot control lifecycle may no-op. */
40
>
stop(): Promise<void>;
41
>
setEnabled(enabled: boolean): void;
42
>
}
43
>
44
>
/**
45
>
* Extended sessions provider for agent host providers (local and remote).
46
>
* Adds remote connection properties and dynamic session configuration.
47
>
*/
48
>
export interface IAgentHostSessionsProvider extends ISessionsProvider {
49
>
// -- Remote Connection (optional, used by remote agent host providers) --
50
>
/** Connection status observable, present on remote providers. */
51
>
readonly connectionStatus?: IObservable<RemoteAgentHostConnectionStatus>;
52
>
/** Progress messages during on-demand connect. */
53
>
readonly onDidReportConnectProgress?: Event<IAgentHostConnectProgress>;
54
>
/** Remote address string, present on remote providers. */
55
>
readonly remoteAddress?: string;
56
>
/**
57
>
* Establish (or re-establish) the connection for this host on demand.
58
>
* Tears down any existing connection first. Present on remote providers
59
>
* that manage their own transport (e.g. tunnel relay); providers that
60
>
* use the generic {@link IRemoteAgentHostService} reconnect flow may
61
>
* leave this undefined.
62
>
*/
63
>
connect?(): Promise<void>;
64
>
/**
65
>
* Tear down the active connection for this host without forgetting the
66
>
* entry. A subsequent {@link connect} call should be able to re-establish
67
>
* it. Present on remote providers that manage their own transport.
68
>
*/
69
>
disconnect?(): Promise<void>;
70
>
71
>
/**
72
>
* When `true`, the workspace picker keeps this provider's browse
73
>
* action(s) enabled even while {@link connectionStatus} reports
74
>
* `disconnected` — the assumption being that clicking the action
75
>
* itself triggers a connect attempt (e.g. booting a stopped WSL
76
>
* distro). The `incompatible` state is still treated as unavailable
77
>
* because the user can't recover from it via a click.
78
>
*/
79
>
readonly canConnectOnDemand?: boolean;
80
>
81
>
// -- Dynamic Session Config --
82
>
83
>
/** Fires when dynamic configuration for a session changes. */
84
>
readonly onDidChangeSessionConfig: Event<string>;
85
>
/** Returns the last resolved dynamic configuration for a session. */
86
>
getSessionConfig(sessionId: string): ResolveSessionConfigResult | undefined;
87
>
/**
88
>
* Observable: `true` while a `resolveSessionConfig` round-trip is in
89
>
* flight. Pickers gate on this rather than `session.loading` so they
90
>
* stay interactive in the required-values-missing state.
91
>
*/
92
>
isSessionConfigResolving(sessionId: string): IObservable<boolean>;
93
>
/** Sets one dynamic configuration property and re-resolves the schema. */
94
>
setSessionConfigValue(sessionId: string, property: string, value: unknown): Promise<void>;
95
>
/**
96
>
* Replaces the full set of running-session config values atomically.
97
>
*
98
>
* Dispatches a single `session/configChanged` action with replace
99
>
* semantics. Only user-editable properties (`sessionMutable: true` and
100
>
* not `readOnly`) are actually replaced from the caller-supplied values —
101
>
* for every other property the current value is carried through, so
102
>
* non-mutable / read-only properties (e.g. `isolation`, `branch`) can
103
>
* never be altered through this API even if included in the input.
104
>
* Unknown keys (no schema entry) are ignored.
105
>
*
106
>
* No-op for pre-creation (new) sessions — use {@link setSessionConfigValue}
107
>
* there since the schema is still being resolved.
108
>
*/
109
>
replaceSessionConfig(sessionId: string, values: Record<string, unknown>): Promise<void>;
110
>
/** Returns dynamic completions for a configuration property. */
111
>
getSessionConfigCompletions(sessionId: string, property: string, query?: string): Promise<readonly SessionConfigValueItem[]>;
112
>
/** Returns the resolved config that should be sent to createSession. */
113
>
getCreateSessionConfig(sessionId: string): Record<string, unknown> | undefined;
114
>
/** Clears dynamic configuration state for an abandoned new session. */
115
>
clearSessionConfig(sessionId: string): void;
116
>
117
>
// -- Root (agent host) Config --
118
>
119
>
/** Fires when the root (agent host) configuration schema or values change. */
120
>
readonly onDidChangeRootConfig: Event<void>;
121
>
/** Returns the last-known root (agent host) configuration, or `undefined` if the host has not published any. */
122
>
getRootConfig(): RootConfigState | undefined;
123
>
getRootState(): RootState | undefined;
124
>
mapAgentHostResource(uri: URI): URI;
125
>
/**
126
>
* Sets one root configuration property.
127
>
*
128
>
* Optimistically updates local state and dispatches a
129
>
* `root/configChanged` action (non-replace) to the agent host.
130
>
*/
131
>
setRootConfigValue(property: string, value: unknown): Promise<void>;
132
>
/**
133
>
* Replaces the full set of root configuration values atomically.
134
>
*
135
>
* Dispatches a single `root/configChanged` action with replace semantics.
136
>
* Unknown keys (no schema entry) are ignored.
137
>
*/
138
>
replaceRootConfig(values: Record<string, unknown>): Promise<void>;
139
>
140
>
/** Authenticate against the backing agent-host connection. */
141
>
authenticate(params: AuthenticateParams): Promise<AuthenticateResult>;
142
>
143
>
// -- Custom Agents --
144
>
145
>
/**
146
>
* Fires when the effective custom-agent set for any session may have
147
>
* changed (root state customizations or per-session customizations
148
>
* updated). The event has no payload — consumers re-read via
149
>
* {@link getCustomAgents}.
150
>
*/
151
>
readonly onDidChangeCustomAgents: Event<void>;
152
>
/**
153
>
* Returns the merged, de-duped custom-agent list a session should see,
154
>
* computed from root, active-client, and session customizations. Returns
155
>
* an empty array when the session is unknown or no agents have been
156
>
* advertised.
157
>
*/
158
>
getCustomAgents(sessionId: string): readonly AgentCustomization[];
159
>
160
>
readonly onDidChangeCustomizations: Event<void>;
161
>
162
>
/**
163
>
* Returns the full set of customizations.
164
>
*/
165
>
getCustomizations(sessionId: string): readonly Customization[];
166
>
167
>
/**
168
>
* Returns the working directory for the session, if provided by the host.
169
>
*/
170
>
getWorkingDirectory(sessionId: string): string | undefined;
171
>
172
>
/**
173
>
* Returns the MCP servers exposed by the session as rich objects whose
174
>
* methods dispatch protocol-level toggle and lifecycle actions.
175
>
* Returns an empty array when the session is unknown or exposes no MCP
176
>
* servers.
177
>
*/
178
>
getMcpServers(sessionId: string): readonly IAgentHostMcpServer[];
179
>
180
>
/**
181
>
* Set (or clear) the selected custom agent for a session. Optional so
182
>
* providers that don't expose custom agents can omit it.
183
>
* @param sessionId The ID of the session.
184
>
* @param agent The agent to select, or `undefined` to clear the selection
185
>
* and use the provider's default behavior.
186
>
*/
187
>
setAgent?(sessionId: string, agent: ISessionAgentRef | undefined): void;
188
>
189
>
/**
190
>
* Returns the agent-host annotations channel for a session so that
191
>
* sessions-layer features (e.g. agent feedback) can subscribe to and
192
>
* dispatch annotation actions against the session's
193
>
* `<sessionUri>/annotations` channel. Returns `undefined` when the
194
>
* session is unknown or the host connection is unavailable.
195
>
*/
196
>
getFeedbackAnnotationsChannel(sessionId: string): { readonly connection: IAgentConnection; readonly annotationsUri: URI } | undefined;
197
>
198
>
}
199
>
200
>
export const LOCAL_AGENT_HOST_PROVIDER_ID = 'local-agent-host';
201
>
202
>
/**
203
>
* Experimental setting id controlling whether the local agent host acts as the
204
>
* default sessions provider. When enabled (and `chat.agentHost.enabled` is
205
>
* true), the local agent host's session types are surfaced before those of
206
>
* other providers. Defaults to `false`.
207
>
*/
208
>
export const LocalAgentHostDefaultProviderSettingId = 'chat.agentHost.defaultSessionsProvider';
209
>
210
>
export const REMOTE_AGENT_HOST_PROVIDER_PREFIX = 'agenthost-';
211
>
export const REMOTE_AGENT_HOST_PROVIDER_RE = /^agenthost-/;
212
>
export const ANY_AGENT_HOST_PROVIDER_RE = /^(local-agent-host|agenthost-)/;
213
>
214
>
/**
215
>
* Checks whether a provider is an agent host provider based on its
216
>
* reserved provider ID (`local-agent-host` or `agenthost-*` prefix).
217
>
*/
218
>
export function isAgentHostProvider(provider: ISessionsProvider): provider is IAgentHostSessionsProvider {
219
return isAgentHostProviderId(provider.id);
220
}
222
>
/**
223
>
* Checks whether a provider ID is for an agent host provider
224
>
* (`local-agent-host` or any `agenthost-*` provider).
225
>
*/
226
>
export function isAgentHostProviderId(providerId: string): boolean {
227
return providerId === LOCAL_AGENT_HOST_PROVIDER_ID || providerId.startsWith(REMOTE_AGENT_HOST_PROVIDER_PREFIX);
228
}
230
>
/**
231
>
* Structural equality for resolved session configs. Returns true when both
232
>
* inputs have the same value-key set with deep-equal values and the same set
233
>
* of schema property keys with identical (by-identity) property objects.
234
>
* Schema property objects are compared by identity since they originate from
235
>
* the same protocol snapshot in the providers that use this helper. Values
236
>
* are deep-compared via {@link equals} so non-string entries (e.g. permission
237
>
* objects) compare correctly.
238
>
*/
239
>
export function resolvedConfigsEqual(a: ResolveSessionConfigResult, b: ResolveSessionConfigResult): boolean {
240
const aValueKeys = Object.keys(a.values);
241
const bValueKeys = Object.keys(b.values);