Path: blob/main/src/vs/sessions/common/agentHostSessionsProvider.ts
13389 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Event } from '../../base/common/event.js';6import { IObservable } from '../../base/common/observable.js';7import { equals } from '../../base/common/objects.js';8import { RemoteAgentHostConnectionStatus } from '../../platform/agentHost/common/remoteAgentHostService.js';9import { ResolveSessionConfigResult, SessionConfigValueItem } from '../../platform/agentHost/common/state/protocol/commands.js';10import { RootConfigState } from '../../platform/agentHost/common/state/protocol/state.js';11import { ISessionsProvider } from '../services/sessions/common/sessionsProvider.js';1213/**14* Extended sessions provider for agent host providers (local and remote).15* Adds remote connection properties and dynamic session configuration.16*/17export interface IAgentHostSessionsProvider extends ISessionsProvider {18// -- Remote Connection (optional, used by remote agent host providers) --19/** Connection status observable, present on remote providers. */20readonly connectionStatus?: IObservable<RemoteAgentHostConnectionStatus>;21/** Remote address string, present on remote providers. */22readonly remoteAddress?: string;23/** Output channel ID for remote provider logs. */24outputChannelId?: string;25/**26* Establish (or re-establish) the connection for this host on demand.27* Tears down any existing connection first. Present on remote providers28* that manage their own transport (e.g. tunnel relay); providers that29* use the generic {@link IRemoteAgentHostService} reconnect flow may30* leave this undefined.31*/32connect?(): Promise<void>;33/**34* Tear down the active connection for this host without forgetting the35* entry. A subsequent {@link connect} call should be able to re-establish36* it. Present on remote providers that manage their own transport.37*/38disconnect?(): Promise<void>;3940// -- Dynamic Session Config --4142/** Fires when dynamic configuration for a session changes. */43readonly onDidChangeSessionConfig: Event<string>;44/** Returns the last resolved dynamic configuration for a session. */45getSessionConfig(sessionId: string): ResolveSessionConfigResult | undefined;46/** Sets one dynamic configuration property and re-resolves the schema. */47setSessionConfigValue(sessionId: string, property: string, value: unknown): Promise<void>;48/**49* Replaces the full set of running-session config values atomically.50*51* Dispatches a single `session/configChanged` action with replace52* semantics. Only user-editable properties (`sessionMutable: true` and53* not `readOnly`) are actually replaced from the caller-supplied values —54* for every other property the current value is carried through, so55* non-mutable / read-only properties (e.g. `isolation`, `branch`) can56* never be altered through this API even if included in the input.57* Unknown keys (no schema entry) are ignored.58*59* No-op for pre-creation (new) sessions — use {@link setSessionConfigValue}60* there since the schema is still being resolved.61*/62replaceSessionConfig(sessionId: string, values: Record<string, unknown>): Promise<void>;63/** Returns dynamic completions for a configuration property. */64getSessionConfigCompletions(sessionId: string, property: string, query?: string): Promise<readonly SessionConfigValueItem[]>;65/** Returns the resolved config that should be sent to createSession. */66getCreateSessionConfig(sessionId: string): Record<string, unknown> | undefined;67/** Clears dynamic configuration state for an abandoned new session. */68clearSessionConfig(sessionId: string): void;6970// -- Root (agent host) Config --7172/** Fires when the root (agent host) configuration schema or values change. */73readonly onDidChangeRootConfig: Event<void>;74/** Returns the last-known root (agent host) configuration, or `undefined` if the host has not published any. */75getRootConfig(): RootConfigState | undefined;76/**77* Sets one root configuration property.78*79* Optimistically updates local state and dispatches a80* `root/configChanged` action (non-replace) to the agent host.81*/82setRootConfigValue(property: string, value: unknown): Promise<void>;83/**84* Replaces the full set of root configuration values atomically.85*86* Dispatches a single `root/configChanged` action with replace semantics.87* Unknown keys (no schema entry) are ignored.88*/89replaceRootConfig(values: Record<string, unknown>): Promise<void>;90}9192export const LOCAL_AGENT_HOST_PROVIDER_ID = 'local-agent-host';93export const REMOTE_AGENT_HOST_PROVIDER_PREFIX = 'agenthost-';94export const REMOTE_AGENT_HOST_PROVIDER_RE = /^agenthost-/;95export const ANY_AGENT_HOST_PROVIDER_RE = /^(local-agent-host|agenthost-)/;9697/**98* Checks whether a provider is an agent host provider based on its99* reserved provider ID (`local-agent-host` or `agenthost-*` prefix).100*/101export function isAgentHostProvider(provider: ISessionsProvider): provider is IAgentHostSessionsProvider {102return provider.id === LOCAL_AGENT_HOST_PROVIDER_ID || provider.id.startsWith(REMOTE_AGENT_HOST_PROVIDER_PREFIX);103}104105/**106* Structural equality for resolved session configs. Returns true when both107* inputs have the same value-key set with deep-equal values and the same set108* of schema property keys with identical (by-identity) property objects.109* Schema property objects are compared by identity since they originate from110* the same protocol snapshot in the providers that use this helper. Values111* are deep-compared via {@link equals} so non-string entries (e.g. permission112* objects) compare correctly.113*/114export function resolvedConfigsEqual(a: ResolveSessionConfigResult, b: ResolveSessionConfigResult): boolean {115const aValueKeys = Object.keys(a.values);116const bValueKeys = Object.keys(b.values);117if (aValueKeys.length !== bValueKeys.length) {118return false;119}120for (const key of aValueKeys) {121if (!equals(a.values[key], b.values[key])) {122return false;123}124}125const aPropKeys = Object.keys(a.schema.properties);126const bPropKeys = Object.keys(b.schema.properties);127if (aPropKeys.length !== bPropKeys.length) {128return false;129}130for (const key of aPropKeys) {131if (a.schema.properties[key] !== b.schema.properties[key]) {132return false;133}134}135return true;136}137138/** Known auto-approve config values. */139const AUTO_APPROVE_ENUM = ['default', 'autoApprove', 'autopilot'];140141type MutableConfigSchemaItem =142| { type: 'string'; title: string; sessionMutable: true; enum: string[] }143| { type: 'number'; title: string; sessionMutable: true }144| { type: 'boolean'; title: string; sessionMutable: true }145| { type: 'array'; title: string; sessionMutable: true }146| { type: 'object'; title: string; sessionMutable: true };147148function buildMutableConfigSchemaItem(key: string, value: unknown): MutableConfigSchemaItem | undefined {149if (typeof value === 'string') {150return {151type: 'string',152title: key,153sessionMutable: true,154enum: key === 'autoApprove' ? AUTO_APPROVE_ENUM : [value],155};156}157if (typeof value === 'number') {158return { type: 'number', title: key, sessionMutable: true };159}160if (typeof value === 'boolean') {161return { type: 'boolean', title: key, sessionMutable: true };162}163if (Array.isArray(value)) {164return { type: 'array', title: key, sessionMutable: true };165}166if (value && typeof value === 'object') {167return { type: 'object', title: key, sessionMutable: true };168}169return undefined;170}171172/**173* Builds a minimal session-mutable config schema from changed values.174* Used when a restored session receives a ConfigChanged action before175* the full schema has been hydrated. Properties whose value type isn't176* representable in the config schema (e.g. `null`, `undefined`) are177* omitted.178*/179export function buildMutableConfigSchema(config: Record<string, unknown>): Record<string, MutableConfigSchemaItem> {180const properties: Record<string, MutableConfigSchemaItem> = {};181for (const key of Object.keys(config)) {182const property = buildMutableConfigSchemaItem(key, config[key]);183if (property) {184properties[key] = property;185}186}187return properties;188}189190191