@github/copilot-sdk 1.0.29-preview.1 → 1.0.29-preview.2
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 +348 -2
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +22 -10
- package/dist/cjs/copilotRequestHandler.js +11 -4
- package/dist/cjs/generated/rpc.js +62 -1
- package/dist/cjs/session.js +47 -0
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.js +22 -10
- package/dist/copilotRequestHandler.js +11 -4
- package/dist/generated/rpc.d.ts +432 -2
- package/dist/generated/rpc.js +62 -1
- package/dist/generated/session-events.d.ts +23 -1
- package/dist/index.d.ts +1 -1
- package/dist/session.d.ts +9 -2
- package/dist/session.js +47 -0
- package/dist/types.d.ts +14 -3
- package/docs/examples.md +7 -7
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -218,6 +218,7 @@ npm start
|
|
|
218
218
|
|
|
219
219
|
## Quick Start
|
|
220
220
|
|
|
221
|
+
<!-- docs-validate: strict -->
|
|
221
222
|
```typescript
|
|
222
223
|
import { CopilotClient, approveAll } from "@github/copilot-sdk";
|
|
223
224
|
|
|
@@ -252,7 +253,10 @@ await client.stop();
|
|
|
252
253
|
|
|
253
254
|
Sessions also support `Symbol.asyncDispose` for use with [`await using`](https://github.com/tc39/proposal-explicit-resource-management) (TypeScript 5.2+ / Node.js 20+):
|
|
254
255
|
|
|
256
|
+
<!-- docs-validate: strict -->
|
|
255
257
|
```typescript
|
|
258
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
259
|
+
|
|
256
260
|
await using session = await client.createSession({
|
|
257
261
|
model: "gpt-5",
|
|
258
262
|
onPermissionRequest: approveAll,
|
|
@@ -897,7 +901,10 @@ Note: `assistant.message` and `assistant.reasoning` (final events) are always se
|
|
|
897
901
|
|
|
898
902
|
### Manual Server Control
|
|
899
903
|
|
|
904
|
+
<!-- docs-validate: strict -->
|
|
900
905
|
```typescript
|
|
906
|
+
import { CopilotClient } from "@github/copilot-sdk";
|
|
907
|
+
|
|
901
908
|
const client = new CopilotClient({});
|
|
902
909
|
|
|
903
910
|
// Start manually
|
|
@@ -913,6 +920,31 @@ await client.stop();
|
|
|
913
920
|
|
|
914
921
|
You can let the CLI call back into your process when the model needs capabilities you own. Use `defineTool` with Zod schemas for type-safe tool definitions:
|
|
915
922
|
|
|
923
|
+
<!-- docs-validate: strict -->
|
|
924
|
+
<!-- docs-validate: hidden -->
|
|
925
|
+
```ts
|
|
926
|
+
import { z } from "zod";
|
|
927
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
928
|
+
|
|
929
|
+
declare function fetchIssue(id: string): Promise<string>;
|
|
930
|
+
|
|
931
|
+
const session = await client.createSession({
|
|
932
|
+
model: "gpt-5",
|
|
933
|
+
tools: [
|
|
934
|
+
defineTool("lookup_issue", {
|
|
935
|
+
description: "Fetch issue details from our tracker",
|
|
936
|
+
parameters: z.object({
|
|
937
|
+
id: z.string().describe("Issue identifier"),
|
|
938
|
+
}),
|
|
939
|
+
handler: async ({ id }) => {
|
|
940
|
+
const issue = await fetchIssue(id);
|
|
941
|
+
return issue;
|
|
942
|
+
},
|
|
943
|
+
}),
|
|
944
|
+
],
|
|
945
|
+
});
|
|
946
|
+
```
|
|
947
|
+
<!-- /docs-validate: hidden -->
|
|
916
948
|
```ts
|
|
917
949
|
import { z } from "zod";
|
|
918
950
|
import { CopilotClient, defineTool } from "@github/copilot-sdk";
|
|
@@ -940,6 +972,22 @@ When Copilot invokes `lookup_issue`, the client automatically runs your handler
|
|
|
940
972
|
|
|
941
973
|
If you register a tool with the same name as a built-in CLI tool (e.g. `edit_file`, `read_file`), the SDK will throw an error unless you explicitly opt in by setting `overridesBuiltInTool: true`. This flag signals that you intend to replace the built-in tool with your custom implementation.
|
|
942
974
|
|
|
975
|
+
<!-- docs-validate: strict -->
|
|
976
|
+
<!-- docs-validate: hidden -->
|
|
977
|
+
```ts
|
|
978
|
+
import { z } from "zod";
|
|
979
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
980
|
+
|
|
981
|
+
defineTool("edit_file", {
|
|
982
|
+
description: "Custom file editor with project-specific validation",
|
|
983
|
+
parameters: z.object({ path: z.string(), content: z.string() }),
|
|
984
|
+
overridesBuiltInTool: true,
|
|
985
|
+
handler: async ({ path, content }) => {
|
|
986
|
+
/* your logic */
|
|
987
|
+
},
|
|
988
|
+
});
|
|
989
|
+
```
|
|
990
|
+
<!-- /docs-validate: hidden -->
|
|
943
991
|
```ts
|
|
944
992
|
defineTool("edit_file", {
|
|
945
993
|
description: "Custom file editor with project-specific validation",
|
|
@@ -956,6 +1004,19 @@ An `apply_patch` override can declare a string schema. The model sees a required
|
|
|
956
1004
|
dispatching to any SDK. Both a Zod-inferred Node handler and
|
|
957
1005
|
`invocation.arguments` receive the patch text as a string:
|
|
958
1006
|
|
|
1007
|
+
<!-- docs-validate: strict -->
|
|
1008
|
+
<!-- docs-validate: hidden -->
|
|
1009
|
+
```ts
|
|
1010
|
+
import { z } from "zod";
|
|
1011
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
1012
|
+
|
|
1013
|
+
defineTool("apply_patch", {
|
|
1014
|
+
parameters: z.string(),
|
|
1015
|
+
overridesBuiltInTool: true,
|
|
1016
|
+
handler: (patch) => patch.trim(),
|
|
1017
|
+
});
|
|
1018
|
+
```
|
|
1019
|
+
<!-- /docs-validate: hidden -->
|
|
959
1020
|
```ts
|
|
960
1021
|
defineTool("apply_patch", {
|
|
961
1022
|
parameters: z.string(),
|
|
@@ -971,6 +1032,22 @@ use an object schema if references are needed.
|
|
|
971
1032
|
|
|
972
1033
|
Set `skipPermission: true` on a tool definition to allow it to execute without triggering a permission prompt:
|
|
973
1034
|
|
|
1035
|
+
<!-- docs-validate: strict -->
|
|
1036
|
+
<!-- docs-validate: hidden -->
|
|
1037
|
+
```ts
|
|
1038
|
+
import { z } from "zod";
|
|
1039
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
1040
|
+
|
|
1041
|
+
defineTool("safe_lookup", {
|
|
1042
|
+
description: "A read-only lookup that needs no confirmation",
|
|
1043
|
+
parameters: z.object({ id: z.string() }),
|
|
1044
|
+
skipPermission: true,
|
|
1045
|
+
handler: async ({ id }) => {
|
|
1046
|
+
/* your logic */
|
|
1047
|
+
},
|
|
1048
|
+
});
|
|
1049
|
+
```
|
|
1050
|
+
<!-- /docs-validate: hidden -->
|
|
974
1051
|
```ts
|
|
975
1052
|
defineTool("safe_lookup", {
|
|
976
1053
|
description: "A read-only lookup that needs no confirmation",
|
|
@@ -986,6 +1063,22 @@ defineTool("safe_lookup", {
|
|
|
986
1063
|
|
|
987
1064
|
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"`.
|
|
988
1065
|
|
|
1066
|
+
<!-- docs-validate: strict -->
|
|
1067
|
+
<!-- docs-validate: hidden -->
|
|
1068
|
+
```ts
|
|
1069
|
+
import { z } from "zod";
|
|
1070
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
1071
|
+
|
|
1072
|
+
defineTool("lookup_issue", {
|
|
1073
|
+
description: "Fetch issue details",
|
|
1074
|
+
parameters: z.object({ id: z.string() }),
|
|
1075
|
+
defer: "auto",
|
|
1076
|
+
handler: async ({ id }) => {
|
|
1077
|
+
/* your logic */
|
|
1078
|
+
},
|
|
1079
|
+
});
|
|
1080
|
+
```
|
|
1081
|
+
<!-- /docs-validate: hidden -->
|
|
989
1082
|
```ts
|
|
990
1083
|
defineTool("lookup_issue", {
|
|
991
1084
|
description: "Fetch issue details",
|
|
@@ -1001,6 +1094,26 @@ defineTool("lookup_issue", {
|
|
|
1001
1094
|
|
|
1002
1095
|
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.
|
|
1003
1096
|
|
|
1097
|
+
<!-- docs-validate: strict -->
|
|
1098
|
+
<!-- docs-validate: hidden -->
|
|
1099
|
+
```ts
|
|
1100
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
1101
|
+
|
|
1102
|
+
const session = await client.createSession({
|
|
1103
|
+
onPermissionRequest: approveAll,
|
|
1104
|
+
commands: [
|
|
1105
|
+
{
|
|
1106
|
+
name: "deploy",
|
|
1107
|
+
description: "Deploy the app to production",
|
|
1108
|
+
handler: async ({ commandName, args }) => {
|
|
1109
|
+
console.log(`Deploying with args: ${args}`);
|
|
1110
|
+
// Do work here — any thrown error is reported back to the CLI
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
],
|
|
1114
|
+
});
|
|
1115
|
+
```
|
|
1116
|
+
<!-- /docs-validate: hidden -->
|
|
1004
1117
|
```ts
|
|
1005
1118
|
const session = await client.createSession({
|
|
1006
1119
|
onPermissionRequest: approveAll,
|
|
@@ -1027,6 +1140,44 @@ When the session has elicitation support — either from the CLI's TUI or from a
|
|
|
1027
1140
|
|
|
1028
1141
|
> **Capability check:** Elicitation is only available when at least one connected participant advertises support. Always check `session.capabilities.ui?.elicitation` before calling UI methods — this property updates automatically as participants join and leave.
|
|
1029
1142
|
|
|
1143
|
+
<!-- docs-validate: strict -->
|
|
1144
|
+
<!-- docs-validate: hidden -->
|
|
1145
|
+
```ts
|
|
1146
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
1147
|
+
|
|
1148
|
+
const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
1149
|
+
|
|
1150
|
+
if (session.capabilities.ui?.elicitation) {
|
|
1151
|
+
// Confirm dialog — returns boolean
|
|
1152
|
+
const ok = await session.ui.confirm("Deploy to production?");
|
|
1153
|
+
|
|
1154
|
+
// Selection dialog — returns selected value or null
|
|
1155
|
+
const env = await session.ui.select("Pick environment", ["production", "staging", "dev"]);
|
|
1156
|
+
|
|
1157
|
+
// Text input — returns string or null
|
|
1158
|
+
const name = await session.ui.input("Project name:", {
|
|
1159
|
+
title: "Name",
|
|
1160
|
+
minLength: 1,
|
|
1161
|
+
maxLength: 50,
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
// Generic elicitation with full schema control
|
|
1165
|
+
const result = await session.ui.elicitation({
|
|
1166
|
+
message: "Configure deployment",
|
|
1167
|
+
requestedSchema: {
|
|
1168
|
+
type: "object",
|
|
1169
|
+
properties: {
|
|
1170
|
+
region: { type: "string", enum: ["us-east", "eu-west"] },
|
|
1171
|
+
dryRun: { type: "boolean", default: true },
|
|
1172
|
+
},
|
|
1173
|
+
required: ["region"],
|
|
1174
|
+
},
|
|
1175
|
+
});
|
|
1176
|
+
// result.action: "accept" | "decline" | "cancel"
|
|
1177
|
+
// result.content: { region: "us-east", dryRun: true } (when accepted)
|
|
1178
|
+
}
|
|
1179
|
+
```
|
|
1180
|
+
<!-- /docs-validate: hidden -->
|
|
1030
1181
|
```ts
|
|
1031
1182
|
const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
1032
1183
|
|
|
@@ -1067,6 +1218,7 @@ All UI methods throw if elicitation is not supported by the host.
|
|
|
1067
1218
|
|
|
1068
1219
|
Control the system prompt using `systemMessage` in session config:
|
|
1069
1220
|
|
|
1221
|
+
<!-- docs-validate: strict -->
|
|
1070
1222
|
```typescript
|
|
1071
1223
|
const session = await client.createSession({
|
|
1072
1224
|
model: "gpt-5",
|
|
@@ -1087,6 +1239,7 @@ The SDK auto-injects environment context, tool instructions, and security guardr
|
|
|
1087
1239
|
|
|
1088
1240
|
Use `mode: "customize"` to selectively override individual sections of the prompt while preserving the rest:
|
|
1089
1241
|
|
|
1242
|
+
<!-- docs-validate: strict -->
|
|
1090
1243
|
```typescript
|
|
1091
1244
|
import { SYSTEM_MESSAGE_SECTIONS } from "@github/copilot-sdk";
|
|
1092
1245
|
import type { SectionOverride, SystemMessageSection } from "@github/copilot-sdk";
|
|
@@ -1134,6 +1287,7 @@ Unknown section IDs are handled gracefully: content from `replace`/`append`/`pre
|
|
|
1134
1287
|
|
|
1135
1288
|
For full control (removes all guardrails), use `mode: "replace"`:
|
|
1136
1289
|
|
|
1290
|
+
<!-- docs-validate: strict -->
|
|
1137
1291
|
```typescript
|
|
1138
1292
|
const session = await client.createSession({
|
|
1139
1293
|
model: "gpt-5",
|
|
@@ -1148,6 +1302,33 @@ const session = await client.createSession({
|
|
|
1148
1302
|
|
|
1149
1303
|
By default, sessions use **infinite sessions** which automatically manage context window limits through background compaction and persist state to a workspace directory.
|
|
1150
1304
|
|
|
1305
|
+
<!-- docs-validate: strict -->
|
|
1306
|
+
<!-- docs-validate: hidden -->
|
|
1307
|
+
```typescript
|
|
1308
|
+
// Default: infinite sessions enabled with default thresholds
|
|
1309
|
+
const session = await client.createSession({ model: "gpt-5" });
|
|
1310
|
+
|
|
1311
|
+
// Access the workspace path for checkpoints and files
|
|
1312
|
+
console.log(session.workspacePath);
|
|
1313
|
+
// => ~/.copilot/session-state/{sessionId}/
|
|
1314
|
+
|
|
1315
|
+
// Custom thresholds
|
|
1316
|
+
const tuned = await client.createSession({
|
|
1317
|
+
model: "gpt-5",
|
|
1318
|
+
infiniteSessions: {
|
|
1319
|
+
enabled: true,
|
|
1320
|
+
backgroundCompactionThreshold: 0.8, // Start compacting at 80% context usage
|
|
1321
|
+
bufferExhaustionThreshold: 0.95, // Block at 95% until compaction completes
|
|
1322
|
+
},
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
// Disable infinite sessions
|
|
1326
|
+
const disabled = await client.createSession({
|
|
1327
|
+
model: "gpt-5",
|
|
1328
|
+
infiniteSessions: { enabled: false },
|
|
1329
|
+
});
|
|
1330
|
+
```
|
|
1331
|
+
<!-- /docs-validate: hidden -->
|
|
1151
1332
|
```typescript
|
|
1152
1333
|
// Default: infinite sessions enabled with default thresholds
|
|
1153
1334
|
const session = await client.createSession({ model: "gpt-5" });
|
|
@@ -1187,6 +1368,22 @@ SDK leaves `memory` unset so the runtime applies its own default, while `"empty"
|
|
|
1187
1368
|
defaults `memory` to disabled unless you set it explicitly.
|
|
1188
1369
|
For more background, see [About GitHub Copilot Memory](https://docs.github.com/en/copilot/concepts/agents/copilot-memory).
|
|
1189
1370
|
|
|
1371
|
+
<!-- docs-validate: strict -->
|
|
1372
|
+
<!-- docs-validate: hidden -->
|
|
1373
|
+
```typescript
|
|
1374
|
+
// Enable memory for a session
|
|
1375
|
+
const enabled = await client.createSession({
|
|
1376
|
+
model: "gpt-5",
|
|
1377
|
+
memory: { enabled: true },
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
// Disable memory for a session
|
|
1381
|
+
const disabled = await client.createSession({
|
|
1382
|
+
model: "gpt-5",
|
|
1383
|
+
memory: { enabled: false },
|
|
1384
|
+
});
|
|
1385
|
+
```
|
|
1386
|
+
<!-- /docs-validate: hidden -->
|
|
1190
1387
|
```typescript
|
|
1191
1388
|
// Enable memory for a session
|
|
1192
1389
|
const session = await client.createSession({
|
|
@@ -1207,6 +1404,29 @@ A skill provider serves skills from your own storage, such as a database, instea
|
|
|
1207
1404
|
files on disk. Provider skills join the session's skill catalog and load on demand through the
|
|
1208
1405
|
`skill` tool, just like file-based skills.
|
|
1209
1406
|
|
|
1407
|
+
<!-- docs-validate: strict -->
|
|
1408
|
+
<!-- docs-validate: hidden -->
|
|
1409
|
+
```typescript
|
|
1410
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
1411
|
+
import type { SkillProvider } from "@github/copilot-sdk";
|
|
1412
|
+
|
|
1413
|
+
declare const db: {
|
|
1414
|
+
findSkill(name: string, options: { signal: AbortSignal }): Promise<{ markdown: string } | undefined>;
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1417
|
+
const skillProvider: SkillProvider = {
|
|
1418
|
+
listSkills: async () => [
|
|
1419
|
+
{ name: "release-notes", description: "Writes release notes in the team's format." },
|
|
1420
|
+
],
|
|
1421
|
+
readSkill: async (name, { signal }) => (await db.findSkill(name, { signal }))?.markdown ?? null,
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
const session = await client.createSession({
|
|
1425
|
+
onPermissionRequest: approveAll,
|
|
1426
|
+
skillProvider,
|
|
1427
|
+
});
|
|
1428
|
+
```
|
|
1429
|
+
<!-- /docs-validate: hidden -->
|
|
1210
1430
|
```typescript
|
|
1211
1431
|
import type { SkillProvider } from "@github/copilot-sdk";
|
|
1212
1432
|
|
|
@@ -1260,6 +1480,7 @@ See [Supporting files](../docs/features/skills.md#supporting-files-experimental)
|
|
|
1260
1480
|
|
|
1261
1481
|
### Multiple Sessions
|
|
1262
1482
|
|
|
1483
|
+
<!-- docs-validate: strict -->
|
|
1263
1484
|
```typescript
|
|
1264
1485
|
const session1 = await client.createSession({ model: "gpt-5" });
|
|
1265
1486
|
const session2 = await client.createSession({ model: "claude-sonnet-4.5" });
|
|
@@ -1271,6 +1492,7 @@ await session2.sendAndWait({ prompt: "Hello from session 2" });
|
|
|
1271
1492
|
|
|
1272
1493
|
### Custom Session IDs
|
|
1273
1494
|
|
|
1495
|
+
<!-- docs-validate: strict -->
|
|
1274
1496
|
```typescript
|
|
1275
1497
|
const session = await client.createSession({
|
|
1276
1498
|
sessionId: "my-custom-session-id",
|
|
@@ -1280,6 +1502,25 @@ const session = await client.createSession({
|
|
|
1280
1502
|
|
|
1281
1503
|
### File Attachments
|
|
1282
1504
|
|
|
1505
|
+
<!-- docs-validate: strict -->
|
|
1506
|
+
<!-- docs-validate: hidden -->
|
|
1507
|
+
```typescript
|
|
1508
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
1509
|
+
|
|
1510
|
+
const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
1511
|
+
|
|
1512
|
+
await session.send({
|
|
1513
|
+
prompt: "Analyze this file",
|
|
1514
|
+
attachments: [
|
|
1515
|
+
{
|
|
1516
|
+
type: "file",
|
|
1517
|
+
path: "/path/to/file.js",
|
|
1518
|
+
displayName: "My File",
|
|
1519
|
+
},
|
|
1520
|
+
],
|
|
1521
|
+
});
|
|
1522
|
+
```
|
|
1523
|
+
<!-- /docs-validate: hidden -->
|
|
1283
1524
|
```typescript
|
|
1284
1525
|
await session.send({
|
|
1285
1526
|
prompt: "Analyze this file",
|
|
@@ -1308,6 +1549,7 @@ The SDK supports custom OpenAI-compatible API providers (BYOK - Bring Your Own K
|
|
|
1308
1549
|
|
|
1309
1550
|
**Example with Ollama:**
|
|
1310
1551
|
|
|
1552
|
+
<!-- docs-validate: strict -->
|
|
1311
1553
|
```typescript
|
|
1312
1554
|
const session = await client.createSession({
|
|
1313
1555
|
model: "deepseek-coder-v2:16b", // Required when using custom provider
|
|
@@ -1323,6 +1565,7 @@ await session.sendAndWait({ prompt: "Hello!" });
|
|
|
1323
1565
|
|
|
1324
1566
|
**Example with custom OpenAI-compatible API:**
|
|
1325
1567
|
|
|
1568
|
+
<!-- docs-validate: strict -->
|
|
1326
1569
|
```typescript
|
|
1327
1570
|
const session = await client.createSession({
|
|
1328
1571
|
model: "gpt-4",
|
|
@@ -1336,6 +1579,7 @@ const session = await client.createSession({
|
|
|
1336
1579
|
|
|
1337
1580
|
**Example with Azure OpenAI:**
|
|
1338
1581
|
|
|
1582
|
+
<!-- docs-validate: strict -->
|
|
1339
1583
|
```typescript
|
|
1340
1584
|
const session = await client.createSession({
|
|
1341
1585
|
model: "gpt-4",
|
|
@@ -1360,7 +1604,10 @@ const session = await client.createSession({
|
|
|
1360
1604
|
|
|
1361
1605
|
The SDK supports OpenTelemetry for distributed tracing. Provide a `telemetry` config to enable trace export from the CLI process — this is all most users need:
|
|
1362
1606
|
|
|
1607
|
+
<!-- docs-validate: strict -->
|
|
1363
1608
|
```typescript
|
|
1609
|
+
import { CopilotClient } from "@github/copilot-sdk";
|
|
1610
|
+
|
|
1364
1611
|
const client = new CopilotClient({
|
|
1365
1612
|
telemetry: {
|
|
1366
1613
|
otlpEndpoint: "http://localhost:4318",
|
|
@@ -1552,6 +1799,7 @@ To let a specific custom tool bypass the permission prompt entirely, set `skipPe
|
|
|
1552
1799
|
|
|
1553
1800
|
Enable the legacy question-and-answer `ask_user` tool by providing an `onUserInputRequest` handler:
|
|
1554
1801
|
|
|
1802
|
+
<!-- docs-validate: strict -->
|
|
1555
1803
|
```typescript
|
|
1556
1804
|
const session = await client.createSession({
|
|
1557
1805
|
model: "gpt-5",
|
|
@@ -1578,7 +1826,10 @@ const session = await client.createSession({
|
|
|
1578
1826
|
|
|
1579
1827
|
Register an `onElicitationRequest` handler to let your client act as an elicitation provider — presenting form-based UI dialogs on behalf of the agent. When provided, the server notifies your client whenever a tool or MCP server needs structured user input.
|
|
1580
1828
|
|
|
1829
|
+
<!-- docs-validate: strict -->
|
|
1581
1830
|
```typescript
|
|
1831
|
+
import { approveAll } from "@github/copilot-sdk";
|
|
1832
|
+
|
|
1582
1833
|
const session = await client.createSession({
|
|
1583
1834
|
model: "gpt-5",
|
|
1584
1835
|
onPermissionRequest: approveAll,
|
|
@@ -1619,6 +1870,100 @@ In multi-client scenarios:
|
|
|
1619
1870
|
|
|
1620
1871
|
Hook into session lifecycle events by providing handlers in the `hooks` configuration:
|
|
1621
1872
|
|
|
1873
|
+
<!-- docs-validate: strict -->
|
|
1874
|
+
<!-- docs-validate: hidden -->
|
|
1875
|
+
```typescript
|
|
1876
|
+
declare function needsMoreWork(): boolean;
|
|
1877
|
+
|
|
1878
|
+
const session = await client.createSession({
|
|
1879
|
+
model: "gpt-5",
|
|
1880
|
+
hooks: {
|
|
1881
|
+
// Called before each tool execution
|
|
1882
|
+
onPreToolUse: async (input, invocation) => {
|
|
1883
|
+
console.log(`About to run tool: ${input.toolName}`);
|
|
1884
|
+
// Return permission decision and optionally modify args
|
|
1885
|
+
return {
|
|
1886
|
+
permissionDecision: "allow", // "allow", "deny", or "ask"
|
|
1887
|
+
modifiedArgs: input.toolArgs, // Optionally modify tool arguments
|
|
1888
|
+
additionalContext: "Extra context for the model",
|
|
1889
|
+
};
|
|
1890
|
+
},
|
|
1891
|
+
|
|
1892
|
+
// Called after each successful tool execution
|
|
1893
|
+
onPostToolUse: async (input, invocation) => {
|
|
1894
|
+
console.log(`Tool ${input.toolName} completed`);
|
|
1895
|
+
// Optionally modify the result or add context
|
|
1896
|
+
return {
|
|
1897
|
+
additionalContext: "Post-execution notes",
|
|
1898
|
+
};
|
|
1899
|
+
},
|
|
1900
|
+
|
|
1901
|
+
// Called after a tool execution whose result was "failure".
|
|
1902
|
+
// onPostToolUse does NOT fire for failed tool calls — register this
|
|
1903
|
+
// hook to observe them. Input includes `error` (the failure message
|
|
1904
|
+
// extracted from the tool's result), not the full result object.
|
|
1905
|
+
onPostToolUseFailure: async (input, invocation) => {
|
|
1906
|
+
console.log(`Tool ${input.toolName} failed: ${input.error}`);
|
|
1907
|
+
// Optionally append hidden guidance to the model.
|
|
1908
|
+
return { additionalContext: "Suggest checking inputs and retrying." };
|
|
1909
|
+
},
|
|
1910
|
+
|
|
1911
|
+
// Called when user submits a prompt
|
|
1912
|
+
onUserPromptSubmitted: async (input, invocation) => {
|
|
1913
|
+
console.log(`User prompt: ${input.prompt}`);
|
|
1914
|
+
return {
|
|
1915
|
+
modifiedPrompt: input.prompt, // Optionally modify the prompt
|
|
1916
|
+
};
|
|
1917
|
+
},
|
|
1918
|
+
|
|
1919
|
+
// Called when session starts
|
|
1920
|
+
onSessionStart: async (input, invocation) => {
|
|
1921
|
+
console.log(`Session started from: ${input.source}`); // "startup", "resume", "new"
|
|
1922
|
+
return {
|
|
1923
|
+
additionalContext: "Session initialization context",
|
|
1924
|
+
};
|
|
1925
|
+
},
|
|
1926
|
+
|
|
1927
|
+
// Called when session ends
|
|
1928
|
+
onSessionEnd: async (input, invocation) => {
|
|
1929
|
+
console.log(`Session ended: ${input.reason}`);
|
|
1930
|
+
},
|
|
1931
|
+
|
|
1932
|
+
// Called when an error occurs
|
|
1933
|
+
onErrorOccurred: async (input, invocation) => {
|
|
1934
|
+
console.error(`Error in ${input.errorContext}: ${input.error}`);
|
|
1935
|
+
return {
|
|
1936
|
+
errorHandling: "retry", // "retry", "skip", or "abort"
|
|
1937
|
+
};
|
|
1938
|
+
},
|
|
1939
|
+
|
|
1940
|
+
// Called when the top-level agent naturally stops
|
|
1941
|
+
onAgentStop: async (input, invocation) => {
|
|
1942
|
+
if (!input.stopHookActive && needsMoreWork()) {
|
|
1943
|
+
return {
|
|
1944
|
+
decision: "block",
|
|
1945
|
+
reason: "Run the final validation and fix any failures.",
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
|
|
1950
|
+
// Called before a sub-agent's first turn (the input identifies the parent session)
|
|
1951
|
+
onSubagentStart: (input, invocation) => {
|
|
1952
|
+
console.log(`Starting ${input.agentDisplayName ?? input.agentName}`);
|
|
1953
|
+
return { additionalContext: "Check the requested file before reporting back." };
|
|
1954
|
+
},
|
|
1955
|
+
|
|
1956
|
+
// Called when a sub-agent completes a turn
|
|
1957
|
+
onSubagentStop: (input, invocation) => {
|
|
1958
|
+
console.log(`${input.agentName} replied: ${input.response}`);
|
|
1959
|
+
// Return { decision: "block", reason: "Continue checking the file." }
|
|
1960
|
+
// to request another child turn instead.
|
|
1961
|
+
return { modifiedResponse: `Reviewed: ${input.response}` };
|
|
1962
|
+
},
|
|
1963
|
+
},
|
|
1964
|
+
});
|
|
1965
|
+
```
|
|
1966
|
+
<!-- /docs-validate: hidden -->
|
|
1622
1967
|
```typescript
|
|
1623
1968
|
const session = await client.createSession({
|
|
1624
1969
|
model: "gpt-5",
|
|
@@ -1724,12 +2069,13 @@ const session = await client.createSession({
|
|
|
1724
2069
|
|
|
1725
2070
|
## Error Handling
|
|
1726
2071
|
|
|
2072
|
+
<!-- docs-validate: strict -->
|
|
1727
2073
|
```typescript
|
|
1728
2074
|
try {
|
|
1729
|
-
const session = await client.createSession();
|
|
2075
|
+
const session = await client.createSession({});
|
|
1730
2076
|
await session.send({ prompt: "Hello" });
|
|
1731
2077
|
} catch (error) {
|
|
1732
|
-
console.error("Error:", error.message);
|
|
2078
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1733
2079
|
}
|
|
1734
2080
|
```
|
|
1735
2081
|
|
package/dist/cjs/cliVersion.js
CHANGED
|
@@ -22,7 +22,7 @@ __export(cliVersion_exports, {
|
|
|
22
22
|
COPILOT_CLI_VERSION: () => COPILOT_CLI_VERSION
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(cliVersion_exports);
|
|
25
|
-
const COPILOT_CLI_VERSION = "1.0.106-
|
|
25
|
+
const COPILOT_CLI_VERSION = "1.0.106-3";
|
|
26
26
|
const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
|
27
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
28
|
0 && (module.exports = {
|
package/dist/cjs/client.js
CHANGED
|
@@ -336,8 +336,10 @@ class CopilotClient {
|
|
|
336
336
|
effectiveConnectionToken;
|
|
337
337
|
onListModels;
|
|
338
338
|
onGetTraceContext;
|
|
339
|
-
modelsCache =
|
|
340
|
-
|
|
339
|
+
modelsCache = {
|
|
340
|
+
models: null,
|
|
341
|
+
lock: Promise.resolve()
|
|
342
|
+
};
|
|
341
343
|
sessionLifecycleHandlers = /* @__PURE__ */ new Set();
|
|
342
344
|
typedLifecycleHandlers = /* @__PURE__ */ new Map();
|
|
343
345
|
_rpc = null;
|
|
@@ -906,7 +908,7 @@ class CopilotClient {
|
|
|
906
908
|
this._rpc = null;
|
|
907
909
|
this._internalRpc = null;
|
|
908
910
|
}
|
|
909
|
-
this.modelsCache = null;
|
|
911
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
910
912
|
if (this.socket) {
|
|
911
913
|
const socket = this.socket;
|
|
912
914
|
this.socket = null;
|
|
@@ -1068,7 +1070,7 @@ class CopilotClient {
|
|
|
1068
1070
|
this._rpc = null;
|
|
1069
1071
|
this._internalRpc = null;
|
|
1070
1072
|
}
|
|
1071
|
-
this.modelsCache = null;
|
|
1073
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
1072
1074
|
if (this.socket) {
|
|
1073
1075
|
try {
|
|
1074
1076
|
this.socket.destroy();
|
|
@@ -2087,14 +2089,16 @@ class CopilotClient {
|
|
|
2087
2089
|
* @throws Error if not connected (when no custom handler is set)
|
|
2088
2090
|
*/
|
|
2089
2091
|
async listModels() {
|
|
2090
|
-
|
|
2092
|
+
const cache = this.modelsCache;
|
|
2093
|
+
const previousLock = cache.lock;
|
|
2091
2094
|
let resolveLock;
|
|
2092
|
-
|
|
2095
|
+
cache.lock = new Promise((resolve2) => {
|
|
2093
2096
|
resolveLock = resolve2;
|
|
2094
2097
|
});
|
|
2098
|
+
await previousLock;
|
|
2095
2099
|
try {
|
|
2096
|
-
if (
|
|
2097
|
-
return [...
|
|
2100
|
+
if (cache.models !== null) {
|
|
2101
|
+
return [...cache.models];
|
|
2098
2102
|
}
|
|
2099
2103
|
let models;
|
|
2100
2104
|
if (this.onListModels) {
|
|
@@ -2123,7 +2127,7 @@ class CopilotClient {
|
|
|
2123
2127
|
}
|
|
2124
2128
|
}
|
|
2125
2129
|
}
|
|
2126
|
-
|
|
2130
|
+
cache.models = [...models];
|
|
2127
2131
|
return [...models];
|
|
2128
2132
|
} finally {
|
|
2129
2133
|
resolveLock();
|
|
@@ -2888,6 +2892,14 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2888
2892
|
"skillProvider.list",
|
|
2889
2893
|
async (params, token) => await this.resolveSkillProviderSession(params)._handleSkillProviderList(token)
|
|
2890
2894
|
);
|
|
2895
|
+
this.connection.onRequest(
|
|
2896
|
+
"sessionManagement.create",
|
|
2897
|
+
async (params, token) => {
|
|
2898
|
+
const session = this.sessions.get(params.sessionId);
|
|
2899
|
+
if (!session) throw new Error("Session creation owner is unavailable");
|
|
2900
|
+
return await session._handleSessionManagementCreate(params, token);
|
|
2901
|
+
}
|
|
2902
|
+
);
|
|
2891
2903
|
this.connection.onRequest(
|
|
2892
2904
|
"skillProvider.read",
|
|
2893
2905
|
async (params, token) => {
|
|
@@ -2925,7 +2937,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2925
2937
|
this.messageWriter = null;
|
|
2926
2938
|
this._rpc = null;
|
|
2927
2939
|
this._internalRpc = null;
|
|
2928
|
-
this.modelsCache = null;
|
|
2940
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
2929
2941
|
};
|
|
2930
2942
|
const disconnectAfterDrain = () => {
|
|
2931
2943
|
if (exitFallback !== void 0) {
|
|
@@ -109,7 +109,9 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
109
109
|
if (this.#upstream) {
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
const upstream = new WebSocket(this.context.url
|
|
112
|
+
const upstream = new WebSocket(this.context.url, {
|
|
113
|
+
headers: forwardedRequestHeaders(this.context.headers)
|
|
114
|
+
});
|
|
113
115
|
upstream.binaryType = "arraybuffer";
|
|
114
116
|
this.#upstream = upstream;
|
|
115
117
|
upstream.addEventListener("message", (event) => {
|
|
@@ -494,19 +496,24 @@ const FORBIDDEN_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
|
494
496
|
"te",
|
|
495
497
|
"trailer"
|
|
496
498
|
]);
|
|
497
|
-
|
|
499
|
+
function forwardedRequestHeaders(source) {
|
|
498
500
|
const headers = new Headers();
|
|
499
|
-
for (const [name, values] of Object.entries(
|
|
501
|
+
for (const [name, values] of Object.entries(source)) {
|
|
500
502
|
if (!values) {
|
|
501
503
|
continue;
|
|
502
504
|
}
|
|
503
|
-
|
|
505
|
+
const lower = name.toLowerCase();
|
|
506
|
+
if (FORBIDDEN_REQUEST_HEADERS.has(lower) || lower.startsWith("sec-websocket-")) {
|
|
504
507
|
continue;
|
|
505
508
|
}
|
|
506
509
|
for (const value of values) {
|
|
507
510
|
headers.append(name, value);
|
|
508
511
|
}
|
|
509
512
|
}
|
|
513
|
+
return headers;
|
|
514
|
+
}
|
|
515
|
+
async function buildFetchRequest(exchange) {
|
|
516
|
+
const headers = forwardedRequestHeaders(exchange.headers);
|
|
510
517
|
const method = exchange.method.toUpperCase();
|
|
511
518
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
512
519
|
let body;
|