@github/copilot-sdk 0.1.20 → 0.1.22

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.
package/README.md CHANGED
@@ -86,8 +86,9 @@ Create a new conversation session.
86
86
 
87
87
  **Config:**
88
88
 
89
- - `sessionId?: string` - Custom session ID
89
+ - `sessionId?: string` - Custom session ID.
90
90
  - `model?: string` - Model to use ("gpt-5", "claude-sonnet-4.5", etc.). **Required when using custom provider.**
91
+ - `reasoningEffort?: "low" | "medium" | "high" | "xhigh"` - Reasoning effort level for models that support it. Use `listModels()` to check which models support this option.
91
92
  - `tools?: Tool[]` - Custom tools exposed to the CLI
92
93
  - `systemMessage?: SystemMessageConfig` - System message customization (see below)
93
94
  - `infiniteSessions?: InfiniteSessionConfig` - Configure automatic context compaction (see below)
@@ -115,6 +116,41 @@ List all available sessions.
115
116
 
116
117
  Delete a session and its data from disk.
117
118
 
119
+ ##### `getForegroundSessionId(): Promise<string | undefined>`
120
+
121
+ Get the ID of the session currently displayed in the TUI. Only available when connecting to a server running in TUI+server mode (`--ui-server`).
122
+
123
+ ##### `setForegroundSessionId(sessionId: string): Promise<void>`
124
+
125
+ Request the TUI to switch to displaying the specified session. Only available in TUI+server mode.
126
+
127
+ ##### `on(eventType: SessionLifecycleEventType, handler): () => void`
128
+
129
+ Subscribe to a specific session lifecycle event type. Returns an unsubscribe function.
130
+
131
+ ```typescript
132
+ const unsubscribe = client.on("session.foreground", (event) => {
133
+ console.log(`Session ${event.sessionId} is now in foreground`);
134
+ });
135
+ ```
136
+
137
+ ##### `on(handler: SessionLifecycleHandler): () => void`
138
+
139
+ Subscribe to all session lifecycle events. Returns an unsubscribe function.
140
+
141
+ ```typescript
142
+ const unsubscribe = client.on((event) => {
143
+ console.log(`${event.type}: ${event.sessionId}`);
144
+ });
145
+ ```
146
+
147
+ **Lifecycle Event Types:**
148
+ - `session.created` - A new session was created
149
+ - `session.deleted` - A session was deleted
150
+ - `session.updated` - A session was updated (e.g., new messages)
151
+ - `session.foreground` - A session became the foreground session in TUI
152
+ - `session.background` - A session is no longer the foreground session
153
+
118
154
  ---
119
155
 
120
156
  ### CopilotSession
@@ -511,12 +547,12 @@ const session = await client.createSession({
511
547
  // request.question - The question to ask
512
548
  // request.choices - Optional array of choices for multiple choice
513
549
  // request.allowFreeform - Whether freeform input is allowed (default: true)
514
-
550
+
515
551
  console.log(`Agent asks: ${request.question}`);
516
552
  if (request.choices) {
517
553
  console.log(`Choices: ${request.choices.join(", ")}`);
518
554
  }
519
-
555
+
520
556
  // Return the user's response
521
557
  return {
522
558
  answer: "User's answer here",
@@ -544,7 +580,7 @@ const session = await client.createSession({
544
580
  additionalContext: "Extra context for the model",
545
581
  };
546
582
  },
547
-
583
+
548
584
  // Called after each tool execution
549
585
  onPostToolUse: async (input, invocation) => {
550
586
  console.log(`Tool ${input.toolName} completed`);
@@ -553,7 +589,7 @@ const session = await client.createSession({
553
589
  additionalContext: "Post-execution notes",
554
590
  };
555
591
  },
556
-
592
+
557
593
  // Called when user submits a prompt
558
594
  onUserPromptSubmitted: async (input, invocation) => {
559
595
  console.log(`User prompt: ${input.prompt}`);
@@ -561,7 +597,7 @@ const session = await client.createSession({
561
597
  modifiedPrompt: input.prompt, // Optionally modify the prompt
562
598
  };
563
599
  },
564
-
600
+
565
601
  // Called when session starts
566
602
  onSessionStart: async (input, invocation) => {
567
603
  console.log(`Session started from: ${input.source}`); // "startup", "resume", "new"
@@ -569,12 +605,12 @@ const session = await client.createSession({
569
605
  additionalContext: "Session initialization context",
570
606
  };
571
607
  },
572
-
608
+
573
609
  // Called when session ends
574
610
  onSessionEnd: async (input, invocation) => {
575
611
  console.log(`Session ended: ${input.reason}`);
576
612
  },
577
-
613
+
578
614
  // Called when an error occurs
579
615
  onErrorOccurred: async (input, invocation) => {
580
616
  console.error(`Error in ${input.errorContext}: ${input.error}`);
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { CopilotSession } from "./session.js";
2
- import type { ConnectionState, CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, ModelInfo, ResumeSessionConfig, SessionConfig, SessionMetadata } from "./types.js";
2
+ import type { ConnectionState, CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, ModelInfo, ResumeSessionConfig, SessionConfig, SessionLifecycleEventType, SessionLifecycleHandler, SessionMetadata, TypedSessionLifecycleHandler } from "./types.js";
3
3
  /**
4
4
  * Main client for interacting with the Copilot CLI.
5
5
  *
@@ -44,6 +44,10 @@ export declare class CopilotClient {
44
44
  private options;
45
45
  private isExternalServer;
46
46
  private forceStopping;
47
+ private modelsCache;
48
+ private modelsCacheLock;
49
+ private sessionLifecycleHandlers;
50
+ private typedLifecycleHandlers;
47
51
  /**
48
52
  * Creates a new CopilotClient instance.
49
53
  *
@@ -229,7 +233,11 @@ export declare class CopilotClient {
229
233
  */
230
234
  getAuthStatus(): Promise<GetAuthStatusResponse>;
231
235
  /**
232
- * List available models with their metadata
236
+ * List available models with their metadata.
237
+ *
238
+ * Results are cached after the first successful call to avoid rate limiting.
239
+ * The cache is cleared when the client disconnects.
240
+ *
233
241
  * @throws Error if not authenticated
234
242
  */
235
243
  listModels(): Promise<ModelInfo[]>;
@@ -288,6 +296,87 @@ export declare class CopilotClient {
288
296
  * ```
289
297
  */
290
298
  listSessions(): Promise<SessionMetadata[]>;
299
+ /**
300
+ * Gets the foreground session ID in TUI+server mode.
301
+ *
302
+ * This returns the ID of the session currently displayed in the TUI.
303
+ * Only available when connecting to a server running in TUI+server mode (--ui-server).
304
+ *
305
+ * @returns A promise that resolves with the foreground session ID, or undefined if none
306
+ * @throws Error if the client is not connected
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * const sessionId = await client.getForegroundSessionId();
311
+ * if (sessionId) {
312
+ * console.log(`TUI is displaying session: ${sessionId}`);
313
+ * }
314
+ * ```
315
+ */
316
+ getForegroundSessionId(): Promise<string | undefined>;
317
+ /**
318
+ * Sets the foreground session in TUI+server mode.
319
+ *
320
+ * This requests the TUI to switch to displaying the specified session.
321
+ * Only available when connecting to a server running in TUI+server mode (--ui-server).
322
+ *
323
+ * @param sessionId - The ID of the session to display in the TUI
324
+ * @returns A promise that resolves when the session is switched
325
+ * @throws Error if the client is not connected or if the operation fails
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * // Switch the TUI to display a specific session
330
+ * await client.setForegroundSessionId("session-123");
331
+ * ```
332
+ */
333
+ setForegroundSessionId(sessionId: string): Promise<void>;
334
+ /**
335
+ * Subscribes to a specific session lifecycle event type.
336
+ *
337
+ * Lifecycle events are emitted when sessions are created, deleted, updated,
338
+ * or change foreground/background state (in TUI+server mode).
339
+ *
340
+ * @param eventType - The specific event type to listen for
341
+ * @param handler - A callback function that receives events of the specified type
342
+ * @returns A function that, when called, unsubscribes the handler
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * // Listen for when a session becomes foreground in TUI
347
+ * const unsubscribe = client.on("session.foreground", (event) => {
348
+ * console.log(`Session ${event.sessionId} is now displayed in TUI`);
349
+ * });
350
+ *
351
+ * // Later, to stop receiving events:
352
+ * unsubscribe();
353
+ * ```
354
+ */
355
+ on<K extends SessionLifecycleEventType>(eventType: K, handler: TypedSessionLifecycleHandler<K>): () => void;
356
+ /**
357
+ * Subscribes to all session lifecycle events.
358
+ *
359
+ * @param handler - A callback function that receives all lifecycle events
360
+ * @returns A function that, when called, unsubscribes the handler
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * const unsubscribe = client.on((event) => {
365
+ * switch (event.type) {
366
+ * case "session.foreground":
367
+ * console.log(`Session ${event.sessionId} is now in foreground`);
368
+ * break;
369
+ * case "session.created":
370
+ * console.log(`New session created: ${event.sessionId}`);
371
+ * break;
372
+ * }
373
+ * });
374
+ *
375
+ * // Later, to stop receiving events:
376
+ * unsubscribe();
377
+ * ```
378
+ */
379
+ on(handler: SessionLifecycleHandler): () => void;
291
380
  /**
292
381
  * Start the CLI server process
293
382
  */
@@ -306,6 +395,7 @@ export declare class CopilotClient {
306
395
  private connectViaTcp;
307
396
  private attachConnectionHandlers;
308
397
  private handleSessionEventNotification;
398
+ private handleSessionLifecycleNotification;
309
399
  private handleToolCallRequest;
310
400
  private executeToolCall;
311
401
  private handlePermissionRequest;
package/dist/client.js CHANGED
@@ -28,6 +28,10 @@ class CopilotClient {
28
28
  options;
29
29
  isExternalServer = false;
30
30
  forceStopping = false;
31
+ modelsCache = null;
32
+ modelsCacheLock = Promise.resolve();
33
+ sessionLifecycleHandlers = /* @__PURE__ */ new Set();
34
+ typedLifecycleHandlers = /* @__PURE__ */ new Map();
31
35
  /**
32
36
  * Creates a new CopilotClient instance.
33
37
  *
@@ -196,6 +200,7 @@ class CopilotClient {
196
200
  }
197
201
  this.connection = null;
198
202
  }
203
+ this.modelsCache = null;
199
204
  if (this.socket) {
200
205
  try {
201
206
  this.socket.end();
@@ -259,6 +264,7 @@ class CopilotClient {
259
264
  }
260
265
  this.connection = null;
261
266
  }
267
+ this.modelsCache = null;
262
268
  if (this.socket) {
263
269
  try {
264
270
  this.socket.destroy();
@@ -315,6 +321,7 @@ class CopilotClient {
315
321
  const response = await this.connection.sendRequest("session.create", {
316
322
  model: config.model,
317
323
  sessionId: config.sessionId,
324
+ reasoningEffort: config.reasoningEffort,
318
325
  tools: config.tools?.map((tool) => ({
319
326
  name: tool.name,
320
327
  description: tool.description,
@@ -384,6 +391,11 @@ class CopilotClient {
384
391
  }
385
392
  const response = await this.connection.sendRequest("session.resume", {
386
393
  sessionId,
394
+ model: config.model,
395
+ reasoningEffort: config.reasoningEffort,
396
+ systemMessage: config.systemMessage,
397
+ availableTools: config.availableTools,
398
+ excludedTools: config.excludedTools,
387
399
  tools: config.tools?.map((tool) => ({
388
400
  name: tool.name,
389
401
  description: tool.description,
@@ -394,11 +406,13 @@ class CopilotClient {
394
406
  requestUserInput: !!config.onUserInputRequest,
395
407
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
396
408
  workingDirectory: config.workingDirectory,
409
+ configDir: config.configDir,
397
410
  streaming: config.streaming,
398
411
  mcpServers: config.mcpServers,
399
412
  customAgents: config.customAgents,
400
413
  skillDirectories: config.skillDirectories,
401
414
  disabledSkills: config.disabledSkills,
415
+ infiniteSessions: config.infiniteSessions,
402
416
  disableResume: config.disableResume
403
417
  });
404
418
  const { sessionId: resumedSessionId, workspacePath } = response;
@@ -472,16 +486,34 @@ class CopilotClient {
472
486
  return result;
473
487
  }
474
488
  /**
475
- * List available models with their metadata
489
+ * List available models with their metadata.
490
+ *
491
+ * Results are cached after the first successful call to avoid rate limiting.
492
+ * The cache is cleared when the client disconnects.
493
+ *
476
494
  * @throws Error if not authenticated
477
495
  */
478
496
  async listModels() {
479
497
  if (!this.connection) {
480
498
  throw new Error("Client not connected");
481
499
  }
482
- const result = await this.connection.sendRequest("models.list", {});
483
- const response = result;
484
- return response.models;
500
+ await this.modelsCacheLock;
501
+ let resolveLock;
502
+ this.modelsCacheLock = new Promise((resolve) => {
503
+ resolveLock = resolve;
504
+ });
505
+ try {
506
+ if (this.modelsCache !== null) {
507
+ return [...this.modelsCache];
508
+ }
509
+ const result = await this.connection.sendRequest("models.list", {});
510
+ const response = result;
511
+ const models = response.models;
512
+ this.modelsCache = models;
513
+ return [...models];
514
+ } finally {
515
+ resolveLock();
516
+ }
485
517
  }
486
518
  /**
487
519
  * Verify that the server's protocol version matches the SDK's expected version
@@ -583,6 +615,77 @@ class CopilotClient {
583
615
  isRemote: s.isRemote
584
616
  }));
585
617
  }
618
+ /**
619
+ * Gets the foreground session ID in TUI+server mode.
620
+ *
621
+ * This returns the ID of the session currently displayed in the TUI.
622
+ * Only available when connecting to a server running in TUI+server mode (--ui-server).
623
+ *
624
+ * @returns A promise that resolves with the foreground session ID, or undefined if none
625
+ * @throws Error if the client is not connected
626
+ *
627
+ * @example
628
+ * ```typescript
629
+ * const sessionId = await client.getForegroundSessionId();
630
+ * if (sessionId) {
631
+ * console.log(`TUI is displaying session: ${sessionId}`);
632
+ * }
633
+ * ```
634
+ */
635
+ async getForegroundSessionId() {
636
+ if (!this.connection) {
637
+ throw new Error("Client not connected");
638
+ }
639
+ const response = await this.connection.sendRequest("session.getForeground", {});
640
+ return response.sessionId;
641
+ }
642
+ /**
643
+ * Sets the foreground session in TUI+server mode.
644
+ *
645
+ * This requests the TUI to switch to displaying the specified session.
646
+ * Only available when connecting to a server running in TUI+server mode (--ui-server).
647
+ *
648
+ * @param sessionId - The ID of the session to display in the TUI
649
+ * @returns A promise that resolves when the session is switched
650
+ * @throws Error if the client is not connected or if the operation fails
651
+ *
652
+ * @example
653
+ * ```typescript
654
+ * // Switch the TUI to display a specific session
655
+ * await client.setForegroundSessionId("session-123");
656
+ * ```
657
+ */
658
+ async setForegroundSessionId(sessionId) {
659
+ if (!this.connection) {
660
+ throw new Error("Client not connected");
661
+ }
662
+ const response = await this.connection.sendRequest("session.setForeground", { sessionId });
663
+ const result = response;
664
+ if (!result.success) {
665
+ throw new Error(result.error || "Failed to set foreground session");
666
+ }
667
+ }
668
+ on(eventTypeOrHandler, handler) {
669
+ if (typeof eventTypeOrHandler === "string" && handler) {
670
+ const eventType = eventTypeOrHandler;
671
+ if (!this.typedLifecycleHandlers.has(eventType)) {
672
+ this.typedLifecycleHandlers.set(eventType, /* @__PURE__ */ new Set());
673
+ }
674
+ const storedHandler = handler;
675
+ this.typedLifecycleHandlers.get(eventType).add(storedHandler);
676
+ return () => {
677
+ const handlers = this.typedLifecycleHandlers.get(eventType);
678
+ if (handlers) {
679
+ handlers.delete(storedHandler);
680
+ }
681
+ };
682
+ }
683
+ const wildcardHandler = eventTypeOrHandler;
684
+ this.sessionLifecycleHandlers.add(wildcardHandler);
685
+ return () => {
686
+ this.sessionLifecycleHandlers.delete(wildcardHandler);
687
+ };
688
+ }
586
689
  /**
587
690
  * Start the CLI server process
588
691
  */
@@ -590,7 +693,7 @@ class CopilotClient {
590
693
  return new Promise((resolve, reject) => {
591
694
  const args = [
592
695
  ...this.options.cliArgs,
593
- "--server",
696
+ "--headless",
594
697
  "--log-level",
595
698
  this.options.logLevel
596
699
  ];
@@ -735,6 +838,9 @@ class CopilotClient {
735
838
  this.connection.onNotification("session.event", (notification) => {
736
839
  this.handleSessionEventNotification(notification);
737
840
  });
841
+ this.connection.onNotification("session.lifecycle", (notification) => {
842
+ this.handleSessionLifecycleNotification(notification);
843
+ });
738
844
  this.connection.onRequest(
739
845
  "tool.call",
740
846
  async (params) => await this.handleToolCallRequest(params)
@@ -768,6 +874,27 @@ class CopilotClient {
768
874
  session._dispatchEvent(notification.event);
769
875
  }
770
876
  }
877
+ handleSessionLifecycleNotification(notification) {
878
+ if (typeof notification !== "object" || !notification || !("type" in notification) || typeof notification.type !== "string" || !("sessionId" in notification) || typeof notification.sessionId !== "string") {
879
+ return;
880
+ }
881
+ const event = notification;
882
+ const typedHandlers = this.typedLifecycleHandlers.get(event.type);
883
+ if (typedHandlers) {
884
+ for (const handler of typedHandlers) {
885
+ try {
886
+ handler(event);
887
+ } catch {
888
+ }
889
+ }
890
+ }
891
+ for (const handler of this.sessionLifecycleHandlers) {
892
+ try {
893
+ handler(event);
894
+ } catch {
895
+ }
896
+ }
897
+ }
771
898
  async handleToolCallRequest(params) {
772
899
  if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") {
773
900
  throw new Error("Invalid tool call payload");
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generated from: @github/copilot/session-events.schema.json
5
5
  * Generated by: scripts/generate-session-types.ts
6
- * Generated at: 2026-01-26T18:08:33.710Z
6
+ * Generated at: 2026-02-03T20:40:49.167Z
7
7
  *
8
8
  * To update these types:
9
9
  * 1. Update the schema in copilot-agent-runtime
@@ -55,6 +55,8 @@ export type SessionEvent = {
55
55
  errorType: string;
56
56
  message: string;
57
57
  stack?: string;
58
+ statusCode?: number;
59
+ providerCallId?: string;
58
60
  };
59
61
  } | {
60
62
  id: string;
@@ -127,6 +129,39 @@ export type SessionEvent = {
127
129
  upToEventId: string;
128
130
  eventsRemoved: number;
129
131
  };
132
+ } | {
133
+ id: string;
134
+ timestamp: string;
135
+ parentId: string | null;
136
+ ephemeral: true;
137
+ type: "session.shutdown";
138
+ data: {
139
+ shutdownType: "routine" | "error";
140
+ errorReason?: string;
141
+ totalPremiumRequests: number;
142
+ totalApiDurationMs: number;
143
+ sessionStartTime: number;
144
+ codeChanges: {
145
+ linesAdded: number;
146
+ linesRemoved: number;
147
+ filesModified: string[];
148
+ };
149
+ modelMetrics: {
150
+ [k: string]: {
151
+ requests: {
152
+ count: number;
153
+ cost: number;
154
+ };
155
+ usage: {
156
+ inputTokens: number;
157
+ outputTokens: number;
158
+ cacheReadTokens: number;
159
+ cacheWriteTokens: number;
160
+ };
161
+ };
162
+ };
163
+ currentModel?: string;
164
+ };
130
165
  } | {
131
166
  id: string;
132
167
  timestamp: string;
@@ -160,6 +195,8 @@ export type SessionEvent = {
160
195
  messagesRemoved?: number;
161
196
  tokensRemoved?: number;
162
197
  summaryContent?: string;
198
+ checkpointNumber?: number;
199
+ checkpointPath?: string;
163
200
  compactionTokensUsed?: {
164
201
  input: number;
165
202
  output: number;
@@ -261,6 +298,9 @@ export type SessionEvent = {
261
298
  arguments?: unknown;
262
299
  type?: "function" | "custom";
263
300
  }[];
301
+ reasoningOpaque?: string;
302
+ reasoningText?: string;
303
+ encryptedContent?: string;
264
304
  parentToolCallId?: string;
265
305
  };
266
306
  } | {
@@ -291,7 +331,7 @@ export type SessionEvent = {
291
331
  ephemeral: true;
292
332
  type: "assistant.usage";
293
333
  data: {
294
- model?: string;
334
+ model: string;
295
335
  inputTokens?: number;
296
336
  outputTokens?: number;
297
337
  cacheReadTokens?: number;
@@ -301,6 +341,7 @@ export type SessionEvent = {
301
341
  initiator?: string;
302
342
  apiCallId?: string;
303
343
  providerCallId?: string;
344
+ parentToolCallId?: string;
304
345
  quotaSnapshots?: {
305
346
  [k: string]: {
306
347
  isUnlimitedEntitlement: boolean;
@@ -391,6 +432,18 @@ export type SessionEvent = {
391
432
  };
392
433
  parentToolCallId?: string;
393
434
  };
435
+ } | {
436
+ id: string;
437
+ timestamp: string;
438
+ parentId: string | null;
439
+ ephemeral?: boolean;
440
+ type: "skill.invoked";
441
+ data: {
442
+ name: string;
443
+ path: string;
444
+ content: string;
445
+ allowedTools?: string[];
446
+ };
394
447
  } | {
395
448
  id: string;
396
449
  timestamp: string;
package/dist/index.d.ts CHANGED
@@ -6,4 +6,4 @@
6
6
  export { CopilotClient } from "./client.js";
7
7
  export { CopilotSession, type AssistantMessageEvent } from "./session.js";
8
8
  export { defineTool } from "./types.js";
9
- export type { ConnectionState, CopilotClientOptions, CustomAgentConfig, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, ZodSchema, } from "./types.js";
9
+ export type { ConnectionState, CopilotClientOptions, CustomAgentConfig, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionMetadata, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageReplaceConfig, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
package/dist/session.js CHANGED
@@ -96,10 +96,11 @@ class CopilotSession {
96
96
  rejectWithError(error);
97
97
  }
98
98
  });
99
+ let timeoutId;
99
100
  try {
100
101
  await this.send(options);
101
102
  const timeoutPromise = new Promise((_, reject) => {
102
- setTimeout(
103
+ timeoutId = setTimeout(
103
104
  () => reject(
104
105
  new Error(
105
106
  `Timeout after ${effectiveTimeout}ms waiting for session.idle`
@@ -111,6 +112,9 @@ class CopilotSession {
111
112
  await Promise.race([idlePromise, timeoutPromise]);
112
113
  return lastAssistantMessage;
113
114
  } finally {
115
+ if (timeoutId !== void 0) {
116
+ clearTimeout(timeoutId);
117
+ }
114
118
  unsubscribe();
115
119
  }
116
120
  }
package/dist/types.d.ts CHANGED
@@ -490,6 +490,10 @@ export interface InfiniteSessionConfig {
490
490
  */
491
491
  bufferExhaustionThreshold?: number;
492
492
  }
493
+ /**
494
+ * Valid reasoning effort levels for models that support it.
495
+ */
496
+ export type ReasoningEffort = "low" | "medium" | "high" | "xhigh";
493
497
  export interface SessionConfig {
494
498
  /**
495
499
  * Optional custom session ID
@@ -500,6 +504,12 @@ export interface SessionConfig {
500
504
  * Model to use for this session
501
505
  */
502
506
  model?: string;
507
+ /**
508
+ * Reasoning effort level for models that support it.
509
+ * Only valid for models where capabilities.supports.reasoningEffort is true.
510
+ * Use client.listModels() to check supported values for each model.
511
+ */
512
+ reasoningEffort?: ReasoningEffort;
503
513
  /**
504
514
  * Override the default configuration directory location.
505
515
  * When specified, the session will use this directory for storing config and state.
@@ -577,7 +587,7 @@ export interface SessionConfig {
577
587
  /**
578
588
  * Configuration for resuming a session
579
589
  */
580
- export type ResumeSessionConfig = Pick<SessionConfig, "tools" | "provider" | "streaming" | "onPermissionRequest" | "onUserInputRequest" | "hooks" | "workingDirectory" | "mcpServers" | "customAgents" | "skillDirectories" | "disabledSkills"> & {
590
+ export type ResumeSessionConfig = Pick<SessionConfig, "model" | "tools" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "streaming" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "hooks" | "workingDirectory" | "configDir" | "mcpServers" | "customAgents" | "skillDirectories" | "disabledSkills" | "infiniteSessions"> & {
581
591
  /**
582
592
  * When true, skips emitting the session.resume event.
583
593
  * Useful for reconnecting to a session without triggering resume-related side effects.
@@ -630,12 +640,31 @@ export interface MessageOptions {
630
640
  */
631
641
  prompt: string;
632
642
  /**
633
- * File or directory attachments
643
+ * File, directory, or selection attachments
634
644
  */
635
645
  attachments?: Array<{
636
- type: "file" | "directory";
646
+ type: "file";
647
+ path: string;
648
+ displayName?: string;
649
+ } | {
650
+ type: "directory";
637
651
  path: string;
638
652
  displayName?: string;
653
+ } | {
654
+ type: "selection";
655
+ filePath: string;
656
+ displayName: string;
657
+ selection?: {
658
+ start: {
659
+ line: number;
660
+ character: number;
661
+ };
662
+ end: {
663
+ line: number;
664
+ character: number;
665
+ };
666
+ };
667
+ text?: string;
639
668
  }>;
640
669
  /**
641
670
  * Message delivery mode
@@ -706,6 +735,8 @@ export interface GetAuthStatusResponse {
706
735
  export interface ModelCapabilities {
707
736
  supports: {
708
737
  vision: boolean;
738
+ /** Whether this model supports reasoning effort configuration */
739
+ reasoningEffort: boolean;
709
740
  };
710
741
  limits: {
711
742
  max_prompt_tokens?: number;
@@ -744,5 +775,48 @@ export interface ModelInfo {
744
775
  policy?: ModelPolicy;
745
776
  /** Billing information */
746
777
  billing?: ModelBilling;
778
+ /** Supported reasoning effort levels (only present if model supports reasoning effort) */
779
+ supportedReasoningEfforts?: ReasoningEffort[];
780
+ /** Default reasoning effort level (only present if model supports reasoning effort) */
781
+ defaultReasoningEffort?: ReasoningEffort;
782
+ }
783
+ /**
784
+ * Types of session lifecycle events
785
+ */
786
+ export type SessionLifecycleEventType = "session.created" | "session.deleted" | "session.updated" | "session.foreground" | "session.background";
787
+ /**
788
+ * Session lifecycle event notification
789
+ * Sent when sessions are created, deleted, updated, or change foreground/background state
790
+ */
791
+ export interface SessionLifecycleEvent {
792
+ /** Type of lifecycle event */
793
+ type: SessionLifecycleEventType;
794
+ /** ID of the session this event relates to */
795
+ sessionId: string;
796
+ /** Session metadata (not included for deleted sessions) */
797
+ metadata?: {
798
+ startTime: string;
799
+ modifiedTime: string;
800
+ summary?: string;
801
+ };
802
+ }
803
+ /**
804
+ * Handler for session lifecycle events
805
+ */
806
+ export type SessionLifecycleHandler = (event: SessionLifecycleEvent) => void;
807
+ /**
808
+ * Typed handler for specific session lifecycle event types
809
+ */
810
+ export type TypedSessionLifecycleHandler<K extends SessionLifecycleEventType> = (event: SessionLifecycleEvent & {
811
+ type: K;
812
+ }) => void;
813
+ /**
814
+ * Information about the foreground session in TUI+server mode
815
+ */
816
+ export interface ForegroundSessionInfo {
817
+ /** ID of the foreground session, or undefined if none */
818
+ sessionId?: string;
819
+ /** Workspace path of the foreground session */
820
+ workspacePath?: string;
747
821
  }
748
822
  export {};
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/github/copilot-sdk.git"
6
6
  },
7
- "version": "0.1.20",
7
+ "version": "0.1.22",
8
8
  "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
9
9
  "main": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -40,26 +40,26 @@
40
40
  "author": "GitHub",
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
- "@github/copilot": "^0.0.399",
43
+ "@github/copilot": "^0.0.403",
44
44
  "vscode-jsonrpc": "^8.2.1",
45
- "zod": "^4.3.5"
45
+ "zod": "^4.3.6"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/node": "^22.19.6",
49
- "@typescript-eslint/eslint-plugin": "^8.0.0",
50
- "@typescript-eslint/parser": "^8.0.0",
51
- "esbuild": "^0.27.0",
48
+ "@types/node": "^25.2.0",
49
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
50
+ "@typescript-eslint/parser": "^8.54.0",
51
+ "esbuild": "^0.27.2",
52
52
  "eslint": "^9.0.0",
53
- "glob": "^11.0.0",
53
+ "glob": "^13.0.1",
54
54
  "json-schema": "^0.4.0",
55
55
  "json-schema-to-typescript": "^15.0.4",
56
- "prettier": "^3.4.0",
56
+ "prettier": "^3.8.1",
57
57
  "quicktype-core": "^23.2.6",
58
58
  "rimraf": "^6.1.2",
59
59
  "semver": "^7.7.3",
60
60
  "tsx": "^4.20.6",
61
61
  "typescript": "^5.0.0",
62
- "vitest": "^4.0.16"
62
+ "vitest": "^4.0.18"
63
63
  },
64
64
  "engines": {
65
65
  "node": ">=18.0.0"