src/vs/platform/agentHost/node/shared/agentServerToolHost.ts

144 LOC · 140 covered · 4 uncovered · 11 ranges · 949 concepts · 5 introducers · 499 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- agentServerToolHost.ts ×5
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 type { IAgentServerToolHost } from '../../common/agentServerTools.js';
7 > import { ActionType } from '../../common/state/protocol/common/actions.js';
8 > import type { StringOrMarkdown, ToolDefinition, URI } from '../../common/state/sessionState.js';
9 > import type { AgentHostStateManager } from '../agentHostStateManager.js';
10 >
11 > /**
12 > * Result of a server tool, passed to {@link IServerToolGroup.getDisplay} so the
13 > * owning group can tailor its past-tense message to what the tool returned
14 > * (for example a count parsed from the textual result). Absent while the tool
15 > * is still running.
16 > */
17 > export interface IServerToolDisplayResult {
18 > /** The textual tool result (the string the group's `execute` returned). */
19 > readonly text?: string;
20 > /** Whether the tool completed successfully. */
21 > readonly success: boolean;
22 > }
23 >
24 > /**
25 > * Display strings for a server tool, authored by the group that owns the tool
26 > * so every provider renders it identically (instead of each provider's display
27 > * layer re-deriving the strings from the tool name). Each field is optional: a
28 > * provider uses the returned value where present and falls back to its own
29 > * generic display otherwise.
30 > */
31 > export interface IServerToolDisplay {
32 > /** Human-readable tool name (e.g. "List Comments"). */
33 > readonly displayName?: string;
34 > /** Present-tense message shown while the tool runs (e.g. "Checking comments"). */
35 > readonly invocationMessage?: StringOrMarkdown;
36 > /** Past-tense message shown once the tool completes (e.g. "Checked 3 comments"). */
37 > readonly pastTenseMessage?: StringOrMarkdown;
38 > }
39 >
40 > /**
41 > * A group of related server tools owned and executed by the agent host. Each
42 > * group bundles the {@link ToolDefinition}s it advertises with an executor
43 > * that runs one of its tools by name against the session's state.
44 > *
45 > * Groups are the unit of extension and are **contributed from outside** — they
46 > * are passed to {@link AgentServerToolHost} at construction (startup), so this
47 > * module stays provider- and feature-agnostic (it knows nothing about
48 > * feedback, annotations, etc.). The feedback group, for example, lives in
49 > * `agentFeedbackServerTools.ts` and is wired in by the agent host. Everything
50 > * downstream — advertising, the Claude in-process MCP server and allow-list,
51 > * and the Copilot SDK tools and auto-approval — derives from the host's
52 > * contributed groups, so no provider code changes are needed to add a group.
53 > */
54 > export interface IServerToolGroup {
55 > /** Tool definitions this group advertises on the session's `serverTools`. */
56 > readonly definitions: readonly ToolDefinition[];
57 > /**
58 > * Whether {@link toolName} (one of this group's {@link definitions}) must be
59 > * confirmed by the user before it runs. Providers exclude such tools from
60 > * their server-tool auto-approve lists so the call surfaces a confirmation.
61 > * Absent or `false` means the tool is auto-approved like every other server
62 > * tool.
63 > */
64 > requiresConfirmation?(toolName: string): boolean;
65 > /**
66 > * Executes {@link toolName} (one of this group's {@link definitions})
67 > * against the session's state, dispatching any resulting actions through
68 > * the state manager (the single writer), and returns the textual tool
69 > * result.
70 > *
71 > * @throws if {@link toolName} is not owned by this group or the arguments
72 > * are invalid.
73 > */
74 > execute(stateManager: AgentHostStateManager, sessionUri: URI, toolName: string, rawArgs: unknown): string | Promise<string>;
75 >
76 > /**
77 > * Display strings for {@link toolName} (one of this group's
78 > * {@link definitions}), authored here so every provider renders this tool
79 > * identically rather than re-deriving the strings from the tool name. The
80 > * caller passes the parsed tool arguments and, once the tool has completed,
81 > * its {@link IServerToolDisplayResult result}. Returns `undefined` (or
82 > * individually-absent fields) to let the provider fall back to its generic
83 > * display. Optional: a group without bespoke display omits this.
84 > *
85 > * `toolName` is the bare tool name (the provider strips any transport
86 > * prefix such as Claude's `mcp__<server>__` before calling).
87 > */
88 > getDisplay?(toolName: string, args: unknown, result?: IServerToolDisplayResult): IServerToolDisplay | undefined;
89 > }
90 >
91 > /**
92 > * Bridges the agent host's server tools to the authoritative state tree.
93 > * Agents execute a server tool by name; the host routes it to the owning
94 > * {@link IServerToolGroup}, which reads the relevant session state, applies the
95 > * tool, dispatches any resulting actions through the state manager (the single
96 > * writer), and returns the textual tool result to the agent.
97 > *
98 > * The groups are contributed at construction; the host itself is generic and
99 > * has no knowledge of any specific tool group. It also advertises every server
100 > * tool on a session's {@link SessionState.serverTools} so clients see them as
101 > * server-provided.
102 > */
103 > export class AgentServerToolHost implements IAgentServerToolHost {
104 >
105 > private readonly _groupByToolName = new Map<string, IServerToolGroup>();
106 >
107 > readonly definitions: readonly ToolDefinition[];
108 > readonly toolNames: readonly string[];
109 >
110 > constructor(
111 > private readonly _stateManager: AgentHostStateManager, agentServerToolHost.ts ×2
112 > groups: readonly IServerToolGroup[],
113 > ) {
114 > for (const group of groups) {
115 > for (const def of group.definitions) {
116 > if (this._groupByToolName.has(def.name)) {
117 throw new Error(`Duplicate server tool registered: ${def.name}`);
118 }
119 > this._groupByToolName.set(def.name, group); agentServerToolHost.ts ×2
120 > }
121 > }
122 > this.definitions = groups.flatMap(group => group.definitions);
123 > this.toolNames = this.definitions.map(def => def.name);
124 > }
126 > advertise(sessionUri: URI): void {
127 > this._stateManager.dispatchServerAction(sessionUri, { reducer.ts ×1
128 > type: ActionType.SessionServerToolsChanged,
129 > tools: [...this.definitions],
130 > });
131 > }
133 > requiresConfirmation(toolName: string): boolean {
134 > return this._groupByToolName.get(toolName)?.requiresConfirmation?.(toolName) ?? false; agentFeedbackServerTools.ts ×1
135 > }
137 > executeTool(sessionUri: URI, toolName: string, rawArgs: unknown): string | Promise<string> {
138 > const group = this._groupByToolName.get(toolName); reducer.ts ×7
139 > if (!group) {
140 throw new Error(`Unknown server tool: ${toolName}`);
141 }
142 > return group.execute(this._stateManager, sessionUri, toolName, rawArgs); reducer.ts ×7
143 > }