@github/copilot-sdk 1.0.0-beta.9 → 1.0.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,8 +2,6 @@
2
2
 
3
3
  TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
4
4
 
5
- > **Note:** This SDK is in public preview and may change in breaking ways.
6
-
7
5
  ## Installation
8
6
 
9
7
  ```bash
@@ -57,7 +55,7 @@ await session.disconnect();
57
55
  await client.stop();
58
56
  ```
59
57
 
60
- Sessions also support `Symbol.asyncDispose` for use with [`await using`](https://github.com/tc39/proposal-explicit-resource-management) (TypeScript 5.2+/Node.js 18.0+):
58
+ Sessions also support `Symbol.asyncDispose` for use with [`await using`](https://github.com/tc39/proposal-explicit-resource-management) (TypeScript 5.2+ / Node.js 20+):
61
59
 
62
60
  ```typescript
63
61
  await using session = await client.createSession({
@@ -82,14 +80,20 @@ new CopilotClient(options?: CopilotClientOptions)
82
80
  - `connection?: RuntimeConnection` - How to connect to the Copilot runtime. Construct via the factory functions on `RuntimeConnection`:
83
81
  - `RuntimeConnection.forStdio({ path?, args? })` (default) — spawn the runtime and communicate over its stdin/stdout.
84
82
  - `RuntimeConnection.forTcp({ port?, connectionToken?, path?, args? })` — spawn the runtime as a TCP server.
85
- - `RuntimeConnection.forUri(url, { connectionToken? })` — connect to an already-running runtime (mutually exclusive with `gitHubToken`/`useLoggedInUser`).
86
- - `cwd?: string` - Working directory for the runtime process (default: current process cwd).
83
+ - `RuntimeConnection.forUri(url, { connectionToken? })` — connect to an already-running runtime (mutually exclusive with `gitHubToken`/`useLoggedInUser`). There is no top-level `cliUrl` shortcut; use this factory for URL-based connections.
84
+ - `mode?: "empty" | "copilot-cli"` - Defaulting strategy. Use `"empty"` for multi-user server mode; defaults to `"copilot-cli"`.
85
+ - `workingDirectory?: string` - Working directory for the runtime process (default: current process cwd).
87
86
  - `baseDirectory?: string` - Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned runtime. When not set, the runtime defaults to `~/.copilot`. Ignored when connecting via `RuntimeConnection.forUri`.
88
- - `logLevel?: string` - Log level. When omitted, the runtime uses its own default (currently `"info"`).
87
+ - `logLevel?: "none" | "error" | "warning" | "info" | "debug" | "all"` - Log level. When omitted, the runtime uses its own default (currently `"info"`).
88
+ - `env?: Record<string, string | undefined>` - Environment variables for the runtime process. When omitted, inherits `process.env`.
89
89
  - `gitHubToken?: string` - GitHub token for authentication. When provided, takes priority over other auth methods.
90
90
  - `useLoggedInUser?: boolean` - Whether to use logged-in user for authentication (default: true, but false when `gitHubToken` is provided). Cannot be used with `RuntimeConnection.forUri`.
91
+ - `onListModels?: () => Promise<ModelInfo[]> | ModelInfo[]` - Optional model-list provider, useful when using a custom provider.
91
92
  - `telemetry?: TelemetryConfig` - OpenTelemetry configuration for the runtime process. Providing this object enables telemetry — no separate flag needed. See [Telemetry](#telemetry) below.
92
93
  - `onGetTraceContext?: TraceContextProvider` - Advanced: callback for linking your application's own OpenTelemetry spans into the same distributed trace as the runtime's spans. Not needed for normal telemetry collection. See [Telemetry](#telemetry) below.
94
+ - `sessionFs?: SessionFsConfig` - Custom session filesystem provider.
95
+ - `sessionIdleTimeoutSeconds?: number` - Server-wide idle timeout for sessions in seconds. Ignored when connecting via `RuntimeConnection.forUri`.
96
+ - `enableRemoteSessions?: boolean` - Enable Mission Control remote session support. Ignored when connecting via `RuntimeConnection.forUri`.
93
97
 
94
98
  #### Methods
95
99
 
@@ -163,7 +167,7 @@ Get the ID of the session currently displayed in the TUI. Only available when co
163
167
 
164
168
  Request the TUI to switch to displaying the specified session. Only available in TUI+server mode.
165
169
 
166
- ##### `on(eventType: SessionLifecycleEventType, handler): () => void`
170
+ ##### `onLifecycle(eventType: SessionLifecycleEventType, handler): () => void`
167
171
 
168
172
  Subscribe to a specific session lifecycle event type. Returns an unsubscribe function.
169
173
 
@@ -173,7 +177,7 @@ const unsubscribe = client.onLifecycle("session.foreground", (event) => {
173
177
  });
174
178
  ```
175
179
 
176
- ##### `on(handler: SessionLifecycleHandler): () => void`
180
+ ##### `onLifecycle(handler: SessionLifecycleHandler): () => void`
177
181
 
178
182
  Subscribe to all session lifecycle events. Returns an unsubscribe function.
179
183
 
package/dist/canvas.d.ts CHANGED
@@ -1,14 +1,17 @@
1
1
  import type { CanvasJsonSchema, CanvasProviderCloseRequest, CanvasProviderInvokeActionRequest, CanvasProviderOpenRequest, CanvasProviderOpenResult } from "./generated/rpc.js";
2
- export type { CanvasJsonSchema, CanvasHostContext } from "./generated/rpc.js";
2
+ export type { CanvasJsonSchema, CanvasHostContext, CanvasHostContextCapabilities, } from "./generated/rpc.js";
3
3
  /**
4
4
  * Extension-owned canvases declared via
5
5
  * `joinSession({ canvases: [createCanvas({...})] })`.
6
6
  *
7
7
  * The runtime sends provider callbacks as `canvas.open`, `canvas.close`, and
8
- * `canvas.invokeAction` JSON-RPC requests via the codegen client session API
8
+ * `canvas.action.invoke` JSON-RPC requests via the codegen client session API
9
9
  * pipeline. The SDK routes those requests by `canvasId` to the in-process
10
10
  * handlers bound by `createCanvas`. Re-opening with an existing `instanceId`
11
11
  * is how the host focuses an existing panel; reload is a renderer-only concern.
12
+ *
13
+ * @experimental Canvas types are part of an experimental wire-protocol surface
14
+ * and may change or be removed in future SDK or CLI releases.
12
15
  */
13
16
  /**
14
17
  * A single agent-callable action contributed by a canvas. The metadata
@@ -18,6 +21,9 @@ export type { CanvasJsonSchema, CanvasHostContext } from "./generated/rpc.js";
18
21
  *
19
22
  * Names MUST NOT start with `canvas.` — that prefix is reserved for
20
23
  * lifecycle verbs.
24
+ *
25
+ * @experimental This type is part of an experimental wire-protocol surface
26
+ * and may change or be removed in future SDK or CLI releases.
21
27
  */
22
28
  export interface CanvasAction {
23
29
  /** Action identifier, unique within the canvas. */
@@ -32,6 +38,9 @@ export interface CanvasAction {
32
38
  /**
33
39
  * Declarative metadata for a single canvas, serialized over the wire on
34
40
  * `session.create` / `session.resume`.
41
+ *
42
+ * @experimental This type is part of an experimental wire-protocol surface
43
+ * and may change or be removed in future SDK or CLI releases.
35
44
  */
36
45
  export interface CanvasDeclaration {
37
46
  /** Canvas id, unique within the declaring connection. */
@@ -45,7 +54,12 @@ export interface CanvasDeclaration {
45
54
  /** Agent-invocable actions exposed via `invoke_canvas_action`. */
46
55
  actions?: Omit<CanvasAction, "handler">[];
47
56
  }
48
- /** Structured error returned from canvas handlers. */
57
+ /**
58
+ * Structured error returned from canvas handlers.
59
+ *
60
+ * @experimental This class is part of an experimental wire-protocol surface
61
+ * and may change or be removed in future SDK or CLI releases.
62
+ */
49
63
  export declare class CanvasError extends Error {
50
64
  readonly code: string;
51
65
  constructor(code: string, message: string);
@@ -55,6 +69,9 @@ export declare class CanvasError extends Error {
55
69
  /**
56
70
  * Options accepted by {@link createCanvas}. Combines the declarative
57
71
  * {@link CanvasDeclaration} fields with the in-process handler closures.
72
+ *
73
+ * @experimental This interface is part of an experimental wire-protocol surface
74
+ * and may change or be removed in future SDK or CLI releases.
58
75
  */
59
76
  export interface CanvasOptions {
60
77
  /** @see CanvasDeclaration.id */
@@ -87,6 +104,9 @@ export interface CanvasOptions {
87
104
  * ergonomics) where other SDKs (Rust, Python, Go, .NET) expose a single
88
105
  * `CanvasHandler` per session that switches on `canvasId`. Both shapes target
89
106
  * the same JSON-RPC wire protocol; the divergence is API ergonomics only.
107
+ *
108
+ * @experimental This class is part of an experimental wire-protocol surface
109
+ * and may change or be removed in future SDK or CLI releases.
90
110
  */
91
111
  export declare class Canvas {
92
112
  readonly declaration: CanvasDeclaration;
@@ -99,5 +119,8 @@ export declare class Canvas {
99
119
  * `DefineTool`'s co-location ergonomics) where other SDKs (Rust, Python, Go,
100
120
  * .NET) expose a single `CanvasHandler` per session that switches on
101
121
  * `canvasId`. Both shapes target the same JSON-RPC wire protocol.
122
+ *
123
+ * @experimental This function is part of an experimental wire-protocol surface
124
+ * and may change or be removed in future SDK or CLI releases.
102
125
  */
103
126
  export declare function createCanvas(options: CanvasOptions): Canvas;
@@ -68,6 +68,15 @@ function toWireCustomAgents(agents) {
68
68
  return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
69
69
  });
70
70
  }
71
+ function toWireLargeOutput(config) {
72
+ if (!config) return void 0;
73
+ const { outputDirectory, ...rest } = config;
74
+ const wire = { ...rest };
75
+ if (outputDirectory !== void 0) {
76
+ wire.outputDir = outputDirectory;
77
+ }
78
+ return wire;
79
+ }
71
80
  function toolFilterListToArray(value) {
72
81
  if (value === void 0) {
73
82
  return void 0;
@@ -620,7 +629,17 @@ class CopilotClient {
620
629
  /** Mode-specific defaults spread under the caller's config (app values win). */
621
630
  configDefaultsForMode() {
622
631
  if (this.options.mode === "empty") {
623
- return { enableSessionTelemetry: false };
632
+ return {
633
+ enableSessionTelemetry: false,
634
+ mcpOAuthTokenStorage: "in-memory",
635
+ skipEmbeddingRetrieval: true,
636
+ embeddingCacheStorage: "in-memory",
637
+ enableOnDemandInstructionDiscovery: false,
638
+ enableFileHooks: false,
639
+ enableHostGitOperations: false,
640
+ enableSessionStore: false,
641
+ enableSkills: false
642
+ };
624
643
  }
625
644
  return {};
626
645
  }
@@ -706,51 +725,64 @@ class CopilotClient {
706
725
  }
707
726
  config = { ...this.configDefaultsForMode(), ...config };
708
727
  config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
709
- const sessionId = config.sessionId ?? (0, import_node_crypto.randomUUID)();
710
- const session = new import_session.CopilotSession(
711
- sessionId,
712
- this.connection,
713
- void 0,
714
- this.onGetTraceContext
715
- );
716
- session.registerTools(config.tools);
717
- session.registerCanvases(config.canvases);
718
- session.registerCommands(config.commands);
719
- session.registerPermissionHandler(config.onPermissionRequest);
720
- if (config.onUserInputRequest) {
721
- session.registerUserInputHandler(config.onUserInputRequest);
722
- }
723
- if (config.onElicitationRequest) {
724
- session.registerElicitationHandler(config.onElicitationRequest);
725
- }
726
- if (config.onExitPlanModeRequest) {
727
- session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
728
- }
729
- if (config.onAutoModeSwitchRequest) {
730
- session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
731
- }
732
- if (config.hooks) {
733
- session.registerHooks(config.hooks);
734
- }
728
+ const callerSessionId = config.sessionId;
729
+ const useServerGeneratedId = config.cloud != null && callerSessionId == null;
730
+ const localSessionId = useServerGeneratedId ? void 0 : callerSessionId ?? (0, import_node_crypto.randomUUID)();
735
731
  const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
736
732
  config.systemMessage
737
733
  );
738
- if (transformCallbacks) {
739
- session.registerTransformCallbacks(transformCallbacks);
740
- }
741
- if (config.onEvent) {
742
- session.on(config.onEvent);
734
+ const initializeSession = (sessionId) => {
735
+ const s = new import_session.CopilotSession(
736
+ sessionId,
737
+ this.connection,
738
+ void 0,
739
+ this.onGetTraceContext
740
+ );
741
+ s.registerTools(config.tools);
742
+ s.registerCanvases(config.canvases);
743
+ s.registerCommands(config.commands);
744
+ s.registerPermissionHandler(config.onPermissionRequest);
745
+ if (config.onUserInputRequest) {
746
+ s.registerUserInputHandler(config.onUserInputRequest);
747
+ }
748
+ if (config.onElicitationRequest) {
749
+ s.registerElicitationHandler(config.onElicitationRequest);
750
+ }
751
+ if (config.onExitPlanModeRequest) {
752
+ s.registerExitPlanModeHandler(config.onExitPlanModeRequest);
753
+ }
754
+ if (config.onAutoModeSwitchRequest) {
755
+ s.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
756
+ }
757
+ if (config.hooks) {
758
+ s.registerHooks(config.hooks);
759
+ }
760
+ if (transformCallbacks) {
761
+ s.registerTransformCallbacks(transformCallbacks);
762
+ }
763
+ if (config.onEvent) {
764
+ s.on(config.onEvent);
765
+ }
766
+ this.sessions.set(sessionId, s);
767
+ this.setupSessionFs(s, config);
768
+ return s;
769
+ };
770
+ let session;
771
+ let registeredId;
772
+ if (localSessionId !== void 0) {
773
+ session = initializeSession(localSessionId);
774
+ registeredId = localSessionId;
743
775
  }
744
- this.sessions.set(sessionId, session);
745
- this.setupSessionFs(session, config);
746
776
  const toolFilterOptions = this.resolveToolFilterOptions(config);
747
777
  try {
748
778
  const response = await this.connection.sendRequest("session.create", {
749
779
  ...await (0, import_telemetry.getTraceContext)(this.onGetTraceContext),
750
780
  model: config.model,
751
- sessionId,
781
+ sessionId: localSessionId,
752
782
  clientName: config.clientName,
753
783
  reasoningEffort: config.reasoningEffort,
784
+ reasoningSummary: config.reasoningSummary,
785
+ contextTier: config.contextTier,
754
786
  tools: config.tools?.map((tool) => ({
755
787
  name: tool.name,
756
788
  description: tool.description,
@@ -761,6 +793,7 @@ class CopilotClient {
761
793
  canvases: config.canvases?.map((canvas) => canvas.declaration),
762
794
  requestCanvasRenderer: config.requestCanvasRenderer,
763
795
  requestExtensions: config.requestExtensions,
796
+ extensionSdkPath: config.extensionSdkPath,
764
797
  extensionInfo: config.extensionInfo,
765
798
  commands: config.commands?.map((cmd) => ({
766
799
  name: cmd.name,
@@ -773,9 +806,11 @@ class CopilotClient {
773
806
  provider: config.provider,
774
807
  enableSessionTelemetry: config.enableSessionTelemetry,
775
808
  modelCapabilities: config.modelCapabilities,
809
+ largeOutput: toWireLargeOutput(config.largeOutput),
776
810
  requestPermission: !!config.onPermissionRequest,
777
811
  requestUserInput: !!config.onUserInputRequest,
778
812
  requestElicitation: !!config.onElicitationRequest,
813
+ ...config.enableMcpApps ? { requestMcpApps: true } : {},
779
814
  requestExitPlanMode: !!config.onExitPlanModeRequest,
780
815
  requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
781
816
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
@@ -783,13 +818,23 @@ class CopilotClient {
783
818
  streaming: config.streaming,
784
819
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
785
820
  mcpServers: toWireMcpServers(config.mcpServers),
821
+ mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
786
822
  envValueMode: "direct",
787
823
  customAgents: toWireCustomAgents(config.customAgents),
788
824
  defaultAgent: config.defaultAgent,
789
825
  agent: config.agent,
790
- configDir: config.configDir,
826
+ configDir: config.configDirectory,
791
827
  enableConfigDiscovery: config.enableConfigDiscovery,
828
+ skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
829
+ embeddingCacheStorage: config.embeddingCacheStorage,
830
+ organizationCustomInstructions: config.organizationCustomInstructions,
831
+ enableOnDemandInstructionDiscovery: config.enableOnDemandInstructionDiscovery,
832
+ enableFileHooks: config.enableFileHooks,
833
+ enableHostGitOperations: config.enableHostGitOperations,
834
+ enableSessionStore: config.enableSessionStore,
835
+ enableSkills: config.enableSkills,
792
836
  skillDirectories: config.skillDirectories,
837
+ pluginDirectories: config.pluginDirectories,
793
838
  instructionDirectories: config.instructionDirectories,
794
839
  disabledSkills: config.disabledSkills,
795
840
  infiniteSessions: config.infiniteSessions,
@@ -797,12 +842,30 @@ class CopilotClient {
797
842
  remoteSession: config.remoteSession,
798
843
  cloud: config.cloud
799
844
  });
800
- const { workspacePath, capabilities } = response;
845
+ const {
846
+ sessionId: returnedSessionId,
847
+ workspacePath,
848
+ capabilities
849
+ } = response;
850
+ if (!returnedSessionId) {
851
+ throw new Error("session.create response did not include a sessionId");
852
+ }
853
+ if (localSessionId !== void 0 && localSessionId !== returnedSessionId) {
854
+ throw new Error(
855
+ `session.create returned sessionId ${returnedSessionId} but the caller requested ${localSessionId}`
856
+ );
857
+ }
858
+ if (session === void 0) {
859
+ session = initializeSession(returnedSessionId);
860
+ registeredId = returnedSessionId;
861
+ }
801
862
  session["_workspacePath"] = workspacePath;
802
863
  session.setCapabilities(capabilities);
803
864
  await this.updateSessionOptionsForMode(session, config);
804
865
  } catch (e) {
805
- this.sessions.delete(sessionId);
866
+ if (registeredId !== void 0) {
867
+ this.sessions.delete(registeredId);
868
+ }
806
869
  throw e;
807
870
  }
808
871
  return session;
@@ -881,6 +944,8 @@ class CopilotClient {
881
944
  clientName: config.clientName,
882
945
  model: config.model,
883
946
  reasoningEffort: config.reasoningEffort,
947
+ reasoningSummary: config.reasoningSummary,
948
+ contextTier: config.contextTier,
884
949
  systemMessage: wireSystemMessage,
885
950
  availableTools: toolFilterOptions.availableTools,
886
951
  excludedTools: toolFilterOptions.excludedTools,
@@ -896,6 +961,7 @@ class CopilotClient {
896
961
  canvases: config.canvases?.map((canvas) => canvas.declaration),
897
962
  requestCanvasRenderer: config.requestCanvasRenderer,
898
963
  requestExtensions: config.requestExtensions,
964
+ extensionSdkPath: config.extensionSdkPath,
899
965
  extensionInfo: config.extensionInfo,
900
966
  commands: config.commands?.map((cmd) => ({
901
967
  name: cmd.name,
@@ -903,27 +969,39 @@ class CopilotClient {
903
969
  })),
904
970
  provider: config.provider,
905
971
  modelCapabilities: config.modelCapabilities,
972
+ largeOutput: toWireLargeOutput(config.largeOutput),
906
973
  requestPermission: config.onPermissionRequest !== import_types.defaultJoinSessionPermissionHandler,
907
974
  requestUserInput: !!config.onUserInputRequest,
908
975
  requestElicitation: !!config.onElicitationRequest,
976
+ ...config.enableMcpApps ? { requestMcpApps: true } : {},
909
977
  requestExitPlanMode: !!config.onExitPlanModeRequest,
910
978
  requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
911
979
  hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
912
980
  workingDirectory: config.workingDirectory,
913
- configDir: config.configDir,
981
+ configDir: config.configDirectory,
914
982
  enableConfigDiscovery: config.enableConfigDiscovery,
983
+ skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
984
+ embeddingCacheStorage: config.embeddingCacheStorage,
985
+ organizationCustomInstructions: config.organizationCustomInstructions,
986
+ enableOnDemandInstructionDiscovery: config.enableOnDemandInstructionDiscovery,
987
+ enableFileHooks: config.enableFileHooks,
988
+ enableHostGitOperations: config.enableHostGitOperations,
989
+ enableSessionStore: config.enableSessionStore,
990
+ enableSkills: config.enableSkills,
915
991
  streaming: config.streaming,
916
992
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
917
993
  mcpServers: toWireMcpServers(config.mcpServers),
994
+ mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
918
995
  envValueMode: "direct",
919
996
  customAgents: toWireCustomAgents(config.customAgents),
920
997
  defaultAgent: config.defaultAgent,
921
998
  agent: config.agent,
922
999
  skillDirectories: config.skillDirectories,
1000
+ pluginDirectories: config.pluginDirectories,
923
1001
  instructionDirectories: config.instructionDirectories,
924
1002
  disabledSkills: config.disabledSkills,
925
1003
  infiniteSessions: config.infiniteSessions,
926
- suppressResumeEvent: config.suppressResumeEvent,
1004
+ disableResume: config.suppressResumeEvent,
927
1005
  continuePendingWork: config.continuePendingWork,
928
1006
  gitHubToken: config.gitHubToken,
929
1007
  remoteSession: config.remoteSession,
@@ -35,8 +35,10 @@ async function joinSession(config = {}) {
35
35
  );
36
36
  }
37
37
  const client = new import_client.CopilotClient({ _internalConnection: { kind: "parent-process" } });
38
+ const { extensionSdkPath: _stripped, ...rest } = config;
39
+ void _stripped;
38
40
  return client.resumeSession(sessionId, {
39
- ...config,
41
+ ...rest,
40
42
  onPermissionRequest: config.onPermissionRequest ?? import_types.defaultJoinSessionPermissionHandler,
41
43
  suppressResumeEvent: config.suppressResumeEvent ?? true
42
44
  });
@@ -111,7 +111,11 @@ function createServerRpc(connection) {
111
111
  *
112
112
  * @param params MCP server names to disable for new sessions.
113
113
  */
114
- disable: async (params) => connection.sendRequest("mcp.config.disable", params)
114
+ disable: async (params) => connection.sendRequest("mcp.config.disable", params),
115
+ /**
116
+ * Drops this runtime process's in-memory MCP server-definition cache so the next MCP config read observes disk.
117
+ */
118
+ reload: async () => connection.sendRequest("mcp.config.reload", {})
115
119
  },
116
120
  /**
117
121
  * Discovers MCP servers from user, workspace, plugin, and builtin sources.
@@ -140,6 +144,20 @@ function createServerRpc(connection) {
140
144
  */
141
145
  discover: async (params) => connection.sendRequest("skills.discover", params)
142
146
  },
147
+ user: {
148
+ settings: {
149
+ /**
150
+ * Drops this runtime process's in-memory user settings cache so the next settings read observes disk.
151
+ */
152
+ reload: async () => connection.sendRequest("user.settings.reload", {})
153
+ }
154
+ },
155
+ runtime: {
156
+ /**
157
+ * Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process.
158
+ */
159
+ shutdown: async () => connection.sendRequest("runtime.shutdown", {})
160
+ },
143
161
  sessionFs: {
144
162
  /**
145
163
  * Registers an SDK client as the session filesystem provider.
@@ -409,27 +427,30 @@ function createSessionRpc(connection, sessionId) {
409
427
  * @param params Canvas close parameters.
410
428
  */
411
429
  close: async (params) => connection.sendRequest("session.canvas.close", { sessionId, ...params }),
412
- /**
413
- * Invokes an action on an open canvas instance.
414
- *
415
- * @param params Canvas action invocation parameters.
416
- *
417
- * @returns Canvas action invocation result.
418
- */
419
- invokeAction: async (params) => connection.sendRequest("session.canvas.invokeAction", { sessionId, ...params })
430
+ /** @experimental */
431
+ action: {
432
+ /**
433
+ * Invokes an action on an open canvas instance.
434
+ *
435
+ * @param params Canvas action invocation parameters.
436
+ *
437
+ * @returns Canvas action invocation result.
438
+ */
439
+ invoke: async (params) => connection.sendRequest("session.canvas.action.invoke", { sessionId, ...params })
440
+ }
420
441
  },
421
442
  /** @experimental */
422
443
  model: {
423
444
  /**
424
445
  * Gets the currently selected model for the session.
425
446
  *
426
- * @returns The currently selected model and reasoning effort for the session.
447
+ * @returns The currently selected model, reasoning effort, and context tier for the session. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume.
427
448
  */
428
449
  getCurrent: async () => connection.sendRequest("session.model.getCurrent", { sessionId }),
429
450
  /**
430
451
  * Switches the session to a model and optional reasoning configuration.
431
452
  *
432
- * @param params Target model identifier and optional reasoning effort, summary, and capability overrides.
453
+ * @param params Target model identifier and optional reasoning effort, summary, capability overrides, and context tier.
433
454
  *
434
455
  * @returns The model identifier active on the session after the switch.
435
456
  */
@@ -441,7 +462,15 @@ function createSessionRpc(connection, sessionId) {
441
462
  *
442
463
  * @returns Update the session's reasoning effort without changing the selected model. Use `switchTo` instead when you also need to change the model. The runtime stores the effort on the session and applies it to subsequent turns.
443
464
  */
444
- setReasoningEffort: async (params) => connection.sendRequest("session.model.setReasoningEffort", { sessionId, ...params })
465
+ setReasoningEffort: async (params) => connection.sendRequest("session.model.setReasoningEffort", { sessionId, ...params }),
466
+ /**
467
+ * Lists models available to this session using its own auth and integration context. Connected hosts (CLI TUI, GitHub App) should call this through the session client so remote sessions return the remote CLI's available models rather than the caller's.
468
+ *
469
+ * @param params Optional listing options.
470
+ *
471
+ * @returns The list of models available to this session.
472
+ */
473
+ list: async (params) => connection.sendRequest("session.model.list", { sessionId, ...params })
445
474
  },
446
475
  /** @experimental */
447
476
  mode: {
@@ -895,7 +924,13 @@ function createSessionRpc(connection, sessionId) {
895
924
  /**
896
925
  * Reloads extension definitions and processes for the session.
897
926
  */
898
- reload: async () => connection.sendRequest("session.extensions.reload", { sessionId })
927
+ reload: async () => connection.sendRequest("session.extensions.reload", { sessionId }),
928
+ /**
929
+ * Push attachments into the next user-message turn from an extension. The host should surface them as composer pills and forward them via the next session.send call. Callable only by extension-owned connections.
930
+ *
931
+ * @param params Parameters for session.extensions.sendAttachmentsToMessage.
932
+ */
933
+ sendAttachmentsToMessage: async (params) => connection.sendRequest("session.extensions.sendAttachmentsToMessage", { sessionId, ...params })
899
934
  },
900
935
  /** @experimental */
901
936
  tools: {
@@ -912,7 +947,13 @@ function createSessionRpc(connection, sessionId) {
912
947
  *
913
948
  * @returns Resolve, build, and validate the runtime tool list for this session. Subagent sessions and consumer flows that need an initialized tool set before `send` invoke this. Default base-class implementation is a no-op for sessions that don't support tool validation.
914
949
  */
915
- initializeAndValidate: async () => connection.sendRequest("session.tools.initializeAndValidate", { sessionId })
950
+ initializeAndValidate: async () => connection.sendRequest("session.tools.initializeAndValidate", { sessionId }),
951
+ /**
952
+ * Returns lightweight metadata for the session's currently initialized tools.
953
+ *
954
+ * @returns Current lightweight tool metadata snapshot for the session.
955
+ */
956
+ getCurrentMetadata: async () => connection.sendRequest("session.tools.getCurrentMetadata", { sessionId })
916
957
  },
917
958
  /** @experimental */
918
959
  commands: {
@@ -1501,10 +1542,10 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
1501
1542
  if (!handler) throw new Error(`No canvas handler registered for session: ${params.sessionId}`);
1502
1543
  return handler.close(params);
1503
1544
  });
1504
- connection.onRequest("canvas.invokeAction", async (params) => {
1545
+ connection.onRequest("canvas.action.invoke", async (params) => {
1505
1546
  const handler = getHandlers(params.sessionId).canvas;
1506
1547
  if (!handler) throw new Error(`No canvas handler registered for session: ${params.sessionId}`);
1507
- return handler.invokeAction(params);
1548
+ return handler.invoke(params);
1508
1549
  });
1509
1550
  }
1510
1551
  // Annotate the CommonJS export names for ESM import in node:
@@ -33,6 +33,13 @@ function deserializeHookInput(raw) {
33
33
  const { cwd, ...rest } = obj;
34
34
  return { ...rest, timestamp: new Date(obj.timestamp), workingDirectory: cwd };
35
35
  }
36
+ function isOpenCanvasInstance(value) {
37
+ if (!value || typeof value !== "object") {
38
+ return false;
39
+ }
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");
42
+ }
36
43
  class CopilotSession {
37
44
  /**
38
45
  * Creates a new CopilotSession instance.
@@ -117,6 +124,7 @@ class CopilotSession {
117
124
  ...await (0, import_telemetry.getTraceContext)(this.traceContextProvider),
118
125
  sessionId: this.sessionId,
119
126
  prompt: options.prompt,
127
+ displayPrompt: options.displayPrompt,
120
128
  attachments: options.attachments,
121
129
  mode: options.mode,
122
130
  agentMode: options.agentMode,
@@ -266,6 +274,25 @@ class CopilotSession {
266
274
  }
267
275
  } else if (event.type === "capabilities.changed") {
268
276
  this._capabilities = { ...this._capabilities, ...event.data };
277
+ } else if (event.type === "session.canvas.opened") {
278
+ this.upsertOpenCanvasFromEvent(event.data);
279
+ }
280
+ }
281
+ upsertOpenCanvasFromEvent(data) {
282
+ if (!isOpenCanvasInstance(data)) {
283
+ console.warn("failed to deserialize session.canvas.opened payload");
284
+ return;
285
+ }
286
+ this.upsertOpenCanvas(data);
287
+ }
288
+ upsertOpenCanvas(instance) {
289
+ const index = this.openCanvasInstances.findIndex(
290
+ (open) => open.instanceId === instance.instanceId
291
+ );
292
+ if (index >= 0) {
293
+ this.openCanvasInstances[index] = instance;
294
+ } else {
295
+ this.openCanvasInstances.push(instance);
269
296
  }
270
297
  }
271
298
  /**
@@ -432,7 +459,7 @@ class CopilotSession {
432
459
  throw toCanvasRpcError(error);
433
460
  }
434
461
  },
435
- async invokeAction(params) {
462
+ async invoke(params) {
436
463
  const canvas = self.canvases.get(params.canvasId);
437
464
  if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
438
465
  const handler = canvas.actionHandlers.get(params.actionName);
@@ -547,10 +574,10 @@ class CopilotSession {
547
574
  this._capabilities = capabilities ?? {};
548
575
  }
549
576
  /**
550
- * Snapshot of canvas instances that were already open when the session was
551
- * resumed. Populated from the `session.resume` response; empty for freshly
552
- * created sessions. Returns a defensive copy — mutating the returned array
553
- * has no effect on the session.
577
+ * Snapshot of canvas instances currently known to be open for this session.
578
+ * Populated from the `session.resume` response and live `session.canvas.opened`
579
+ * events. Returns a defensive copy — mutating the returned array has no effect
580
+ * on the session.
554
581
  */
555
582
  get openCanvases() {
556
583
  return [...this.openCanvasInstances];