@github/copilot-sdk 0.1.30 → 0.1.31
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 +14 -3
- package/dist/client.d.ts +16 -12
- package/dist/client.js +41 -104
- package/dist/extension.d.ts +2 -0
- package/dist/extension.js +5 -0
- package/dist/generated/rpc.d.ts +57 -3
- package/dist/generated/rpc.js +6 -0
- package/dist/generated/session-events.d.ts +1942 -13
- package/dist/sdkProtocolVersion.d.ts +1 -1
- package/dist/sdkProtocolVersion.js +1 -1
- package/dist/session.d.ts +48 -21
- package/dist/session.js +115 -32
- package/dist/types.d.ts +8 -4
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -52,10 +52,17 @@ await session.send({ prompt: "What is 2+2?" });
|
|
|
52
52
|
await done;
|
|
53
53
|
|
|
54
54
|
// Clean up
|
|
55
|
-
await session.
|
|
55
|
+
await session.disconnect();
|
|
56
56
|
await client.stop();
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
Sessions also support `Symbol.asyncDispose` for use with [`await using`](https://github.com/tc39/proposal-explicit-resource-management) (TypeScript 5.2+/Node.js 18.0+):
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
await using session = await client.createSession({ model: "gpt-5" });
|
|
63
|
+
// session is automatically disconnected when leaving scope
|
|
64
|
+
```
|
|
65
|
+
|
|
59
66
|
## API Reference
|
|
60
67
|
|
|
61
68
|
### CopilotClient
|
|
@@ -265,9 +272,13 @@ Abort the currently processing message in this session.
|
|
|
265
272
|
|
|
266
273
|
Get all events/messages from this session.
|
|
267
274
|
|
|
268
|
-
##### `
|
|
275
|
+
##### `disconnect(): Promise<void>`
|
|
276
|
+
|
|
277
|
+
Disconnect the session and free resources. Session data on disk is preserved for later resumption.
|
|
278
|
+
|
|
279
|
+
##### `destroy(): Promise<void>` *(deprecated)*
|
|
269
280
|
|
|
270
|
-
|
|
281
|
+
Deprecated — use `disconnect()` instead.
|
|
271
282
|
|
|
272
283
|
---
|
|
273
284
|
|
package/dist/client.d.ts
CHANGED
|
@@ -74,10 +74,14 @@ export declare class CopilotClient {
|
|
|
74
74
|
* Stops the CLI server and closes all active sessions.
|
|
75
75
|
*
|
|
76
76
|
* This method performs graceful cleanup:
|
|
77
|
-
* 1.
|
|
77
|
+
* 1. Closes all active sessions (releases in-memory resources)
|
|
78
78
|
* 2. Closes the JSON-RPC connection
|
|
79
79
|
* 3. Terminates the CLI server process (if spawned by this client)
|
|
80
80
|
*
|
|
81
|
+
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
82
|
+
* To permanently remove session data before stopping, call
|
|
83
|
+
* {@link deleteSession} for each session first.
|
|
84
|
+
*
|
|
81
85
|
* @returns A promise that resolves with an array of errors encountered during cleanup.
|
|
82
86
|
* An empty array indicates all cleanup succeeded.
|
|
83
87
|
*
|
|
@@ -242,10 +246,12 @@ export declare class CopilotClient {
|
|
|
242
246
|
*/
|
|
243
247
|
getLastSessionId(): Promise<string | undefined>;
|
|
244
248
|
/**
|
|
245
|
-
*
|
|
249
|
+
* Permanently deletes a session and all its data from disk, including
|
|
250
|
+
* conversation history, planning state, and artifacts.
|
|
246
251
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
252
|
+
* Unlike {@link CopilotSession.disconnect}, which only releases in-memory
|
|
253
|
+
* resources and preserves session data for later resumption, this method
|
|
254
|
+
* is irreversible. The session cannot be resumed after deletion.
|
|
249
255
|
*
|
|
250
256
|
* @param sessionId - The ID of the session to delete
|
|
251
257
|
* @returns A promise that resolves when the session is deleted
|
|
@@ -361,9 +367,13 @@ export declare class CopilotClient {
|
|
|
361
367
|
*/
|
|
362
368
|
private connectToServer;
|
|
363
369
|
/**
|
|
364
|
-
* Connect via stdio pipes
|
|
370
|
+
* Connect to child via stdio pipes
|
|
371
|
+
*/
|
|
372
|
+
private connectToChildProcessViaStdio;
|
|
373
|
+
/**
|
|
374
|
+
* Connect to parent via stdio pipes
|
|
365
375
|
*/
|
|
366
|
-
private
|
|
376
|
+
private connectToParentProcessViaStdio;
|
|
367
377
|
/**
|
|
368
378
|
* Connect to the CLI server via TCP socket
|
|
369
379
|
*/
|
|
@@ -371,14 +381,8 @@ export declare class CopilotClient {
|
|
|
371
381
|
private attachConnectionHandlers;
|
|
372
382
|
private handleSessionEventNotification;
|
|
373
383
|
private handleSessionLifecycleNotification;
|
|
374
|
-
private handleToolCallRequest;
|
|
375
|
-
private executeToolCall;
|
|
376
|
-
private handlePermissionRequest;
|
|
377
384
|
private handleUserInputRequest;
|
|
378
385
|
private handleHooksInvoke;
|
|
379
|
-
private normalizeToolResult;
|
|
380
|
-
private isToolResultObject;
|
|
381
|
-
private buildUnsupportedToolResult;
|
|
382
386
|
/**
|
|
383
387
|
* Attempt to reconnect to the server
|
|
384
388
|
*/
|
package/dist/client.js
CHANGED
|
@@ -90,6 +90,11 @@ class CopilotClient {
|
|
|
90
90
|
if (options.cliUrl && (options.useStdio === true || options.cliPath)) {
|
|
91
91
|
throw new Error("cliUrl is mutually exclusive with useStdio and cliPath");
|
|
92
92
|
}
|
|
93
|
+
if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
"isChildProcess must be used in conjunction with useStdio and not with cliUrl"
|
|
96
|
+
);
|
|
97
|
+
}
|
|
93
98
|
if (options.cliUrl && (options.githubToken || options.useLoggedInUser !== void 0)) {
|
|
94
99
|
throw new Error(
|
|
95
100
|
"githubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)"
|
|
@@ -101,6 +106,9 @@ class CopilotClient {
|
|
|
101
106
|
this.actualPort = port;
|
|
102
107
|
this.isExternalServer = true;
|
|
103
108
|
}
|
|
109
|
+
if (options.isChildProcess) {
|
|
110
|
+
this.isExternalServer = true;
|
|
111
|
+
}
|
|
104
112
|
this.options = {
|
|
105
113
|
cliPath: options.cliPath || getBundledCliPath(),
|
|
106
114
|
cliArgs: options.cliArgs ?? [],
|
|
@@ -108,6 +116,7 @@ class CopilotClient {
|
|
|
108
116
|
port: options.port || 0,
|
|
109
117
|
useStdio: options.cliUrl ? false : options.useStdio ?? true,
|
|
110
118
|
// Default to stdio unless cliUrl is provided
|
|
119
|
+
isChildProcess: options.isChildProcess ?? false,
|
|
111
120
|
cliUrl: options.cliUrl,
|
|
112
121
|
logLevel: options.logLevel || "debug",
|
|
113
122
|
autoStart: options.autoStart ?? true,
|
|
@@ -179,10 +188,14 @@ class CopilotClient {
|
|
|
179
188
|
* Stops the CLI server and closes all active sessions.
|
|
180
189
|
*
|
|
181
190
|
* This method performs graceful cleanup:
|
|
182
|
-
* 1.
|
|
191
|
+
* 1. Closes all active sessions (releases in-memory resources)
|
|
183
192
|
* 2. Closes the JSON-RPC connection
|
|
184
193
|
* 3. Terminates the CLI server process (if spawned by this client)
|
|
185
194
|
*
|
|
195
|
+
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
196
|
+
* To permanently remove session data before stopping, call
|
|
197
|
+
* {@link deleteSession} for each session first.
|
|
198
|
+
*
|
|
186
199
|
* @returns A promise that resolves with an array of errors encountered during cleanup.
|
|
187
200
|
* An empty array indicates all cleanup succeeded.
|
|
188
201
|
*
|
|
@@ -201,7 +214,7 @@ class CopilotClient {
|
|
|
201
214
|
let lastError = null;
|
|
202
215
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
203
216
|
try {
|
|
204
|
-
await session.
|
|
217
|
+
await session.disconnect();
|
|
205
218
|
lastError = null;
|
|
206
219
|
break;
|
|
207
220
|
} catch (error) {
|
|
@@ -215,7 +228,7 @@ class CopilotClient {
|
|
|
215
228
|
if (lastError) {
|
|
216
229
|
errors.push(
|
|
217
230
|
new Error(
|
|
218
|
-
`Failed to
|
|
231
|
+
`Failed to disconnect session ${sessionId} after 3 attempts: ${lastError.message}`
|
|
219
232
|
)
|
|
220
233
|
);
|
|
221
234
|
}
|
|
@@ -616,10 +629,12 @@ class CopilotClient {
|
|
|
616
629
|
return response.sessionId;
|
|
617
630
|
}
|
|
618
631
|
/**
|
|
619
|
-
*
|
|
632
|
+
* Permanently deletes a session and all its data from disk, including
|
|
633
|
+
* conversation history, planning state, and artifacts.
|
|
620
634
|
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
635
|
+
* Unlike {@link CopilotSession.disconnect}, which only releases in-memory
|
|
636
|
+
* resources and preserves session data for later resumption, this method
|
|
637
|
+
* is irreversible. The session cannot be resumed after deletion.
|
|
623
638
|
*
|
|
624
639
|
* @param sessionId - The ID of the session to delete
|
|
625
640
|
* @returns A promise that resolves when the session is deleted
|
|
@@ -886,16 +901,18 @@ stderr: ${stderrOutput}`
|
|
|
886
901
|
* Connect to the CLI server (via socket or stdio)
|
|
887
902
|
*/
|
|
888
903
|
async connectToServer() {
|
|
889
|
-
if (this.options.
|
|
890
|
-
return this.
|
|
904
|
+
if (this.options.isChildProcess) {
|
|
905
|
+
return this.connectToParentProcessViaStdio();
|
|
906
|
+
} else if (this.options.useStdio) {
|
|
907
|
+
return this.connectToChildProcessViaStdio();
|
|
891
908
|
} else {
|
|
892
909
|
return this.connectViaTcp();
|
|
893
910
|
}
|
|
894
911
|
}
|
|
895
912
|
/**
|
|
896
|
-
* Connect via stdio pipes
|
|
913
|
+
* Connect to child via stdio pipes
|
|
897
914
|
*/
|
|
898
|
-
async
|
|
915
|
+
async connectToChildProcessViaStdio() {
|
|
899
916
|
if (!this.cliProcess) {
|
|
900
917
|
throw new Error("CLI process not started");
|
|
901
918
|
}
|
|
@@ -911,6 +928,20 @@ stderr: ${stderrOutput}`
|
|
|
911
928
|
this.attachConnectionHandlers();
|
|
912
929
|
this.connection.listen();
|
|
913
930
|
}
|
|
931
|
+
/**
|
|
932
|
+
* Connect to parent via stdio pipes
|
|
933
|
+
*/
|
|
934
|
+
async connectToParentProcessViaStdio() {
|
|
935
|
+
if (this.cliProcess) {
|
|
936
|
+
throw new Error("CLI child process was unexpectedly started in parent process mode");
|
|
937
|
+
}
|
|
938
|
+
this.connection = createMessageConnection(
|
|
939
|
+
new StreamMessageReader(process.stdin),
|
|
940
|
+
new StreamMessageWriter(process.stdout)
|
|
941
|
+
);
|
|
942
|
+
this.attachConnectionHandlers();
|
|
943
|
+
this.connection.listen();
|
|
944
|
+
}
|
|
914
945
|
/**
|
|
915
946
|
* Connect to the CLI server via TCP socket
|
|
916
947
|
*/
|
|
@@ -944,14 +975,6 @@ stderr: ${stderrOutput}`
|
|
|
944
975
|
this.connection.onNotification("session.lifecycle", (notification) => {
|
|
945
976
|
this.handleSessionLifecycleNotification(notification);
|
|
946
977
|
});
|
|
947
|
-
this.connection.onRequest(
|
|
948
|
-
"tool.call",
|
|
949
|
-
async (params) => await this.handleToolCallRequest(params)
|
|
950
|
-
);
|
|
951
|
-
this.connection.onRequest(
|
|
952
|
-
"permission.request",
|
|
953
|
-
async (params) => await this.handlePermissionRequest(params)
|
|
954
|
-
);
|
|
955
978
|
this.connection.onRequest(
|
|
956
979
|
"userInput.request",
|
|
957
980
|
async (params) => await this.handleUserInputRequest(params)
|
|
@@ -998,62 +1021,6 @@ stderr: ${stderrOutput}`
|
|
|
998
1021
|
}
|
|
999
1022
|
}
|
|
1000
1023
|
}
|
|
1001
|
-
async handleToolCallRequest(params) {
|
|
1002
|
-
if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") {
|
|
1003
|
-
throw new Error("Invalid tool call payload");
|
|
1004
|
-
}
|
|
1005
|
-
const session = this.sessions.get(params.sessionId);
|
|
1006
|
-
if (!session) {
|
|
1007
|
-
throw new Error(`Unknown session ${params.sessionId}`);
|
|
1008
|
-
}
|
|
1009
|
-
const handler = session.getToolHandler(params.toolName);
|
|
1010
|
-
if (!handler) {
|
|
1011
|
-
return { result: this.buildUnsupportedToolResult(params.toolName) };
|
|
1012
|
-
}
|
|
1013
|
-
return await this.executeToolCall(handler, params);
|
|
1014
|
-
}
|
|
1015
|
-
async executeToolCall(handler, request) {
|
|
1016
|
-
try {
|
|
1017
|
-
const invocation = {
|
|
1018
|
-
sessionId: request.sessionId,
|
|
1019
|
-
toolCallId: request.toolCallId,
|
|
1020
|
-
toolName: request.toolName,
|
|
1021
|
-
arguments: request.arguments
|
|
1022
|
-
};
|
|
1023
|
-
const result = await handler(request.arguments, invocation);
|
|
1024
|
-
return { result: this.normalizeToolResult(result) };
|
|
1025
|
-
} catch (error) {
|
|
1026
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1027
|
-
return {
|
|
1028
|
-
result: {
|
|
1029
|
-
// Don't expose detailed error information to the LLM for security reasons
|
|
1030
|
-
textResultForLlm: "Invoking this tool produced an error. Detailed information is not available.",
|
|
1031
|
-
resultType: "failure",
|
|
1032
|
-
error: message,
|
|
1033
|
-
toolTelemetry: {}
|
|
1034
|
-
}
|
|
1035
|
-
};
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
async handlePermissionRequest(params) {
|
|
1039
|
-
if (!params || typeof params.sessionId !== "string" || !params.permissionRequest) {
|
|
1040
|
-
throw new Error("Invalid permission request payload");
|
|
1041
|
-
}
|
|
1042
|
-
const session = this.sessions.get(params.sessionId);
|
|
1043
|
-
if (!session) {
|
|
1044
|
-
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1045
|
-
}
|
|
1046
|
-
try {
|
|
1047
|
-
const result = await session._handlePermissionRequest(params.permissionRequest);
|
|
1048
|
-
return { result };
|
|
1049
|
-
} catch (_error) {
|
|
1050
|
-
return {
|
|
1051
|
-
result: {
|
|
1052
|
-
kind: "denied-no-approval-rule-and-could-not-request-from-user"
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
1024
|
async handleUserInputRequest(params) {
|
|
1058
1025
|
if (!params || typeof params.sessionId !== "string" || typeof params.question !== "string") {
|
|
1059
1026
|
throw new Error("Invalid user input request payload");
|
|
@@ -1080,36 +1047,6 @@ stderr: ${stderrOutput}`
|
|
|
1080
1047
|
const output = await session._handleHooksInvoke(params.hookType, params.input);
|
|
1081
1048
|
return { output };
|
|
1082
1049
|
}
|
|
1083
|
-
normalizeToolResult(result) {
|
|
1084
|
-
if (result === void 0 || result === null) {
|
|
1085
|
-
return {
|
|
1086
|
-
textResultForLlm: "Tool returned no result",
|
|
1087
|
-
resultType: "failure",
|
|
1088
|
-
error: "tool returned no result",
|
|
1089
|
-
toolTelemetry: {}
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
if (this.isToolResultObject(result)) {
|
|
1093
|
-
return result;
|
|
1094
|
-
}
|
|
1095
|
-
const textResult = typeof result === "string" ? result : JSON.stringify(result);
|
|
1096
|
-
return {
|
|
1097
|
-
textResultForLlm: textResult,
|
|
1098
|
-
resultType: "success",
|
|
1099
|
-
toolTelemetry: {}
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
isToolResultObject(value) {
|
|
1103
|
-
return typeof value === "object" && value !== null && "textResultForLlm" in value && typeof value.textResultForLlm === "string" && "resultType" in value;
|
|
1104
|
-
}
|
|
1105
|
-
buildUnsupportedToolResult(toolName) {
|
|
1106
|
-
return {
|
|
1107
|
-
textResultForLlm: `Tool '${toolName}' is not supported by this client instance.`,
|
|
1108
|
-
resultType: "failure",
|
|
1109
|
-
error: `tool '${toolName}' not supported`,
|
|
1110
|
-
toolTelemetry: {}
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
1050
|
/**
|
|
1114
1051
|
* Attempt to reconnect to the server
|
|
1115
1052
|
*/
|
package/dist/generated/rpc.d.ts
CHANGED
|
@@ -193,13 +193,17 @@ export interface SessionModeSetParams {
|
|
|
193
193
|
}
|
|
194
194
|
export interface SessionPlanReadResult {
|
|
195
195
|
/**
|
|
196
|
-
* Whether plan
|
|
196
|
+
* Whether the plan file exists in the workspace
|
|
197
197
|
*/
|
|
198
198
|
exists: boolean;
|
|
199
199
|
/**
|
|
200
|
-
* The content of plan
|
|
200
|
+
* The content of the plan file, or null if it does not exist
|
|
201
201
|
*/
|
|
202
202
|
content: string | null;
|
|
203
|
+
/**
|
|
204
|
+
* Absolute file path of the plan file, or null if workspace is not enabled
|
|
205
|
+
*/
|
|
206
|
+
path: string | null;
|
|
203
207
|
}
|
|
204
208
|
export interface SessionPlanReadParams {
|
|
205
209
|
/**
|
|
@@ -215,7 +219,7 @@ export interface SessionPlanUpdateParams {
|
|
|
215
219
|
*/
|
|
216
220
|
sessionId: string;
|
|
217
221
|
/**
|
|
218
|
-
* The new content for plan
|
|
222
|
+
* The new content for the plan file
|
|
219
223
|
*/
|
|
220
224
|
content: string;
|
|
221
225
|
}
|
|
@@ -394,6 +398,50 @@ export interface SessionCompactionCompactParams {
|
|
|
394
398
|
*/
|
|
395
399
|
sessionId: string;
|
|
396
400
|
}
|
|
401
|
+
export interface SessionToolsHandlePendingToolCallResult {
|
|
402
|
+
success: boolean;
|
|
403
|
+
}
|
|
404
|
+
export interface SessionToolsHandlePendingToolCallParams {
|
|
405
|
+
/**
|
|
406
|
+
* Target session identifier
|
|
407
|
+
*/
|
|
408
|
+
sessionId: string;
|
|
409
|
+
requestId: string;
|
|
410
|
+
result?: string | {
|
|
411
|
+
textResultForLlm: string;
|
|
412
|
+
resultType?: string;
|
|
413
|
+
error?: string;
|
|
414
|
+
toolTelemetry?: {
|
|
415
|
+
[k: string]: unknown;
|
|
416
|
+
};
|
|
417
|
+
};
|
|
418
|
+
error?: string;
|
|
419
|
+
}
|
|
420
|
+
export interface SessionPermissionsHandlePendingPermissionRequestResult {
|
|
421
|
+
success: boolean;
|
|
422
|
+
}
|
|
423
|
+
export interface SessionPermissionsHandlePendingPermissionRequestParams {
|
|
424
|
+
/**
|
|
425
|
+
* Target session identifier
|
|
426
|
+
*/
|
|
427
|
+
sessionId: string;
|
|
428
|
+
requestId: string;
|
|
429
|
+
result: {
|
|
430
|
+
kind: "approved";
|
|
431
|
+
} | {
|
|
432
|
+
kind: "denied-by-rules";
|
|
433
|
+
rules: unknown[];
|
|
434
|
+
} | {
|
|
435
|
+
kind: "denied-no-approval-rule-and-could-not-request-from-user";
|
|
436
|
+
} | {
|
|
437
|
+
kind: "denied-interactively-by-user";
|
|
438
|
+
feedback?: string;
|
|
439
|
+
} | {
|
|
440
|
+
kind: "denied-by-content-exclusion-policy";
|
|
441
|
+
path: string;
|
|
442
|
+
message: string;
|
|
443
|
+
};
|
|
444
|
+
}
|
|
397
445
|
/** Create typed server-scoped RPC methods (no session required). */
|
|
398
446
|
export declare function createServerRpc(connection: MessageConnection): {
|
|
399
447
|
ping: (params: PingParams) => Promise<PingResult>;
|
|
@@ -439,4 +487,10 @@ export declare function createSessionRpc(connection: MessageConnection, sessionI
|
|
|
439
487
|
compaction: {
|
|
440
488
|
compact: () => Promise<SessionCompactionCompactResult>;
|
|
441
489
|
};
|
|
490
|
+
tools: {
|
|
491
|
+
handlePendingToolCall: (params: Omit<SessionToolsHandlePendingToolCallParams, "sessionId">) => Promise<SessionToolsHandlePendingToolCallResult>;
|
|
492
|
+
};
|
|
493
|
+
permissions: {
|
|
494
|
+
handlePendingPermissionRequest: (params: Omit<SessionPermissionsHandlePendingPermissionRequestParams, "sessionId">) => Promise<SessionPermissionsHandlePendingPermissionRequestResult>;
|
|
495
|
+
};
|
|
442
496
|
};
|
package/dist/generated/rpc.js
CHANGED
|
@@ -43,6 +43,12 @@ function createSessionRpc(connection, sessionId) {
|
|
|
43
43
|
},
|
|
44
44
|
compaction: {
|
|
45
45
|
compact: async () => connection.sendRequest("session.compaction.compact", { sessionId })
|
|
46
|
+
},
|
|
47
|
+
tools: {
|
|
48
|
+
handlePendingToolCall: async (params) => connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params })
|
|
49
|
+
},
|
|
50
|
+
permissions: {
|
|
51
|
+
handlePendingPermissionRequest: async (params) => connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params })
|
|
46
52
|
}
|
|
47
53
|
};
|
|
48
54
|
}
|