@github/copilot-sdk 1.0.13-preview.4 → 1.0.13

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
@@ -8,6 +8,20 @@ To use the SDK, you'll need:
8
8
 
9
9
  - Node.js ^20.19.0 or >=22.12.0
10
10
 
11
+ The SDK uses an optional `@github/copilot-sdk-<platform>` package containing the
12
+ Copilot CLI runtime for the host platform. These packages are built from
13
+ verified `github/copilot-cli` release assets when the SDK is published, so
14
+ starting the SDK performs no runtime download. Set `COPILOT_CLI_PATH` to use an
15
+ existing installation instead.
16
+
17
+ The checked-in release pin is `copilotCliVersion` in `package.json`. Run
18
+ `npm run set:cli-version -- <version>` to update it and regenerate the compiled
19
+ metadata in `src/cliVersion.ts`. Packaging verifies release assets against the
20
+ release's `SHA256SUMS.txt`.
21
+
22
+ `npm run pack:release` builds the main package and all platform packages. Set
23
+ `COPILOT_CLI_DOWNLOAD_BASE_URL` to use a release mirror while packaging.
24
+
11
25
  ## Installation
12
26
 
13
27
  ```bash
@@ -22,6 +36,7 @@ Try the interactive chat sample (from the repo root):
22
36
  cd nodejs
23
37
  npm ci
24
38
  npm run build
39
+ export COPILOT_CLI_PATH="$(npm run --silent prepare:runtime -- --print-path)"
25
40
  cd samples
26
41
  npm install
27
42
  npm start
@@ -132,6 +147,7 @@ Create a new conversation session.
132
147
 
133
148
  - `sessionId?: string` - Custom session ID.
134
149
  - `model?: string` - Model to use ("gpt-5", "claude-sonnet-4.5", etc.). **Required when using custom provider.**
150
+ - `capi?: CapiSessionOptions` - Copilot API options. With `model: "auto"`, set `autoTier` to `"efficiency"`, `"balance"`, or `"intelligence"` to choose a routing preference. Requires a runtime with Auto tier support and V2 Auto routing. Omission preserves default behavior. See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-persistence) for resume semantics.
135
151
  - `reasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max"` - Reasoning effort level for models that support it. Use `listModels()` to check which models support this option.
136
152
  - `tools?: Tool[]` - Custom tools exposed to the CLI. Tools without `handler` are declaration-only and must be resolved via pending tool-call RPCs.
137
153
  - `systemMessage?: SystemMessageConfig` - System message customization (see below)
@@ -303,6 +319,32 @@ const unsubscribe = session.on((event) => {
303
319
  unsubscribe();
304
320
  ```
305
321
 
322
+ ##### `setModel(model: string, options?): Promise<void>`
323
+
324
+ Change the model for this session. The new model takes effect for the next message; conversation history is preserved.
325
+
326
+ **Options:**
327
+
328
+ - `reasoningEffort?: string` - Reasoning effort level
329
+ - `autoTier?: AutoTier | null` - Auto routing preference to stage together with selecting `auto`. Pass `null` to return to the provider's default Auto routing; omit it to leave the current preference unchanged.
330
+
331
+ ##### `setAutoTier(autoTier: AutoTier | null): Promise<ModelSwitchAutoTierResult>`
332
+
333
+ Change the Auto routing preference without changing the selected model. Pass `null` to return to the provider's default Auto routing.
334
+
335
+ The runtime does not apply the preference immediately. It records the request and commits it only when a later user turn using the `auto` model successfully obtains a usable model from the provider, so a `pending` status confirms acceptance rather than effect. Only the most recent request survives.
336
+
337
+ Watch for the outcome through the `session.model_change` event on success or the ephemeral `session.auto_tier_switch_failed` event on failure, and read the authoritative state at any time with `session.rpc.model.getCurrent()`.
338
+
339
+ ```typescript
340
+ const result = await session.setAutoTier("intelligence");
341
+ if (result.status === "pending") {
342
+ // Accepted, but not yet in effect.
343
+ }
344
+ ```
345
+
346
+ See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-persistence) for the full lifecycle rules.
347
+
306
348
  ##### `abort(): Promise<void>`
307
349
 
308
350
  Abort the currently processing message in this session.
@@ -935,15 +977,15 @@ const session = await client.createSession({
935
977
 
936
978
  The handler must return one of the `PermissionDecision` shapes (or `{ kind: "no-result" }`). Approval scopes are present-tense — they describe the decision to apply, not the outcome reported back on session events:
937
979
 
938
- | Kind | Meaning | Extra fields |
939
- | ------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
940
- | `"approve-once"` | Allow this single request | — |
941
- | `"approve-for-session"` | Allow this request and remember the approval for the rest of the session | `approval?` (rule to remember), `domain?` (for URL approvals) |
942
- | `"approve-for-location"` | Allow this request and persist the approval for this project location (git root or cwd) | `approval` (rule to persist), `locationKey` (location to persist under) |
943
- | `"approve-permanently"` | Allow this request and persist the approval across sessions (currently used for URL domains) | `domain` (URL domain to approve) |
944
- | `"reject"` | Deny the request | `feedback?` (optional string surfaced to the agent) |
945
- | `"user-not-available"` | Deny the request because no user is available to confirm it | — |
946
- | `"no-result"` | Suppress this SDK client's response so another connected client can answer the pending request | — |
980
+ | Kind | Meaning | Extra fields |
981
+ | ------------------------ | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
982
+ | `"approve-once"` | Allow this single request | — |
983
+ | `"approve-for-session"` | Allow this request and remember the approval for the rest of the session | `approval?` (rule to remember), `domain?` (for URL approvals) |
984
+ | `"approve-for-location"` | Allow this request and persist the approval for this project location (git root or cwd) | `approval` (rule to persist), `locationKey` (location to persist under) |
985
+ | `"approve-permanently"` | Allow this request and persist the approval across sessions (currently used for URL domains) | `domain` (URL domain to approve) |
986
+ | `"reject"` | Deny the request | `feedback?` (optional string surfaced to the agent) |
987
+ | `"user-not-available"` | Deny the request because no user is available to confirm it | — |
988
+ | `"no-result"` | Suppress this SDK client's response so another connected client can answer the pending request | — |
947
989
 
948
990
  ### Resuming Sessions
949
991
 
@@ -0,0 +1,31 @@
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 cliVersion_exports = {};
20
+ __export(cliVersion_exports, {
21
+ COPILOT_CLI_USE_NPM_PACKAGE: () => COPILOT_CLI_USE_NPM_PACKAGE,
22
+ COPILOT_CLI_VERSION: () => COPILOT_CLI_VERSION
23
+ });
24
+ module.exports = __toCommonJS(cliVersion_exports);
25
+ const COPILOT_CLI_VERSION = "1.0.83";
26
+ const COPILOT_CLI_USE_NPM_PACKAGE = false;
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ COPILOT_CLI_USE_NPM_PACKAGE,
30
+ COPILOT_CLI_VERSION
31
+ });
@@ -34,21 +34,19 @@ module.exports = __toCommonJS(client_exports);
34
34
  var import_node_child_process = require("node:child_process");
35
35
  var import_node_crypto = require("node:crypto");
36
36
  var import_node_fs = require("node:fs");
37
- var import_node_module = require("node:module");
38
37
  var import_node_net = require("node:net");
39
38
  var import_node_path = require("node:path");
40
- var import_node_url = require("node:url");
41
39
  var import_node = require("vscode-jsonrpc/node.js");
42
40
  var import_rpc = require("./generated/rpc.js");
43
41
  var import_sdkProtocolVersion = require("./sdkProtocolVersion.js");
44
42
  var import_session = require("./session.js");
45
43
  var import_runtimeArtifacts = require("./runtimeArtifacts.js");
44
+ var import_cliVersion = require("./cliVersion.js");
46
45
  var import_sessionFsProvider = require("./sessionFsProvider.js");
47
46
  var import_copilotRequestHandler = require("./copilotRequestHandler.js");
48
47
  var import_telemetry = require("./telemetry.js");
49
48
  var import_toolSet = require("./toolSet.js");
50
49
  var import_types = require("./types.js");
51
- const import_meta = {};
52
50
  const MIN_PROTOCOL_VERSION = 3;
53
51
  const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
54
52
  function isZodSchema(value) {
@@ -151,6 +149,15 @@ function toWireCustomAgents(agents) {
151
149
  return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
152
150
  });
153
151
  }
152
+ function clientInfoToWire(info) {
153
+ if (info == null) return void 0;
154
+ const wire = {};
155
+ if (info.applicationName) wire.editorName = info.applicationName;
156
+ if (info.applicationVersion) wire.editorVersion = info.applicationVersion;
157
+ if (info.integrationName) wire.extensionName = info.integrationName;
158
+ if (info.integrationVersion) wire.extensionVersion = info.integrationVersion;
159
+ return Object.keys(wire).length > 0 ? wire : void 0;
160
+ }
154
161
  function toWireLargeOutput(config) {
155
162
  if (!config) return void 0;
156
163
  const { outputDirectory, ...rest } = config;
@@ -208,53 +215,8 @@ function getNodeExecPath() {
208
215
  }
209
216
  return process.execPath;
210
217
  }
211
- function getCliPlatformPackageNames() {
212
- const arch = process.arch;
213
- const variants = process.platform === "linux" ? ["linux", "linuxmusl"] : [process.platform];
214
- return variants.map((variant) => `@github/copilot-${variant}-${arch}`);
215
- }
216
- function getBundledCliPackage() {
217
- const packageNames = getCliPlatformPackageNames();
218
- if (typeof import_meta.resolve === "function") {
219
- for (const packageName of packageNames) {
220
- try {
221
- const packageEntryUrl = import_meta.resolve(packageName);
222
- const packageEntryPath = (0, import_node_url.fileURLToPath)(packageEntryUrl);
223
- return {
224
- root: (0, import_node_path.dirname)(packageEntryPath),
225
- platform: packageName.slice("@github/copilot-".length)
226
- };
227
- } catch {
228
- }
229
- }
230
- throw new Error(
231
- `Could not resolve a @github/copilot platform package (tried ${packageNames.join(", ")}). Ensure @github/copilot is installed, or pass cliPath/cliUrl to CopilotClient.`
232
- );
233
- }
234
- const req = (0, import_node_module.createRequire)(__filename);
235
- const searchPaths = req.resolve.paths("@github/copilot") ?? [];
236
- for (const base of searchPaths) {
237
- for (const packageName of packageNames) {
238
- const root = (0, import_node_path.join)(base, ...packageName.split("/"));
239
- const candidate = (0, import_node_path.join)(root, "index.js");
240
- if ((0, import_node_fs.existsSync)(candidate)) {
241
- return {
242
- root,
243
- platform: packageName.slice("@github/copilot-".length)
244
- };
245
- }
246
- }
247
- }
248
- throw new Error(
249
- `Could not find a @github/copilot platform package (tried ${packageNames.join(", ")}). Searched ${searchPaths.length} paths. Ensure @github/copilot is installed, or pass cliPath/cliUrl to CopilotClient.`
250
- );
251
- }
252
218
  function getBundledRuntimePath() {
253
- const bundled = getBundledCliPackage();
254
- return (0, import_runtimeArtifacts.materializeRuntimeBundle)({
255
- packageRoot: bundled.root,
256
- platform: bundled.platform
257
- });
219
+ return (0, import_runtimeArtifacts.ensureRuntimeBundle)(import_cliVersion.COPILOT_CLI_VERSION);
258
220
  }
259
221
  class TeardownResilientStreamMessageWriter extends import_node.StreamMessageWriter {
260
222
  suppressWriteErrors = false;
@@ -274,6 +236,7 @@ class CopilotClient {
274
236
  ffiHost = null;
275
237
  connection = null;
276
238
  messageWriter = null;
239
+ connectionClosed = false;
277
240
  socket = null;
278
241
  runtimePort = null;
279
242
  actualHost = "localhost";
@@ -473,8 +436,6 @@ class CopilotClient {
473
436
  const explicitCliPath = conn.path ?? effectiveEnv.COPILOT_CLI_PATH;
474
437
  if (explicitCliPath) {
475
438
  this.resolvedCliPath = explicitCliPath;
476
- } else {
477
- this.resolvedCliPath = getBundledRuntimePath();
478
439
  }
479
440
  }
480
441
  const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
@@ -489,7 +450,8 @@ class CopilotClient {
489
450
  baseDirectory: options.baseDirectory,
490
451
  sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
491
452
  enableRemoteSessions: options.enableRemoteSessions ?? false,
492
- mode: options.mode ?? "copilot-cli"
453
+ mode: options.mode ?? "copilot-cli",
454
+ clientInfo: options.clientInfo
493
455
  };
494
456
  if (this.options.mode === "empty") {
495
457
  const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
@@ -505,17 +467,29 @@ class CopilotClient {
505
467
  connectionExtraArgs = [];
506
468
  /**
507
469
  * Parse CLI URL into host and port
508
- * Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
470
+ * Supports formats: "host:port", "[ipv6]:port", "http://host:port", "https://host:port", or just "port"
509
471
  */
510
472
  parseCliUrl(url) {
511
- let cleanUrl = url.replace(/^https?:\/\//, "");
473
+ const cleanUrl = url.replace(/^https?:\/\//, "");
512
474
  if (/^\d+$/.test(cleanUrl)) {
513
475
  return { host: "localhost", port: parseInt(cleanUrl, 10) };
514
476
  }
477
+ const ipv6Match = cleanUrl.match(/^\[([^\]]+)\]:(\d+)$/);
478
+ if (ipv6Match) {
479
+ const host2 = ipv6Match[1];
480
+ if (!(0, import_node_net.isIPv6)(host2)) {
481
+ throw new Error(`Invalid cliUrl format: ${url}`);
482
+ }
483
+ const port2 = parseInt(ipv6Match[2], 10);
484
+ if (isNaN(port2) || port2 <= 0 || port2 > 65535) {
485
+ throw new Error(`Invalid port in cliUrl: ${url}`);
486
+ }
487
+ return { host: host2, port: port2 };
488
+ }
515
489
  const parts = cleanUrl.split(":");
516
490
  if (parts.length !== 2) {
517
491
  throw new Error(
518
- `Invalid cliUrl format: ${url}. Expected "host:port", "http://host:port", or "port"`
492
+ `Invalid cliUrl format: ${url}. Expected "host:port", "[ipv6]:port", "http://host:port", or "port"`
519
493
  );
520
494
  }
521
495
  const host = parts[0] || "localhost";
@@ -645,6 +619,7 @@ class CopilotClient {
645
619
  return;
646
620
  }
647
621
  this.forceStopping = false;
622
+ this.connectionClosed = false;
648
623
  this.processTransportError = null;
649
624
  this.state = "connecting";
650
625
  try {
@@ -743,7 +718,7 @@ class CopilotClient {
743
718
  }
744
719
  this.sessions.clear();
745
720
  this.githubTokenProviders.clear();
746
- if (this.connection && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
721
+ if (this.connection && !this.connectionClosed && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
747
722
  const runtimeShutdownStart = Date.now();
748
723
  const shutdownPromise = this.rpc.runtime.shutdown();
749
724
  void shutdownPromise.catch(() => void 0);
@@ -1274,6 +1249,7 @@ class CopilotClient {
1274
1249
  gitHubTokenProviderRegistrationId,
1275
1250
  remoteSession: config.remoteSession,
1276
1251
  cloud: config.cloud,
1252
+ featureFlags: config.featureFlags,
1277
1253
  expAssignments: config.expAssignments,
1278
1254
  enableManagedSettings: config.enableManagedSettings,
1279
1255
  managedSettings: config.managedSettings
@@ -1307,6 +1283,7 @@ class CopilotClient {
1307
1283
  await this.updateSessionOptionsForMode(session, config);
1308
1284
  this.commitGitHubTokenProvider(returnedSessionId, gitHubTokenProviderRegistrationId);
1309
1285
  } catch (e) {
1286
+ session?._markDisconnected();
1310
1287
  if (registeredId !== void 0) {
1311
1288
  this.sessions.delete(registeredId);
1312
1289
  }
@@ -1509,6 +1486,7 @@ class CopilotClient {
1509
1486
  gitHubTokenProviderRegistrationId,
1510
1487
  remoteSession: config.remoteSession,
1511
1488
  openCanvases: config.openCanvases,
1489
+ featureFlags: config.featureFlags,
1512
1490
  expAssignments: config.expAssignments,
1513
1491
  enableManagedSettings: config.enableManagedSettings,
1514
1492
  managedSettings: config.managedSettings,
@@ -1538,6 +1516,7 @@ class CopilotClient {
1538
1516
  await this.updateSessionOptionsForMode(session, config);
1539
1517
  this.commitGitHubTokenProvider(sessionId, gitHubTokenProviderRegistrationId);
1540
1518
  } catch (e) {
1519
+ session._markDisconnected();
1541
1520
  this.sessions.delete(sessionId);
1542
1521
  if (gitHubTokenProviderRegistrationId !== void 0) {
1543
1522
  this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
@@ -1653,10 +1632,17 @@ class CopilotClient {
1653
1632
  const raceAgainstExit = (p) => this.processExitPromise ? Promise.race([p, this.processExitPromise]) : p;
1654
1633
  let serverVersion;
1655
1634
  try {
1656
- const connectParams = { token: this.effectiveConnectionToken };
1635
+ const connectParams = {
1636
+ token: this.effectiveConnectionToken,
1637
+ supportedTaskKinds: ["agent", "client", "shell"]
1638
+ };
1657
1639
  if (this.onGitHubTelemetry != null) {
1658
1640
  connectParams.enableGitHubTelemetryForwarding = true;
1659
1641
  }
1642
+ const clientInfo = clientInfoToWire(this.options.clientInfo);
1643
+ if (clientInfo != null) {
1644
+ connectParams.clientInfo = clientInfo;
1645
+ }
1660
1646
  const result = await raceAgainstExit(this.internalRpc.connect(connectParams));
1661
1647
  serverVersion = result.protocolVersion;
1662
1648
  } catch (err) {
@@ -1917,6 +1903,7 @@ class CopilotClient {
1917
1903
  * Start the CLI server process
1918
1904
  */
1919
1905
  async startCLIServer() {
1906
+ this.resolvedCliPath ??= await getBundledRuntimePath();
1920
1907
  return new Promise((resolve2, reject) => {
1921
1908
  this.stderrBuffer = "";
1922
1909
  const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
@@ -1954,7 +1941,7 @@ class CopilotClient {
1954
1941
  }
1955
1942
  if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) {
1956
1943
  throw new Error(
1957
- `Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
1944
+ `Copilot CLI not found at ${this.resolvedCliPath}. Set COPILOT_CLI_PATH to use a custom installation.`
1958
1945
  );
1959
1946
  }
1960
1947
  const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
@@ -2081,12 +2068,19 @@ stderr: ${stderrOutput}`
2081
2068
  /** Starts the in-process FFI runtime with SDK-managed typed options. */
2082
2069
  async startInProcessFfi() {
2083
2070
  const explicitEntrypoint = this.resolvedEnv.COPILOT_CLI_PATH;
2084
- const runtimeLibrary = explicitEntrypoint ? (0, import_node_path.join)(
2085
- (0, import_node_path.dirname)((0, import_node_path.resolve)(explicitEntrypoint)),
2086
- "prebuilds",
2087
- CopilotClient.getNapiPrebuildsFolder(explicitEntrypoint),
2088
- "runtime.node"
2089
- ) : (0, import_node_path.join)((0, import_node_path.dirname)(getBundledRuntimePath()), "runtime.node");
2071
+ let runtimeLibrary;
2072
+ if (explicitEntrypoint) {
2073
+ const entrypointDirectory = (0, import_node_path.dirname)((0, import_node_path.resolve)(explicitEntrypoint));
2074
+ const adjacentRuntime = (0, import_node_path.join)(entrypointDirectory, "runtime.node");
2075
+ runtimeLibrary = (0, import_node_fs.existsSync)(adjacentRuntime) ? adjacentRuntime : (0, import_node_path.join)(
2076
+ entrypointDirectory,
2077
+ "prebuilds",
2078
+ CopilotClient.getNapiPrebuildsFolder(explicitEntrypoint),
2079
+ "runtime.node"
2080
+ );
2081
+ } else {
2082
+ runtimeLibrary = (0, import_node_path.join)((0, import_node_path.dirname)(await getBundledRuntimePath()), "runtime.node");
2083
+ }
2090
2084
  const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
2091
2085
  const environment = {};
2092
2086
  if (this.options.gitHubToken) {
@@ -2272,12 +2266,24 @@ stderr: ${stderrOutput}` : ""}`
2272
2266
  return await this.handleHooksInvoke(params);
2273
2267
  }
2274
2268
  );
2275
- this.connection.onClose(() => {
2269
+ const connection = this.connection;
2270
+ const markDisconnected = () => {
2271
+ if (this.connection !== connection) {
2272
+ return;
2273
+ }
2274
+ this.connectionClosed = true;
2276
2275
  this.state = "disconnected";
2276
+ for (const session of this.sessions.values()) {
2277
+ session._markDisconnected();
2278
+ }
2279
+ this.sessions.clear();
2277
2280
  this.githubTokenProviders.clear();
2278
- });
2279
- this.connection.onError((_error) => {
2280
- this.state = "disconnected";
2281
+ };
2282
+ this.connection.onClose(markDisconnected);
2283
+ this.connection.onError(() => {
2284
+ if (this.connection === connection) {
2285
+ this.state = "disconnected";
2286
+ }
2281
2287
  });
2282
2288
  }
2283
2289
  handleSessionEventNotification(notification) {
@@ -39,6 +39,17 @@ function createServerRpc(connection) {
39
39
  */
40
40
  ping: async (params) => connection.sendRequest("ping", params),
41
41
  /** @experimental */
42
+ hooks: {
43
+ /**
44
+ * Discovers hook actions enabled under server-side discovery settings from user, repository, plugin, and managed-policy sources.
45
+ *
46
+ * @param params Optional project paths and host-exclusion behavior for server-scoped hook discovery.
47
+ *
48
+ * @returns Server-discovered hook actions and partial-load diagnostics from user, repository, plugin, and managed-policy sources. Concrete sessions may include additional session-specific hook sources.
49
+ */
50
+ discover: async (params) => connection.sendRequest("hooks.discover", params)
51
+ },
52
+ /** @experimental */
42
53
  models: {
43
54
  /**
44
55
  * Lists Copilot models available to the authenticated user.
@@ -427,7 +438,11 @@ function createServerRpc(connection) {
427
438
  *
428
439
  * @returns Validated device-managed settings discovered before a session exists.
429
440
  */
430
- read: async () => connection.sendRequest("managedSettings.read", {})
441
+ read: async () => connection.sendRequest("managedSettings.read", {}),
442
+ /**
443
+ * Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed.
444
+ */
445
+ clearCache: async () => connection.sendRequest("managedSettings.clearCache", {})
431
446
  },
432
447
  /** @experimental */
433
448
  runtime: {
@@ -506,6 +521,14 @@ function createServerRpc(connection) {
506
521
  * @returns Sessions matching the filter, ordered most-recently-modified first.
507
522
  */
508
523
  list: async (params) => connection.sendRequest("sessions.list", params),
524
+ /**
525
+ * Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The initial backward read uses a bounded tail scan for fast first paint; cursor continuations preserve the session event-log paging semantics. Persisted events may omit payloads that are reconstructed only for an active session.
526
+ *
527
+ * @param params Pagination options for reading an inactive or active local session's persisted event journal.
528
+ *
529
+ * @returns Batch of session events returned by a read, with cursor and continuation metadata.
530
+ */
531
+ readPersistedEvents: async (params) => connection.sendRequest("sessions.readPersistedEvents", params),
509
532
  /**
510
533
  * Finds the local session bound to a GitHub task ID, if any.
511
534
  *
@@ -983,9 +1006,9 @@ function createSessionRpc(connection, sessionId) {
983
1006
  /** @experimental */
984
1007
  model: {
985
1008
  /**
986
- * Gets the currently selected model for the session.
1009
+ * Gets the session's authoritative model snapshot, including the committed Auto preference and any newer unclaimed Auto preference waiting for a future user turn.
987
1010
  *
988
- * @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.
1011
+ * @returns The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume.
989
1012
  */
990
1013
  getCurrent: async () => connection.sendRequest("session.model.getCurrent", { sessionId }),
991
1014
  /**
@@ -996,6 +1019,14 @@ function createSessionRpc(connection, sessionId) {
996
1019
  * @returns The model identifier active on the session after the switch.
997
1020
  */
998
1021
  switchTo: async (params) => connection.sendRequest("session.model.switchTo", { sessionId, ...params }),
1022
+ /**
1023
+ * Requests an Auto preference change without changing the session's selected model. The latest unclaimed request wins; the runtime commits it only after a later prompt using the `auto` model mints a usable model and token pair. A `pending` response confirms that the request was accepted, not that it committed. Observe eventual success through `session.model_change`, failure through the ephemeral `session.auto_tier_switch_failed` event, or current unclaimed state through `session.model.getCurrent`.
1024
+ *
1025
+ * @param params An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`.
1026
+ *
1027
+ * @returns Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed.
1028
+ */
1029
+ switchAutoTier: async (params) => connection.sendRequest("session.model.switchAutoTier", { sessionId, ...params }),
999
1030
  /**
1000
1031
  * Updates the session's reasoning effort without changing the selected model.
1001
1032
  *
@@ -1202,6 +1233,15 @@ function createSessionRpc(connection, sessionId) {
1202
1233
  diff: async (params) => connection.sendRequest("session.workspaces.diff", { sessionId, ...params })
1203
1234
  },
1204
1235
  /** @experimental */
1236
+ autopilotObjective: {
1237
+ /**
1238
+ * Reads the current canonical autopilot objective state for this session.
1239
+ *
1240
+ * @returns Canonical runtime state for the session's current autopilot objective.
1241
+ */
1242
+ getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId })
1243
+ },
1244
+ /** @experimental */
1205
1245
  completions: {
1206
1246
  /**
1207
1247
  * Gets the characters that should trigger host-driven completions for the session. Empty disables host-driven completions (e.g. local sessions, or a relay host that does not advertise them).
@@ -1295,6 +1335,22 @@ function createSessionRpc(connection, sessionId) {
1295
1335
  * @returns Background tasks currently tracked by the session.
1296
1336
  */
1297
1337
  list: async () => connection.sendRequest("session.tasks.list", { sessionId }),
1338
+ /**
1339
+ * Registers a client-owned task, or reclaims an orphaned task belonging to the same extension principal.
1340
+ *
1341
+ * @param params Registers or reclaims a client-owned task.
1342
+ *
1343
+ * @returns Result of registering or reclaiming a client-owned task.
1344
+ */
1345
+ register: async (params) => connection.sendRequest("session.tasks.register", { sessionId, ...params }),
1346
+ /**
1347
+ * Publishes generic progress or a terminal outcome for a client-owned task.
1348
+ *
1349
+ * @param params Updates a client-owned task.
1350
+ *
1351
+ * @returns Result of publishing a client-owned task update.
1352
+ */
1353
+ update: async (params) => connection.sendRequest("session.tasks.update", { sessionId, ...params }),
1298
1354
  /**
1299
1355
  * Refreshes metadata for any detached background shells the runtime knows about.
1300
1356
  *
@@ -2763,6 +2819,11 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
2763
2819
  if (!handler) throw new Error(`No factory handler registered for session: ${params.sessionId}`);
2764
2820
  return handler.abort(params);
2765
2821
  });
2822
+ connection.onRequest("tasks.cancel", async (params) => {
2823
+ const handler = getHandlers(params.sessionId).tasks;
2824
+ if (!handler) throw new Error(`No tasks handler registered for session: ${params.sessionId}`);
2825
+ return handler.cancel(params);
2826
+ });
2766
2827
  connection.onRequest("sessionFs.readFile", async (params) => {
2767
2828
  const handler = getHandlers(params.sessionId).sessionFs;
2768
2829
  if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);