@github/copilot-sdk 0.2.1-unstable.0 → 0.2.2-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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
4
4
 
5
- > **Note:** This SDK is in technical preview and may change in breaking ways.
5
+ > **Note:** This SDK is in public preview and may change in breaking ways.
6
6
 
7
7
  ## Installation
8
8
 
@@ -910,13 +910,14 @@ Register an `onElicitationRequest` handler to let your client act as an elicitat
910
910
  const session = await client.createSession({
911
911
  model: "gpt-5",
912
912
  onPermissionRequest: approveAll,
913
- onElicitationRequest: async (request, invocation) => {
914
- // request.message - Description of what information is needed
915
- // request.requestedSchema - JSON Schema describing the form fields
916
- // request.mode - "form" (structured input) or "url" (browser redirect)
917
- // request.elicitationSource - Origin of the request (e.g. MCP server name)
918
-
919
- console.log(`Elicitation from ${request.elicitationSource}: ${request.message}`);
913
+ onElicitationRequest: async (context) => {
914
+ // context.sessionId - Session that triggered the request
915
+ // context.message - Description of what information is needed
916
+ // context.requestedSchema - JSON Schema describing the form fields
917
+ // context.mode - "form" (structured input) or "url" (browser redirect)
918
+ // context.elicitationSource - Origin of the request (e.g. MCP server name)
919
+
920
+ console.log(`Elicitation from ${context.elicitationSource}: ${context.message}`);
920
921
 
921
922
  // Present UI to the user and collect their response...
922
923
  return {
@@ -166,6 +166,9 @@ class CopilotClient {
166
166
  "githubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)"
167
167
  );
168
168
  }
169
+ if (options.sessionFs) {
170
+ this.validateSessionFsConfig(options.sessionFs);
171
+ }
169
172
  if (options.cliUrl) {
170
173
  const { host, port } = this.parseCliUrl(options.cliUrl);
171
174
  this.actualHost = host;
@@ -220,6 +223,17 @@ class CopilotClient {
220
223
  }
221
224
  return { host, port };
222
225
  }
226
+ validateSessionFsConfig(config) {
227
+ if (!config.initialCwd) {
228
+ throw new Error("sessionFs.initialCwd is required");
229
+ }
230
+ if (!config.sessionStatePath) {
231
+ throw new Error("sessionFs.sessionStatePath is required");
232
+ }
233
+ if (config.conventions !== "windows" && config.conventions !== "posix") {
234
+ throw new Error("sessionFs.conventions must be either 'windows' or 'posix'");
235
+ }
236
+ }
223
237
  /**
224
238
  * Starts the CLI server and establishes a connection.
225
239
  *
@@ -514,6 +528,7 @@ class CopilotClient {
514
528
  availableTools: config.availableTools,
515
529
  excludedTools: config.excludedTools,
516
530
  provider: config.provider,
531
+ modelCapabilities: config.modelCapabilities,
517
532
  requestPermission: true,
518
533
  requestUserInput: !!config.onUserInputRequest,
519
534
  requestElicitation: !!config.onElicitationRequest,
@@ -634,6 +649,7 @@ class CopilotClient {
634
649
  description: cmd.description
635
650
  })),
636
651
  provider: config.provider,
652
+ modelCapabilities: config.modelCapabilities,
637
653
  requestPermission: true,
638
654
  requestUserInput: !!config.onUserInputRequest,
639
655
  requestElicitation: !!config.onElicitationRequest,
@@ -265,7 +265,10 @@ class CopilotSession {
265
265
  );
266
266
  }
267
267
  } else if (event.type === "permission.requested") {
268
- const { requestId, permissionRequest } = event.data;
268
+ const { requestId, permissionRequest, resolvedByHook } = event.data;
269
+ if (resolvedByHook) {
270
+ return;
271
+ }
269
272
  if (this.permissionHandler) {
270
273
  void this._executePermissionAndRespond(requestId, permissionRequest);
271
274
  }
@@ -277,6 +280,7 @@ class CopilotSession {
277
280
  const { message, requestedSchema, mode, elicitationSource, url, requestId } = event.data;
278
281
  void this._handleElicitationRequest(
279
282
  {
283
+ sessionId: this.sessionId,
280
284
  message,
281
285
  requestedSchema,
282
286
  mode,
@@ -309,6 +313,8 @@ class CopilotSession {
309
313
  result = "";
310
314
  } else if (typeof rawResult === "string") {
311
315
  result = rawResult;
316
+ } else if (isToolResultObject(rawResult)) {
317
+ result = rawResult;
312
318
  } else {
313
319
  result = JSON.stringify(rawResult);
314
320
  }
@@ -442,12 +448,12 @@ class CopilotSession {
442
448
  * Invokes the registered handler and responds via handlePendingElicitation RPC.
443
449
  * @internal
444
450
  */
445
- async _handleElicitationRequest(request, requestId) {
451
+ async _handleElicitationRequest(context, requestId) {
446
452
  if (!this.elicitationHandler) {
447
453
  return;
448
454
  }
449
455
  try {
450
- const result = await this.elicitationHandler(request, { sessionId: this.sessionId });
456
+ const result = await this.elicitationHandler(context);
451
457
  await this.rpc.ui.handlePendingElicitation({ requestId, result });
452
458
  } catch {
453
459
  try {
@@ -820,6 +826,25 @@ class CopilotSession {
820
826
  await this.rpc.log({ message, ...options });
821
827
  }
822
828
  }
829
+ function isToolResultObject(value) {
830
+ if (typeof value !== "object" || value === null) {
831
+ return false;
832
+ }
833
+ if (!("textResultForLlm" in value) || typeof value.textResultForLlm !== "string") {
834
+ return false;
835
+ }
836
+ if (!("resultType" in value) || typeof value.resultType !== "string") {
837
+ return false;
838
+ }
839
+ const allowedResultTypes = [
840
+ "success",
841
+ "failure",
842
+ "rejected",
843
+ "denied",
844
+ "timeout"
845
+ ];
846
+ return allowedResultTypes.includes(value.resultType);
847
+ }
823
848
  // Annotate the CommonJS export names for ESM import in node:
824
849
  0 && (module.exports = {
825
850
  CopilotSession,
package/dist/client.d.ts CHANGED
@@ -89,6 +89,7 @@ export declare class CopilotClient {
89
89
  * Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
90
90
  */
91
91
  private parseCliUrl;
92
+ private validateSessionFsConfig;
92
93
  /**
93
94
  * Starts the CLI server and establishes a connection.
94
95
  *
package/dist/client.js CHANGED
@@ -146,6 +146,9 @@ class CopilotClient {
146
146
  "githubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)"
147
147
  );
148
148
  }
149
+ if (options.sessionFs) {
150
+ this.validateSessionFsConfig(options.sessionFs);
151
+ }
149
152
  if (options.cliUrl) {
150
153
  const { host, port } = this.parseCliUrl(options.cliUrl);
151
154
  this.actualHost = host;
@@ -200,6 +203,17 @@ class CopilotClient {
200
203
  }
201
204
  return { host, port };
202
205
  }
206
+ validateSessionFsConfig(config) {
207
+ if (!config.initialCwd) {
208
+ throw new Error("sessionFs.initialCwd is required");
209
+ }
210
+ if (!config.sessionStatePath) {
211
+ throw new Error("sessionFs.sessionStatePath is required");
212
+ }
213
+ if (config.conventions !== "windows" && config.conventions !== "posix") {
214
+ throw new Error("sessionFs.conventions must be either 'windows' or 'posix'");
215
+ }
216
+ }
203
217
  /**
204
218
  * Starts the CLI server and establishes a connection.
205
219
  *
@@ -494,6 +508,7 @@ class CopilotClient {
494
508
  availableTools: config.availableTools,
495
509
  excludedTools: config.excludedTools,
496
510
  provider: config.provider,
511
+ modelCapabilities: config.modelCapabilities,
497
512
  requestPermission: true,
498
513
  requestUserInput: !!config.onUserInputRequest,
499
514
  requestElicitation: !!config.onElicitationRequest,
@@ -614,6 +629,7 @@ class CopilotClient {
614
629
  description: cmd.description
615
630
  })),
616
631
  provider: config.provider,
632
+ modelCapabilities: config.modelCapabilities,
617
633
  requestPermission: true,
618
634
  requestUserInput: !!config.onUserInputRequest,
619
635
  requestElicitation: !!config.onElicitationRequest,
@@ -36,41 +36,7 @@ export interface ModelsListResult {
36
36
  * Display name
37
37
  */
38
38
  name: string;
39
- /**
40
- * Model capabilities and limits
41
- */
42
- capabilities: {
43
- /**
44
- * Feature flags indicating what the model supports
45
- */
46
- supports: {
47
- /**
48
- * Whether this model supports vision/image input
49
- */
50
- vision?: boolean;
51
- /**
52
- * Whether this model supports reasoning effort configuration
53
- */
54
- reasoningEffort?: boolean;
55
- };
56
- /**
57
- * Token limits for prompts, outputs, and context window
58
- */
59
- limits: {
60
- /**
61
- * Maximum number of prompt/input tokens
62
- */
63
- max_prompt_tokens?: number;
64
- /**
65
- * Maximum number of output/completion tokens
66
- */
67
- max_output_tokens?: number;
68
- /**
69
- * Maximum total context window size in tokens
70
- */
71
- max_context_window_tokens: number;
72
- };
73
- };
39
+ capabilities: ModelCapabilities;
74
40
  /**
75
41
  * Policy state (if applicable)
76
42
  */
@@ -103,6 +69,61 @@ export interface ModelsListResult {
103
69
  defaultReasoningEffort?: string;
104
70
  }[];
105
71
  }
72
+ /**
73
+ * Model capabilities and limits
74
+ */
75
+ export interface ModelCapabilities {
76
+ supports: ModelCapabilitiesSupports;
77
+ limits: ModelCapabilitiesLimits;
78
+ }
79
+ /**
80
+ * Feature flags indicating what the model supports
81
+ */
82
+ export interface ModelCapabilitiesSupports {
83
+ /**
84
+ * Whether this model supports vision/image input
85
+ */
86
+ vision?: boolean;
87
+ /**
88
+ * Whether this model supports reasoning effort configuration
89
+ */
90
+ reasoningEffort?: boolean;
91
+ }
92
+ /**
93
+ * Token limits for prompts, outputs, and context window
94
+ */
95
+ export interface ModelCapabilitiesLimits {
96
+ /**
97
+ * Maximum number of prompt/input tokens
98
+ */
99
+ max_prompt_tokens?: number;
100
+ /**
101
+ * Maximum number of output/completion tokens
102
+ */
103
+ max_output_tokens?: number;
104
+ /**
105
+ * Maximum total context window size in tokens
106
+ */
107
+ max_context_window_tokens: number;
108
+ vision?: ModelCapabilitiesLimitsVision;
109
+ }
110
+ /**
111
+ * Vision-specific limits
112
+ */
113
+ export interface ModelCapabilitiesLimitsVision {
114
+ /**
115
+ * MIME types the model accepts
116
+ */
117
+ supported_media_types: string[];
118
+ /**
119
+ * Maximum number of images per prompt
120
+ */
121
+ max_prompt_images: number;
122
+ /**
123
+ * Maximum image size in bytes
124
+ */
125
+ max_prompt_image_size: number;
126
+ }
106
127
  export interface ToolsListResult {
107
128
  /**
108
129
  * List of available built-in tools with metadata
@@ -361,6 +382,47 @@ export interface SessionModelSwitchToParams {
361
382
  * Reasoning effort level to use for the model
362
383
  */
363
384
  reasoningEffort?: string;
385
+ modelCapabilities?: ModelCapabilitiesOverride;
386
+ }
387
+ /**
388
+ * Override individual model capabilities resolved by the runtime
389
+ */
390
+ export interface ModelCapabilitiesOverride {
391
+ supports?: ModelCapabilitiesOverrideSupports;
392
+ limits?: ModelCapabilitiesOverrideLimits;
393
+ }
394
+ /**
395
+ * Feature flags indicating what the model supports
396
+ */
397
+ export interface ModelCapabilitiesOverrideSupports {
398
+ vision?: boolean;
399
+ reasoningEffort?: boolean;
400
+ }
401
+ /**
402
+ * Token limits for prompts, outputs, and context window
403
+ */
404
+ export interface ModelCapabilitiesOverrideLimits {
405
+ max_prompt_tokens?: number;
406
+ max_output_tokens?: number;
407
+ /**
408
+ * Maximum total context window size in tokens
409
+ */
410
+ max_context_window_tokens?: number;
411
+ vision?: ModelCapabilitiesOverrideLimitsVision;
412
+ }
413
+ export interface ModelCapabilitiesOverrideLimitsVision {
414
+ /**
415
+ * MIME types the model accepts
416
+ */
417
+ supported_media_types?: string[];
418
+ /**
419
+ * Maximum number of images per prompt
420
+ */
421
+ max_prompt_images?: number;
422
+ /**
423
+ * Maximum image size in bytes
424
+ */
425
+ max_prompt_image_size?: number;
364
426
  }
365
427
  export interface SessionModeGetResult {
366
428
  /**
@@ -1083,6 +1145,10 @@ export interface SessionPermissionsHandlePendingPermissionRequestParams {
1083
1145
  kind: "denied-by-content-exclusion-policy";
1084
1146
  path: string;
1085
1147
  message: string;
1148
+ } | {
1149
+ kind: "denied-by-permission-request-hook";
1150
+ message?: string;
1151
+ interrupt?: boolean;
1086
1152
  };
1087
1153
  }
1088
1154
  export interface SessionLogResult {
@@ -224,7 +224,7 @@ export type SessionEvent = {
224
224
  */
225
225
  data: {
226
226
  /**
227
- * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "query")
227
+ * Category of error (e.g., "authentication", "authorization", "quota", "rate_limit", "context_limit", "query")
228
228
  */
229
229
  errorType: string;
230
230
  /**
@@ -264,44 +264,9 @@ export type SessionEvent = {
264
264
  ephemeral: true;
265
265
  type: "session.idle";
266
266
  /**
267
- * Payload indicating the agent is idle; includes any background tasks still in flight
267
+ * Payload indicating the session is fully idle with no background tasks in flight
268
268
  */
269
269
  data: {
270
- /**
271
- * Background tasks still running when the agent became idle
272
- */
273
- backgroundTasks?: {
274
- /**
275
- * Currently running background agents
276
- */
277
- agents: {
278
- /**
279
- * Unique identifier of the background agent
280
- */
281
- agentId: string;
282
- /**
283
- * Type of the background agent
284
- */
285
- agentType: string;
286
- /**
287
- * Human-readable description of the agent task
288
- */
289
- description?: string;
290
- }[];
291
- /**
292
- * Currently running background shell commands
293
- */
294
- shells: {
295
- /**
296
- * Unique identifier of the background shell
297
- */
298
- shellId: string;
299
- /**
300
- * Human-readable description of the shell command
301
- */
302
- description?: string;
303
- }[];
304
- };
305
270
  /**
306
271
  * True when the preceding agentic loop was cancelled via abort signal
307
272
  */
@@ -1444,6 +1409,10 @@ export type SessionEvent = {
1444
1409
  * Human-readable display title for the tool
1445
1410
  */
1446
1411
  toolTitle?: string;
1412
+ /**
1413
+ * Name of the MCP server hosting this tool, when the tool is an MCP tool
1414
+ */
1415
+ mcpServerName?: string;
1447
1416
  /**
1448
1417
  * Resolved intention summary describing what this specific call does
1449
1418
  */
@@ -2795,6 +2764,10 @@ export type SessionEvent = {
2795
2764
  */
2796
2765
  hookMessage?: string;
2797
2766
  };
2767
+ /**
2768
+ * When true, this permission was already resolved by a permissionRequest hook and requires no client action
2769
+ */
2770
+ resolvedByHook?: boolean;
2798
2771
  };
2799
2772
  } | {
2800
2773
  /**
@@ -2826,7 +2799,7 @@ export type SessionEvent = {
2826
2799
  /**
2827
2800
  * The outcome of the permission request
2828
2801
  */
2829
- kind: "approved" | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user" | "denied-by-content-exclusion-policy";
2802
+ kind: "approved" | "denied-by-rules" | "denied-no-approval-rule-and-could-not-request-from-user" | "denied-interactively-by-user" | "denied-by-content-exclusion-policy" | "denied-by-permission-request-hook";
2830
2803
  };
2831
2804
  };
2832
2805
  } | {
@@ -2885,13 +2858,21 @@ export type SessionEvent = {
2885
2858
  ephemeral: true;
2886
2859
  type: "user_input.completed";
2887
2860
  /**
2888
- * User input request completion notification signaling UI dismissal
2861
+ * User input request completion with the user's response
2889
2862
  */
2890
2863
  data: {
2891
2864
  /**
2892
2865
  * Request ID of the resolved user input request; clients should dismiss any UI for this request
2893
2866
  */
2894
2867
  requestId: string;
2868
+ /**
2869
+ * The user's answer to the input request
2870
+ */
2871
+ answer?: string;
2872
+ /**
2873
+ * Whether the answer was typed as free-form text rather than selected from choices
2874
+ */
2875
+ wasFreeform?: boolean;
2895
2876
  };
2896
2877
  } | {
2897
2878
  /**
@@ -2973,13 +2954,23 @@ export type SessionEvent = {
2973
2954
  ephemeral: true;
2974
2955
  type: "elicitation.completed";
2975
2956
  /**
2976
- * Elicitation request completion notification signaling UI dismissal
2957
+ * Elicitation request completion with the user's response
2977
2958
  */
2978
2959
  data: {
2979
2960
  /**
2980
2961
  * Request ID of the resolved elicitation request; clients should dismiss any UI for this request
2981
2962
  */
2982
2963
  requestId: string;
2964
+ /**
2965
+ * The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed)
2966
+ */
2967
+ action?: "accept" | "decline" | "cancel";
2968
+ /**
2969
+ * The submitted form data when action is 'accept'; keys match the requested schema fields
2970
+ */
2971
+ content?: {
2972
+ [k: string]: string | number | boolean | string[];
2973
+ };
2983
2974
  };
2984
2975
  } | {
2985
2976
  /**
@@ -3381,13 +3372,29 @@ export type SessionEvent = {
3381
3372
  ephemeral: true;
3382
3373
  type: "exit_plan_mode.completed";
3383
3374
  /**
3384
- * Plan mode exit completion notification signaling UI dismissal
3375
+ * Plan mode exit completion with the user's approval decision and optional feedback
3385
3376
  */
3386
3377
  data: {
3387
3378
  /**
3388
3379
  * Request ID of the resolved exit plan mode request; clients should dismiss any UI for this request
3389
3380
  */
3390
3381
  requestId: string;
3382
+ /**
3383
+ * Whether the plan was approved by the user
3384
+ */
3385
+ approved?: boolean;
3386
+ /**
3387
+ * Which action the user selected (e.g. 'autopilot', 'interactive', 'exit_only')
3388
+ */
3389
+ selectedAction?: string;
3390
+ /**
3391
+ * Whether edits should be auto-approved without confirmation
3392
+ */
3393
+ autoApproveEdits?: boolean;
3394
+ /**
3395
+ * Free-form feedback from the user if they requested changes to the plan
3396
+ */
3397
+ feedback?: string;
3391
3398
  };
3392
3399
  } | {
3393
3400
  /**
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, approveAll, SYSTEM_PROMPT_SECTIONS } from "./types.js";
9
- export type { CommandContext, CommandDefinition, CommandHandler, ConnectionState, CopilotClientOptions, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationRequest, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, InputOptions, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsHandler, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
9
+ export type { CommandContext, CommandDefinition, CommandHandler, ConnectionState, CopilotClientOptions, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, InfiniteSessionConfig, InputOptions, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, MessageOptions, ModelBilling, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, PermissionHandler, PermissionRequest, PermissionRequestResult, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventType, SessionLifecycleHandler, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsHandler, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemPromptSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, ToolResultObject, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
package/dist/session.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import type { MessageConnection } from "vscode-jsonrpc/node.js";
6
6
  import { createSessionRpc } from "./generated/rpc.js";
7
7
  import type { ClientSessionApiHandlers } from "./generated/rpc.js";
8
- import type { CommandHandler, ElicitationHandler, ElicitationRequest, MessageOptions, PermissionHandler, PermissionRequestResult, ReasoningEffort, SectionTransformFn, SessionCapabilities, SessionEvent, SessionEventHandler, SessionEventType, SessionHooks, SessionUiApi, Tool, ToolHandler, TraceContextProvider, TypedSessionEventHandler, UserInputHandler, UserInputResponse } from "./types.js";
8
+ import type { CommandHandler, ElicitationHandler, ElicitationContext, MessageOptions, PermissionHandler, PermissionRequestResult, ReasoningEffort, ModelCapabilitiesOverride, SectionTransformFn, SessionCapabilities, SessionEvent, SessionEventHandler, SessionEventType, SessionHooks, SessionUiApi, Tool, ToolHandler, TraceContextProvider, TypedSessionEventHandler, UserInputHandler, UserInputResponse } from "./types.js";
9
9
  export declare const NO_RESULT_PERMISSION_V2_ERROR = "Permission handlers cannot return 'no-result' when connected to a protocol v2 server.";
10
10
  /** Assistant message event - the final response from the assistant. */
11
11
  export type AssistantMessageEvent = Extract<SessionEvent, {
@@ -251,7 +251,7 @@ export declare class CopilotSession {
251
251
  * Invokes the registered handler and responds via handlePendingElicitation RPC.
252
252
  * @internal
253
253
  */
254
- _handleElicitationRequest(request: ElicitationRequest, requestId: string): Promise<void>;
254
+ _handleElicitationRequest(context: ElicitationContext, requestId: string): Promise<void>;
255
255
  /**
256
256
  * Sets the host capabilities for this session.
257
257
  *
@@ -432,6 +432,7 @@ export declare class CopilotSession {
432
432
  */
433
433
  setModel(model: string, options?: {
434
434
  reasoningEffort?: ReasoningEffort;
435
+ modelCapabilities?: ModelCapabilitiesOverride;
435
436
  }): Promise<void>;
436
437
  /**
437
438
  * Log a message to the session timeline.
package/dist/session.js CHANGED
@@ -241,7 +241,10 @@ class CopilotSession {
241
241
  );
242
242
  }
243
243
  } else if (event.type === "permission.requested") {
244
- const { requestId, permissionRequest } = event.data;
244
+ const { requestId, permissionRequest, resolvedByHook } = event.data;
245
+ if (resolvedByHook) {
246
+ return;
247
+ }
245
248
  if (this.permissionHandler) {
246
249
  void this._executePermissionAndRespond(requestId, permissionRequest);
247
250
  }
@@ -253,6 +256,7 @@ class CopilotSession {
253
256
  const { message, requestedSchema, mode, elicitationSource, url, requestId } = event.data;
254
257
  void this._handleElicitationRequest(
255
258
  {
259
+ sessionId: this.sessionId,
256
260
  message,
257
261
  requestedSchema,
258
262
  mode,
@@ -285,6 +289,8 @@ class CopilotSession {
285
289
  result = "";
286
290
  } else if (typeof rawResult === "string") {
287
291
  result = rawResult;
292
+ } else if (isToolResultObject(rawResult)) {
293
+ result = rawResult;
288
294
  } else {
289
295
  result = JSON.stringify(rawResult);
290
296
  }
@@ -418,12 +424,12 @@ class CopilotSession {
418
424
  * Invokes the registered handler and responds via handlePendingElicitation RPC.
419
425
  * @internal
420
426
  */
421
- async _handleElicitationRequest(request, requestId) {
427
+ async _handleElicitationRequest(context, requestId) {
422
428
  if (!this.elicitationHandler) {
423
429
  return;
424
430
  }
425
431
  try {
426
- const result = await this.elicitationHandler(request, { sessionId: this.sessionId });
432
+ const result = await this.elicitationHandler(context);
427
433
  await this.rpc.ui.handlePendingElicitation({ requestId, result });
428
434
  } catch {
429
435
  try {
@@ -796,6 +802,25 @@ class CopilotSession {
796
802
  await this.rpc.log({ message, ...options });
797
803
  }
798
804
  }
805
+ function isToolResultObject(value) {
806
+ if (typeof value !== "object" || value === null) {
807
+ return false;
808
+ }
809
+ if (!("textResultForLlm" in value) || typeof value.textResultForLlm !== "string") {
810
+ return false;
811
+ }
812
+ if (!("resultType" in value) || typeof value.resultType !== "string") {
813
+ return false;
814
+ }
815
+ const allowedResultTypes = [
816
+ "success",
817
+ "failure",
818
+ "rejected",
819
+ "denied",
820
+ "timeout"
821
+ ];
822
+ return allowedResultTypes.includes(value.resultType);
823
+ }
799
824
  export {
800
825
  CopilotSession,
801
826
  NO_RESULT_PERMISSION_V2_ERROR
package/dist/types.d.ts CHANGED
@@ -160,7 +160,7 @@ export interface CopilotClientOptions {
160
160
  /**
161
161
  * Configuration for creating a session
162
162
  */
163
- export type ToolResultType = "success" | "failure" | "rejected" | "denied";
163
+ export type ToolResultType = "success" | "failure" | "rejected" | "denied" | "timeout";
164
164
  export type ToolBinaryResult = {
165
165
  data: string;
166
166
  mimeType: string;
@@ -364,10 +364,12 @@ export interface ElicitationParams {
364
364
  requestedSchema: ElicitationSchema;
365
365
  }
366
366
  /**
367
- * Request payload passed to an elicitation handler callback.
368
- * Extends ElicitationParams with optional metadata fields.
367
+ * Context for an elicitation handler invocation, combining the request data
368
+ * with session context. Mirrors the single-argument pattern of {@link CommandContext}.
369
369
  */
370
- export interface ElicitationRequest {
370
+ export interface ElicitationContext {
371
+ /** Identifier of the session that triggered the elicitation request. */
372
+ sessionId: string;
371
373
  /** Message describing what information is needed from the user. */
372
374
  message: string;
373
375
  /** JSON Schema describing the form fields to present. */
@@ -383,9 +385,7 @@ export interface ElicitationRequest {
383
385
  * Handler invoked when the server dispatches an elicitation request to this client.
384
386
  * Return an {@link ElicitationResult} with the user's response.
385
387
  */
386
- export type ElicitationHandler = (request: ElicitationRequest, invocation: {
387
- sessionId: string;
388
- }) => Promise<ElicitationResult> | ElicitationResult;
388
+ export type ElicitationHandler = (context: ElicitationContext) => Promise<ElicitationResult> | ElicitationResult;
389
389
  /**
390
390
  * Options for the `input()` convenience method.
391
391
  */
@@ -880,6 +880,8 @@ export interface SessionConfig {
880
880
  * Use client.listModels() to check supported values for each model.
881
881
  */
882
882
  reasoningEffort?: ReasoningEffort;
883
+ /** Per-property overrides for model capabilities, deep-merged over runtime defaults. */
884
+ modelCapabilities?: ModelCapabilitiesOverride;
883
885
  /**
884
886
  * Override the default configuration directory location.
885
887
  * When specified, the session will use this directory for storing config and state.
@@ -990,7 +992,7 @@ export interface SessionConfig {
990
992
  /**
991
993
  * Configuration for resuming a session
992
994
  */
993
- export type ResumeSessionConfig = Pick<SessionConfig, "clientName" | "model" | "tools" | "commands" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "streaming" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "onElicitationRequest" | "hooks" | "workingDirectory" | "configDir" | "mcpServers" | "customAgents" | "agent" | "skillDirectories" | "disabledSkills" | "infiniteSessions" | "onEvent" | "createSessionFsHandler"> & {
995
+ export type ResumeSessionConfig = Pick<SessionConfig, "clientName" | "model" | "tools" | "commands" | "systemMessage" | "availableTools" | "excludedTools" | "provider" | "modelCapabilities" | "streaming" | "reasoningEffort" | "onPermissionRequest" | "onUserInputRequest" | "onElicitationRequest" | "hooks" | "workingDirectory" | "configDir" | "mcpServers" | "customAgents" | "agent" | "skillDirectories" | "disabledSkills" | "infiniteSessions" | "onEvent" | "createSessionFsHandler"> & {
994
996
  /**
995
997
  * When true, skips emitting the session.resume event.
996
998
  * Useful for reconnecting to a session without triggering resume-related side effects.
@@ -1202,6 +1204,12 @@ export interface ModelCapabilities {
1202
1204
  };
1203
1205
  };
1204
1206
  }
1207
+ /** Recursively makes all properties optional, preserving arrays as-is. */
1208
+ type DeepPartial<T> = T extends readonly (infer U)[] ? DeepPartial<U>[] : T extends object ? {
1209
+ [K in keyof T]?: DeepPartial<T[K]>;
1210
+ } : T;
1211
+ /** Deep-partial override for model capabilities — every property at any depth is optional. */
1212
+ export type ModelCapabilitiesOverride = DeepPartial<ModelCapabilities>;
1205
1213
  /**
1206
1214
  * Model policy state
1207
1215
  */
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.2.1-unstable.0",
7
+ "version": "0.2.2-preview.0",
8
8
  "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
9
9
  "main": "./dist/cjs/index.js",
10
10
  "types": "./dist/index.d.ts",
@@ -56,7 +56,7 @@
56
56
  "author": "GitHub",
57
57
  "license": "MIT",
58
58
  "dependencies": {
59
- "@github/copilot": "^1.0.15-1",
59
+ "@github/copilot": "^1.0.20-1",
60
60
  "vscode-jsonrpc": "^8.2.1",
61
61
  "zod": "^4.3.6"
62
62
  },