@github/copilot-sdk 0.1.33-unstable.1 → 0.2.1-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,774 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var session_exports = {};
20
+ __export(session_exports, {
21
+ CopilotSession: () => CopilotSession,
22
+ NO_RESULT_PERMISSION_V2_ERROR: () => NO_RESULT_PERMISSION_V2_ERROR
23
+ });
24
+ module.exports = __toCommonJS(session_exports);
25
+ var import_node = require("vscode-jsonrpc/node.js");
26
+ var import_rpc = require("./generated/rpc.js");
27
+ var import_telemetry = require("./telemetry.js");
28
+ const NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server.";
29
+ class CopilotSession {
30
+ /**
31
+ * Creates a new CopilotSession instance.
32
+ *
33
+ * @param sessionId - The unique identifier for this session
34
+ * @param connection - The JSON-RPC message connection to the Copilot CLI
35
+ * @param workspacePath - Path to the session workspace directory (when infinite sessions enabled)
36
+ * @param traceContextProvider - Optional callback to get W3C Trace Context for outbound RPCs
37
+ * @internal This constructor is internal. Use {@link CopilotClient.createSession} to create sessions.
38
+ */
39
+ constructor(sessionId, connection, _workspacePath, traceContextProvider) {
40
+ this.sessionId = sessionId;
41
+ this.connection = connection;
42
+ this._workspacePath = _workspacePath;
43
+ this.traceContextProvider = traceContextProvider;
44
+ }
45
+ eventHandlers = /* @__PURE__ */ new Set();
46
+ typedEventHandlers = /* @__PURE__ */ new Map();
47
+ toolHandlers = /* @__PURE__ */ new Map();
48
+ commandHandlers = /* @__PURE__ */ new Map();
49
+ permissionHandler;
50
+ userInputHandler;
51
+ hooks;
52
+ transformCallbacks;
53
+ _rpc = null;
54
+ traceContextProvider;
55
+ _capabilities = {};
56
+ /**
57
+ * Typed session-scoped RPC methods.
58
+ */
59
+ get rpc() {
60
+ if (!this._rpc) {
61
+ this._rpc = (0, import_rpc.createSessionRpc)(this.connection, this.sessionId);
62
+ }
63
+ return this._rpc;
64
+ }
65
+ /**
66
+ * Path to the session workspace directory when infinite sessions are enabled.
67
+ * Contains checkpoints/, plan.md, and files/ subdirectories.
68
+ * Undefined if infinite sessions are disabled.
69
+ */
70
+ get workspacePath() {
71
+ return this._workspacePath;
72
+ }
73
+ /**
74
+ * Host capabilities reported when the session was created or resumed.
75
+ * Use this to check feature support before calling capability-gated APIs.
76
+ */
77
+ get capabilities() {
78
+ return this._capabilities;
79
+ }
80
+ /**
81
+ * Interactive UI methods for showing dialogs to the user.
82
+ * Only available when the CLI host supports elicitation
83
+ * (`session.capabilities.ui?.elicitation === true`).
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * if (session.capabilities.ui?.elicitation) {
88
+ * const ok = await session.ui.confirm("Deploy to production?");
89
+ * }
90
+ * ```
91
+ */
92
+ get ui() {
93
+ return {
94
+ elicitation: (params) => this._elicitation(params),
95
+ confirm: (message) => this._confirm(message),
96
+ select: (message, options) => this._select(message, options),
97
+ input: (message, options) => this._input(message, options)
98
+ };
99
+ }
100
+ /**
101
+ * Sends a message to this session and waits for the response.
102
+ *
103
+ * The message is processed asynchronously. Subscribe to events via {@link on}
104
+ * to receive streaming responses and other session events.
105
+ *
106
+ * @param options - The message options including the prompt and optional attachments
107
+ * @returns A promise that resolves with the message ID of the response
108
+ * @throws Error if the session has been disconnected or the connection fails
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const messageId = await session.send({
113
+ * prompt: "Explain this code",
114
+ * attachments: [{ type: "file", path: "./src/index.ts" }]
115
+ * });
116
+ * ```
117
+ */
118
+ async send(options) {
119
+ const response = await this.connection.sendRequest("session.send", {
120
+ ...await (0, import_telemetry.getTraceContext)(this.traceContextProvider),
121
+ sessionId: this.sessionId,
122
+ prompt: options.prompt,
123
+ attachments: options.attachments,
124
+ mode: options.mode
125
+ });
126
+ return response.messageId;
127
+ }
128
+ /**
129
+ * Sends a message to this session and waits until the session becomes idle.
130
+ *
131
+ * This is a convenience method that combines {@link send} with waiting for
132
+ * the `session.idle` event. Use this when you want to block until the
133
+ * assistant has finished processing the message.
134
+ *
135
+ * Events are still delivered to handlers registered via {@link on} while waiting.
136
+ *
137
+ * @param options - The message options including the prompt and optional attachments
138
+ * @param timeout - Timeout in milliseconds (default: 60000). Controls how long to wait; does not abort in-flight agent work.
139
+ * @returns A promise that resolves with the final assistant message when the session becomes idle,
140
+ * or undefined if no assistant message was received
141
+ * @throws Error if the timeout is reached before the session becomes idle
142
+ * @throws Error if the session has been disconnected or the connection fails
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * // Send and wait for completion with default 60s timeout
147
+ * const response = await session.sendAndWait({ prompt: "What is 2+2?" });
148
+ * console.log(response?.data.content); // "4"
149
+ * ```
150
+ */
151
+ async sendAndWait(options, timeout) {
152
+ const effectiveTimeout = timeout ?? 6e4;
153
+ let resolveIdle;
154
+ let rejectWithError;
155
+ const idlePromise = new Promise((resolve, reject) => {
156
+ resolveIdle = resolve;
157
+ rejectWithError = reject;
158
+ });
159
+ let lastAssistantMessage;
160
+ const unsubscribe = this.on((event) => {
161
+ if (event.type === "assistant.message") {
162
+ lastAssistantMessage = event;
163
+ } else if (event.type === "session.idle") {
164
+ resolveIdle();
165
+ } else if (event.type === "session.error") {
166
+ const error = new Error(event.data.message);
167
+ error.stack = event.data.stack;
168
+ rejectWithError(error);
169
+ }
170
+ });
171
+ let timeoutId;
172
+ try {
173
+ await this.send(options);
174
+ const timeoutPromise = new Promise((_, reject) => {
175
+ timeoutId = setTimeout(
176
+ () => reject(
177
+ new Error(
178
+ `Timeout after ${effectiveTimeout}ms waiting for session.idle`
179
+ )
180
+ ),
181
+ effectiveTimeout
182
+ );
183
+ });
184
+ await Promise.race([idlePromise, timeoutPromise]);
185
+ return lastAssistantMessage;
186
+ } finally {
187
+ if (timeoutId !== void 0) {
188
+ clearTimeout(timeoutId);
189
+ }
190
+ unsubscribe();
191
+ }
192
+ }
193
+ on(eventTypeOrHandler, handler) {
194
+ if (typeof eventTypeOrHandler === "string" && handler) {
195
+ const eventType = eventTypeOrHandler;
196
+ if (!this.typedEventHandlers.has(eventType)) {
197
+ this.typedEventHandlers.set(eventType, /* @__PURE__ */ new Set());
198
+ }
199
+ const storedHandler = handler;
200
+ this.typedEventHandlers.get(eventType).add(storedHandler);
201
+ return () => {
202
+ const handlers = this.typedEventHandlers.get(eventType);
203
+ if (handlers) {
204
+ handlers.delete(storedHandler);
205
+ }
206
+ };
207
+ }
208
+ const wildcardHandler = eventTypeOrHandler;
209
+ this.eventHandlers.add(wildcardHandler);
210
+ return () => {
211
+ this.eventHandlers.delete(wildcardHandler);
212
+ };
213
+ }
214
+ /**
215
+ * Dispatches an event to all registered handlers.
216
+ * Also handles broadcast request events internally (external tool calls, permissions).
217
+ *
218
+ * @param event - The session event to dispatch
219
+ * @internal This method is for internal use by the SDK.
220
+ */
221
+ _dispatchEvent(event) {
222
+ this._handleBroadcastEvent(event);
223
+ const typedHandlers = this.typedEventHandlers.get(event.type);
224
+ if (typedHandlers) {
225
+ for (const handler of typedHandlers) {
226
+ try {
227
+ handler(event);
228
+ } catch (_error) {
229
+ }
230
+ }
231
+ }
232
+ for (const handler of this.eventHandlers) {
233
+ try {
234
+ handler(event);
235
+ } catch (_error) {
236
+ }
237
+ }
238
+ }
239
+ /**
240
+ * Handles broadcast request events by executing local handlers and responding via RPC.
241
+ * Handlers are dispatched as fire-and-forget — rejections propagate as unhandled promise
242
+ * rejections, consistent with standard EventEmitter / event handler semantics.
243
+ * @internal
244
+ */
245
+ _handleBroadcastEvent(event) {
246
+ if (event.type === "external_tool.requested") {
247
+ const { requestId, toolName } = event.data;
248
+ const args = event.data.arguments;
249
+ const toolCallId = event.data.toolCallId;
250
+ const traceparent = event.data.traceparent;
251
+ const tracestate = event.data.tracestate;
252
+ const handler = this.toolHandlers.get(toolName);
253
+ if (handler) {
254
+ void this._executeToolAndRespond(
255
+ requestId,
256
+ toolName,
257
+ toolCallId,
258
+ args,
259
+ handler,
260
+ traceparent,
261
+ tracestate
262
+ );
263
+ }
264
+ } else if (event.type === "permission.requested") {
265
+ const { requestId, permissionRequest } = event.data;
266
+ if (this.permissionHandler) {
267
+ void this._executePermissionAndRespond(requestId, permissionRequest);
268
+ }
269
+ } else if (event.type === "command.execute") {
270
+ const { requestId, commandName, command, args } = event.data;
271
+ void this._executeCommandAndRespond(requestId, commandName, command, args);
272
+ }
273
+ }
274
+ /**
275
+ * Executes a tool handler and sends the result back via RPC.
276
+ * @internal
277
+ */
278
+ async _executeToolAndRespond(requestId, toolName, toolCallId, args, handler, traceparent, tracestate) {
279
+ try {
280
+ const rawResult = await handler(args, {
281
+ sessionId: this.sessionId,
282
+ toolCallId,
283
+ toolName,
284
+ arguments: args,
285
+ traceparent,
286
+ tracestate
287
+ });
288
+ let result;
289
+ if (rawResult == null) {
290
+ result = "";
291
+ } else if (typeof rawResult === "string") {
292
+ result = rawResult;
293
+ } else {
294
+ result = JSON.stringify(rawResult);
295
+ }
296
+ await this.rpc.tools.handlePendingToolCall({ requestId, result });
297
+ } catch (error) {
298
+ const message = error instanceof Error ? error.message : String(error);
299
+ try {
300
+ await this.rpc.tools.handlePendingToolCall({ requestId, error: message });
301
+ } catch (rpcError) {
302
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
303
+ throw rpcError;
304
+ }
305
+ }
306
+ }
307
+ }
308
+ /**
309
+ * Executes a permission handler and sends the result back via RPC.
310
+ * @internal
311
+ */
312
+ async _executePermissionAndRespond(requestId, permissionRequest) {
313
+ try {
314
+ const result = await this.permissionHandler(permissionRequest, {
315
+ sessionId: this.sessionId
316
+ });
317
+ if (result.kind === "no-result") {
318
+ return;
319
+ }
320
+ await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
321
+ } catch (_error) {
322
+ try {
323
+ await this.rpc.permissions.handlePendingPermissionRequest({
324
+ requestId,
325
+ result: {
326
+ kind: "denied-no-approval-rule-and-could-not-request-from-user"
327
+ }
328
+ });
329
+ } catch (rpcError) {
330
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
331
+ throw rpcError;
332
+ }
333
+ }
334
+ }
335
+ }
336
+ /**
337
+ * Executes a command handler and sends the result back via RPC.
338
+ * @internal
339
+ */
340
+ async _executeCommandAndRespond(requestId, commandName, command, args) {
341
+ const handler = this.commandHandlers.get(commandName);
342
+ if (!handler) {
343
+ try {
344
+ await this.rpc.commands.handlePendingCommand({
345
+ requestId,
346
+ error: `Unknown command: ${commandName}`
347
+ });
348
+ } catch (rpcError) {
349
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
350
+ throw rpcError;
351
+ }
352
+ }
353
+ return;
354
+ }
355
+ try {
356
+ await handler({ sessionId: this.sessionId, command, commandName, args });
357
+ await this.rpc.commands.handlePendingCommand({ requestId });
358
+ } catch (error) {
359
+ const message = error instanceof Error ? error.message : String(error);
360
+ try {
361
+ await this.rpc.commands.handlePendingCommand({ requestId, error: message });
362
+ } catch (rpcError) {
363
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
364
+ throw rpcError;
365
+ }
366
+ }
367
+ }
368
+ }
369
+ /**
370
+ * Registers custom tool handlers for this session.
371
+ *
372
+ * Tools allow the assistant to execute custom functions. When the assistant
373
+ * invokes a tool, the corresponding handler is called with the tool arguments.
374
+ *
375
+ * @param tools - An array of tool definitions with their handlers, or undefined to clear all tools
376
+ * @internal This method is typically called internally when creating a session with tools.
377
+ */
378
+ registerTools(tools) {
379
+ this.toolHandlers.clear();
380
+ if (!tools) {
381
+ return;
382
+ }
383
+ for (const tool of tools) {
384
+ this.toolHandlers.set(tool.name, tool.handler);
385
+ }
386
+ }
387
+ /**
388
+ * Retrieves a registered tool handler by name.
389
+ *
390
+ * @param name - The name of the tool to retrieve
391
+ * @returns The tool handler if found, or undefined
392
+ * @internal This method is for internal use by the SDK.
393
+ */
394
+ getToolHandler(name) {
395
+ return this.toolHandlers.get(name);
396
+ }
397
+ /**
398
+ * Registers command handlers for this session.
399
+ *
400
+ * @param commands - An array of command definitions with handlers, or undefined to clear
401
+ * @internal This method is typically called internally when creating/resuming a session.
402
+ */
403
+ registerCommands(commands) {
404
+ this.commandHandlers.clear();
405
+ if (!commands) {
406
+ return;
407
+ }
408
+ for (const cmd of commands) {
409
+ this.commandHandlers.set(cmd.name, cmd.handler);
410
+ }
411
+ }
412
+ /**
413
+ * Sets the host capabilities for this session.
414
+ *
415
+ * @param capabilities - The capabilities object from the create/resume response
416
+ * @internal This method is typically called internally when creating/resuming a session.
417
+ */
418
+ setCapabilities(capabilities) {
419
+ this._capabilities = capabilities ?? {};
420
+ }
421
+ assertElicitation() {
422
+ if (!this._capabilities.ui?.elicitation) {
423
+ throw new Error(
424
+ "Elicitation is not supported by the host. Check session.capabilities.ui?.elicitation before calling UI methods."
425
+ );
426
+ }
427
+ }
428
+ async _elicitation(params) {
429
+ this.assertElicitation();
430
+ return this.rpc.ui.elicitation({
431
+ message: params.message,
432
+ requestedSchema: params.requestedSchema
433
+ });
434
+ }
435
+ async _confirm(message) {
436
+ this.assertElicitation();
437
+ const result = await this.rpc.ui.elicitation({
438
+ message,
439
+ requestedSchema: {
440
+ type: "object",
441
+ properties: {
442
+ confirmed: { type: "boolean", default: true }
443
+ },
444
+ required: ["confirmed"]
445
+ }
446
+ });
447
+ return result.action === "accept" && result.content?.confirmed === true;
448
+ }
449
+ async _select(message, options) {
450
+ this.assertElicitation();
451
+ const result = await this.rpc.ui.elicitation({
452
+ message,
453
+ requestedSchema: {
454
+ type: "object",
455
+ properties: {
456
+ selection: { type: "string", enum: options }
457
+ },
458
+ required: ["selection"]
459
+ }
460
+ });
461
+ if (result.action === "accept" && result.content?.selection != null) {
462
+ return result.content.selection;
463
+ }
464
+ return null;
465
+ }
466
+ async _input(message, options) {
467
+ this.assertElicitation();
468
+ const field = { type: "string" };
469
+ if (options?.title) field.title = options.title;
470
+ if (options?.description) field.description = options.description;
471
+ if (options?.minLength != null) field.minLength = options.minLength;
472
+ if (options?.maxLength != null) field.maxLength = options.maxLength;
473
+ if (options?.format) field.format = options.format;
474
+ if (options?.default != null) field.default = options.default;
475
+ const result = await this.rpc.ui.elicitation({
476
+ message,
477
+ requestedSchema: {
478
+ type: "object",
479
+ properties: {
480
+ value: field
481
+ },
482
+ required: ["value"]
483
+ }
484
+ });
485
+ if (result.action === "accept" && result.content?.value != null) {
486
+ return result.content.value;
487
+ }
488
+ return null;
489
+ }
490
+ /**
491
+ * Registers a handler for permission requests.
492
+ *
493
+ * When the assistant needs permission to perform certain actions (e.g., file operations),
494
+ * this handler is called to approve or deny the request.
495
+ *
496
+ * @param handler - The permission handler function, or undefined to remove the handler
497
+ * @internal This method is typically called internally when creating a session.
498
+ */
499
+ registerPermissionHandler(handler) {
500
+ this.permissionHandler = handler;
501
+ }
502
+ /**
503
+ * Registers a user input handler for ask_user requests.
504
+ *
505
+ * When the agent needs input from the user (via ask_user tool),
506
+ * this handler is called to provide the response.
507
+ *
508
+ * @param handler - The user input handler function, or undefined to remove the handler
509
+ * @internal This method is typically called internally when creating a session.
510
+ */
511
+ registerUserInputHandler(handler) {
512
+ this.userInputHandler = handler;
513
+ }
514
+ /**
515
+ * Registers hook handlers for session lifecycle events.
516
+ *
517
+ * Hooks allow custom logic to be executed at various points during
518
+ * the session lifecycle (before/after tool use, session start/end, etc.).
519
+ *
520
+ * @param hooks - The hook handlers object, or undefined to remove all hooks
521
+ * @internal This method is typically called internally when creating a session.
522
+ */
523
+ registerHooks(hooks) {
524
+ this.hooks = hooks;
525
+ }
526
+ /**
527
+ * Registers transform callbacks for system message sections.
528
+ *
529
+ * @param callbacks - Map of section ID to transform callback, or undefined to clear
530
+ * @internal This method is typically called internally when creating a session.
531
+ */
532
+ registerTransformCallbacks(callbacks) {
533
+ this.transformCallbacks = callbacks;
534
+ }
535
+ /**
536
+ * Handles a systemMessage.transform request from the runtime.
537
+ * Dispatches each section to its registered transform callback.
538
+ *
539
+ * @param sections - Map of section IDs to their current rendered content
540
+ * @returns A promise that resolves with the transformed sections
541
+ * @internal This method is for internal use by the SDK.
542
+ */
543
+ async _handleSystemMessageTransform(sections) {
544
+ const result = {};
545
+ for (const [sectionId, { content }] of Object.entries(sections)) {
546
+ const callback = this.transformCallbacks?.get(sectionId);
547
+ if (callback) {
548
+ try {
549
+ const transformed = await callback(content);
550
+ result[sectionId] = { content: transformed };
551
+ } catch (_error) {
552
+ result[sectionId] = { content };
553
+ }
554
+ } else {
555
+ result[sectionId] = { content };
556
+ }
557
+ }
558
+ return { sections: result };
559
+ }
560
+ /**
561
+ * Handles a permission request in the v2 protocol format (synchronous RPC).
562
+ * Used as a back-compat adapter when connected to a v2 server.
563
+ *
564
+ * @param request - The permission request data from the CLI
565
+ * @returns A promise that resolves with the permission decision
566
+ * @internal This method is for internal use by the SDK.
567
+ */
568
+ async _handlePermissionRequestV2(request) {
569
+ if (!this.permissionHandler) {
570
+ return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
571
+ }
572
+ try {
573
+ const result = await this.permissionHandler(request, {
574
+ sessionId: this.sessionId
575
+ });
576
+ if (result.kind === "no-result") {
577
+ throw new Error(NO_RESULT_PERMISSION_V2_ERROR);
578
+ }
579
+ return result;
580
+ } catch (error) {
581
+ if (error instanceof Error && error.message === NO_RESULT_PERMISSION_V2_ERROR) {
582
+ throw error;
583
+ }
584
+ return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
585
+ }
586
+ }
587
+ /**
588
+ * Handles a user input request from the Copilot CLI.
589
+ *
590
+ * @param request - The user input request data from the CLI
591
+ * @returns A promise that resolves with the user's response
592
+ * @internal This method is for internal use by the SDK.
593
+ */
594
+ async _handleUserInputRequest(request) {
595
+ if (!this.userInputHandler) {
596
+ throw new Error("User input requested but no handler registered");
597
+ }
598
+ try {
599
+ const result = await this.userInputHandler(request, {
600
+ sessionId: this.sessionId
601
+ });
602
+ return result;
603
+ } catch (error) {
604
+ throw error;
605
+ }
606
+ }
607
+ /**
608
+ * Handles a hooks invocation from the Copilot CLI.
609
+ *
610
+ * @param hookType - The type of hook being invoked
611
+ * @param input - The input data for the hook
612
+ * @returns A promise that resolves with the hook output, or undefined
613
+ * @internal This method is for internal use by the SDK.
614
+ */
615
+ async _handleHooksInvoke(hookType, input) {
616
+ if (!this.hooks) {
617
+ return void 0;
618
+ }
619
+ const handlerMap = {
620
+ preToolUse: this.hooks.onPreToolUse,
621
+ postToolUse: this.hooks.onPostToolUse,
622
+ userPromptSubmitted: this.hooks.onUserPromptSubmitted,
623
+ sessionStart: this.hooks.onSessionStart,
624
+ sessionEnd: this.hooks.onSessionEnd,
625
+ errorOccurred: this.hooks.onErrorOccurred
626
+ };
627
+ const handler = handlerMap[hookType];
628
+ if (!handler) {
629
+ return void 0;
630
+ }
631
+ try {
632
+ const result = await handler(input, { sessionId: this.sessionId });
633
+ return result;
634
+ } catch (_error) {
635
+ return void 0;
636
+ }
637
+ }
638
+ /**
639
+ * Retrieves all events and messages from this session's history.
640
+ *
641
+ * This returns the complete conversation history including user messages,
642
+ * assistant responses, tool executions, and other session events.
643
+ *
644
+ * @returns A promise that resolves with an array of all session events
645
+ * @throws Error if the session has been disconnected or the connection fails
646
+ *
647
+ * @example
648
+ * ```typescript
649
+ * const events = await session.getMessages();
650
+ * for (const event of events) {
651
+ * if (event.type === "assistant.message") {
652
+ * console.log("Assistant:", event.data.content);
653
+ * }
654
+ * }
655
+ * ```
656
+ */
657
+ async getMessages() {
658
+ const response = await this.connection.sendRequest("session.getMessages", {
659
+ sessionId: this.sessionId
660
+ });
661
+ return response.events;
662
+ }
663
+ /**
664
+ * Disconnects this session and releases all in-memory resources (event handlers,
665
+ * tool handlers, permission handlers).
666
+ *
667
+ * Session state on disk (conversation history, planning state, artifacts) is
668
+ * preserved, so the conversation can be resumed later by calling
669
+ * {@link CopilotClient.resumeSession} with the session ID. To permanently
670
+ * remove all session data including files on disk, use
671
+ * {@link CopilotClient.deleteSession} instead.
672
+ *
673
+ * After calling this method, the session object can no longer be used.
674
+ *
675
+ * @returns A promise that resolves when the session is disconnected
676
+ * @throws Error if the connection fails
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * // Clean up when done — session can still be resumed later
681
+ * await session.disconnect();
682
+ * ```
683
+ */
684
+ async disconnect() {
685
+ await this.connection.sendRequest("session.destroy", {
686
+ sessionId: this.sessionId
687
+ });
688
+ this.eventHandlers.clear();
689
+ this.typedEventHandlers.clear();
690
+ this.toolHandlers.clear();
691
+ this.permissionHandler = void 0;
692
+ }
693
+ /**
694
+ * @deprecated Use {@link disconnect} instead. This method will be removed in a future release.
695
+ *
696
+ * Disconnects this session and releases all in-memory resources.
697
+ * Session data on disk is preserved for later resumption.
698
+ *
699
+ * @returns A promise that resolves when the session is disconnected
700
+ * @throws Error if the connection fails
701
+ */
702
+ async destroy() {
703
+ return this.disconnect();
704
+ }
705
+ /** Enables `await using session = ...` syntax for automatic cleanup. */
706
+ async [Symbol.asyncDispose]() {
707
+ return this.disconnect();
708
+ }
709
+ /**
710
+ * Aborts the currently processing message in this session.
711
+ *
712
+ * Use this to cancel a long-running request. The session remains valid
713
+ * and can continue to be used for new messages.
714
+ *
715
+ * @returns A promise that resolves when the abort request is acknowledged
716
+ * @throws Error if the session has been disconnected or the connection fails
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * // Start a long-running request
721
+ * const messagePromise = session.send({ prompt: "Write a very long story..." });
722
+ *
723
+ * // Abort after 5 seconds
724
+ * setTimeout(async () => {
725
+ * await session.abort();
726
+ * }, 5000);
727
+ * ```
728
+ */
729
+ async abort() {
730
+ await this.connection.sendRequest("session.abort", {
731
+ sessionId: this.sessionId
732
+ });
733
+ }
734
+ /**
735
+ * Change the model for this session.
736
+ * The new model takes effect for the next message. Conversation history is preserved.
737
+ *
738
+ * @param model - Model ID to switch to
739
+ * @param options - Optional settings for the new model
740
+ *
741
+ * @example
742
+ * ```typescript
743
+ * await session.setModel("gpt-4.1");
744
+ * await session.setModel("claude-sonnet-4.6", { reasoningEffort: "high" });
745
+ * ```
746
+ */
747
+ async setModel(model, options) {
748
+ await this.rpc.model.switchTo({ modelId: model, ...options });
749
+ }
750
+ /**
751
+ * Log a message to the session timeline.
752
+ * The message appears in the session event stream and is visible to SDK consumers
753
+ * and (for non-ephemeral messages) persisted to the session event log on disk.
754
+ *
755
+ * @param message - Human-readable message text
756
+ * @param options - Optional log level and ephemeral flag
757
+ *
758
+ * @example
759
+ * ```typescript
760
+ * await session.log("Processing started");
761
+ * await session.log("Disk usage high", { level: "warning" });
762
+ * await session.log("Connection failed", { level: "error" });
763
+ * await session.log("Debug info", { ephemeral: true });
764
+ * ```
765
+ */
766
+ async log(message, options) {
767
+ await this.rpc.log({ message, ...options });
768
+ }
769
+ }
770
+ // Annotate the CommonJS export names for ESM import in node:
771
+ 0 && (module.exports = {
772
+ CopilotSession,
773
+ NO_RESULT_PERMISSION_V2_ERROR
774
+ });