@github/copilot-sdk 1.0.3 → 1.0.5-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.
@@ -22,6 +22,7 @@ __export(rpc_exports, {
22
22
  createInternalSessionRpc: () => createInternalSessionRpc,
23
23
  createServerRpc: () => createServerRpc,
24
24
  createSessionRpc: () => createSessionRpc,
25
+ registerClientGlobalApiHandlers: () => registerClientGlobalApiHandlers,
25
26
  registerClientSessionApiHandlers: () => registerClientSessionApiHandlers
26
27
  });
27
28
  module.exports = __toCommonJS(rpc_exports);
@@ -63,7 +64,35 @@ function createServerRpc(connection) {
63
64
  *
64
65
  * @returns Quota usage snapshots for the resolved user, keyed by quota type.
65
66
  */
66
- getQuota: async (params) => connection.sendRequest("account.getQuota", params)
67
+ getQuota: async (params) => connection.sendRequest("account.getQuota", params),
68
+ /**
69
+ * Gets the currently active authentication credentials from the global auth manager.
70
+ *
71
+ * @returns Current authentication state
72
+ */
73
+ getCurrentAuth: async () => connection.sendRequest("account.getCurrentAuth", {}),
74
+ /**
75
+ * Gets all authenticated users available for account switching.
76
+ *
77
+ * @returns List of all authenticated users
78
+ */
79
+ getAllUsers: async () => connection.sendRequest("account.getAllUsers", {}),
80
+ /**
81
+ * Stores authentication credentials after successful login (e.g., device code flow).
82
+ *
83
+ * @param params Credentials to store after successful authentication
84
+ *
85
+ * @returns Result of a successful login; throws on failure
86
+ */
87
+ login: async (params) => connection.sendRequest("account.login", params),
88
+ /**
89
+ * Removes user authentication from keychain and persisted state.
90
+ *
91
+ * @param params User to log out
92
+ *
93
+ * @returns Logout result indicating if more users remain
94
+ */
95
+ logout: async (params) => connection.sendRequest("account.logout", params)
67
96
  },
68
97
  secrets: {
69
98
  /**
@@ -626,13 +655,13 @@ function createSessionRpc(connection, sessionId) {
626
655
  */
627
656
  shutdown: async (params) => connection.sendRequest("session.shutdown", { sessionId, ...params }),
628
657
  /** @experimental */
629
- auth: {
658
+ gitHubAuth: {
630
659
  /**
631
660
  * Gets authentication status and account metadata for the session.
632
661
  *
633
662
  * @returns Authentication status and account metadata for the session.
634
663
  */
635
- getStatus: async () => connection.sendRequest("session.auth.getStatus", { sessionId }),
664
+ getStatus: async () => connection.sendRequest("session.gitHubAuth.getStatus", { sessionId }),
636
665
  /**
637
666
  * Updates the session's auth credentials used for outbound model and API requests.
638
667
  *
@@ -640,7 +669,7 @@ function createSessionRpc(connection, sessionId) {
640
669
  *
641
670
  * @returns Indicates whether the credential update succeeded.
642
671
  */
643
- setCredentials: async (params) => connection.sendRequest("session.auth.setCredentials", { sessionId, ...params })
672
+ setCredentials: async (params) => connection.sendRequest("session.gitHubAuth.setCredentials", { sessionId, ...params })
644
673
  },
645
674
  /** @experimental */
646
675
  canvas: {
@@ -1103,13 +1132,24 @@ function createSessionRpc(connection, sessionId) {
1103
1132
  /**
1104
1133
  * Starts OAuth authentication for a remote MCP server.
1105
1134
  *
1106
- * @param params Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, and the callback success-page copy.
1135
+ * @param params Remote MCP server name and optional overrides controlling reauthentication, OAuth client display name, callback success-page copy, and static OAuth client selection.
1107
1136
  *
1108
1137
  * @returns OAuth authorization URL the caller should open, or empty when cached tokens already authenticated the server.
1109
1138
  */
1110
1139
  login: async (params) => connection.sendRequest("session.mcp.oauth.login", { sessionId, ...params })
1111
1140
  },
1112
1141
  /** @experimental */
1142
+ headers: {
1143
+ /**
1144
+ * Responds to a pending MCP dynamic headers refresh request. Hosts that subscribe to `mcp.headers_refresh_required` use this to provide short-lived per-server headers or to indicate that no dynamic headers are available for this refresh.
1145
+ *
1146
+ * @param params MCP headers refresh request id and the host response.
1147
+ *
1148
+ * @returns Indicates whether the pending MCP headers refresh response was accepted.
1149
+ */
1150
+ handlePendingHeadersRefreshRequest: async (params) => connection.sendRequest("session.mcp.headers.handlePendingHeadersRefreshRequest", { sessionId, ...params })
1151
+ },
1152
+ /** @experimental */
1113
1153
  apps: {
1114
1154
  /**
1115
1155
  * Fetch an MCP resource (typically a `ui://` MCP App bundle, per SEP-1865) from a connected server. Requires the `mcp-apps` session capability.
@@ -1181,7 +1221,15 @@ function createSessionRpc(connection, sessionId) {
1181
1221
  *
1182
1222
  * @returns A snapshot of the provider endpoint the session is currently configured to talk to.
1183
1223
  */
1184
- getEndpoint: async (params) => connection.sendRequest("session.provider.getEndpoint", { sessionId, ...params })
1224
+ getEndpoint: async (params) => connection.sendRequest("session.provider.getEndpoint", { sessionId, ...params }),
1225
+ /**
1226
+ * Adds BYOK providers and/or models to the session's registry at runtime, extending the additive registry built from the session's `providers`/`models` options. Both fields are optional, so a call may add providers only, models only, or both. Within a single call providers are registered before models, so a model may reference a provider added in the same call; across calls a model may reference any provider already registered (from session creation or a prior add). A model whose referenced provider is not registered by the end of the call is rejected. Newly added models become selectable via `model.list` / `model.switchTo` and are inherited by sub-agents spawned afterwards.
1227
+ *
1228
+ * @param params BYOK providers and/or models to add to the session's registry at runtime. Both fields are optional; provide providers, models, or both.
1229
+ *
1230
+ * @returns The selectable model entries synthesized for the models added by this call.
1231
+ */
1232
+ add: async (params) => connection.sendRequest("session.provider.add", { sessionId, ...params })
1185
1233
  },
1186
1234
  /** @experimental */
1187
1235
  options: {
@@ -1280,7 +1328,7 @@ function createSessionRpc(connection, sessionId) {
1280
1328
  *
1281
1329
  * @param params Slash command name and optional raw input string to invoke.
1282
1330
  *
1283
- * @returns Result of invoking the slash command (text output, prompt to send to the agent, or completion).
1331
+ * @returns Result of invoking the slash command (text output, prompt to send to the agent, completion, or subcommand selection).
1284
1332
  */
1285
1333
  invoke: async (params) => connection.sendRequest("session.commands.invoke", { sessionId, ...params }),
1286
1334
  /**
@@ -1876,6 +1924,11 @@ function createInternalSessionRpc(connection, sessionId) {
1876
1924
  };
1877
1925
  }
1878
1926
  function registerClientSessionApiHandlers(connection, getHandlers) {
1927
+ connection.onRequest("providerToken.getToken", async (params) => {
1928
+ const handler = getHandlers(params.sessionId).providerToken;
1929
+ if (!handler) throw new Error(`No providerToken handler registered for session: ${params.sessionId}`);
1930
+ return handler.getToken(params);
1931
+ });
1879
1932
  connection.onRequest("sessionFs.readFile", async (params) => {
1880
1933
  const handler = getHandlers(params.sessionId).sessionFs;
1881
1934
  if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
@@ -1952,11 +2005,24 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
1952
2005
  return handler.invoke(params);
1953
2006
  });
1954
2007
  }
2008
+ function registerClientGlobalApiHandlers(connection, handlers) {
2009
+ connection.onRequest("llmInference.httpRequestStart", async (params) => {
2010
+ const handler = handlers.llmInference;
2011
+ if (!handler) throw new Error("No llmInference client-global handler registered");
2012
+ return handler.httpRequestStart(params);
2013
+ });
2014
+ connection.onRequest("llmInference.httpRequestChunk", async (params) => {
2015
+ const handler = handlers.llmInference;
2016
+ if (!handler) throw new Error("No llmInference client-global handler registered");
2017
+ return handler.httpRequestChunk(params);
2018
+ });
2019
+ }
1955
2020
  // Annotate the CommonJS export names for ESM import in node:
1956
2021
  0 && (module.exports = {
1957
2022
  createInternalServerRpc,
1958
2023
  createInternalSessionRpc,
1959
2024
  createServerRpc,
1960
2025
  createSessionRpc,
2026
+ registerClientGlobalApiHandlers,
1961
2027
  registerClientSessionApiHandlers
1962
2028
  });
package/dist/cjs/index.js CHANGED
@@ -22,7 +22,11 @@ __export(index_exports, {
22
22
  Canvas: () => import_canvas.Canvas,
23
23
  CanvasError: () => import_canvas.CanvasError,
24
24
  CopilotClient: () => import_client.CopilotClient,
25
+ CopilotRequestHandler: () => import_types2.CopilotRequestHandler,
25
26
  CopilotSession: () => import_session.CopilotSession,
27
+ CopilotWebSocketCloseStatus: () => import_types2.CopilotWebSocketCloseStatus,
28
+ CopilotWebSocketForwarder: () => import_types2.CopilotWebSocketForwarder,
29
+ CopilotWebSocketHandler: () => import_types2.CopilotWebSocketHandler,
26
30
  RuntimeConnection: () => import_types.RuntimeConnection,
27
31
  SYSTEM_MESSAGE_SECTIONS: () => import_types2.SYSTEM_MESSAGE_SECTIONS,
28
32
  ToolSet: () => import_toolSet.ToolSet,
@@ -45,7 +49,11 @@ var import_types2 = require("./types.js");
45
49
  Canvas,
46
50
  CanvasError,
47
51
  CopilotClient,
52
+ CopilotRequestHandler,
48
53
  CopilotSession,
54
+ CopilotWebSocketCloseStatus,
55
+ CopilotWebSocketForwarder,
56
+ CopilotWebSocketHandler,
49
57
  RuntimeConnection,
50
58
  SYSTEM_MESSAGE_SECTIONS,
51
59
  ToolSet,
@@ -38,7 +38,7 @@ function isOpenCanvasInstance(value) {
38
38
  return false;
39
39
  }
40
40
  const instance = value;
41
- return typeof instance.instanceId === "string" && instance.instanceId.length > 0 && typeof instance.extensionId === "string" && instance.extensionId.length > 0 && typeof instance.canvasId === "string" && instance.canvasId.length > 0 && typeof instance.reopen === "boolean" && (instance.availability === "ready" || instance.availability === "stale");
41
+ return typeof instance.instanceId === "string" && instance.instanceId.length > 0 && typeof instance.extensionId === "string" && instance.extensionId.length > 0 && typeof instance.canvasId === "string" && instance.canvasId.length > 0;
42
42
  }
43
43
  class CopilotSession {
44
44
  /**
@@ -63,6 +63,7 @@ class CopilotSession {
63
63
  typedEventHandlers = /* @__PURE__ */ new Map();
64
64
  toolHandlers = /* @__PURE__ */ new Map();
65
65
  canvases = /* @__PURE__ */ new Map();
66
+ bearerTokenProviders = /* @__PURE__ */ new Map();
66
67
  commandHandlers = /* @__PURE__ */ new Map();
67
68
  permissionHandler;
68
69
  userInputHandler;
@@ -75,6 +76,7 @@ class CopilotSession {
75
76
  traceContextProvider;
76
77
  _capabilities = {};
77
78
  openCanvasInstances = [];
79
+ disconnected = false;
78
80
  /** @internal Client session API handlers, populated by CopilotClient during create/resume. */
79
81
  clientSessionApis = {};
80
82
  /**
@@ -178,6 +180,21 @@ class CopilotSession {
178
180
  unsubscribe();
179
181
  }
180
182
  }
183
+ /** @internal */
184
+ _markDisconnected() {
185
+ this.disconnected = true;
186
+ this.eventHandlers.clear();
187
+ this.typedEventHandlers.clear();
188
+ this.toolHandlers.clear();
189
+ this.permissionHandler = void 0;
190
+ this.userInputHandler = void 0;
191
+ this.elicitationHandler = void 0;
192
+ this.exitPlanModeHandler = void 0;
193
+ this.autoModeSwitchHandler = void 0;
194
+ this.commandHandlers.clear();
195
+ this.canvases.clear();
196
+ this.transformCallbacks?.clear();
197
+ }
181
198
  on(eventTypeOrHandler, handler) {
182
199
  if (typeof eventTypeOrHandler === "string" && handler) {
183
200
  const eventType = eventTypeOrHandler;
@@ -231,6 +248,9 @@ class CopilotSession {
231
248
  * @internal
232
249
  */
233
250
  _handleBroadcastEvent(event) {
251
+ if (this.disconnected) {
252
+ return;
253
+ }
234
254
  if (event.type === "external_tool.requested") {
235
255
  const { requestId, toolName } = event.data;
236
256
  const args = event.data.arguments;
@@ -336,8 +356,14 @@ class CopilotSession {
336
356
  } else {
337
357
  result = JSON.stringify(rawResult);
338
358
  }
359
+ if (this.disconnected) {
360
+ return;
361
+ }
339
362
  await this.rpc.tools.handlePendingToolCall({ requestId, result });
340
363
  } catch (error) {
364
+ if (this.disconnected) {
365
+ return;
366
+ }
341
367
  const message = error instanceof Error ? error.message : String(error);
342
368
  try {
343
369
  await this.rpc.tools.handlePendingToolCall({ requestId, error: message });
@@ -360,8 +386,14 @@ class CopilotSession {
360
386
  if (result.kind === "no-result") {
361
387
  return;
362
388
  }
389
+ if (this.disconnected) {
390
+ return;
391
+ }
363
392
  await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
364
393
  } catch (_error) {
394
+ if (this.disconnected) {
395
+ return;
396
+ }
365
397
  try {
366
398
  await this.rpc.permissions.handlePendingPermissionRequest({
367
399
  requestId,
@@ -397,8 +429,14 @@ class CopilotSession {
397
429
  }
398
430
  try {
399
431
  await handler({ sessionId: this.sessionId, command, commandName, args });
432
+ if (this.disconnected) {
433
+ return;
434
+ }
400
435
  await this.rpc.commands.handlePendingCommand({ requestId });
401
436
  } catch (error) {
437
+ if (this.disconnected) {
438
+ return;
439
+ }
402
440
  const message = error instanceof Error ? error.message : String(error);
403
441
  try {
404
442
  await this.rpc.commands.handlePendingCommand({ requestId, error: message });
@@ -494,6 +532,44 @@ class CopilotSession {
494
532
  }
495
533
  };
496
534
  }
535
+ /**
536
+ * Registers per-provider {@link BearerTokenProvider} callbacks for BYOK providers
537
+ * configured with managed-identity / on-demand bearer-token auth.
538
+ *
539
+ * The runtime never receives the callback itself; the SDK strips it from the
540
+ * provider config and instead sends `hasBearerTokenProvider: true`. When the
541
+ * runtime needs a token it issues a session-scoped `providerToken.getToken`
542
+ * request, which this handler routes to the matching per-provider callback.
543
+ *
544
+ * @param providers - Map of provider name → callback, or undefined/empty to clear.
545
+ * @internal This method is called internally when creating/resuming a session.
546
+ */
547
+ registerBearerTokenProviders(providers) {
548
+ this.bearerTokenProviders.clear();
549
+ if (!providers || providers.size === 0) {
550
+ delete this.clientSessionApis.providerToken;
551
+ return;
552
+ }
553
+ for (const [name, callback] of providers) {
554
+ this.bearerTokenProviders.set(name, callback);
555
+ }
556
+ const self = this;
557
+ this.clientSessionApis.providerToken = {
558
+ async getToken(params) {
559
+ const callback = self.bearerTokenProviders.get(params.providerName);
560
+ if (!callback) {
561
+ throw new Error(
562
+ `No bearer-token provider registered for provider "${params.providerName}"`
563
+ );
564
+ }
565
+ const token = await callback({
566
+ providerName: params.providerName,
567
+ sessionId: params.sessionId
568
+ });
569
+ return { token };
570
+ }
571
+ };
572
+ }
497
573
  /**
498
574
  * Registers command handlers for this session.
499
575
  *
@@ -848,17 +924,13 @@ class CopilotSession {
848
924
  * ```
849
925
  */
850
926
  async disconnect() {
927
+ if (this.disconnected) {
928
+ return;
929
+ }
851
930
  await this.connection.sendRequest("session.destroy", {
852
931
  sessionId: this.sessionId
853
932
  });
854
- this.eventHandlers.clear();
855
- this.typedEventHandlers.clear();
856
- this.toolHandlers.clear();
857
- this.permissionHandler = void 0;
858
- this.userInputHandler = void 0;
859
- this.elicitationHandler = void 0;
860
- this.exitPlanModeHandler = void 0;
861
- this.autoModeSwitchHandler = void 0;
933
+ this._markDisconnected();
862
934
  }
863
935
  /** Enables `await using session = ...` syntax for automatic cleanup. */
864
936
  async [Symbol.asyncDispose]() {
package/dist/cjs/types.js CHANGED
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var types_exports = {};
20
20
  __export(types_exports, {
21
+ CopilotRequestHandler: () => import_copilotRequestHandler.CopilotRequestHandler,
22
+ CopilotWebSocketCloseStatus: () => import_copilotRequestHandler.CopilotWebSocketCloseStatus,
23
+ CopilotWebSocketForwarder: () => import_copilotRequestHandler.CopilotWebSocketForwarder,
24
+ CopilotWebSocketHandler: () => import_copilotRequestHandler.CopilotWebSocketHandler,
21
25
  RuntimeConnection: () => RuntimeConnection,
22
26
  SYSTEM_MESSAGE_SECTIONS: () => SYSTEM_MESSAGE_SECTIONS,
23
27
  approveAll: () => approveAll,
@@ -28,6 +32,7 @@ __export(types_exports, {
28
32
  });
29
33
  module.exports = __toCommonJS(types_exports);
30
34
  var import_sessionFsProvider = require("./sessionFsProvider.js");
35
+ var import_copilotRequestHandler = require("./copilotRequestHandler.js");
31
36
  const RuntimeConnection = {
32
37
  /**
33
38
  * Spawn a runtime child process and communicate over its stdin/stdout.
@@ -102,7 +107,10 @@ function defineTool(name, config) {
102
107
  return { name, ...config };
103
108
  }
104
109
  const SYSTEM_MESSAGE_SECTIONS = {
105
- identity: { description: "Agent identity preamble and mode statement" },
110
+ preamble: { description: "Agent identity preamble and mode statement" },
111
+ identity: {
112
+ description: "Section group covering the identity preamble and its sibling sub-sections (tone, tool efficiency, etc.)"
113
+ },
106
114
  tone: { description: "Response style, conciseness rules, output formatting preferences" },
107
115
  tool_efficiency: { description: "Tool usage patterns, parallel calling, batching guidelines" },
108
116
  environment_context: { description: "CWD, OS, git root, directory listing, available tools" },
@@ -124,6 +132,10 @@ const defaultJoinSessionPermissionHandler = () => ({
124
132
  });
125
133
  // Annotate the CommonJS export names for ESM import in node:
126
134
  0 && (module.exports = {
135
+ CopilotRequestHandler,
136
+ CopilotWebSocketCloseStatus,
137
+ CopilotWebSocketForwarder,
138
+ CopilotWebSocketHandler,
127
139
  RuntimeConnection,
128
140
  SYSTEM_MESSAGE_SECTIONS,
129
141
  approveAll,
package/dist/client.d.ts CHANGED
@@ -1,43 +1,11 @@
1
1
  import { createServerRpc } from "./generated/rpc.js";
2
2
  import { CopilotSession } from "./session.js";
3
3
  import type { CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, ModelInfo, ResumeSessionConfig, SessionConfig, SessionLifecycleEventType, SessionLifecycleHandler, SessionListFilter, SessionMetadata, TypedSessionLifecycleHandler } from "./types.js";
4
- /**
5
- * Main client for interacting with the Copilot CLI.
6
- *
7
- * The CopilotClient manages the connection to the Copilot CLI server and provides
8
- * methods to create and manage conversation sessions. It can either spawn a CLI
9
- * server process or connect to an existing server.
10
- *
11
- * @example
12
- * ```typescript
13
- * import { CopilotClient } from "@github/copilot-sdk";
14
- *
15
- * // Create a client with default options (spawns CLI server)
16
- * const client = new CopilotClient();
17
- *
18
- * // Or connect to an existing server
19
- * const client = new CopilotClient({ connection: RuntimeConnection.forUri("localhost:3000") });
20
- *
21
- * // Create a session
22
- * const session = await client.createSession({ onPermissionRequest: approveAll, model: "gpt-4" });
23
- *
24
- * // Send messages and handle responses
25
- * session.on((event) => {
26
- * if (event.type === "assistant.message") {
27
- * console.log(event.data.content);
28
- * }
29
- * });
30
- * await session.send({ prompt: "Hello!" });
31
- *
32
- * // Clean up
33
- * await session.disconnect();
34
- * await client.stop();
35
- * ```
36
- */
37
4
  export declare class CopilotClient {
38
5
  private cliStartTimeout;
39
6
  private cliProcess;
40
7
  private connection;
8
+ private messageWriter;
41
9
  private socket;
42
10
  private runtimePort;
43
11
  private actualHost;
@@ -67,12 +35,15 @@ export declare class CopilotClient {
67
35
  private negotiatedProtocolVersion;
68
36
  /** Connection-level session filesystem config, set via constructor option. */
69
37
  private sessionFsConfig;
38
+ private requestHandler;
39
+ private llmInferenceHandlers;
70
40
  /**
71
41
  * Typed server-scoped RPC methods.
72
42
  * @throws Error if the client is not connected
73
43
  */
74
44
  get rpc(): ReturnType<typeof createServerRpc>;
75
45
  private logDebugTiming;
46
+ private logDebug;
76
47
  /**
77
48
  * Creates a new CopilotClient instance.
78
49
  *
@@ -109,6 +80,7 @@ export declare class CopilotClient {
109
80
  private parseCliUrl;
110
81
  private validateSessionFsConfig;
111
82
  private setupSessionFs;
83
+ private setupLlmInference;
112
84
  /**
113
85
  * Starts the CLI server and establishes a connection.
114
86
  *