@github/copilot-sdk 1.0.29-preview.0 → 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 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
 
@@ -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-1";
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 = {
@@ -336,8 +336,10 @@ class CopilotClient {
336
336
  effectiveConnectionToken;
337
337
  onListModels;
338
338
  onGetTraceContext;
339
- modelsCache = null;
340
- modelsCacheLock = Promise.resolve();
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
- await this.modelsCacheLock;
2092
+ const cache = this.modelsCache;
2093
+ const previousLock = cache.lock;
2091
2094
  let resolveLock;
2092
- this.modelsCacheLock = new Promise((resolve2) => {
2095
+ cache.lock = new Promise((resolve2) => {
2093
2096
  resolveLock = resolve2;
2094
2097
  });
2098
+ await previousLock;
2095
2099
  try {
2096
- if (this.modelsCache !== null) {
2097
- return [...this.modelsCache];
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
- this.modelsCache = [...models];
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
- async function buildFetchRequest(exchange) {
499
+ function forwardedRequestHeaders(source) {
498
500
  const headers = new Headers();
499
- for (const [name, values] of Object.entries(exchange.headers)) {
501
+ for (const [name, values] of Object.entries(source)) {
500
502
  if (!values) {
501
503
  continue;
502
504
  }
503
- if (FORBIDDEN_REQUEST_HEADERS.has(name.toLowerCase())) {
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;