@github/copilot-sdk 1.0.0-beta.7 → 1.0.0-beta.9

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/dist/cjs/index.js CHANGED
@@ -18,12 +18,14 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var index_exports = {};
20
20
  __export(index_exports, {
21
+ BuiltInTools: () => import_toolSet.BuiltInTools,
21
22
  Canvas: () => import_canvas.Canvas,
22
23
  CanvasError: () => import_canvas.CanvasError,
23
24
  CopilotClient: () => import_client.CopilotClient,
24
25
  CopilotSession: () => import_session.CopilotSession,
25
26
  RuntimeConnection: () => import_types.RuntimeConnection,
26
27
  SYSTEM_MESSAGE_SECTIONS: () => import_types2.SYSTEM_MESSAGE_SECTIONS,
28
+ ToolSet: () => import_toolSet.ToolSet,
27
29
  approveAll: () => import_types2.approveAll,
28
30
  convertMcpCallToolResult: () => import_types2.convertMcpCallToolResult,
29
31
  createCanvas: () => import_canvas.createCanvas,
@@ -33,17 +35,20 @@ __export(index_exports, {
33
35
  module.exports = __toCommonJS(index_exports);
34
36
  var import_client = require("./client.js");
35
37
  var import_types = require("./types.js");
38
+ var import_toolSet = require("./toolSet.js");
36
39
  var import_session = require("./session.js");
37
40
  var import_canvas = require("./canvas.js");
38
41
  var import_types2 = require("./types.js");
39
42
  // Annotate the CommonJS export names for ESM import in node:
40
43
  0 && (module.exports = {
44
+ BuiltInTools,
41
45
  Canvas,
42
46
  CanvasError,
43
47
  CopilotClient,
44
48
  CopilotSession,
45
49
  RuntimeConnection,
46
50
  SYSTEM_MESSAGE_SECTIONS,
51
+ ToolSet,
47
52
  approveAll,
48
53
  convertMcpCallToolResult,
49
54
  createCanvas,
@@ -23,6 +23,7 @@ __export(session_exports, {
23
23
  module.exports = __toCommonJS(session_exports);
24
24
  var import_node = require("vscode-jsonrpc/node.js");
25
25
  var import_rpc = require("./generated/rpc.js");
26
+ var import_canvas = require("./canvas.js");
26
27
  var import_telemetry = require("./telemetry.js");
27
28
  function deserializeHookInput(raw) {
28
29
  if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") {
@@ -118,6 +119,7 @@ class CopilotSession {
118
119
  prompt: options.prompt,
119
120
  attachments: options.attachments,
120
121
  mode: options.mode,
122
+ agentMode: options.agentMode,
121
123
  requestHeaders: options.requestHeaders
122
124
  });
123
125
  return response.messageId;
@@ -401,22 +403,52 @@ class CopilotSession {
401
403
  */
402
404
  registerCanvases(canvases) {
403
405
  this.canvases.clear();
404
- if (!canvases) {
406
+ if (!canvases || canvases.length === 0) {
407
+ delete this.clientSessionApis.canvas;
405
408
  return;
406
409
  }
407
410
  for (const canvas of canvases) {
408
411
  this.canvases.set(canvas.declaration.id, canvas);
409
412
  }
410
- }
411
- /**
412
- * Retrieves a registered canvas by id.
413
- *
414
- * @param canvasId - The id of the canvas to retrieve
415
- * @returns The registered Canvas if found, or undefined
416
- * @internal Used by the SDK's direct `canvas.*` dispatcher.
417
- */
418
- getCanvas(canvasId) {
419
- return this.canvases.get(canvasId);
413
+ const self = this;
414
+ this.clientSessionApis.canvas = {
415
+ async open(params) {
416
+ const canvas = self.canvases.get(params.canvasId);
417
+ if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
418
+ try {
419
+ return await canvas.open(params) ?? {};
420
+ } catch (error) {
421
+ throw toCanvasRpcError(error);
422
+ }
423
+ },
424
+ async close(params) {
425
+ const canvas = self.canvases.get(params.canvasId);
426
+ if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
427
+ try {
428
+ if (canvas.onClose) {
429
+ await canvas.onClose(params);
430
+ }
431
+ } catch (error) {
432
+ throw toCanvasRpcError(error);
433
+ }
434
+ },
435
+ async invokeAction(params) {
436
+ const canvas = self.canvases.get(params.canvasId);
437
+ if (!canvas) throw new Error(`No canvas registered with id "${params.canvasId}"`);
438
+ const handler = canvas.actionHandlers.get(params.actionName);
439
+ if (!handler) {
440
+ throw new import_canvas.CanvasError(
441
+ "canvas_action_no_handler",
442
+ "No handler implemented for this canvas action"
443
+ );
444
+ }
445
+ try {
446
+ return await handler(params);
447
+ } catch (error) {
448
+ throw toCanvasRpcError(error);
449
+ }
450
+ }
451
+ };
420
452
  }
421
453
  /**
422
454
  * Registers command handlers for this session.
@@ -708,6 +740,7 @@ class CopilotSession {
708
740
  preToolUse: this.hooks.onPreToolUse,
709
741
  preMcpToolCall: this.hooks.onPreMcpToolCall,
710
742
  postToolUse: this.hooks.onPostToolUse,
743
+ postToolUseFailure: this.hooks.onPostToolUseFailure,
711
744
  userPromptSubmitted: this.hooks.onUserPromptSubmitted,
712
745
  sessionStart: this.hooks.onSessionStart,
713
746
  sessionEnd: this.hooks.onSessionEnd,
@@ -867,6 +900,12 @@ function isToolResultObject(value) {
867
900
  ];
868
901
  return allowedResultTypes.includes(value.resultType);
869
902
  }
903
+ function toCanvasRpcError(error) {
904
+ if (error instanceof import_node.ResponseError) return error;
905
+ const code = error instanceof import_canvas.CanvasError ? error.code : "canvas_handler_error";
906
+ const message = error instanceof Error ? error.message : String(error);
907
+ return new import_node.ResponseError(import_node.ErrorCodes.InternalError, message, { code, message });
908
+ }
870
909
  // Annotate the CommonJS export names for ESM import in node:
871
910
  0 && (module.exports = {
872
911
  CopilotSession
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var toolSet_exports = {};
20
+ __export(toolSet_exports, {
21
+ BuiltInTools: () => BuiltInTools,
22
+ ToolSet: () => ToolSet
23
+ });
24
+ module.exports = __toCommonJS(toolSet_exports);
25
+ const VALID_TOOL_NAME = /^[a-zA-Z0-9_-]+$/;
26
+ function validateName(kind, name) {
27
+ if (name === "*") {
28
+ return;
29
+ }
30
+ if (!VALID_TOOL_NAME.test(name)) {
31
+ throw new Error(
32
+ `Invalid ${kind} tool name '${name}': tool names must match /^[a-zA-Z0-9_-]+$/ or be the wildcard '*'.`
33
+ );
34
+ }
35
+ }
36
+ class ToolSet {
37
+ items = [];
38
+ addBuiltIn(nameOrNames) {
39
+ const names = typeof nameOrNames === "string" ? [nameOrNames] : nameOrNames;
40
+ for (const name of names) {
41
+ validateName("builtin", name);
42
+ this.items.push(`builtin:${name}`);
43
+ }
44
+ return this;
45
+ }
46
+ /**
47
+ * Adds a custom tool pattern. Matches tools registered via the SDK's
48
+ * `tools` option or via custom agents.
49
+ *
50
+ * @param name A specific custom tool name or `"*"` to match all custom tools.
51
+ */
52
+ addCustom(name) {
53
+ validateName("custom", name);
54
+ this.items.push(`custom:${name}`);
55
+ return this;
56
+ }
57
+ /**
58
+ * Adds an MCP tool pattern. Matches tools advertised by any configured
59
+ * MCP server.
60
+ *
61
+ * @param toolName The runtime's canonical wire name for the MCP tool
62
+ * (e.g. `"github-list_issues"`), or `"*"` to match all MCP tools from
63
+ * any server.
64
+ */
65
+ addMcp(toolName) {
66
+ validateName("mcp", toolName);
67
+ this.items.push(`mcp:${toolName}`);
68
+ return this;
69
+ }
70
+ /**
71
+ * Returns a defensive copy of the accumulated filter strings, suitable for
72
+ * passing as {@link SessionConfigBase.availableTools}.
73
+ */
74
+ toArray() {
75
+ return [...this.items];
76
+ }
77
+ }
78
+ const BuiltInTools = {
79
+ /**
80
+ * Built-in tools that operate only within the bounds of a single session —
81
+ * no host filesystem access outside the session, no cross-session state,
82
+ * no host environment access, no network. Safe to enable in `Mode = "empty"`
83
+ * scenarios (e.g. multi-tenant servers) without leaking host capabilities.
84
+ *
85
+ * **Contract:** tools in this set MUST NOT be extended (even behind options
86
+ * or args) to read or write state outside the session boundary. Adding
87
+ * cross-session or host-state behavior to one of these tools is a
88
+ * breaking change that requires removing it from this set.
89
+ */
90
+ Isolated: [
91
+ "ask_user",
92
+ "task_complete",
93
+ "exit_plan_mode",
94
+ "task",
95
+ "read_agent",
96
+ "write_agent",
97
+ "list_agents",
98
+ "send_inbox",
99
+ "context_board",
100
+ "skill"
101
+ ]
102
+ };
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ BuiltInTools,
106
+ ToolSet
107
+ });
package/dist/client.d.ts CHANGED
@@ -190,34 +190,26 @@ export declare class CopilotClient {
190
190
  * ```
191
191
  */
192
192
  forceStop(): Promise<void>;
193
+ /** Mode-specific defaults spread under the caller's config (app values win). */
194
+ private configDefaultsForMode;
193
195
  /**
194
- * Creates a new conversation session with the Copilot CLI.
195
- *
196
- * Sessions maintain conversation state, handle events, and manage tool execution.
197
- * If the client is not connected, this method automatically starts the connection.
198
- *
199
- * @param config - Optional configuration for the session
200
- * @returns A promise that resolves with the created session
201
- * @throws Error if the client fails to start
202
- *
203
- * @example
204
- * ```typescript
205
- * // Basic session
206
- * const session = await client.createSession({ onPermissionRequest: approveAll });
196
+ * Returns the systemMessage config to use, adjusted for the current mode.
197
+ * In empty mode we ensure the environment_context section is removed
198
+ * unless the app has already taken control of it. `append` (and
199
+ * unspecified) mode is promoted to `customize` so we can also strip
200
+ * environment_context; the caller's `content` is preserved verbatim
201
+ * because the runtime appends it as additional instructions in both
202
+ * customize and append modes.
203
+ */
204
+ private getSystemMessageConfigForMode;
205
+ /**
206
+ * Mode-specific options applied via session.options.update after create/resume.
207
207
  *
208
- * // Session with model and tools
209
- * const session = await client.createSession({
210
- * onPermissionRequest: approveAll,
211
- * model: "gpt-4",
212
- * tools: [{
213
- * name: "get_weather",
214
- * description: "Get weather for a location",
215
- * parameters: { type: "object", properties: { location: { type: "string" } } },
216
- * handler: async (args) => ({ temperature: 72 })
217
- * }]
218
- * });
219
- * ```
208
+ * In empty mode, defaults the four overridable feature flags to safe values
209
+ * (caller values from `config` win). `installedPlugins=[]` is unconditional
210
+ * in empty mode — apps that need custom plugins should switch modes.
220
211
  */
212
+ private updateSessionOptionsForMode;
221
213
  createSession(config: SessionConfig): Promise<CopilotSession>;
222
214
  /**
223
215
  * Resumes an existing conversation session by its ID.
@@ -467,6 +459,4 @@ export declare class CopilotClient {
467
459
  private handleAutoModeSwitchRequest;
468
460
  private handleHooksInvoke;
469
461
  private handleSystemMessageTransform;
470
- private handleCanvasProviderRequest;
471
- private handleCanvasActionInvokeRequest;
472
462
  }
package/dist/client.js CHANGED
@@ -17,13 +17,11 @@ import {
17
17
  createInternalServerRpc,
18
18
  registerClientSessionApiHandlers
19
19
  } from "./generated/rpc.js";
20
- import {
21
- dispatchCanvasProviderRequest
22
- } from "./canvas.js";
23
20
  import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
24
21
  import { CopilotSession } from "./session.js";
25
22
  import { createSessionFsAdapter } from "./sessionFsProvider.js";
26
23
  import { getTraceContext } from "./telemetry.js";
24
+ import { ToolSet } from "./toolSet.js";
27
25
  import { defaultJoinSessionPermissionHandler } from "./types.js";
28
26
  const MIN_PROTOCOL_VERSION = 3;
29
27
  function isZodSchema(value) {
@@ -56,15 +54,23 @@ function toWireCustomAgents(agents) {
56
54
  return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
57
55
  });
58
56
  }
59
- function isCanvasProviderRequestParams(params) {
60
- if (!params || typeof params !== "object") {
61
- return false;
57
+ function toolFilterListToArray(value) {
58
+ if (value === void 0) {
59
+ return void 0;
62
60
  }
63
- const request = params;
64
- return typeof request.sessionId === "string" && typeof request.extensionId === "string" && typeof request.canvasId === "string" && typeof request.instanceId === "string";
61
+ return value instanceof ToolSet ? value.toArray() : value;
65
62
  }
66
- function isCanvasActionInvokeParams(params) {
67
- return isCanvasProviderRequestParams(params) && typeof params.actionName === "string";
63
+ function validateToolFilterList(field, list) {
64
+ if (!list) {
65
+ return;
66
+ }
67
+ for (const entry of list) {
68
+ if (entry === "*") {
69
+ throw new Error(
70
+ `Invalid ${field} entry '*': there is no bare wildcard. Use one or more of \`new ToolSet().addBuiltIn('*')\`, \`.addMcp('*')\`, or \`.addCustom('*')\` to target a specific source.`
71
+ );
72
+ }
73
+ }
68
74
  }
69
75
  function extractTransformCallbacks(systemMessage) {
70
76
  if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
@@ -248,8 +254,19 @@ class CopilotClient {
248
254
  telemetry: options.telemetry,
249
255
  baseDirectory: options.baseDirectory,
250
256
  sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
251
- enableRemoteSessions: options.enableRemoteSessions ?? false
257
+ enableRemoteSessions: options.enableRemoteSessions ?? false,
258
+ mode: options.mode ?? "copilot-cli"
252
259
  };
260
+ if (this.options.mode === "empty") {
261
+ const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
262
+ // can't enforce it from here.
263
+ conn.kind === "uri" || conn.kind === "parent-process";
264
+ if (!hasPersistence) {
265
+ throw new Error(
266
+ "CopilotClient was created with mode: 'empty' but neither 'baseDirectory' nor 'sessionFs' was set. Empty mode requires an explicit per-session persistence location; pick one."
267
+ );
268
+ }
269
+ }
253
270
  }
254
271
  connectionExtraArgs = [];
255
272
  /**
@@ -559,10 +576,122 @@ class CopilotClient {
559
576
  * });
560
577
  * ```
561
578
  */
579
+ /**
580
+ * Normalizes session-level tool filter options. Converts {@link ToolSet}
581
+ * instances to plain string arrays, rejects misuse (bare `"*"`) and the
582
+ * missing-availableTools case in `mode = "empty"`.
583
+ *
584
+ * The SDK always sends `toolFilterPrecedence: "excluded"` so callers can
585
+ * compose include + exclude lists naturally (e.g. "everything matching X
586
+ * except Y") regardless of mode. Allowlist-precedence is intentionally not
587
+ * exposed — it's available on the runtime side as a CLI-only concession to
588
+ * legacy behavior, but SDK consumers always get the composable semantics.
589
+ *
590
+ * @internal
591
+ */
592
+ resolveToolFilterOptions(config) {
593
+ const availableTools = toolFilterListToArray(config.availableTools);
594
+ const excludedTools = toolFilterListToArray(config.excludedTools);
595
+ validateToolFilterList("availableTools", availableTools);
596
+ validateToolFilterList("excludedTools", excludedTools);
597
+ if (this.options.mode === "empty") {
598
+ if (availableTools === void 0) {
599
+ throw new Error(
600
+ "CopilotClient is in mode: 'empty' but the session config did not specify 'availableTools'. Empty mode requires every session to explicitly opt into the tools it wants \u2014 e.g. `new ToolSet().addBuiltIn(BuiltInTools.Isolated)`."
601
+ );
602
+ }
603
+ }
604
+ return { availableTools, excludedTools, toolFilterPrecedence: "excluded" };
605
+ }
606
+ /** Mode-specific defaults spread under the caller's config (app values win). */
607
+ configDefaultsForMode() {
608
+ if (this.options.mode === "empty") {
609
+ return { enableSessionTelemetry: false };
610
+ }
611
+ return {};
612
+ }
613
+ /**
614
+ * Returns the systemMessage config to use, adjusted for the current mode.
615
+ * In empty mode we ensure the environment_context section is removed
616
+ * unless the app has already taken control of it. `append` (and
617
+ * unspecified) mode is promoted to `customize` so we can also strip
618
+ * environment_context; the caller's `content` is preserved verbatim
619
+ * because the runtime appends it as additional instructions in both
620
+ * customize and append modes.
621
+ */
622
+ getSystemMessageConfigForMode(supplied) {
623
+ if (this.options.mode !== "empty") return supplied;
624
+ if (!supplied) {
625
+ return {
626
+ mode: "customize",
627
+ sections: { environment_context: { action: "remove" } }
628
+ };
629
+ }
630
+ switch (supplied.mode) {
631
+ case "replace":
632
+ return supplied;
633
+ case "customize":
634
+ if (supplied.sections?.environment_context) return supplied;
635
+ return {
636
+ ...supplied,
637
+ sections: {
638
+ ...supplied.sections,
639
+ environment_context: { action: "remove" }
640
+ }
641
+ };
642
+ case "append":
643
+ case void 0:
644
+ return {
645
+ mode: "customize",
646
+ content: supplied.content,
647
+ sections: { environment_context: { action: "remove" } }
648
+ };
649
+ }
650
+ }
651
+ /**
652
+ * Mode-specific options applied via session.options.update after create/resume.
653
+ *
654
+ * In empty mode, defaults the four overridable feature flags to safe values
655
+ * (caller values from `config` win). `installedPlugins=[]` is unconditional
656
+ * in empty mode — apps that need custom plugins should switch modes.
657
+ */
658
+ async updateSessionOptionsForMode(session, config) {
659
+ const patch = {};
660
+ if (this.options.mode === "empty") {
661
+ patch.skipCustomInstructions = config.skipCustomInstructions ?? true;
662
+ patch.customAgentsLocalOnly = config.customAgentsLocalOnly ?? true;
663
+ patch.coauthorEnabled = config.coauthorEnabled ?? false;
664
+ patch.manageScheduleEnabled = config.manageScheduleEnabled ?? false;
665
+ patch.installedPlugins = [];
666
+ } else {
667
+ if (config.skipCustomInstructions !== void 0)
668
+ patch.skipCustomInstructions = config.skipCustomInstructions;
669
+ if (config.customAgentsLocalOnly !== void 0)
670
+ patch.customAgentsLocalOnly = config.customAgentsLocalOnly;
671
+ if (config.coauthorEnabled !== void 0)
672
+ patch.coauthorEnabled = config.coauthorEnabled;
673
+ if (config.manageScheduleEnabled !== void 0)
674
+ patch.manageScheduleEnabled = config.manageScheduleEnabled;
675
+ }
676
+ if (Object.keys(patch).length === 0) {
677
+ return;
678
+ }
679
+ try {
680
+ await session.rpc.options.update(patch);
681
+ } catch (e) {
682
+ try {
683
+ await session.disconnect();
684
+ } catch {
685
+ }
686
+ throw e;
687
+ }
688
+ }
562
689
  async createSession(config) {
563
690
  if (!this.connection) {
564
691
  await this.start();
565
692
  }
693
+ config = { ...this.configDefaultsForMode(), ...config };
694
+ config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
566
695
  const sessionId = config.sessionId ?? randomUUID();
567
696
  const session = new CopilotSession(
568
697
  sessionId,
@@ -600,6 +729,7 @@ class CopilotClient {
600
729
  }
601
730
  this.sessions.set(sessionId, session);
602
731
  this.setupSessionFs(session, config);
732
+ const toolFilterOptions = this.resolveToolFilterOptions(config);
603
733
  try {
604
734
  const response = await this.connection.sendRequest("session.create", {
605
735
  ...await getTraceContext(this.onGetTraceContext),
@@ -623,8 +753,9 @@ class CopilotClient {
623
753
  description: cmd.description
624
754
  })),
625
755
  systemMessage: wireSystemMessage,
626
- availableTools: config.availableTools,
627
- excludedTools: config.excludedTools,
756
+ availableTools: toolFilterOptions.availableTools,
757
+ excludedTools: toolFilterOptions.excludedTools,
758
+ toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
628
759
  provider: config.provider,
629
760
  enableSessionTelemetry: config.enableSessionTelemetry,
630
761
  modelCapabilities: config.modelCapabilities,
@@ -655,6 +786,7 @@ class CopilotClient {
655
786
  const { workspacePath, capabilities } = response;
656
787
  session["_workspacePath"] = workspacePath;
657
788
  session.setCapabilities(capabilities);
789
+ await this.updateSessionOptionsForMode(session, config);
658
790
  } catch (e) {
659
791
  this.sessions.delete(sessionId);
660
792
  throw e;
@@ -714,6 +846,8 @@ class CopilotClient {
714
846
  if (config.hooks) {
715
847
  session.registerHooks(config.hooks);
716
848
  }
849
+ config = { ...this.configDefaultsForMode(), ...config };
850
+ config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
717
851
  const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
718
852
  config.systemMessage
719
853
  );
@@ -725,6 +859,7 @@ class CopilotClient {
725
859
  }
726
860
  this.sessions.set(sessionId, session);
727
861
  this.setupSessionFs(session, config);
862
+ const toolFilterOptions = this.resolveToolFilterOptions(config);
728
863
  try {
729
864
  const response = await this.connection.sendRequest("session.resume", {
730
865
  ...await getTraceContext(this.onGetTraceContext),
@@ -733,8 +868,9 @@ class CopilotClient {
733
868
  model: config.model,
734
869
  reasoningEffort: config.reasoningEffort,
735
870
  systemMessage: wireSystemMessage,
736
- availableTools: config.availableTools,
737
- excludedTools: config.excludedTools,
871
+ availableTools: toolFilterOptions.availableTools,
872
+ excludedTools: toolFilterOptions.excludedTools,
873
+ toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
738
874
  enableSessionTelemetry: config.enableSessionTelemetry,
739
875
  tools: config.tools?.map((tool) => ({
740
876
  name: tool.name,
@@ -783,6 +919,7 @@ class CopilotClient {
783
919
  session["_workspacePath"] = workspacePath;
784
920
  session.setCapabilities(capabilities);
785
921
  session.setOpenCanvases(openCanvases ?? []);
922
+ await this.updateSessionOptionsForMode(session, config);
786
923
  } catch (e) {
787
924
  this.sessions.delete(sessionId);
788
925
  throw e;
@@ -1161,6 +1298,9 @@ class CopilotClient {
1161
1298
  if (this.options.baseDirectory) {
1162
1299
  envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
1163
1300
  }
1301
+ if (this.options.mode === "empty") {
1302
+ envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
1303
+ }
1164
1304
  if (!this.resolvedCliPath) {
1165
1305
  throw new Error(
1166
1306
  "Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime."
@@ -1397,18 +1537,6 @@ stderr: ${stderrOutput}`
1397
1537
  "systemMessage.transform",
1398
1538
  async (params) => await this.handleSystemMessageTransform(params)
1399
1539
  );
1400
- this.connection.onRequest(
1401
- "canvas.open",
1402
- async (params) => this.handleCanvasProviderRequest("canvas.open", params)
1403
- );
1404
- this.connection.onRequest(
1405
- "canvas.close",
1406
- async (params) => this.handleCanvasProviderRequest("canvas.close", params)
1407
- );
1408
- this.connection.onRequest(
1409
- "canvas.action.invoke",
1410
- async (params) => this.handleCanvasActionInvokeRequest(params)
1411
- );
1412
1540
  const sessions = this.sessions;
1413
1541
  registerClientSessionApiHandlers(this.connection, (sessionId) => {
1414
1542
  const session = sessions.get(sessionId);
@@ -1530,26 +1658,6 @@ stderr: ${stderrOutput}`
1530
1658
  }
1531
1659
  return await session._handleSystemMessageTransform(params.sections);
1532
1660
  }
1533
- async handleCanvasProviderRequest(actionName, params) {
1534
- if (!isCanvasProviderRequestParams(params)) {
1535
- throw new Error("Invalid canvas provider request payload");
1536
- }
1537
- const session = this.sessions.get(params.sessionId);
1538
- if (!session) {
1539
- throw new Error(`Session not found: ${params.sessionId}`);
1540
- }
1541
- const canvas = session.getCanvas(params.canvasId);
1542
- if (!canvas) {
1543
- throw new Error(`No canvas registered with id "${params.canvasId}"`);
1544
- }
1545
- return dispatchCanvasProviderRequest(canvas, actionName, params);
1546
- }
1547
- async handleCanvasActionInvokeRequest(params) {
1548
- if (!isCanvasActionInvokeParams(params)) {
1549
- throw new Error("Invalid canvas provider request payload");
1550
- }
1551
- return this.handleCanvasProviderRequest(params.actionName, params);
1552
- }
1553
1661
  }
1554
1662
  export {
1555
1663
  CopilotClient
@@ -1,6 +1,6 @@
1
1
  import type { CopilotSession } from "./session.js";
2
2
  import { type ExtensionInfo, type PermissionHandler, type ResumeSessionConfig } from "./types.js";
3
- export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasActionContext, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasLifecycleContext, type CanvasOpenContext, type CanvasOpenResponse, type CanvasOptions, } from "./canvas.js";
3
+ export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js";
4
4
  export type JoinSessionConfig = Omit<ResumeSessionConfig, "onPermissionRequest"> & {
5
5
  onPermissionRequest?: PermissionHandler;
6
6
  };