@github/copilot-sdk 1.0.1 → 1.0.2-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/dist/canvas.js +1 -0
- package/dist/cjs/canvas.js +1 -0
- package/dist/cjs/client.js +107 -11
- package/dist/cjs/generated/rpc.js +56 -5
- package/dist/cjs/session.js +3 -0
- package/dist/client.d.ts +4 -2
- package/dist/client.js +107 -11
- package/dist/generated/rpc.d.ts +642 -24
- package/dist/generated/rpc.js +56 -5
- package/dist/generated/session-events.d.ts +316 -16
- package/dist/index.d.ts +1 -1
- package/dist/session.js +3 -0
- package/dist/types.d.ts +29 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC.
|
|
4
4
|
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
To use the SDK, you'll need:
|
|
8
|
+
|
|
9
|
+
- Node.js ^20.19.0 or >=22.12.0
|
|
10
|
+
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
7
13
|
```bash
|
|
@@ -482,6 +488,21 @@ defineTool("safe_lookup", {
|
|
|
482
488
|
});
|
|
483
489
|
```
|
|
484
490
|
|
|
491
|
+
#### Deferring Tools
|
|
492
|
+
|
|
493
|
+
Set `defer` to control whether a tool may be loaded lazily via tool search rather than always pre-loaded. Use `"auto"` to allow the tool to be deferred and surfaced through tool search, or `"never"` to force it to always be pre-loaded. Defaults to `"auto"`.
|
|
494
|
+
|
|
495
|
+
```ts
|
|
496
|
+
defineTool("lookup_issue", {
|
|
497
|
+
description: "Fetch issue details",
|
|
498
|
+
parameters: z.object({ id: z.string() }),
|
|
499
|
+
defer: "auto",
|
|
500
|
+
handler: async ({ id }) => {
|
|
501
|
+
/* your logic */
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
```
|
|
505
|
+
|
|
485
506
|
### Commands
|
|
486
507
|
|
|
487
508
|
Register slash commands so that users of the CLI's TUI can invoke custom actions via `/commandName`. Each command has a `name`, optional `description`, and a `handler` called when the user executes it.
|
|
@@ -656,6 +677,28 @@ When enabled, sessions emit compaction events:
|
|
|
656
677
|
- `session.compaction_start` - Background compaction started
|
|
657
678
|
- `session.compaction_complete` - Compaction finished (includes token counts)
|
|
658
679
|
|
|
680
|
+
### Memory
|
|
681
|
+
|
|
682
|
+
Sessions can opt in to the memory feature, which lets the agent persist and recall
|
|
683
|
+
information across turns. Provide a `memory` configuration on session create or resume;
|
|
684
|
+
when omitted, the runtime default applies. In the default `"copilot-cli"` client mode the
|
|
685
|
+
SDK leaves `memory` unset so the runtime applies its own default, while `"empty"` mode
|
|
686
|
+
defaults `memory` to disabled unless you set it explicitly.
|
|
687
|
+
|
|
688
|
+
```typescript
|
|
689
|
+
// Enable memory for a session
|
|
690
|
+
const session = await client.createSession({
|
|
691
|
+
model: "gpt-5",
|
|
692
|
+
memory: { enabled: true },
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Disable memory for a session
|
|
696
|
+
const session = await client.createSession({
|
|
697
|
+
model: "gpt-5",
|
|
698
|
+
memory: { enabled: false },
|
|
699
|
+
});
|
|
700
|
+
```
|
|
701
|
+
|
|
659
702
|
### Multiple Sessions
|
|
660
703
|
|
|
661
704
|
```typescript
|
|
@@ -771,6 +814,7 @@ With just this configuration, the CLI emits spans for every session, message, an
|
|
|
771
814
|
**TelemetryConfig options:**
|
|
772
815
|
|
|
773
816
|
- `otlpEndpoint?: string` - OTLP HTTP endpoint URL
|
|
817
|
+
- `otlpProtocol?: "http/json" | "http/protobuf"` - OTLP HTTP protocol for all signals
|
|
774
818
|
- `filePath?: string` - File path for JSON-lines trace output
|
|
775
819
|
- `exporterType?: string` - `"otlp-http"` or `"file"`
|
|
776
820
|
- `sourceName?: string` - Instrumentation scope name
|
|
@@ -1033,11 +1077,6 @@ try {
|
|
|
1033
1077
|
}
|
|
1034
1078
|
```
|
|
1035
1079
|
|
|
1036
|
-
## Requirements
|
|
1037
|
-
|
|
1038
|
-
- Node.js ^20.19.0 or >=22.12.0
|
|
1039
|
-
- GitHub Copilot CLI installed and in PATH (or provide a custom `connection`)
|
|
1040
|
-
|
|
1041
1080
|
## License
|
|
1042
1081
|
|
|
1043
1082
|
MIT
|
package/dist/canvas.js
CHANGED
package/dist/cjs/canvas.js
CHANGED
package/dist/cjs/client.js
CHANGED
|
@@ -38,9 +38,54 @@ var import_toolSet = require("./toolSet.js");
|
|
|
38
38
|
var import_types = require("./types.js");
|
|
39
39
|
const import_meta = {};
|
|
40
40
|
const MIN_PROTOCOL_VERSION = 3;
|
|
41
|
+
const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
|
|
41
42
|
function isZodSchema(value) {
|
|
42
43
|
return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
|
|
43
44
|
}
|
|
45
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
46
|
+
let timeout;
|
|
47
|
+
try {
|
|
48
|
+
return await Promise.race([
|
|
49
|
+
promise,
|
|
50
|
+
new Promise((_, reject) => {
|
|
51
|
+
timeout = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
52
|
+
})
|
|
53
|
+
]);
|
|
54
|
+
} finally {
|
|
55
|
+
if (timeout !== void 0) {
|
|
56
|
+
clearTimeout(timeout);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function waitForChildExit(child, timeoutMs) {
|
|
61
|
+
if (child.exitCode != null || child.signalCode != null) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
let timeout;
|
|
66
|
+
let settled = false;
|
|
67
|
+
const onExit = () => {
|
|
68
|
+
if (settled) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
settled = true;
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
resolve(true);
|
|
74
|
+
};
|
|
75
|
+
timeout = setTimeout(() => {
|
|
76
|
+
if (settled) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
settled = true;
|
|
80
|
+
child.off("exit", onExit);
|
|
81
|
+
resolve(false);
|
|
82
|
+
}, timeoutMs);
|
|
83
|
+
child.once("exit", onExit);
|
|
84
|
+
if (child.exitCode != null || child.signalCode != null) {
|
|
85
|
+
onExit();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
44
89
|
function toJsonSchema(parameters) {
|
|
45
90
|
if (!parameters) return void 0;
|
|
46
91
|
if (isZodSchema(parameters)) {
|
|
@@ -204,6 +249,13 @@ class CopilotClient {
|
|
|
204
249
|
}
|
|
205
250
|
return this._internalRpc;
|
|
206
251
|
}
|
|
252
|
+
logDebugTiming(message, startMs) {
|
|
253
|
+
const level = this.options.logLevel?.toLowerCase();
|
|
254
|
+
if (level === "debug" || level === "all") {
|
|
255
|
+
process.stderr.write(`[copilot-sdk] ${message}. Elapsed=${Date.now() - startMs}ms
|
|
256
|
+
`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
207
259
|
/**
|
|
208
260
|
* Creates a new CopilotClient instance.
|
|
209
261
|
*
|
|
@@ -390,8 +442,9 @@ class CopilotClient {
|
|
|
390
442
|
*
|
|
391
443
|
* This method performs graceful cleanup:
|
|
392
444
|
* 1. Closes all active sessions (releases in-memory resources)
|
|
393
|
-
* 2.
|
|
394
|
-
* 3.
|
|
445
|
+
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
446
|
+
* 3. Closes the JSON-RPC connection
|
|
447
|
+
* 4. Terminates the CLI server process (if spawned by this client)
|
|
395
448
|
*
|
|
396
449
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
397
450
|
* To permanently remove session data before stopping, call
|
|
@@ -435,6 +488,34 @@ class CopilotClient {
|
|
|
435
488
|
}
|
|
436
489
|
}
|
|
437
490
|
this.sessions.clear();
|
|
491
|
+
let runtimeShutdownCompleted = false;
|
|
492
|
+
if (this.connection && this.cliProcess && !this.isExternalServer) {
|
|
493
|
+
const runtimeShutdownStart = Date.now();
|
|
494
|
+
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
495
|
+
void shutdownPromise.catch(() => void 0);
|
|
496
|
+
try {
|
|
497
|
+
await withTimeout(
|
|
498
|
+
shutdownPromise,
|
|
499
|
+
RUNTIME_SHUTDOWN_TIMEOUT_MS,
|
|
500
|
+
`runtime.shutdown timed out after ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms`
|
|
501
|
+
);
|
|
502
|
+
runtimeShutdownCompleted = true;
|
|
503
|
+
this.logDebugTiming(
|
|
504
|
+
"CopilotClient.stop runtime shutdown complete",
|
|
505
|
+
runtimeShutdownStart
|
|
506
|
+
);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
this.logDebugTiming(
|
|
509
|
+
"CopilotClient.stop runtime shutdown failed",
|
|
510
|
+
runtimeShutdownStart
|
|
511
|
+
);
|
|
512
|
+
errors.push(
|
|
513
|
+
new Error(
|
|
514
|
+
`Failed to gracefully shut down runtime: ${error instanceof Error ? error.message : String(error)}`
|
|
515
|
+
)
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
438
519
|
if (this.connection) {
|
|
439
520
|
try {
|
|
440
521
|
this.connection.dispose();
|
|
@@ -447,6 +528,7 @@ class CopilotClient {
|
|
|
447
528
|
}
|
|
448
529
|
this.connection = null;
|
|
449
530
|
this._rpc = null;
|
|
531
|
+
this._internalRpc = null;
|
|
450
532
|
}
|
|
451
533
|
this.modelsCache = null;
|
|
452
534
|
if (this.socket) {
|
|
@@ -471,12 +553,18 @@ class CopilotClient {
|
|
|
471
553
|
const child = this.cliProcess;
|
|
472
554
|
this.cliProcess = null;
|
|
473
555
|
try {
|
|
474
|
-
if (child.exitCode
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
556
|
+
if (child.exitCode == null && child.signalCode == null) {
|
|
557
|
+
const exitedGracefully = runtimeShutdownCompleted ? await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS) : false;
|
|
558
|
+
if (!exitedGracefully) {
|
|
559
|
+
child.kill();
|
|
560
|
+
if (!await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS)) {
|
|
561
|
+
errors.push(
|
|
562
|
+
new Error(
|
|
563
|
+
`Timed out waiting for CLI process to exit after kill: ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms`
|
|
564
|
+
)
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
480
568
|
}
|
|
481
569
|
} catch (error) {
|
|
482
570
|
errors.push(
|
|
@@ -546,6 +634,7 @@ class CopilotClient {
|
|
|
546
634
|
}
|
|
547
635
|
this.connection = null;
|
|
548
636
|
this._rpc = null;
|
|
637
|
+
this._internalRpc = null;
|
|
549
638
|
}
|
|
550
639
|
this.modelsCache = null;
|
|
551
640
|
if (this.socket) {
|
|
@@ -638,7 +727,8 @@ class CopilotClient {
|
|
|
638
727
|
enableFileHooks: false,
|
|
639
728
|
enableHostGitOperations: false,
|
|
640
729
|
enableSessionStore: false,
|
|
641
|
-
enableSkills: false
|
|
730
|
+
enableSkills: false,
|
|
731
|
+
memory: { enabled: false }
|
|
642
732
|
};
|
|
643
733
|
}
|
|
644
734
|
return {};
|
|
@@ -788,7 +878,8 @@ class CopilotClient {
|
|
|
788
878
|
description: tool.description,
|
|
789
879
|
parameters: toJsonSchema(tool.parameters),
|
|
790
880
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
791
|
-
skipPermission: tool.skipPermission
|
|
881
|
+
skipPermission: tool.skipPermission,
|
|
882
|
+
defer: tool.defer
|
|
792
883
|
})),
|
|
793
884
|
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
794
885
|
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
@@ -838,6 +929,7 @@ class CopilotClient {
|
|
|
838
929
|
instructionDirectories: config.instructionDirectories,
|
|
839
930
|
disabledSkills: config.disabledSkills,
|
|
840
931
|
infiniteSessions: config.infiniteSessions,
|
|
932
|
+
memory: config.memory,
|
|
841
933
|
gitHubToken: config.gitHubToken,
|
|
842
934
|
remoteSession: config.remoteSession,
|
|
843
935
|
cloud: config.cloud
|
|
@@ -956,7 +1048,8 @@ class CopilotClient {
|
|
|
956
1048
|
description: tool.description,
|
|
957
1049
|
parameters: toJsonSchema(tool.parameters),
|
|
958
1050
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
959
|
-
skipPermission: tool.skipPermission
|
|
1051
|
+
skipPermission: tool.skipPermission,
|
|
1052
|
+
defer: tool.defer
|
|
960
1053
|
})),
|
|
961
1054
|
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
962
1055
|
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
@@ -1001,6 +1094,7 @@ class CopilotClient {
|
|
|
1001
1094
|
instructionDirectories: config.instructionDirectories,
|
|
1002
1095
|
disabledSkills: config.disabledSkills,
|
|
1003
1096
|
infiniteSessions: config.infiniteSessions,
|
|
1097
|
+
memory: config.memory,
|
|
1004
1098
|
disableResume: config.suppressResumeEvent,
|
|
1005
1099
|
continuePendingWork: config.continuePendingWork,
|
|
1006
1100
|
gitHubToken: config.gitHubToken,
|
|
@@ -1403,6 +1497,8 @@ class CopilotClient {
|
|
|
1403
1497
|
envWithoutNodeDebug.COPILOT_OTEL_ENABLED = "true";
|
|
1404
1498
|
if (t.otlpEndpoint !== void 0)
|
|
1405
1499
|
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
|
|
1500
|
+
if (t.otlpProtocol !== void 0)
|
|
1501
|
+
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
|
|
1406
1502
|
if (t.filePath !== void 0)
|
|
1407
1503
|
envWithoutNodeDebug.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
|
|
1408
1504
|
if (t.exporterType !== void 0)
|
|
@@ -233,7 +233,17 @@ function createServerRpc(connection) {
|
|
|
233
233
|
*
|
|
234
234
|
* @returns Skills discovered across global and project sources.
|
|
235
235
|
*/
|
|
236
|
-
discover: async (params) => connection.sendRequest("skills.discover", params)
|
|
236
|
+
discover: async (params) => connection.sendRequest("skills.discover", params),
|
|
237
|
+
/**
|
|
238
|
+
* Returns the canonical directories where a client may create skills that the runtime will recognize, including ones that do not exist yet. Project directories become active once created.
|
|
239
|
+
*
|
|
240
|
+
* @param params Optional project paths to enumerate.
|
|
241
|
+
*
|
|
242
|
+
* @returns Canonical locations where skills can be created so the runtime will recognize them.
|
|
243
|
+
*
|
|
244
|
+
* @experimental
|
|
245
|
+
*/
|
|
246
|
+
getDiscoveryPaths: async (params) => connection.sendRequest("skills.getDiscoveryPaths", params)
|
|
237
247
|
},
|
|
238
248
|
/** @experimental */
|
|
239
249
|
agents: {
|
|
@@ -244,7 +254,15 @@ function createServerRpc(connection) {
|
|
|
244
254
|
*
|
|
245
255
|
* @returns Agents discovered across user, project, plugin, and remote sources.
|
|
246
256
|
*/
|
|
247
|
-
discover: async (params) => connection.sendRequest("agents.discover", params)
|
|
257
|
+
discover: async (params) => connection.sendRequest("agents.discover", params),
|
|
258
|
+
/**
|
|
259
|
+
* Returns the canonical directories where a client may create custom agents that the runtime will recognize, including ones that do not exist yet. Project directories become active once created.
|
|
260
|
+
*
|
|
261
|
+
* @param params Optional project paths to include when enumerating agent discovery directories.
|
|
262
|
+
*
|
|
263
|
+
* @returns Canonical locations where custom agents can be created so the runtime will recognize them.
|
|
264
|
+
*/
|
|
265
|
+
getDiscoveryPaths: async (params) => connection.sendRequest("agents.getDiscoveryPaths", params)
|
|
248
266
|
},
|
|
249
267
|
/** @experimental */
|
|
250
268
|
instructions: {
|
|
@@ -255,7 +273,15 @@ function createServerRpc(connection) {
|
|
|
255
273
|
*
|
|
256
274
|
* @returns Instruction sources discovered across user, repository, and plugin sources.
|
|
257
275
|
*/
|
|
258
|
-
discover: async (params) => connection.sendRequest("instructions.discover", params)
|
|
276
|
+
discover: async (params) => connection.sendRequest("instructions.discover", params),
|
|
277
|
+
/**
|
|
278
|
+
* Returns the canonical files and directories where a client may create custom instructions that the runtime will recognize, including ones that do not exist yet. Repository targets become active once created.
|
|
279
|
+
*
|
|
280
|
+
* @param params Optional project paths to include when enumerating instruction discovery targets.
|
|
281
|
+
*
|
|
282
|
+
* @returns Canonical files and directories where custom instructions can be created so the runtime will recognize them.
|
|
283
|
+
*/
|
|
284
|
+
getDiscoveryPaths: async (params) => connection.sendRequest("instructions.getDiscoveryPaths", params)
|
|
259
285
|
},
|
|
260
286
|
user: {
|
|
261
287
|
settings: {
|
|
@@ -725,7 +751,13 @@ function createSessionRpc(connection, sessionId) {
|
|
|
725
751
|
*
|
|
726
752
|
* @returns Todo rows read from the session SQL database. Empty when no session database is available.
|
|
727
753
|
*/
|
|
728
|
-
readSqlTodos: async () => connection.sendRequest("session.plan.readSqlTodos", { sessionId })
|
|
754
|
+
readSqlTodos: async () => connection.sendRequest("session.plan.readSqlTodos", { sessionId }),
|
|
755
|
+
/**
|
|
756
|
+
* Reads todo rows AND dependency edges from the session SQL database for structured progress UI. Same defensive behavior as readSqlTodos — returns empty arrays when the database, tables, or columns aren't available. Clients should call this on session start and after every `session.todos_changed` event to refresh structured-UI rendering.
|
|
757
|
+
*
|
|
758
|
+
* @returns Todo rows + dependency edges read from the session SQL database.
|
|
759
|
+
*/
|
|
760
|
+
readSqlTodosWithDependencies: async () => connection.sendRequest("session.plan.readSqlTodosWithDependencies", { sessionId })
|
|
729
761
|
},
|
|
730
762
|
/** @experimental */
|
|
731
763
|
workspaces: {
|
|
@@ -1108,6 +1140,17 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1108
1140
|
reload: async (params) => connection.sendRequest("session.plugins.reload", { sessionId, ...params })
|
|
1109
1141
|
},
|
|
1110
1142
|
/** @experimental */
|
|
1143
|
+
provider: {
|
|
1144
|
+
/**
|
|
1145
|
+
* Returns the provider endpoint and credentials the session is currently configured to talk to, so the caller can make inference calls directly against the same backend the session uses.
|
|
1146
|
+
*
|
|
1147
|
+
* @param params Optional model identifier to scope the endpoint snapshot to.
|
|
1148
|
+
*
|
|
1149
|
+
* @returns A snapshot of the provider endpoint the session is currently configured to talk to.
|
|
1150
|
+
*/
|
|
1151
|
+
getEndpoint: async (params) => connection.sendRequest("session.provider.getEndpoint", { sessionId, ...params })
|
|
1152
|
+
},
|
|
1153
|
+
/** @experimental */
|
|
1111
1154
|
options: {
|
|
1112
1155
|
/**
|
|
1113
1156
|
* Patches the genuinely-mutable subset of session options.
|
|
@@ -1179,7 +1222,15 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1179
1222
|
*
|
|
1180
1223
|
* @returns Current lightweight tool metadata snapshot for the session.
|
|
1181
1224
|
*/
|
|
1182
|
-
getCurrentMetadata: async () => connection.sendRequest("session.tools.getCurrentMetadata", { sessionId })
|
|
1225
|
+
getCurrentMetadata: async () => connection.sendRequest("session.tools.getCurrentMetadata", { sessionId }),
|
|
1226
|
+
/**
|
|
1227
|
+
* Updates the current session's live subagent settings after user settings change. The persisted user settings remain the source of truth for future sessions.
|
|
1228
|
+
*
|
|
1229
|
+
* @param params Subagent settings to apply to the current session
|
|
1230
|
+
*
|
|
1231
|
+
* @returns Empty result after applying subagent settings
|
|
1232
|
+
*/
|
|
1233
|
+
updateSubagentSettings: async (params) => connection.sendRequest("session.tools.updateSubagentSettings", { sessionId, ...params })
|
|
1183
1234
|
},
|
|
1184
1235
|
/** @experimental */
|
|
1185
1236
|
commands: {
|
package/dist/cjs/session.js
CHANGED
|
@@ -56,6 +56,9 @@ class CopilotSession {
|
|
|
56
56
|
this._workspacePath = _workspacePath;
|
|
57
57
|
this.traceContextProvider = traceContextProvider;
|
|
58
58
|
}
|
|
59
|
+
sessionId;
|
|
60
|
+
connection;
|
|
61
|
+
_workspacePath;
|
|
59
62
|
eventHandlers = /* @__PURE__ */ new Set();
|
|
60
63
|
typedEventHandlers = /* @__PURE__ */ new Map();
|
|
61
64
|
toolHandlers = /* @__PURE__ */ new Map();
|
package/dist/client.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ export declare class CopilotClient {
|
|
|
72
72
|
* @throws Error if the client is not connected
|
|
73
73
|
*/
|
|
74
74
|
get rpc(): ReturnType<typeof createServerRpc>;
|
|
75
|
+
private logDebugTiming;
|
|
75
76
|
/**
|
|
76
77
|
* Creates a new CopilotClient instance.
|
|
77
78
|
*
|
|
@@ -132,8 +133,9 @@ export declare class CopilotClient {
|
|
|
132
133
|
*
|
|
133
134
|
* This method performs graceful cleanup:
|
|
134
135
|
* 1. Closes all active sessions (releases in-memory resources)
|
|
135
|
-
* 2.
|
|
136
|
-
* 3.
|
|
136
|
+
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
137
|
+
* 3. Closes the JSON-RPC connection
|
|
138
|
+
* 4. Terminates the CLI server process (if spawned by this client)
|
|
137
139
|
*
|
|
138
140
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
139
141
|
* To permanently remove session data before stopping, call
|
package/dist/client.js
CHANGED
|
@@ -24,9 +24,54 @@ import { getTraceContext } from "./telemetry.js";
|
|
|
24
24
|
import { ToolSet } from "./toolSet.js";
|
|
25
25
|
import { defaultJoinSessionPermissionHandler } from "./types.js";
|
|
26
26
|
const MIN_PROTOCOL_VERSION = 3;
|
|
27
|
+
const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
|
|
27
28
|
function isZodSchema(value) {
|
|
28
29
|
return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
|
|
29
30
|
}
|
|
31
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
32
|
+
let timeout;
|
|
33
|
+
try {
|
|
34
|
+
return await Promise.race([
|
|
35
|
+
promise,
|
|
36
|
+
new Promise((_, reject) => {
|
|
37
|
+
timeout = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
38
|
+
})
|
|
39
|
+
]);
|
|
40
|
+
} finally {
|
|
41
|
+
if (timeout !== void 0) {
|
|
42
|
+
clearTimeout(timeout);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function waitForChildExit(child, timeoutMs) {
|
|
47
|
+
if (child.exitCode != null || child.signalCode != null) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
let timeout;
|
|
52
|
+
let settled = false;
|
|
53
|
+
const onExit = () => {
|
|
54
|
+
if (settled) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
settled = true;
|
|
58
|
+
clearTimeout(timeout);
|
|
59
|
+
resolve(true);
|
|
60
|
+
};
|
|
61
|
+
timeout = setTimeout(() => {
|
|
62
|
+
if (settled) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
settled = true;
|
|
66
|
+
child.off("exit", onExit);
|
|
67
|
+
resolve(false);
|
|
68
|
+
}, timeoutMs);
|
|
69
|
+
child.once("exit", onExit);
|
|
70
|
+
if (child.exitCode != null || child.signalCode != null) {
|
|
71
|
+
onExit();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
30
75
|
function toJsonSchema(parameters) {
|
|
31
76
|
if (!parameters) return void 0;
|
|
32
77
|
if (isZodSchema(parameters)) {
|
|
@@ -190,6 +235,13 @@ class CopilotClient {
|
|
|
190
235
|
}
|
|
191
236
|
return this._internalRpc;
|
|
192
237
|
}
|
|
238
|
+
logDebugTiming(message, startMs) {
|
|
239
|
+
const level = this.options.logLevel?.toLowerCase();
|
|
240
|
+
if (level === "debug" || level === "all") {
|
|
241
|
+
process.stderr.write(`[copilot-sdk] ${message}. Elapsed=${Date.now() - startMs}ms
|
|
242
|
+
`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
193
245
|
/**
|
|
194
246
|
* Creates a new CopilotClient instance.
|
|
195
247
|
*
|
|
@@ -376,8 +428,9 @@ class CopilotClient {
|
|
|
376
428
|
*
|
|
377
429
|
* This method performs graceful cleanup:
|
|
378
430
|
* 1. Closes all active sessions (releases in-memory resources)
|
|
379
|
-
* 2.
|
|
380
|
-
* 3.
|
|
431
|
+
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
432
|
+
* 3. Closes the JSON-RPC connection
|
|
433
|
+
* 4. Terminates the CLI server process (if spawned by this client)
|
|
381
434
|
*
|
|
382
435
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
383
436
|
* To permanently remove session data before stopping, call
|
|
@@ -421,6 +474,34 @@ class CopilotClient {
|
|
|
421
474
|
}
|
|
422
475
|
}
|
|
423
476
|
this.sessions.clear();
|
|
477
|
+
let runtimeShutdownCompleted = false;
|
|
478
|
+
if (this.connection && this.cliProcess && !this.isExternalServer) {
|
|
479
|
+
const runtimeShutdownStart = Date.now();
|
|
480
|
+
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
481
|
+
void shutdownPromise.catch(() => void 0);
|
|
482
|
+
try {
|
|
483
|
+
await withTimeout(
|
|
484
|
+
shutdownPromise,
|
|
485
|
+
RUNTIME_SHUTDOWN_TIMEOUT_MS,
|
|
486
|
+
`runtime.shutdown timed out after ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms`
|
|
487
|
+
);
|
|
488
|
+
runtimeShutdownCompleted = true;
|
|
489
|
+
this.logDebugTiming(
|
|
490
|
+
"CopilotClient.stop runtime shutdown complete",
|
|
491
|
+
runtimeShutdownStart
|
|
492
|
+
);
|
|
493
|
+
} catch (error) {
|
|
494
|
+
this.logDebugTiming(
|
|
495
|
+
"CopilotClient.stop runtime shutdown failed",
|
|
496
|
+
runtimeShutdownStart
|
|
497
|
+
);
|
|
498
|
+
errors.push(
|
|
499
|
+
new Error(
|
|
500
|
+
`Failed to gracefully shut down runtime: ${error instanceof Error ? error.message : String(error)}`
|
|
501
|
+
)
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
424
505
|
if (this.connection) {
|
|
425
506
|
try {
|
|
426
507
|
this.connection.dispose();
|
|
@@ -433,6 +514,7 @@ class CopilotClient {
|
|
|
433
514
|
}
|
|
434
515
|
this.connection = null;
|
|
435
516
|
this._rpc = null;
|
|
517
|
+
this._internalRpc = null;
|
|
436
518
|
}
|
|
437
519
|
this.modelsCache = null;
|
|
438
520
|
if (this.socket) {
|
|
@@ -457,12 +539,18 @@ class CopilotClient {
|
|
|
457
539
|
const child = this.cliProcess;
|
|
458
540
|
this.cliProcess = null;
|
|
459
541
|
try {
|
|
460
|
-
if (child.exitCode
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
542
|
+
if (child.exitCode == null && child.signalCode == null) {
|
|
543
|
+
const exitedGracefully = runtimeShutdownCompleted ? await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS) : false;
|
|
544
|
+
if (!exitedGracefully) {
|
|
545
|
+
child.kill();
|
|
546
|
+
if (!await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS)) {
|
|
547
|
+
errors.push(
|
|
548
|
+
new Error(
|
|
549
|
+
`Timed out waiting for CLI process to exit after kill: ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms`
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
466
554
|
}
|
|
467
555
|
} catch (error) {
|
|
468
556
|
errors.push(
|
|
@@ -532,6 +620,7 @@ class CopilotClient {
|
|
|
532
620
|
}
|
|
533
621
|
this.connection = null;
|
|
534
622
|
this._rpc = null;
|
|
623
|
+
this._internalRpc = null;
|
|
535
624
|
}
|
|
536
625
|
this.modelsCache = null;
|
|
537
626
|
if (this.socket) {
|
|
@@ -624,7 +713,8 @@ class CopilotClient {
|
|
|
624
713
|
enableFileHooks: false,
|
|
625
714
|
enableHostGitOperations: false,
|
|
626
715
|
enableSessionStore: false,
|
|
627
|
-
enableSkills: false
|
|
716
|
+
enableSkills: false,
|
|
717
|
+
memory: { enabled: false }
|
|
628
718
|
};
|
|
629
719
|
}
|
|
630
720
|
return {};
|
|
@@ -774,7 +864,8 @@ class CopilotClient {
|
|
|
774
864
|
description: tool.description,
|
|
775
865
|
parameters: toJsonSchema(tool.parameters),
|
|
776
866
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
777
|
-
skipPermission: tool.skipPermission
|
|
867
|
+
skipPermission: tool.skipPermission,
|
|
868
|
+
defer: tool.defer
|
|
778
869
|
})),
|
|
779
870
|
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
780
871
|
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
@@ -824,6 +915,7 @@ class CopilotClient {
|
|
|
824
915
|
instructionDirectories: config.instructionDirectories,
|
|
825
916
|
disabledSkills: config.disabledSkills,
|
|
826
917
|
infiniteSessions: config.infiniteSessions,
|
|
918
|
+
memory: config.memory,
|
|
827
919
|
gitHubToken: config.gitHubToken,
|
|
828
920
|
remoteSession: config.remoteSession,
|
|
829
921
|
cloud: config.cloud
|
|
@@ -942,7 +1034,8 @@ class CopilotClient {
|
|
|
942
1034
|
description: tool.description,
|
|
943
1035
|
parameters: toJsonSchema(tool.parameters),
|
|
944
1036
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
945
|
-
skipPermission: tool.skipPermission
|
|
1037
|
+
skipPermission: tool.skipPermission,
|
|
1038
|
+
defer: tool.defer
|
|
946
1039
|
})),
|
|
947
1040
|
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
948
1041
|
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
@@ -987,6 +1080,7 @@ class CopilotClient {
|
|
|
987
1080
|
instructionDirectories: config.instructionDirectories,
|
|
988
1081
|
disabledSkills: config.disabledSkills,
|
|
989
1082
|
infiniteSessions: config.infiniteSessions,
|
|
1083
|
+
memory: config.memory,
|
|
990
1084
|
disableResume: config.suppressResumeEvent,
|
|
991
1085
|
continuePendingWork: config.continuePendingWork,
|
|
992
1086
|
gitHubToken: config.gitHubToken,
|
|
@@ -1389,6 +1483,8 @@ class CopilotClient {
|
|
|
1389
1483
|
envWithoutNodeDebug.COPILOT_OTEL_ENABLED = "true";
|
|
1390
1484
|
if (t.otlpEndpoint !== void 0)
|
|
1391
1485
|
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
|
|
1486
|
+
if (t.otlpProtocol !== void 0)
|
|
1487
|
+
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
|
|
1392
1488
|
if (t.filePath !== void 0)
|
|
1393
1489
|
envWithoutNodeDebug.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
|
|
1394
1490
|
if (t.exporterType !== void 0)
|