@github/copilot-sdk 1.0.0-beta.8 → 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/README.md CHANGED
@@ -957,7 +957,7 @@ const session = await client.createSession({
957
957
  };
958
958
  },
959
959
 
960
- // Called after each tool execution
960
+ // Called after each successful tool execution
961
961
  onPostToolUse: async (input, invocation) => {
962
962
  console.log(`Tool ${input.toolName} completed`);
963
963
  // Optionally modify the result or add context
@@ -966,6 +966,16 @@ const session = await client.createSession({
966
966
  };
967
967
  },
968
968
 
969
+ // Called after a tool execution whose result was "failure".
970
+ // onPostToolUse does NOT fire for failed tool calls — register this
971
+ // hook to observe them. Input includes `error` (the failure message
972
+ // extracted from the tool's result), not the full result object.
973
+ onPostToolUseFailure: async (input, invocation) => {
974
+ console.log(`Tool ${input.toolName} failed: ${input.error}`);
975
+ // Optionally append hidden guidance to the model.
976
+ return { additionalContext: "Suggest checking inputs and retrying." };
977
+ },
978
+
969
979
  // Called when user submits a prompt
970
980
  onUserPromptSubmitted: async (input, invocation) => {
971
981
  console.log(`User prompt: ${input.prompt}`);
@@ -1001,7 +1011,8 @@ const session = await client.createSession({
1001
1011
  **Available hooks:**
1002
1012
 
1003
1013
  - `onPreToolUse` - Intercept tool calls before execution. Can allow/deny or modify arguments.
1004
- - `onPostToolUse` - Process tool results after execution. Can modify results or add context.
1014
+ - `onPostToolUse` - Process tool results after **successful** execution. Can modify results or add context.
1015
+ - `onPostToolUseFailure` - Observe and append hidden guidance to the model after tool executions whose result was `"failure"`. Register this in addition to `onPostToolUse` to see failed tool calls.
1005
1016
  - `onUserPromptSubmitted` - Intercept user prompts. Can modify the prompt before processing.
1006
1017
  - `onSessionStart` - Run logic when a session starts or resumes.
1007
1018
  - `onSessionEnd` - Cleanup or logging when session ends.
@@ -34,6 +34,7 @@ var import_sdkProtocolVersion = require("./sdkProtocolVersion.js");
34
34
  var import_session = require("./session.js");
35
35
  var import_sessionFsProvider = require("./sessionFsProvider.js");
36
36
  var import_telemetry = require("./telemetry.js");
37
+ var import_toolSet = require("./toolSet.js");
37
38
  var import_types = require("./types.js");
38
39
  const import_meta = {};
39
40
  const MIN_PROTOCOL_VERSION = 3;
@@ -67,6 +68,24 @@ function toWireCustomAgents(agents) {
67
68
  return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
68
69
  });
69
70
  }
71
+ function toolFilterListToArray(value) {
72
+ if (value === void 0) {
73
+ return void 0;
74
+ }
75
+ return value instanceof import_toolSet.ToolSet ? value.toArray() : value;
76
+ }
77
+ function validateToolFilterList(field, list) {
78
+ if (!list) {
79
+ return;
80
+ }
81
+ for (const entry of list) {
82
+ if (entry === "*") {
83
+ throw new Error(
84
+ `Invalid ${field} entry '*': there is no bare wildcard. Use one or more of \`new ToolSet().addBuiltIn('*')\`, \`.addMcp('*')\`, or \`.addCustom('*')\` to target a specific source.`
85
+ );
86
+ }
87
+ }
88
+ }
70
89
  function extractTransformCallbacks(systemMessage) {
71
90
  if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
72
91
  return { wirePayload: systemMessage, transformCallbacks: void 0 };
@@ -249,8 +268,19 @@ class CopilotClient {
249
268
  telemetry: options.telemetry,
250
269
  baseDirectory: options.baseDirectory,
251
270
  sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
252
- enableRemoteSessions: options.enableRemoteSessions ?? false
271
+ enableRemoteSessions: options.enableRemoteSessions ?? false,
272
+ mode: options.mode ?? "copilot-cli"
253
273
  };
274
+ if (this.options.mode === "empty") {
275
+ const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
276
+ // can't enforce it from here.
277
+ conn.kind === "uri" || conn.kind === "parent-process";
278
+ if (!hasPersistence) {
279
+ throw new Error(
280
+ "CopilotClient was created with mode: 'empty' but neither 'baseDirectory' nor 'sessionFs' was set. Empty mode requires an explicit per-session persistence location; pick one."
281
+ );
282
+ }
283
+ }
254
284
  }
255
285
  connectionExtraArgs = [];
256
286
  /**
@@ -560,10 +590,122 @@ class CopilotClient {
560
590
  * });
561
591
  * ```
562
592
  */
593
+ /**
594
+ * Normalizes session-level tool filter options. Converts {@link ToolSet}
595
+ * instances to plain string arrays, rejects misuse (bare `"*"`) and the
596
+ * missing-availableTools case in `mode = "empty"`.
597
+ *
598
+ * The SDK always sends `toolFilterPrecedence: "excluded"` so callers can
599
+ * compose include + exclude lists naturally (e.g. "everything matching X
600
+ * except Y") regardless of mode. Allowlist-precedence is intentionally not
601
+ * exposed — it's available on the runtime side as a CLI-only concession to
602
+ * legacy behavior, but SDK consumers always get the composable semantics.
603
+ *
604
+ * @internal
605
+ */
606
+ resolveToolFilterOptions(config) {
607
+ const availableTools = toolFilterListToArray(config.availableTools);
608
+ const excludedTools = toolFilterListToArray(config.excludedTools);
609
+ validateToolFilterList("availableTools", availableTools);
610
+ validateToolFilterList("excludedTools", excludedTools);
611
+ if (this.options.mode === "empty") {
612
+ if (availableTools === void 0) {
613
+ throw new Error(
614
+ "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)`."
615
+ );
616
+ }
617
+ }
618
+ return { availableTools, excludedTools, toolFilterPrecedence: "excluded" };
619
+ }
620
+ /** Mode-specific defaults spread under the caller's config (app values win). */
621
+ configDefaultsForMode() {
622
+ if (this.options.mode === "empty") {
623
+ return { enableSessionTelemetry: false };
624
+ }
625
+ return {};
626
+ }
627
+ /**
628
+ * Returns the systemMessage config to use, adjusted for the current mode.
629
+ * In empty mode we ensure the environment_context section is removed
630
+ * unless the app has already taken control of it. `append` (and
631
+ * unspecified) mode is promoted to `customize` so we can also strip
632
+ * environment_context; the caller's `content` is preserved verbatim
633
+ * because the runtime appends it as additional instructions in both
634
+ * customize and append modes.
635
+ */
636
+ getSystemMessageConfigForMode(supplied) {
637
+ if (this.options.mode !== "empty") return supplied;
638
+ if (!supplied) {
639
+ return {
640
+ mode: "customize",
641
+ sections: { environment_context: { action: "remove" } }
642
+ };
643
+ }
644
+ switch (supplied.mode) {
645
+ case "replace":
646
+ return supplied;
647
+ case "customize":
648
+ if (supplied.sections?.environment_context) return supplied;
649
+ return {
650
+ ...supplied,
651
+ sections: {
652
+ ...supplied.sections,
653
+ environment_context: { action: "remove" }
654
+ }
655
+ };
656
+ case "append":
657
+ case void 0:
658
+ return {
659
+ mode: "customize",
660
+ content: supplied.content,
661
+ sections: { environment_context: { action: "remove" } }
662
+ };
663
+ }
664
+ }
665
+ /**
666
+ * Mode-specific options applied via session.options.update after create/resume.
667
+ *
668
+ * In empty mode, defaults the four overridable feature flags to safe values
669
+ * (caller values from `config` win). `installedPlugins=[]` is unconditional
670
+ * in empty mode — apps that need custom plugins should switch modes.
671
+ */
672
+ async updateSessionOptionsForMode(session, config) {
673
+ const patch = {};
674
+ if (this.options.mode === "empty") {
675
+ patch.skipCustomInstructions = config.skipCustomInstructions ?? true;
676
+ patch.customAgentsLocalOnly = config.customAgentsLocalOnly ?? true;
677
+ patch.coauthorEnabled = config.coauthorEnabled ?? false;
678
+ patch.manageScheduleEnabled = config.manageScheduleEnabled ?? false;
679
+ patch.installedPlugins = [];
680
+ } else {
681
+ if (config.skipCustomInstructions !== void 0)
682
+ patch.skipCustomInstructions = config.skipCustomInstructions;
683
+ if (config.customAgentsLocalOnly !== void 0)
684
+ patch.customAgentsLocalOnly = config.customAgentsLocalOnly;
685
+ if (config.coauthorEnabled !== void 0)
686
+ patch.coauthorEnabled = config.coauthorEnabled;
687
+ if (config.manageScheduleEnabled !== void 0)
688
+ patch.manageScheduleEnabled = config.manageScheduleEnabled;
689
+ }
690
+ if (Object.keys(patch).length === 0) {
691
+ return;
692
+ }
693
+ try {
694
+ await session.rpc.options.update(patch);
695
+ } catch (e) {
696
+ try {
697
+ await session.disconnect();
698
+ } catch {
699
+ }
700
+ throw e;
701
+ }
702
+ }
563
703
  async createSession(config) {
564
704
  if (!this.connection) {
565
705
  await this.start();
566
706
  }
707
+ config = { ...this.configDefaultsForMode(), ...config };
708
+ config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
567
709
  const sessionId = config.sessionId ?? (0, import_node_crypto.randomUUID)();
568
710
  const session = new import_session.CopilotSession(
569
711
  sessionId,
@@ -601,6 +743,7 @@ class CopilotClient {
601
743
  }
602
744
  this.sessions.set(sessionId, session);
603
745
  this.setupSessionFs(session, config);
746
+ const toolFilterOptions = this.resolveToolFilterOptions(config);
604
747
  try {
605
748
  const response = await this.connection.sendRequest("session.create", {
606
749
  ...await (0, import_telemetry.getTraceContext)(this.onGetTraceContext),
@@ -624,8 +767,9 @@ class CopilotClient {
624
767
  description: cmd.description
625
768
  })),
626
769
  systemMessage: wireSystemMessage,
627
- availableTools: config.availableTools,
628
- excludedTools: config.excludedTools,
770
+ availableTools: toolFilterOptions.availableTools,
771
+ excludedTools: toolFilterOptions.excludedTools,
772
+ toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
629
773
  provider: config.provider,
630
774
  enableSessionTelemetry: config.enableSessionTelemetry,
631
775
  modelCapabilities: config.modelCapabilities,
@@ -656,6 +800,7 @@ class CopilotClient {
656
800
  const { workspacePath, capabilities } = response;
657
801
  session["_workspacePath"] = workspacePath;
658
802
  session.setCapabilities(capabilities);
803
+ await this.updateSessionOptionsForMode(session, config);
659
804
  } catch (e) {
660
805
  this.sessions.delete(sessionId);
661
806
  throw e;
@@ -715,6 +860,8 @@ class CopilotClient {
715
860
  if (config.hooks) {
716
861
  session.registerHooks(config.hooks);
717
862
  }
863
+ config = { ...this.configDefaultsForMode(), ...config };
864
+ config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
718
865
  const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
719
866
  config.systemMessage
720
867
  );
@@ -726,6 +873,7 @@ class CopilotClient {
726
873
  }
727
874
  this.sessions.set(sessionId, session);
728
875
  this.setupSessionFs(session, config);
876
+ const toolFilterOptions = this.resolveToolFilterOptions(config);
729
877
  try {
730
878
  const response = await this.connection.sendRequest("session.resume", {
731
879
  ...await (0, import_telemetry.getTraceContext)(this.onGetTraceContext),
@@ -734,8 +882,9 @@ class CopilotClient {
734
882
  model: config.model,
735
883
  reasoningEffort: config.reasoningEffort,
736
884
  systemMessage: wireSystemMessage,
737
- availableTools: config.availableTools,
738
- excludedTools: config.excludedTools,
885
+ availableTools: toolFilterOptions.availableTools,
886
+ excludedTools: toolFilterOptions.excludedTools,
887
+ toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
739
888
  enableSessionTelemetry: config.enableSessionTelemetry,
740
889
  tools: config.tools?.map((tool) => ({
741
890
  name: tool.name,
@@ -784,6 +933,7 @@ class CopilotClient {
784
933
  session["_workspacePath"] = workspacePath;
785
934
  session.setCapabilities(capabilities);
786
935
  session.setOpenCanvases(openCanvases ?? []);
936
+ await this.updateSessionOptionsForMode(session, config);
787
937
  } catch (e) {
788
938
  this.sessions.delete(sessionId);
789
939
  throw e;
@@ -1162,6 +1312,9 @@ class CopilotClient {
1162
1312
  if (this.options.baseDirectory) {
1163
1313
  envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
1164
1314
  }
1315
+ if (this.options.mode === "empty") {
1316
+ envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
1317
+ }
1165
1318
  if (!this.resolvedCliPath) {
1166
1319
  throw new Error(
1167
1320
  "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."
@@ -171,7 +171,7 @@ function createServerRpc(connection) {
171
171
  /**
172
172
  * Lists persisted sessions, optionally filtered by working-directory context.
173
173
  *
174
- * @param params Optional metadata-load limit and context filter applied to the returned sessions.
174
+ * @param params Optional metadata-load limit and filters applied to the returned sessions.
175
175
  *
176
176
  * @returns Persisted sessions matching the filter, ordered most-recently-modified first.
177
177
  */
@@ -302,6 +302,17 @@ function createServerRpc(connection) {
302
302
  * @returns Replace the manager-wide additional plugins. New session creations and subsequent hook reloads see the new set; already-running sessions keep their existing hook installation until the next reload.
303
303
  */
304
304
  setAdditionalPlugins: async (params) => connection.sendRequest("sessions.setAdditionalPlugins", params)
305
+ },
306
+ /** @experimental */
307
+ agentRegistry: {
308
+ /**
309
+ * Spawns a managed-server child with the supplied configuration and returns a discriminated-union result. The caller (typically the CLI controller) is responsible for attaching to the spawned child and sending any follow-up prompt. When the controller-local spawn gate is closed the server returns JSON-RPC MethodNotFound.
310
+ *
311
+ * @param params Inputs to spawn a managed-server child via the controller's spawn delegate.
312
+ *
313
+ * @returns Outcome of an agentRegistry.spawn call.
314
+ */
315
+ spawn: async (params) => connection.sendRequest("agentRegistry.spawn", params)
305
316
  }
306
317
  };
307
318
  }
@@ -1060,6 +1071,20 @@ function createSessionRpc(connection, sessionId) {
1060
1071
  * @returns Indicates whether the operation succeeded.
1061
1072
  */
1062
1073
  setApproveAll: async (params) => connection.sendRequest("session.permissions.setApproveAll", { sessionId, ...params }),
1074
+ /**
1075
+ * Enables or disables full allow-all permissions (tools, paths, and URLs) for the session. Used by attach-mode clients (e.g. LocalRpcSession's `/allow-all` forwarder) to flip the target session's permission state. Unlike `setApproveAll`, this swaps in the unrestricted path and URL managers and emits `session.permissions_changed` on transition. The result returns the authoritative post-mutation state so callers can update their local mirrors without racing the `session.permissions_changed` notification on the same wire.
1076
+ *
1077
+ * @param params Whether to enable full allow-all permissions for the session.
1078
+ *
1079
+ * @returns Indicates whether the operation succeeded and reports the post-mutation state.
1080
+ */
1081
+ setAllowAll: async (params) => connection.sendRequest("session.permissions.setAllowAll", { sessionId, ...params }),
1082
+ /**
1083
+ * Returns whether full allow-all permissions are currently active for the session.
1084
+ *
1085
+ * @returns Current full allow-all permission state.
1086
+ */
1087
+ getAllowAll: async () => connection.sendRequest("session.permissions.getAllowAll", { sessionId }),
1063
1088
  /**
1064
1089
  * Adds or removes session-scoped or location-scoped permission rules.
1065
1090
  *
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,
@@ -119,6 +119,7 @@ class CopilotSession {
119
119
  prompt: options.prompt,
120
120
  attachments: options.attachments,
121
121
  mode: options.mode,
122
+ agentMode: options.agentMode,
122
123
  requestHeaders: options.requestHeaders
123
124
  });
124
125
  return response.messageId;
@@ -739,6 +740,7 @@ class CopilotSession {
739
740
  preToolUse: this.hooks.onPreToolUse,
740
741
  preMcpToolCall: this.hooks.onPreMcpToolCall,
741
742
  postToolUse: this.hooks.onPostToolUse,
743
+ postToolUseFailure: this.hooks.onPostToolUseFailure,
742
744
  userPromptSubmitted: this.hooks.onUserPromptSubmitted,
743
745
  sessionStart: this.hooks.onSessionStart,
744
746
  sessionEnd: this.hooks.onSessionEnd,
@@ -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.