Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/chat/common/sessionTranscriptService.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
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 { createServiceIdentifier } from '../../../util/common/services';
7
import { URI } from '../../../util/vs/base/common/uri';
8
9
export const ISessionTranscriptService = createServiceIdentifier<ISessionTranscriptService>('ISessionTranscriptService');
10
11
// #region Transcript Entry Types
12
13
/**
14
* Common fields shared by all transcript entries.
15
*/
16
interface TranscriptEntryBase {
17
/** Entry type discriminator. */
18
readonly type: string;
19
/** Entry-specific data payload. */
20
readonly data: unknown;
21
/** Unique entry identifier. */
22
readonly id: string;
23
/** ISO 8601 timestamp of when this entry was created. */
24
readonly timestamp: string;
25
/** ID of the previous entry for ordering (null for first entry). */
26
readonly parentId: string | null;
27
}
28
29
export interface SessionStartData {
30
readonly sessionId: string;
31
readonly version: number;
32
readonly producer: string;
33
readonly copilotVersion: string;
34
readonly vscodeVersion: string;
35
readonly startTime: string;
36
readonly context?: {
37
readonly cwd?: string;
38
};
39
}
40
41
export interface SessionStartEntry extends TranscriptEntryBase {
42
readonly type: 'session.start';
43
readonly data: SessionStartData;
44
}
45
46
export interface UserMessageData {
47
readonly content: string;
48
readonly attachments?: readonly unknown[];
49
}
50
51
export interface UserMessageEntry extends TranscriptEntryBase {
52
readonly type: 'user.message';
53
readonly data: UserMessageData;
54
}
55
56
export interface AssistantTurnStartData {
57
readonly turnId: string;
58
}
59
60
export interface AssistantTurnStartEntry extends TranscriptEntryBase {
61
readonly type: 'assistant.turn_start';
62
readonly data: AssistantTurnStartData;
63
}
64
65
export interface ToolRequest {
66
readonly toolCallId: string;
67
readonly name: string;
68
readonly arguments: string;
69
readonly type: 'function';
70
}
71
72
export interface AssistantMessageData {
73
readonly messageId: string;
74
readonly content: string;
75
readonly toolRequests: readonly ToolRequest[];
76
readonly reasoningText?: string;
77
}
78
79
export interface AssistantMessageEntry extends TranscriptEntryBase {
80
readonly type: 'assistant.message';
81
readonly data: AssistantMessageData;
82
}
83
84
export interface ToolExecutionStartData {
85
readonly toolCallId: string;
86
readonly toolName: string;
87
readonly arguments: unknown;
88
}
89
90
export interface ToolExecutionStartEntry extends TranscriptEntryBase {
91
readonly type: 'tool.execution_start';
92
readonly data: ToolExecutionStartData;
93
}
94
95
export interface ToolExecutionCompleteData {
96
readonly toolCallId: string;
97
readonly success: boolean;
98
readonly result?: {
99
readonly content: string;
100
};
101
}
102
103
export interface ToolExecutionCompleteEntry extends TranscriptEntryBase {
104
readonly type: 'tool.execution_complete';
105
readonly data: ToolExecutionCompleteData;
106
}
107
108
export interface AssistantTurnEndData {
109
readonly turnId: string;
110
}
111
112
export interface AssistantTurnEndEntry extends TranscriptEntryBase {
113
readonly type: 'assistant.turn_end';
114
readonly data: AssistantTurnEndData;
115
}
116
117
export type TranscriptEntry =
118
| SessionStartEntry
119
| UserMessageEntry
120
| AssistantTurnStartEntry
121
| AssistantMessageEntry
122
| ToolExecutionStartEntry
123
| ToolExecutionCompleteEntry
124
| AssistantTurnEndEntry;
125
126
// #endregion
127
128
// #region Historical Replay Types
129
130
/**
131
* A tool call from a historical round, used when replaying conversation
132
* history into a transcript file.
133
*/
134
export interface IHistoricalToolCall {
135
readonly name: string;
136
readonly arguments: string;
137
readonly id: string;
138
}
139
140
/**
141
* A single assistant round from conversation history.
142
* Maps to a `user.message → assistant.turn_start → assistant.message → assistant.turn_end`
143
* sequence in the transcript.
144
*/
145
export interface IHistoricalToolCallRound {
146
/** The assistant's text response for this round. */
147
readonly response: string;
148
/** Tool calls made by the assistant in this round. */
149
readonly toolCalls: readonly IHistoricalToolCall[];
150
/** Optional reasoning / thinking text. */
151
readonly reasoningText?: string;
152
/** Epoch millis (`Date.now()`) when this round started, if known. */
153
readonly timestamp?: number;
154
}
155
156
/**
157
* A single turn from conversation history, containing the user message
158
* and all assistant rounds that followed.
159
*/
160
export interface IHistoricalTurn {
161
/** The user's prompt text for this turn. */
162
readonly userMessage: string;
163
/** Epoch millis (`Date.now()`) when this turn started. */
164
readonly timestamp: number;
165
/** The assistant rounds that occurred during this turn. */
166
readonly rounds: readonly IHistoricalToolCallRound[];
167
}
168
169
// #endregion
170
171
export interface ISessionTranscriptService {
172
readonly _serviceBrand: undefined;
173
174
/**
175
* Start tracking a new session. Creates the transcript file.
176
*
177
* If `history` is provided and no transcript file exists on disk yet,
178
* the historical turns are replayed into the transcript before the
179
* current turn begins. If a file already exists, history is ignored.
180
*
181
* @param sessionId Unique session identifier (typically `conversation.sessionId`).
182
* @param context Optional context about the session environment.
183
* @param history Previous turns to replay if the transcript must be created from scratch.
184
*/
185
startSession(sessionId: string, context?: { cwd?: string }, history?: readonly IHistoricalTurn[]): Promise<void>;
186
187
/**
188
* Record the user's prompt message.
189
* Entries are buffered; call {@link flush} to write to disk.
190
*/
191
logUserMessage(sessionId: string, content: string, attachments?: readonly unknown[]): void;
192
193
/**
194
* Record the start of an assistant turn (one iteration of the tool calling loop).
195
* Entries are buffered; call {@link flush} to write to disk.
196
*/
197
logAssistantTurnStart(sessionId: string, turnId: string): void;
198
199
/**
200
* Record an assistant message containing text and/or tool call requests.
201
* Entries are buffered; call {@link flush} to write to disk.
202
*/
203
logAssistantMessage(sessionId: string, content: string, toolRequests: readonly ToolRequest[], reasoningText?: string): void;
204
205
/**
206
* Record the start of a tool execution.
207
* Entries are buffered; call {@link flush} to write to disk.
208
*/
209
logToolExecutionStart(sessionId: string, toolCallId: string, toolName: string, args: unknown): void;
210
211
/**
212
* Record the completion of a tool execution.
213
* Entries are buffered; call {@link flush} to write to disk.
214
*/
215
logToolExecutionComplete(sessionId: string, toolCallId: string, success: boolean, resultContent?: string): void;
216
217
/**
218
* Record the end of an assistant turn.
219
* Entries are buffered; call {@link flush} to write to disk.
220
*/
221
logAssistantTurnEnd(sessionId: string, turnId: string): void;
222
223
/**
224
* Flush all buffered transcript entries for a session to disk.
225
* Safe to call multiple times; concurrent flushes are serialized.
226
*/
227
flush(sessionId: string): Promise<void>;
228
229
/**
230
* Mark a session as ended. The transcript file is retained for lazy cleanup.
231
*/
232
endSession(sessionId: string): Promise<void>;
233
234
/**
235
* Get the URI of the transcript file for a session, if one exists.
236
* Returns `undefined` if the session has no transcript.
237
*/
238
getTranscriptPath(sessionId: string): URI | undefined;
239
240
/**
241
* Get the current number of lines in the transcript for a session.
242
* Returns `undefined` if the session is not active.
243
*/
244
getLineCount(sessionId: string): number | undefined;
245
246
/**
247
* Remove transcript files for sessions that are no longer active,
248
* keeping at most `maxRetained` most-recent ended sessions.
249
*/
250
cleanupOldTranscripts(maxRetained?: number): Promise<void>;
251
252
/**
253
* Check whether a URI is under the transcripts storage directory.
254
* Used by {@link assertFileOkForTool} to allowlist tool reads.
255
*/
256
isTranscriptUri(uri: URI): boolean;
257
}
258
259
export class NullSessionTranscriptService implements ISessionTranscriptService {
260
declare readonly _serviceBrand: undefined;
261
262
async startSession(): Promise<void> { }
263
logUserMessage(): void { }
264
logAssistantTurnStart(): void { }
265
logAssistantMessage(): void { }
266
logToolExecutionStart(): void { }
267
logToolExecutionComplete(): void { }
268
logAssistantTurnEnd(): void { }
269
async flush(): Promise<void> { }
270
async endSession(): Promise<void> { }
271
getTranscriptPath(): URI | undefined { return undefined; }
272
getLineCount(): number | undefined { return undefined; }
273
async cleanupOldTranscripts(): Promise<void> { }
274
isTranscriptUri(): boolean { return false; }
275
}
276
277