mcpTaskManager.ts ×13

Frontier kind: Code frontier

unlabeled · c_167885351095

98 tests · 28822 LOC · 141 files · introduces 0 tests · 394 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
21 ranges394 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2754 ranges28822 lines · 141 files · Browse complete extent
All tests (intent)
98 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

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 native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 394 introduced LOC across 21 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/services/output/common/output.ts 296 introduced LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- output.ts
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, Emitter } from '../../../../base/common/event.js';
7 > import { Registry } from '../../../../platform/registry/common/platform.js';
8 > import { URI } from '../../../../base/common/uri.js';
9 > import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
10 > import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
11 > import { LogLevel } from '../../../../platform/log/common/log.js';
12 > import { Range } from '../../../../editor/common/core/range.js';
13 > import { Disposable } from '../../../../base/common/lifecycle.js';
14 >
15 > /**
16 > * Mime type used by the output editor.
17 > */
18 > export const OUTPUT_MIME = 'text/x-code-output';
19 >
20 > /**
21 > * Id used by the output editor.
22 > */
23 > export const OUTPUT_MODE_ID = 'Log';
24 >
25 > /**
26 > * Mime type used by the log output editor.
27 > */
28 > export const LOG_MIME = 'text/x-code-log-output';
29 >
30 > /**
31 > * Id used by the log output editor.
32 > */
33 > export const LOG_MODE_ID = 'log';
34 >
35 > /**
36 > * Output view id
37 > */
38 > export const OUTPUT_VIEW_ID = 'workbench.panel.output';
39 >
40 > export const CONTEXT_IN_OUTPUT = new RawContextKey<boolean>('inOutput', false);
41 > export const CONTEXT_ACTIVE_FILE_OUTPUT = new RawContextKey<boolean>('activeLogOutput', false);
42 > export const CONTEXT_ACTIVE_LOG_FILE_OUTPUT = new RawContextKey<boolean>('activeLogOutput.isLog', false);
43 > export const CONTEXT_ACTIVE_OUTPUT_LEVEL_SETTABLE = new RawContextKey<boolean>('activeLogOutput.levelSettable', false);
44 > export const CONTEXT_ACTIVE_OUTPUT_LEVEL = new RawContextKey<string>('activeLogOutput.level', '');
45 > export const CONTEXT_ACTIVE_OUTPUT_LEVEL_IS_DEFAULT = new RawContextKey<boolean>('activeLogOutput.levelIsDefault', false);
46 > export const CONTEXT_OUTPUT_SCROLL_LOCK = new RawContextKey<boolean>(`outputView.scrollLock`, false);
47 > export const ACTIVE_OUTPUT_CHANNEL_CONTEXT = new RawContextKey<string>('activeOutputChannel', '');
48 > export const SHOW_TRACE_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.trace', true);
49 > export const SHOW_DEBUG_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.debug', true);
50 > export const SHOW_INFO_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.info', true);
51 > export const SHOW_WARNING_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.warning', true);
52 > export const SHOW_ERROR_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.error', true);
53 > export const OUTPUT_FILTER_FOCUS_CONTEXT = new RawContextKey<boolean>('outputFilterFocus', false);
54 > export const HIDE_CATEGORY_FILTER_CONTEXT = new RawContextKey<string>('output.filter.categories', '');
55 >
56 > export interface IOutputViewFilters {
57 > readonly onDidChange: Event<void>;
58 > text: string;
59 > readonly includePatterns: string[];
60 > readonly excludePatterns: string[];
61 > trace: boolean;
62 > debug: boolean;
63 > info: boolean;
64 > warning: boolean;
65 > error: boolean;
66 > categories: string;
67 > toggleCategory(category: string): void;
68 > hasCategory(category: string): boolean;
69 > }
70 >
71 > export const IOutputService = createDecorator<IOutputService>('outputService');
72 >
73 > /**
74 > * The output service to manage output from the various processes running.
75 > */
76 > export interface IOutputService {
77 > readonly _serviceBrand: undefined;
78 >
79 > /**
80 > * Output view filters.
81 > */
82 > readonly filters: IOutputViewFilters;
83 >
84 > /**
85 > * Given the channel id returns the output channel instance.
86 > * Channel should be first registered via OutputChannelRegistry.
87 > */
88 > getChannel(id: string): IOutputChannel | undefined;
89 >
90 > /**
91 > * Given the channel id returns the registered output channel descriptor.
92 > */
93 > getChannelDescriptor(id: string): IOutputChannelDescriptor | undefined;
94 >
95 > /**
96 > * Returns an array of all known output channels descriptors.
97 > */
98 > getChannelDescriptors(): IOutputChannelDescriptor[];
99 >
100 > /**
101 > * Returns the currently active channel.
102 > * Only one channel can be active at a given moment.
103 > */
104 > getActiveChannel(): IOutputChannel | undefined;
105 >
106 > /**
107 > * Show the channel with the passed id.
108 > */
109 > showChannel(id: string, preserveFocus?: boolean): Promise<void>;
110 >
111 > /**
112 > * Allows to register on active output channel change.
113 > */
114 > readonly onActiveOutputChannel: Event<string>;
115 >
116 > /**
117 > * Register a compound log channel with the given channels.
118 > */
119 > registerCompoundLogChannel(channels: IOutputChannelDescriptor[]): string;
120 >
121 > /**
122 > * Save the logs to a file.
123 > */
124 > saveOutputAs(outputPath?: URI, ...channels: IOutputChannelDescriptor[]): Promise<void>;
125 >
126 > /**
127 > * Checks if the log level can be set for the given channel.
128 > * @param channel
129 > */
130 > canSetLogLevel(channel: IOutputChannelDescriptor): boolean;
131 >
132 > /**
133 > * Returns the log level for the given channel.
134 > * @param channel
135 > */
136 > getLogLevel(channel: IOutputChannelDescriptor): LogLevel | undefined;
137 >
138 > /**
139 > * Sets the log level for the given channel.
140 > * @param channel
141 > * @param logLevel
142 > */
143 > setLogLevel(channel: IOutputChannelDescriptor, logLevel: LogLevel): void;
144 > }
145 >
146 > export enum OutputChannelUpdateMode {
147 > Append = 1,
148 > Replace,
149 > Clear
150 > }
151 >
152 > export interface ILogEntry {
153 > readonly range: Range;
154 > readonly timestamp: number;
155 > readonly timestampRange: Range;
156 > readonly logLevel: LogLevel;
157 > readonly logLevelRange: Range;
158 > readonly category: string | undefined;
159 > }
160 >
161 > export interface IOutputChannel {
162 >
163 > /**
164 > * Identifier of the output channel.
165 > */
166 > readonly id: string;
167 >
168 > /**
169 > * Label of the output channel to be displayed to the user.
170 > */
171 > readonly label: string;
172 >
173 > /**
174 > * URI of the output channel.
175 > */
176 > readonly uri: URI;
177 >
178 > /**
179 > * Log entries of the output channel.
180 > */
181 > getLogEntries(): readonly ILogEntry[];
182 >
183 > /**
184 > * Appends output to the channel.
185 > */
186 > append(output: string): void;
187 >
188 > /**
189 > * Clears all received output for this channel.
190 > */
191 > clear(): void;
192 >
193 > /**
194 > * Replaces the content of the channel with given output
195 > */
196 > replace(output: string): void;
197 >
198 > /**
199 > * Update the channel.
200 > */
201 > update(mode: OutputChannelUpdateMode.Append): void;
202 > update(mode: OutputChannelUpdateMode, till: number): void;
203 >
204 > /**
205 > * Disposes the output channel.
206 > */
207 > dispose(): void;
208 > }
209 >
210 > export const Extensions = {
211 > OutputChannels: 'workbench.contributions.outputChannels'
212 > };
213 >
214 > export interface IOutputChannelDescriptor {
215 > id: string;
216 > label: string;
217 > log: boolean;
218 > languageId?: string;
219 > source?: IOutputContentSource | ReadonlyArray<IOutputContentSource>;
220 > extensionId?: string;
221 > user?: boolean;
222 > }
223 >
224 > export interface ISingleSourceOutputChannelDescriptor extends IOutputChannelDescriptor {
225 > source: IOutputContentSource;
226 > }
227 >
228 > export interface IMultiSourceOutputChannelDescriptor extends IOutputChannelDescriptor {
229 > source: ReadonlyArray<IOutputContentSource>;
230 > }
231 >
232 > export function isSingleSourceOutputChannelDescriptor(descriptor: IOutputChannelDescriptor): descriptor is ISingleSourceOutputChannelDescriptor {
233 return !!descriptor.source && !Array.isArray(descriptor.source);
234 }
235 > output.ts
236 > export function isMultiSourceOutputChannelDescriptor(descriptor: IOutputChannelDescriptor): descriptor is IMultiSourceOutputChannelDescriptor {
237 return Array.isArray(descriptor.source);
238 }
239 > output.ts
240 > export interface IOutputContentSource {
241 > readonly name?: string;
242 > readonly resource: URI;
243 > }
244 >
245 > export interface IOutputChannelRegistry {
246 >
247 > readonly onDidRegisterChannel: Event<string>;
248 > readonly onDidRemoveChannel: Event<IOutputChannelDescriptor>;
249 > readonly onDidUpdateChannelSources: Event<IMultiSourceOutputChannelDescriptor>;
250 >
251 > /**
252 > * Make an output channel known to the output world.
253 > */
254 > registerChannel(descriptor: IOutputChannelDescriptor): void;
255 >
256 > /**
257 > * Update the files for the given output channel.
258 > */
259 > updateChannelSources(id: string, sources: IOutputContentSource[]): void;
260 >
261 > /**
262 > * Returns the list of channels known to the output world.
263 > */
264 > getChannels(): IOutputChannelDescriptor[];
265 >
266 > /**
267 > * Returns the channel with the passed id.
268 > */
269 > getChannel(id: string): IOutputChannelDescriptor | undefined;
270 >
271 > /**
272 > * Remove the output channel with the passed id.
273 > */
274 > removeChannel(id: string): void;
275 > }
276 >
277 > class OutputChannelRegistry extends Disposable implements IOutputChannelRegistry {
278 > private channels = new Map<string, IOutputChannelDescriptor>();
279 >
280 > private readonly _onDidRegisterChannel = this._register(new Emitter<string>());
281 > readonly onDidRegisterChannel = this._onDidRegisterChannel.event;
282 >
283 > private readonly _onDidRemoveChannel = this._register(new Emitter<IOutputChannelDescriptor>());
284 > readonly onDidRemoveChannel = this._onDidRemoveChannel.event;
285 >
286 > private readonly _onDidUpdateChannelFiles = this._register(new Emitter<IMultiSourceOutputChannelDescriptor>());
287 > readonly onDidUpdateChannelSources = this._onDidUpdateChannelFiles.event;
288 >
289 > public registerChannel(descriptor: IOutputChannelDescriptor): void {
290 if (!this.channels.has(descriptor.id)) {
291 this.channels.set(descriptor.id, descriptor);
293 }
294 }
295 > output.ts
296 > public getChannels(): IOutputChannelDescriptor[] {
297 const result: IOutputChannelDescriptor[] = [];
298 this.channels.forEach(value => result.push(value));
299 return result;
300 }
301 > output.ts
302 > public getChannel(id: string): IOutputChannelDescriptor | undefined {
303 return this.channels.get(id);
304 }
305 > output.ts
306 > public updateChannelSources(id: string, sources: IOutputContentSource[]): void {
307 const channel = this.channels.get(id);
308 if (channel && isMultiSourceOutputChannelDescriptor(channel)) {
311 }
312 }
313 > output.ts
314 > public removeChannel(id: string): void {
315 const channel = this.channels.get(id);
316 if (channel) {
319 }
320 }
321 > } output.ts
322 >
323 > Registry.add(Extensions.OutputChannels, new OutputChannelRegistry());
src/vs/workbench/contrib/mcp/common/mcpTaskManager.ts 98 introduced LOC · 13 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- mcpTaskManager.ts
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 { disposableTimeout } from '../../../../base/common/async.js';
7 > import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
8 > import { CancellationError } from '../../../../base/common/errors.js';
9 > import { Emitter } from '../../../../base/common/event.js';
10 > import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
11 > import { generateUuid } from '../../../../base/common/uuid.js';
12 > import type { McpServerRequestHandler } from './mcpServerRequestHandler.js';
13 > import { McpError } from './mcpTypes.js';
14 > import { MCP } from './modelContextProtocol.js';
15 >
16 > export interface IMcpTaskInternal extends IDisposable {
17 > readonly id: string;
18 > onDidUpdateState(task: MCP.Task): void;
19 > setHandler(handler: McpServerRequestHandler | undefined): void;
20 > }
21 >
22 > interface TaskEntry extends IDisposable {
23 > task: MCP.Task;
24 > result?: MCP.Result;
25 > error?: MCP.Error;
26 > cts: CancellationTokenSource;
27 > /** Time when the task was created (client time), used to calculate TTL expiration */
28 > createdAtTime: number;
29 > /** Promise that resolves when the task execution completes */
30 > executionPromise: Promise<void>;
31 > }
32 >
33 > /**
34 > * Manages in-memory task state for server-side MCP tasks (sampling and elicitation).
35 > * Also tracks client-side tasks to survive handler reconnections.
36 > * Lifecycle is tied to the McpServer instance.
37 > */
38 > export class McpTaskManager extends Disposable {
39 private readonly _serverTasks = this._register(new DisposableMap<string, TaskEntry>());
40 private readonly _clientTasks = this._register(new DisposableMap<string, IMcpTaskInternal>());
41 private readonly _onDidUpdateTask = this._register(new Emitter<MCP.Task>());
42 public readonly onDidUpdateTask = this._onDidUpdateTask.event;
44 > /**
45 > * Attach a new handler to this task manager.
46 > * Updates all client tasks to use the new handler.
47 > */
48 > setHandler(handler: McpServerRequestHandler | undefined): void {
49 for (const task of this._clientTasks.values()) {
50 task.setHandler(handler);
51 }
52 }
54 > /**
55 > * Get a client task by ID for status notification handling.
56 > */
57 > getClientTask(taskId: string): IMcpTaskInternal | undefined {
58 return this._clientTasks.get(taskId);
59 }
61 > /**
62 > * Track a new client task.
63 > */
64 > adoptClientTask(task: IMcpTaskInternal): void {
65 this._clientTasks.set(task.id, task);
66 }
68 > /**
69 > * Untracks a client task.
70 > */
71 > abandonClientTask(taskId: string): void {
72 this._clientTasks.deleteAndDispose(taskId);
73 }
75 > /**
76 > * Create a new task and execute it asynchronously.
77 > * Returns the task immediately while execution continues in the background.
78 > */
79 > public createTask<TResult extends MCP.Result>(
80 ttl: number | null,
81 executor: (token: CancellationToken) => Promise<TResult>
122 return { task };
123 }
125 > /**
126 > * Execute a task asynchronously and update its state.
127 > */
128 > private async _executeTask<TResult extends MCP.Result>(
129 taskId: string,
130 executor: (token: CancellationToken) => Promise<TResult>,
156 }
157 }
159 > /**
160 > * Update task status and optionally store result or error.
161 > */
162 > private _updateTaskStatus(
163 taskId: string,
164 status: MCP.TaskStatus,
187 this._onDidUpdateTask.fire({ ...entry.task });
188 }
190 > /**
191 > * Get the current state of a task.
192 > * Returns an error if the task doesn't exist or has expired.
193 > */
194 > public getTask(taskId: string): MCP.GetTaskResult {
195 const entry = this._serverTasks.get(taskId);
196 if (!entry) {
200 return { ...entry.task };
201 }
203 > /**
204 > * Get the result of a completed task.
205 > * Blocks until the task completes if it's still in progress.
206 > */
207 > public async getTaskResult(taskId: string): Promise<MCP.GetTaskPayloadResult> {
208 const entry = this._serverTasks.get(taskId);
209 if (!entry) {
231 return updatedEntry.result;
232 }
234 > /**
235 > * Cancel a task.
236 > */
237 > public cancelTask(taskId: string): MCP.CancelTaskResult {
238 const entry = this._serverTasks.get(taskId);
239 if (!entry) {
252 return { ...entry.task };
253 }
255 > /**
256 > * List all tasks.
257 > */
258 > public listTasks(): MCP.ListTasksResult {
259 const tasks: MCP.Task[] = [];
260