1
>
/*---------------------------------------------------------------------------------------------
chatDebugService.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 } from '../../../../base/common/event.js';
7
>
import { IDisposable } from '../../../../base/common/lifecycle.js';
8
>
import { URI } from '../../../../base/common/uri.js';
9
>
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10
>
import { CancellationToken } from '../../../../base/common/cancellation.js';
11
>
12
>
/**
13
>
* The severity level of a chat debug log event.
14
>
*/
15
>
export enum ChatDebugLogLevel {
16
>
Trace = 0,
17
>
Info = 1,
18
>
Warning = 2,
19
>
Error = 3
20
>
}
21
>
22
>
/**
23
>
* The result of a hook execution.
24
>
*/
25
>
export enum ChatDebugHookResult {
26
>
/** The hook executed successfully (exit code 0). */
27
>
Success = 0,
28
>
/** The hook returned a blocking error (exit code 2). */
29
>
Error = 1,
30
>
/** The hook returned a non-blocking warning (other non-zero exit codes). */
31
>
NonBlockingError = 2
32
>
}
33
>
34
>
/**
35
>
* Common properties shared by all chat debug event types.
36
>
*/
37
>
export interface IChatDebugEventCommon {
38
>
readonly id?: string;
39
>
readonly sessionResource: URI;
40
>
readonly created: Date;
41
>
readonly parentEventId?: string;
42
>
}
43
>
44
>
/**
45
>
* A tool call event in the chat debug log.
46
>
*/
47
>
export interface IChatDebugToolCallEvent extends IChatDebugEventCommon {
48
>
readonly kind: 'toolCall';
49
>
readonly toolName: string;
50
>
readonly toolCallId?: string;
51
>
readonly input?: string;
52
>
readonly output?: string;
53
>
readonly result?: 'success' | 'error';
54
>
readonly durationInMillis?: number;
55
>
}
56
>
57
>
/**
58
>
* A model turn event representing an LLM request/response.
59
>
*/
60
>
export interface IChatDebugModelTurnEvent extends IChatDebugEventCommon {
61
>
readonly kind: 'modelTurn';
62
>
readonly model?: string;
63
>
readonly requestName?: string;
64
>
readonly inputTokens?: number;
65
>
readonly outputTokens?: number;
66
>
readonly cachedTokens?: number;
67
>
readonly totalTokens?: number;
68
>
readonly copilotUsageNanoAiu?: number;
69
>
readonly durationInMillis?: number;
70
>
}
71
>
72
>
/**
73
>
* A generic log event for unstructured or miscellaneous messages.
74
>
*/
75
>
export interface IChatDebugGenericEvent extends IChatDebugEventCommon {
76
>
readonly kind: 'generic';
77
>
readonly name: string;
78
>
readonly details?: string;
79
>
readonly level: ChatDebugLogLevel;
80
>
readonly category?: string;
81
>
}
82
>
83
>
/**
84
>
* A subagent invocation event, representing a spawned sub-agent within a session.
85
>
*/
86
>
export interface IChatDebugSubagentInvocationEvent extends IChatDebugEventCommon {
87
>
readonly kind: 'subagentInvocation';
88
>
readonly agentName: string;
89
>
readonly description?: string;
90
>
readonly status?: 'running' | 'completed' | 'failed';
91
>
readonly durationInMillis?: number;
92
>
readonly toolCallCount?: number;
93
>
readonly modelTurnCount?: number;
94
>
}
95
>
96
>
/**
97
>
* A named section within a user message or agent response.
98
>
*/
99
>
export interface IChatDebugMessageSection {
100
>
readonly name: string;
101
>
readonly content: string;
102
>
}
103
>
104
>
/**
105
>
* A user message event, representing the full prompt sent by the user.
106
>
*/
107
>
export interface IChatDebugUserMessageEvent extends IChatDebugEventCommon {
108
>
readonly kind: 'userMessage';
109
>
readonly message: string;
110
>
readonly sections: readonly IChatDebugMessageSection[];
111
>
}
112
>
113
>
/**
114
>
* An agent response event, representing the agent's response.
115
>
*/
116
>
export interface IChatDebugAgentResponseEvent extends IChatDebugEventCommon {
117
>
readonly kind: 'agentResponse';
118
>
readonly message: string;
119
>
readonly sections: readonly IChatDebugMessageSection[];
120
>
}
121
>
122
>
/**
123
>
* Union of all internal chat debug event types.
124
>
*/
125
>
export type IChatDebugEvent = IChatDebugToolCallEvent | IChatDebugModelTurnEvent | IChatDebugGenericEvent | IChatDebugSubagentInvocationEvent | IChatDebugUserMessageEvent | IChatDebugAgentResponseEvent;
126
>
127
>
export const IChatDebugService = createDecorator<IChatDebugService>('chatDebugService');
128
>
129
>
/**
130
>
* Service for collecting and exposing chat debug events.
131
>
* Internal components can log events,
132
>
* and the debug editor pane can display them.
133
>
*/
134
>
export interface IChatDebugService extends IDisposable {
135
>
readonly _serviceBrand: undefined;
136
>
137
>
/**
138
>
* Fired when a new event is added.
139
>
*/
140
>
readonly onDidAddEvent: Event<IChatDebugEvent>;
141
>
142
>
/**
143
>
* Fired when provider events are cleared for a session (before re-invoking providers).
144
>
*/
145
>
readonly onDidClearProviderEvents: Event<URI>;
146
>
147
>
/**
148
>
* Fired when a debug session ends (see {@link endSession}), so providers
149
>
* can release any per-session resources (e.g. live file watchers).
150
>
*/
151
>
readonly onDidEndSession: Event<URI>;
152
>
153
>
/**
154
>
* Log a generic event to the debug service.
155
>
*/
156
>
log(sessionResource: URI, name: string, details?: string, level?: ChatDebugLogLevel, options?: { id?: string; category?: string; parentEventId?: string }): void;
157
>
158
>
/**
159
>
* Add a typed event to the debug service.
160
>
*/
161
>
addEvent(event: IChatDebugEvent): void;
162
>
163
>
/**
164
>
* Add an event sourced from an external provider.
165
>
* These events are cleared before re-invoking providers to avoid duplicates.
166
>
*/
167
>
addProviderEvent(event: IChatDebugEvent): void;
168
>
169
>
/**
170
>
* Get all events for a specific session.
171
>
*/
172
>
getEvents(sessionResource?: URI): readonly IChatDebugEvent[];
173
>
174
>
/**
175
>
* Get all session resources that have logged events.
176
>
*/
177
>
getSessionResources(): readonly URI[];
178
>
179
>
/**
180
>
* The currently active session resource for debugging.
181
>
*/
182
>
activeSessionResource: URI | undefined;
183
>
184
>
/**
185
>
* Clear all logged events.
186
>
*/
187
>
clear(): void;
188
>
189
>
/**
190
>
* Register an external provider that can supply additional debug events.
191
>
* This is used by the extension API (ChatDebugLogProvider).
192
>
*/
193
>
registerProvider(provider: IChatDebugLogProvider): IDisposable;
194
>
195
>
/**
196
>
* Check whether providers have already been invoked for a given session.
197
>
*/
198
>
hasInvokedProviders(sessionResource: URI): boolean;
199
>
200
>
/**
201
>
* Invoke all registered providers for a given session resource.
202
>
* Called when the Debug View is opened to fetch events from extensions.
203
>
*/
204
>
invokeProviders(sessionResource: URI): Promise<void>;
205
>
206
>
/**
207
>
* End a debug session: cancels any in-flight provider invocation,
208
>
* disposes the associated CancellationTokenSource, and removes it.
209
>
* Called when the chat session is disposed/archived.
210
>
*/
211
>
endSession(sessionResource: URI): void;
212
>
213
>
/**
214
>
* Resolve the full details of an event by its id.
215
>
* Delegates to the registered provider's resolveChatDebugLogEvent.
216
>
*/
217
>
resolveEvent(eventId: string): Promise<IChatDebugResolvedEventContent | undefined>;
218
>
219
>
/**
220
>
/**
221
>
* Export the debug log for a session via the registered provider.
222
>
*/
223
>
exportLog(sessionResource: URI): Promise<Uint8Array | undefined>;
224
>
225
>
/**
226
>
* Import a previously exported debug log via the registered provider.
227
>
* Returns the session URI for the imported data.
228
>
*/
229
>
importLog(data: Uint8Array): Promise<URI | undefined>;
230
>
231
>
/**
232
>
* Returns true if the event was logged by VS Code core
233
>
* (not sourced from an external provider).
234
>
*/
235
>
isCoreEvent(event: IChatDebugEvent): boolean;
236
>
237
>
/**
238
>
* Store a human-readable title for an imported session.
239
>
*/
240
>
setImportedSessionTitle(sessionResource: URI, title: string): void;
241
>
242
>
/**
243
>
* Get the stored title for an imported session, if available.
244
>
*/
245
>
getImportedSessionTitle(sessionResource: URI): string | undefined;
246
>
247
>
/**
248
>
* Fired when available session resources change (e.g. historical sessions discovered from disk).
249
>
*/
250
>
readonly onDidChangeAvailableSessionResources: Event<void>;
251
>
252
>
/**
253
>
* Store session resources that have debug log data available on disk.
254
>
* Called by the main thread after the extension reports historical sessions.
255
>
*/
256
>
addAvailableSessionResources(resources: readonly { uri: URI; title?: string }[]): void;
257
>
258
>
/**
259
>
* Get all session resources that have debug log data available,
260
>
* including historical sessions persisted on disk by the provider.
261
>
* Triggers a lazy fetch from the registered fetcher on first call.
262
>
*/
263
>
getAvailableSessionResources(): readonly URI[];
264
>
265
>
/**
266
>
* Register a callback that fetches available session resources from a provider.
267
>
* Called lazily when `getAvailableSessionResources()` is first invoked. Multiple
268
>
* fetchers may be registered (e.g. the extension host and local agent-host
269
>
* discovery); each is invoked at most once. Dispose to unregister.
270
>
*/
271
>
registerAvailableSessionsFetcher(fetcher: (token: CancellationToken) => Promise<{ uri: URI; title?: string }[]>): IDisposable;
272
>
273
>
/**
274
>
* Get the stored title for a historical session discovered from disk.
275
>
*/
276
>
getHistoricalSessionTitle(sessionResource: URI): string | undefined;
277
>
278
>
}
279
>
280
>
/**
281
>
* Plain text content for a resolved debug event.
282
>
*/
283
>
export interface IChatDebugEventTextContent {
284
>
readonly kind: 'text';
285
>
readonly value: string;
286
>
}
287
>
288
>
/**
289
>
* The status of a file in a file list content.
290
>
*/
291
>
export type ChatDebugFileStatus = 'loaded' | 'skipped';
292
>
293
>
/**
294
>
* A single file entry in a file list content.
295
>
*/
296
>
export interface IChatDebugFileEntry {
297
>
readonly uri: URI;
298
>
readonly name?: string;
299
>
readonly status: ChatDebugFileStatus;
300
>
readonly storage?: string;
301
>
readonly extensionId?: string;
302
>
readonly skipReason?: string;
303
>
readonly errorMessage?: string;
304
>
readonly duplicateOf?: URI;
305
>
}
306
>
307
>
/**
308
>
* A source folder entry in a file list content.
309
>
*/
310
>
export interface IChatDebugSourceFolderEntry {
311
>
readonly uri: URI;
312
>
readonly storage: string;
313
>
}
314
>
315
>
/**
316
>
* Structured file list content for a resolved debug event.
317
>
* Contains resolved files and skipped/failed paths for rich rendering.
318
>
*/
319
>
export interface IChatDebugEventFileListContent {
320
>
readonly kind: 'fileList';
321
>
readonly discoveryType: string;
322
>
readonly durationInMillis: number;
323
>
readonly files: readonly IChatDebugFileEntry[];
324
>
readonly sourceFolders?: readonly IChatDebugSourceFolderEntry[];
325
>
}
326
>
327
>
/**
328
>
* Structured message content for a resolved debug event,
329
>
* containing collapsible sections.
330
>
*/
331
>
export interface IChatDebugEventMessageContent {
332
>
readonly kind: 'message';
333
>
readonly type: 'user' | 'agent';
334
>
readonly message: string;
335
>
readonly sections: readonly IChatDebugMessageSection[];
336
>
}
337
>
338
>
/**
339
>
* Structured tool call content for a resolved debug event.
340
>
* Contains the tool name, status, arguments, and output for rich rendering.
341
>
*/
342
>
export interface IChatDebugEventToolCallContent {
343
>
readonly kind: 'toolCall';
344
>
readonly toolName: string;
345
>
readonly result?: 'success' | 'error';
346
>
readonly durationInMillis?: number;
347
>
readonly input?: string;
348
>
readonly output?: string;
349
>
}
350
>
351
>
/**
352
>
* Structured model turn content for a resolved debug event.
353
>
* Contains request metadata, token usage, and timing for rich rendering.
354
>
*/
355
>
export interface IChatDebugEventModelTurnContent {
356
>
readonly kind: 'modelTurn';
357
>
readonly requestName: string;
358
>
readonly model?: string;
359
>
readonly status?: string;
360
>
readonly durationInMillis?: number;
361
>
readonly timeToFirstTokenInMillis?: number;
362
>
readonly requestId?: string;
363
>
readonly maxInputTokens?: number;
364
>
readonly maxOutputTokens?: number;
365
>
readonly inputTokens?: number;
366
>
readonly outputTokens?: number;
367
>
readonly cachedTokens?: number;
368
>
readonly totalTokens?: number;
369
>
readonly requestOptions?: string;
370
>
readonly errorMessage?: string;
371
>
readonly sections?: readonly IChatDebugMessageSection[];
372
>
}
373
>
374
>
/**
375
>
* Structured hook execution content for a resolved debug event.
376
>
* Contains the hook type, command, input, output, and result for rich rendering.
377
>
*/
378
>
export interface IChatDebugEventHookContent {
379
>
readonly kind: 'hook';
380
>
readonly hookType: string;
381
>
readonly command?: string;
382
>
readonly result?: ChatDebugHookResult;
383
>
readonly durationInMillis?: number;
384
>
readonly input?: string;
385
>
readonly output?: string;
386
>
readonly exitCode?: number;
387
>
readonly errorMessage?: string;
388
>
}
389
>
390
>
/**
391
>
* A single entry in the customization resolution log.
392
>
*/
393
>
export interface IChatDebugCustomizationLogEntry {
394
>
readonly category: 'applying' | 'skipped' | 'referenced' | 'skill' | 'custom-agent' | 'hook';
395
>
readonly name: string;
396
>
readonly uri?: URI;
397
>
readonly reason?: string;
398
>
}
399
>
400
>
/**
401
>
* Structured customization summary content for a resolved debug event.
402
>
* Contains per-file resolution logs showing how applyTo patterns, agent
403
>
* instructions, and referenced files were resolved by the instructions
404
>
* context computer.
405
>
*/
406
>
export interface IChatDebugEventCustomizationSummaryContent {
407
>
readonly kind: 'customizationSummary';
408
>
/** Per-file resolution detail entries. */
409
>
readonly resolutionLogs: readonly IChatDebugCustomizationLogEntry[];
410
>
/** Total wall-clock time of the collect() call in milliseconds. */
411
>
readonly durationInMillis: number;
412
>
/** Counts by type for the summary header. */
413
>
readonly counts: {
414
>
readonly instructions: number;
415
>
readonly skills: number;
416
>
readonly agents: number;
417
>
readonly hooks: number;
418
>
readonly skipped: number;
419
>
};
420
>
}
421
>
422
>
/**
423
>
* Union of all resolved event content types.
424
>
*/
425
>
export type IChatDebugResolvedEventContent = IChatDebugEventTextContent | IChatDebugEventFileListContent | IChatDebugEventMessageContent | IChatDebugEventToolCallContent | IChatDebugEventModelTurnContent | IChatDebugEventHookContent | IChatDebugEventCustomizationSummaryContent;
426
>
427
>
/**
428
>
* Provider interface for debug events.
429
>
*/
430
>
export interface IChatDebugLogProvider {
431
>
provideChatDebugLog(sessionResource: URI, token: CancellationToken): Promise<IChatDebugEvent[] | undefined>;
432
>
resolveChatDebugLogEvent?(eventId: string, token: CancellationToken): Promise<IChatDebugResolvedEventContent | undefined>;
433
>
provideChatDebugLogExport?(sessionResource: URI, token: CancellationToken): Promise<Uint8Array | undefined>;
434
>
resolveChatDebugLogImport?(data: Uint8Array, token: CancellationToken): Promise<URI | undefined>;
435
>
}