@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 +51 -9
- package/dist/cjs/cliVersion.js +31 -0
- package/dist/cjs/client.js +74 -68
- package/dist/cjs/generated/rpc.js +64 -3
- package/dist/cjs/runtimeArtifacts.js +112 -17
- package/dist/cjs/session.js +108 -10
- package/dist/cliVersion.d.ts +2 -0
- package/dist/cliVersion.js +6 -0
- package/dist/client.d.ts +2 -1
- package/dist/client.js +76 -69
- package/dist/generated/rpc.d.ts +965 -27
- package/dist/generated/rpc.js +64 -3
- package/dist/generated/session-events.d.ts +493 -43
- package/dist/index.d.ts +1 -1
- package/dist/runtimeArtifacts.d.ts +13 -1
- package/dist/runtimeArtifacts.js +103 -16
- package/dist/session.d.ts +52 -1
- package/dist/session.js +108 -10
- package/dist/types.d.ts +60 -2
- package/package.json +103 -88
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
|
|
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
|
|
942
|
-
| `"approve-for-location"` | Allow this request and persist the approval for this project location (git root or cwd)
|
|
943
|
-
| `"approve-permanently"` | Allow this request and persist the approval across sessions (currently used for URL domains)
|
|
944
|
-
| `"reject"` | Deny the request
|
|
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
|
+
});
|
package/dist/cjs/client.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 = {
|
|
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}.
|
|
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
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
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
|
|
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.
|
|
2280
|
-
|
|
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
|
|
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
|
|
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}`);
|