import { Event } from "@codingame/monaco-vscode-api/vscode/vs/base/common/event"; import { IReference } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle"; import type { IObservable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/observable"; import { URI } from "@codingame/monaco-vscode-api/vscode/vs/base/common/uri"; import type { ISyncedCustomization } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/agentPluginManager"; import type { IAgentSubscription } from "./state/agentSubscription.js"; import type { CompletionsParams, CompletionsResult, CreateTerminalParams, ResolveSessionConfigResult, SessionConfigCompletionsResult } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/commands"; import { ProtectedResourceMetadata, type ConfigSchema, type FileEdit, type MessageAttachment, type ModelSelection, type SessionActiveClient, type ToolCallPendingConfirmationState, type ToolDefinition } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/protocol/state"; import type { ActionEnvelope, INotification, IRootConfigChangedAction, SessionAction, TerminalAction } from "./state/sessionActions.js"; import type { ResourceCopyParams, ResourceCopyResult, ResourceDeleteParams, ResourceDeleteResult, ResourceListResult, ResourceMoveParams, ResourceMoveResult, ResourceReadResult, ResourceWriteParams, ResourceWriteResult } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/sessionProtocol"; import { ComponentToState, SessionInputResponseKind, SessionStatus, StateComponents, type CustomizationRef, type PendingMessage, type RootState, type SessionCustomization, type SessionInputAnswer, type SessionMeta, type ToolCallResult, type Turn, type PolicyState } from "@codingame/monaco-vscode-api/vscode/vs/platform/agentHost/common/state/sessionState"; export declare enum AgentHostIpcChannels { /** Channel for the agent host service on the main-process side */ AgentHost = "agentHost", /** Channel for log forwarding from the agent host process */ Logger = "agentHostLogger", /** Channel for WebSocket client connection count (server process management only) */ ConnectionTracker = "agentHostConnectionTracker", /** * Channel registered by the remote server that proxies AHP JSON-RPC * frames between a renderer and the agent host running on the server. * Pairs with `AgentHostIpcChannelTransport` on the renderer side. */ RemoteProxy = "agentHostProxy" } /** Configuration key that controls whether the local agent host process is spawned. */ export declare const AgentHostEnabledSettingId = "chat.agentHost.enabled"; /** Configuration key that controls whether per-host IPC traffic output channels are created. */ export declare const AgentHostIpcLoggingSettingId = "chat.agentHost.ipcLoggingEnabled"; /** Configuration key that controls whether AHP JSONL logs are written for agent host transports. */ export declare const AgentHostAhpJsonlLoggingSettingId = "chat.agentHost.ahpJsonlLoggingEnabled"; /** Configuration key that controls whether Agent Host uses its terminal tool override for Copilot SDK sessions. */ export declare const AgentHostCustomTerminalToolEnabledSettingId = "chat.agentHost.customTerminalTool.enabled"; /** * Configuration key that holds the absolute path to a locally-installed * `@anthropic-ai/claude-agent-sdk` package. When non-empty, the Claude agent * provider is registered inside the agent host and the SDK module is loaded * via dynamic `import()` from this path. When empty (the default), the * Claude provider is not registered. The SDK is intentionally not bundled * with VS Code; users opting into the Claude agent install the SDK * themselves and point this setting at it. The agent host process must be * restarted for changes to take effect. */ export declare const AgentHostClaudeAgentSdkPathSettingId = "chat.agentHost.claudeAgent.path"; /** * Environment variable that holds the absolute path to a locally-installed * `@anthropic-ai/claude-agent-sdk` package. When set to a non-empty value, * the agent host process registers the Claude agent provider and loads the * SDK module from this path. Set by the agent host starters from * {@link AgentHostClaudeAgentSdkPathSettingId}, and may also be set directly * by developers as an override. */ export declare const AgentHostClaudeSdkPathEnvVar = "VSCODE_AGENT_HOST_CLAUDE_SDK_PATH"; /** Master toggle for agent-host OTel. Explicit opt-in; other settings imply this when set. */ export declare const AgentHostOTelEnabledSettingId = "chat.agentHost.otel.enabled"; /** Exporter type for the SDK's OTel pipeline. One of: `otlp-http`, `otlp-grpc`, `console`, `file`. */ export declare const AgentHostOTelExporterTypeSettingId = "chat.agentHost.otel.exporterType"; /** OTLP endpoint URL when `exporterType` is `otlp-http` or `otlp-grpc`. */ export declare const AgentHostOTelOtlpEndpointSettingId = "chat.agentHost.otel.otlpEndpoint"; /** Whether to include prompt/response content in span attributes (privacy-sensitive). */ export declare const AgentHostOTelCaptureContentSettingId = "chat.agentHost.otel.captureContent"; /** Output path when `exporterType` is `file`. */ export declare const AgentHostOTelOutfileSettingId = "chat.agentHost.otel.outfile"; /** When true, ALL spans are persisted to a local SQLite store regardless of `exporterType`. */ export declare const AgentHostOTelDbSpanExporterEnabledSettingId = "chat.agentHost.otel.dbSpanExporter.enabled"; /** * Path of the local SQLite span database, relative to `INativeEnvironmentService.userDataPath`. * Kept here so both the renderer-side export action and the agent-host-side service * use the same on-disk location. */ export declare const AgentHostOTelSpansDbSubPath = "agent-host/otel/agent-host-traces.db"; /** * Environment variables consumed by `AgentHostOTelService` inside the agent host * process. The workbench-side agent-host starters translate the corresponding * `chat.agentHost.otel.*` settings into these variables (settings → env), while * any value already present on the parent process's env wins (developer override). * * These names match the conventions documented in * `extensions/copilot/docs/monitoring/agent_monitoring.md` so the same external * tooling and `OTEL_EXPORTER_OTLP_*` config recipes work unchanged. */ export declare const AgentHostOTelEnvVars: Readonly<{ readonly Enabled: "COPILOT_OTEL_ENABLED"; readonly ExporterType: "COPILOT_OTEL_EXPORTER_TYPE"; readonly OtlpEndpoint: "OTEL_EXPORTER_OTLP_ENDPOINT"; readonly OtlpEndpointAlt: "COPILOT_OTEL_ENDPOINT"; readonly OtlpProtocol: "OTEL_EXPORTER_OTLP_PROTOCOL"; readonly OtlpHeaders: "OTEL_EXPORTER_OTLP_HEADERS"; readonly CaptureContent: "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"; readonly FilePath: "COPILOT_OTEL_FILE_EXPORTER_PATH"; readonly SourceName: "COPILOT_OTEL_SOURCE_NAME"; readonly DbSpanExporterEnabled: "COPILOT_OTEL_DB_SPAN_EXPORTER_ENABLED"; }>; /** * Snapshot of the `chat.agentHost.otel.*` settings; produced by the workbench-side * starters and merged with the parent process's env (env wins on key collision). */ export interface IAgentHostOTelSettings { readonly enabled?: boolean; readonly exporterType?: string; readonly otlpEndpoint?: string; readonly captureContent?: boolean; readonly outfile?: string; readonly dbSpanExporterEnabled?: boolean; } /** * Build the env-var overlay for the agent host process from user settings and * inherited env. Settings are translated to env vars, but if the same env var is * already present on `inheritedEnv` it wins (developer override). * * Only sets a key when the underlying setting was explicitly configured — empty * string / undefined settings are dropped so they don't shadow inherited env. */ export declare function buildAgentHostOTelEnv(settings: IAgentHostOTelSettings, inheritedEnv: Readonly>): Record; /** Result of starting the agent host WebSocket server on-demand. */ export interface IAgentHostSocketInfo { readonly socketPath: string; } /** Inspector listener information for the agent host process. */ export interface IAgentHostInspectInfo { readonly host: string; readonly port: number; /** A `devtools://` URL that can be opened with `INativeHostService.openDevToolsWindow`. */ readonly devtoolsUrl: string; } /** * IPC service exposed on the {@link AgentHostIpcChannels.ConnectionTracker} * channel. Used by the server process for lifetime management and by the * shared process to request a local WebSocket listener on-demand. */ export interface IConnectionTrackerService { readonly onDidChangeConnectionCount: Event; /** * Request the agent host to start a WebSocket server on a local * pipe/socket. Returns the socket path. * If a server is already running, returns the existing info. */ startWebSocketServer(): Promise; /** * Get inspector listener info for the agent host process. If the inspector * is not currently active and `tryEnable` is true, opens the inspector on * a random local port. Returns `undefined` if the inspector cannot be * enabled (e.g. running in an environment without `node:inspector`). */ getInspectInfo(tryEnable: boolean): Promise; } export interface IAgentSessionMetadata { readonly session: URI; readonly startTime: number; readonly modifiedTime: number; readonly project?: IAgentSessionProjectInfo; readonly summary?: string; readonly status?: SessionStatus; /** Human-readable description of what the session is currently doing. */ readonly activity?: string; readonly model?: ModelSelection; readonly workingDirectory?: URI; readonly customizationDirectory?: URI; readonly isRead?: boolean; readonly isArchived?: boolean; readonly diffs?: readonly FileEdit[]; /** * Side-channel metadata mirroring {@link SessionState._meta}, propagated * to clients via per-session state subscriptions. * Producers SHOULD use namespaced keys; consumers MUST ignore unknown * keys. Use the typed accessors in `sessionState.ts` (e.g. * `readSessionGitState`) for well-known slots. */ readonly _meta?: SessionMeta; } export interface IAgentSessionProjectInfo { readonly uri: URI; readonly displayName: string; } export interface IAgentCreateSessionResult { readonly session: URI; readonly project?: IAgentSessionProjectInfo; /** The resolved working directory, which may differ from the requested one (e.g. worktree). */ readonly workingDirectory?: URI; /** * `true` when the agent only allocated an in-memory placeholder for this * session (no SDK session, no worktree, no on-disk state). Materialization * happens lazily on the first {@link IAgent.sendMessage}, at which point * the agent fires {@link IAgent.onDidMaterializeSession}. The * {@link IAgentService} uses this flag to defer the `sessionAdded` protocol * notification so observers don't see the session in their list until it * has been persisted. */ readonly provisional?: boolean; } /** * Payload of {@link IAgent.onDidMaterializeSession}. Fired once per session * when a previously {@link IAgentCreateSessionResult.provisional} session has * its SDK session, worktree (if any), and on-disk metadata in place. */ export interface IAgentMaterializeSessionEvent { readonly session: URI; readonly workingDirectory: URI | undefined; readonly project: IAgentSessionProjectInfo | undefined; } export type AgentProvider = string; /** Metadata describing an agent backend, discovered over IPC. */ export interface IAgentDescriptor { readonly provider: AgentProvider; readonly displayName: string; readonly description: string; } /** * Parameters for the `authenticate` command. * Analogous to sending `Authorization: Bearer ` (RFC 6750 section 2.1). */ export interface AuthenticateParams { /** * The `resource` identifier from the server's * {@link IAuthorizationProtectedResourceMetadata} that this token targets. */ readonly resource: string; /** The bearer token value (RFC 6750). */ readonly token: string; } /** * Result of the `authenticate` command. */ export interface AuthenticateResult { /** Whether the token was accepted. */ readonly authenticated: boolean; } /** * Canonical {@link ProtectedResourceMetadata} for the GitHub Copilot * resource. Shared between every agent provider that consumes a GitHub * Copilot bearer token (e.g. Copilot CLI, Claude) so they advertise an * identical resource identifier to the auth flow — clients dispatch by * `resource`, and divergent metadata would silently route the same * token down separate code paths. */ export declare const GITHUB_COPILOT_PROTECTED_RESOURCE: ProtectedResourceMetadata; export interface IAgentCreateSessionConfig { readonly provider?: AgentProvider; readonly model?: ModelSelection; readonly session?: URI; readonly workingDirectory?: URI; readonly config?: Record; /** * Eagerly claim the active client role for the new session. When provided, * the server initializes the session with this client as the active * client, equivalent to dispatching a `session/activeClientChanged` * action immediately after creation. The `clientId` MUST match the * connection's own `clientId`. */ readonly activeClient?: SessionActiveClient; /** Fork from an existing session at a specific turn. */ readonly fork?: { readonly session: URI; readonly turnIndex: number; readonly turnId: string; /** * Maps old protocol turn IDs to new protocol turn IDs. * Populated by the service layer after generating fresh UUIDs * for the forked session's turns. Used by the agent to remap * per-turn data (e.g. SDK event ID mappings) in the session database. */ readonly turnIdMapping?: ReadonlyMap; }; } export interface IAgentResolveSessionConfigParams { readonly provider?: AgentProvider; readonly workingDirectory?: URI; readonly config?: Record; } export interface IAgentSessionConfigCompletionsParams extends IAgentResolveSessionConfigParams { readonly property: string; readonly query?: string; } /** Serializable model information from the agent host. */ export interface IAgentModelInfo { readonly provider: AgentProvider; readonly id: string; readonly name: string; readonly maxContextWindow?: number; readonly supportsVision: boolean; readonly configSchema?: ConfigSchema; readonly policyState?: PolicyState; readonly _meta?: Record; } /** * A signal emitted by an agent during session execution. * * Most signals carry a protocol {@link SessionAction} directly via the * `kind: 'action'` shape, eliminating a parallel event ontology. A small * number of cases that have no clean protocol action (permission * auto-approval, subagent session creation, steering message * acknowledgment) remain as discriminated non-action signals so the host * can perform side effects before — or instead of — dispatching an action. */ export type AgentSignal = IAgentActionSignal | IAgentToolPendingConfirmationSignal | IAgentSubagentStartedSignal | IAgentSubagentCompletedSignal | IAgentSteeringConsumedSignal; /** * Carries a protocol {@link SessionAction} produced by an agent. The host * dispatches the action through the state manager after routing via * {@link IAgentActionSignal.parentToolCallId} (if set). * * Agents are responsible for populating `session` and any `turnId` / * `partId` fields on the action. */ export interface IAgentActionSignal { readonly kind: "action"; /** Top-level session URI. For inner subagent events this is the parent session — see {@link parentToolCallId}. */ readonly session: URI; /** Protocol action to dispatch. */ readonly action: SessionAction; /** If set, route the action to the subagent session belonging to this tool call. */ readonly parentToolCallId?: string; } /** * A tool has finished collecting parameters and needs the host to decide * whether it should run (or, mid-execution, re-confirm). The host applies * auto-approval logic over {@link permissionKind} / {@link permissionPath} * (see `SessionPermissionManager.getAutoApproval`) and then dispatches the * appropriate `SessionToolCallReady` action — with confirmation options * baked in when the user must approve, or with `confirmed: NotNeeded` when * the host auto-approved. * * Kept as a non-action signal because the host owns this approval policy; * the agent only describes the tool call and the kind of permission being * requested. The {@link state} field carries the protocol-shaped tool-call * state and is dispatched verbatim into the action. */ export interface IAgentToolPendingConfirmationSignal { readonly kind: "pending_confirmation"; readonly session: URI; /** Protocol-shaped pending-confirmation state, dispatched verbatim into `SessionToolCallReady`. */ readonly state: ToolCallPendingConfirmationState; /** Host-only auto-approval kind (not part of the dispatched action). */ readonly permissionKind?: "shell" | "write" | "mcp" | "read" | "url" | "custom-tool" | "hook" | "memory"; /** Host-only auto-approval path target (not part of the dispatched action). */ readonly permissionPath?: string; /** * If set, the tool call belongs to the subagent rooted at this * parent tool call. Used by the host to route the resulting * `SessionToolCallReady` to the subagent session — otherwise the * action would land on the parent session, where there is no * matching `SessionToolCallStart`. */ readonly parentToolCallId?: string; } /** * A subagent was spawned by a tool call. The host creates a child session * silently and routes subsequent inner-tool events to it. * * Kept as a non-action signal because subagent session creation has no * protocol action — it's a host-side composition primitive. */ export interface IAgentSubagentStartedSignal { readonly kind: "subagent_started"; readonly session: URI; readonly toolCallId: string; readonly agentName: string; readonly agentDisplayName: string; readonly agentDescription?: string; } /** * A subagent has finished — either successfully or with an error. The host * uses this to tear down the child session after all of its events have been * routed. The parent tool call completing is not a reliable signal for this * because background subagents (e.g. Copilot's `mode: background` task) keep * emitting events after their parent tool call returns immediately. */ export interface IAgentSubagentCompletedSignal { readonly kind: "subagent_completed"; readonly session: URI; readonly toolCallId: string; } /** A steering message was consumed (sent to the model). */ export interface IAgentSteeringConsumedSignal { readonly kind: "steering_consumed"; readonly session: URI; readonly id: string; } export declare namespace AgentSession { /** * Creates a session URI from a provider name and raw session ID. * The URI scheme is the provider name (e.g., `copilot:/`). */ function uri(provider: AgentProvider, rawSessionId: string): URI; /** * Extracts the raw session ID from a session URI (the path without leading slash). * Accepts both a URI object and a URI string. */ function id(session: URI | string): string; /** * Extracts the provider name from a session URI scheme. * Accepts both a URI object and a URI string. */ function provider(session: URI | string): AgentProvider | undefined; } /** * Implemented by each agent backend (e.g. Copilot SDK). * The {@link IAgentService} dispatches to the appropriate agent based on * the agent id. */ export interface IAgent { /** Unique identifier for this provider (e.g. `'copilot'`). */ readonly id: AgentProvider; /** Fires when the provider streams progress for a session. */ readonly onDidSessionProgress: Event; /** * Fires once when a previously * {@link IAgentCreateSessionResult.provisional} session has been * materialized — i.e. its SDK session, worktree (if any), and on-disk * metadata are all in place. The {@link IAgentService} uses this event * to fire the deferred `sessionAdded` notification with the now-final * summary. */ readonly onDidMaterializeSession?: Event; /** Create a new session. Returns server-owned session metadata. */ createSession(config?: IAgentCreateSessionConfig): Promise; /** Resolve the dynamic configuration schema for creating a session. */ resolveSessionConfig(params: IAgentResolveSessionConfigParams): Promise; /** Return dynamic completions for a session configuration property. */ sessionConfigCompletions(params: IAgentSessionConfigCompletionsParams): Promise; /** Send a user message into an existing session. */ sendMessage(session: URI, prompt: string, attachments?: readonly MessageAttachment[], turnId?: string): Promise; /** * Called when the session's pending (steering) message changes. * The agent harness decides how to react — e.g. inject steering * mid-turn via `mode: 'immediate'`. * * Queued messages are consumed on the server side and are not * forwarded to the agent; `queuedMessages` will always be empty. */ setPendingMessages?(session: URI, steeringMessage: PendingMessage | undefined, queuedMessages: readonly PendingMessage[]): void; /** * Retrieve the reconstructed turns for a session, used when restoring * sessions from persistent storage. Each agent owns the conversion from * its SDK-specific event log to protocol {@link Turn}s, including * subagent sessions (callers pass the subagent URI to retrieve the * child session's turns). */ getSessionMessages(session: URI): Promise; /** Dispose a session, freeing resources. */ disposeSession(session: URI): Promise; /** Abort the current turn, stopping any in-flight processing. */ abortSession(session: URI): Promise; /** Change the model for an existing session. */ changeModel(session: URI, model: ModelSelection): Promise; /** Respond to a pending permission request from the SDK. */ respondToPermissionRequest(requestId: string, approved: boolean): void; /** Respond to a pending user input request from the SDK's ask_user tool. */ respondToUserInputRequest(requestId: string, response: SessionInputResponseKind, answers?: Record): void; /** Return the descriptor for this agent. */ getDescriptor(): IAgentDescriptor; /** Available models from this provider. */ readonly models: IObservable; /** List persisted sessions from this provider. */ listSessions(): Promise; /** Retrieve metadata for a single persisted session, without enumerating the provider catalog. */ getSessionMetadata?(session: URI): Promise; /** Declare protected resources this agent requires auth for (RFC 9728). */ getProtectedResources(): ProtectedResourceMetadata[]; /** * Fires when the agent's host-owned customizations change * (loading state, resolution results, etc.), so infrastructure * can republish {@link AgentInfo} and session customization state. */ readonly onDidCustomizationsChange?: Event; /** * Returns the host-owned customization refs this agent currently exposes. * * Used to publish baseline customization metadata on {@link AgentInfo}. */ getCustomizations?(): readonly CustomizationRef[]; /** * Returns the effective customization list for a session, including * source, enablement, and loading/error status. */ getSessionCustomizations?(session: URI): Promise; /** * Authenticate for a specific resource. Returns true if accepted. * The `resource` matches {@link IAuthorizationProtectedResourceMetadata.resource}. */ authenticate(resource: string, token: string): Promise; /** * Truncate a session's history. If `turnId` is provided, keeps turns up to * and including that turn. If omitted, all turns are removed. * Optional — not all providers support truncation. */ truncateSession?(session: URI, turnId?: string): Promise; /** * Notifies the provider that a session's archived state has changed. * Providers may use this to clean up or restore per-session resources * (for example, removing a session-owned worktree on archive and * recreating it on unarchive). Optional. */ onArchivedChanged?(session: URI, isArchived: boolean): Promise; /** * Receives client-provided customization refs and syncs them (e.g. copies * plugin files to local storage). Returns per-customization status with * local plugin directories. * * The agent MAY defer a client restart until all active sessions are idle. */ setClientCustomizations(clientId: string, customizations: CustomizationRef[], progress?: (results: ISyncedCustomization[]) => void): Promise; /** * Receives client-provided tool definitions to make available in a * specific session. The agent registers these as custom tools so the * LLM can call them; execution is routed back to the owning client. * * Always called on `activeClientChanged`, even with an empty array, * to clear a previous client's tools. * * @param session The session URI this tool set applies to. * @param clientId The client that owns these tools. * @param tools The tool definitions (full replacement). */ setClientTools(session: URI, clientId: string, tools: ToolDefinition[]): void; /** * Called when a client completes a client-provided tool call. * Resolves the tool handler's deferred promise so the SDK can continue. * * @param session The session the tool call belongs to. * @param toolCallId The id of the tool call being completed. * @param result The result of the tool call. */ onClientToolCallComplete(session: URI, toolCallId: string, result: ToolCallResult): void; /** * Notifies the agent that a customization has been toggled on or off. * The agent MAY restart its client before the next message is sent. */ setCustomizationEnabled(uri: string, enabled: boolean): void; /** Gracefully shut down all sessions. */ shutdown(): Promise; /** Dispose this provider and all its resources. */ dispose(): void; } /** * Consumer-facing connection to an agent host. Session handlers, terminal * contributions, and other features program against this interface. * * Implementations wrap an {@link IAgentService} and layer subscription * management and optimistic write-ahead on top. */ export interface IAgentConnection { readonly _serviceBrand: undefined; readonly clientId: string; readonly rootState: IAgentSubscription; getSubscription(kind: T, resource: URI): IReference>; getSubscriptionUnmanaged(kind: T, resource: URI): IAgentSubscription | undefined; dispatch(action: SessionAction | TerminalAction | IRootConfigChangedAction): void; readonly onDidNotification: Event; readonly onDidAction: Event; authenticate(params: AuthenticateParams): Promise; listSessions(): Promise; createSession(config?: IAgentCreateSessionConfig): Promise; resolveSessionConfig(params: IAgentResolveSessionConfigParams): Promise; sessionConfigCompletions(params: IAgentSessionConfigCompletionsParams): Promise; completions(params: CompletionsParams): Promise; /** * Trigger characters announced by the connected agent host that should * cause the client to issue a `completions` request when typed in a * user-message input. Resolves once on first request and is cached. */ getCompletionTriggerCharacters(): Promise; disposeSession(session: URI): Promise; createTerminal(params: CreateTerminalParams): Promise; disposeTerminal(terminal: URI): Promise; resourceList(uri: URI): Promise; resourceRead(uri: URI): Promise; resourceWrite(params: ResourceWriteParams): Promise; resourceCopy(params: ResourceCopyParams): Promise; resourceDelete(params: ResourceDeleteParams): Promise; resourceMove(params: ResourceMoveParams): Promise; }