@github/copilot-language-server 1.551.2 → 1.551.3

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.
Files changed (73) hide show
  1. package/dist/main.js +657 -657
  2. package/dist/node_modules/@github/copilot-sdk/dist/cjs/cliVersion.js +1 -1
  3. package/dist/node_modules/@github/copilot-sdk/dist/cjs/client.js +499 -36
  4. package/dist/node_modules/@github/copilot-sdk/dist/cjs/copilotRequestHandler.js +156 -20
  5. package/dist/node_modules/@github/copilot-sdk/dist/cjs/extension.js +11 -9
  6. package/dist/node_modules/@github/copilot-sdk/dist/cjs/ffiRuntimeHost.js +14 -3
  7. package/dist/node_modules/@github/copilot-sdk/dist/cjs/generated/rpc.js +1305 -304
  8. package/dist/node_modules/@github/copilot-sdk/dist/cjs/host.js +67 -0
  9. package/dist/node_modules/@github/copilot-sdk/dist/cjs/index.js +12 -7
  10. package/dist/node_modules/@github/copilot-sdk/dist/cjs/installationConfirmation.js +98 -0
  11. package/dist/node_modules/@github/copilot-sdk/dist/cjs/runtimeArtifacts.js +1 -0
  12. package/dist/node_modules/@github/copilot-sdk/dist/cjs/schema.js +40 -0
  13. package/dist/node_modules/@github/copilot-sdk/dist/cjs/session.js +474 -151
  14. package/dist/node_modules/@github/copilot-sdk/dist/cjs/sessionFsProvider.js +57 -0
  15. package/dist/node_modules/@github/copilot-sdk/dist/cjs/types.js +5 -2
  16. package/dist/node_modules/@github/copilot-sdk/dist/cjs/{factory.js → workflow.js} +33 -33
  17. package/dist/node_modules/@github/copilot-sdk/package.json +27 -16
  18. package/dist/node_modules/zod/locales/package.json +1 -2
  19. package/dist/node_modules/zod/mini/package.json +1 -2
  20. package/dist/node_modules/zod/package.json +1 -1
  21. package/dist/node_modules/zod/v3/package.json +1 -2
  22. package/dist/node_modules/zod/v4/classic/errors.js +2 -2
  23. package/dist/node_modules/zod/v4/classic/from-json-schema.cjs +16 -31
  24. package/dist/node_modules/zod/v4/classic/from-json-schema.js +16 -31
  25. package/dist/node_modules/zod/v4/classic/package.json +1 -2
  26. package/dist/node_modules/zod/v4/classic/schemas.cjs +119 -358
  27. package/dist/node_modules/zod/v4/classic/schemas.js +118 -356
  28. package/dist/node_modules/zod/v4/core/api.cjs +2 -7
  29. package/dist/node_modules/zod/v4/core/api.js +2 -7
  30. package/dist/node_modules/zod/v4/core/core.cjs +1 -3
  31. package/dist/node_modules/zod/v4/core/core.js +2 -4
  32. package/dist/node_modules/zod/v4/core/errors.cjs +23 -26
  33. package/dist/node_modules/zod/v4/core/errors.js +23 -26
  34. package/dist/node_modules/zod/v4/core/json-schema-processors.cjs +20 -16
  35. package/dist/node_modules/zod/v4/core/json-schema-processors.js +20 -16
  36. package/dist/node_modules/zod/v4/core/package.json +1 -2
  37. package/dist/node_modules/zod/v4/core/parse.cjs +7 -7
  38. package/dist/node_modules/zod/v4/core/parse.js +7 -7
  39. package/dist/node_modules/zod/v4/core/regexes.cjs +3 -9
  40. package/dist/node_modules/zod/v4/core/regexes.js +1 -7
  41. package/dist/node_modules/zod/v4/core/schemas.cjs +65 -211
  42. package/dist/node_modules/zod/v4/core/schemas.js +64 -210
  43. package/dist/node_modules/zod/v4/core/to-json-schema.cjs +1 -12
  44. package/dist/node_modules/zod/v4/core/to-json-schema.js +1 -12
  45. package/dist/node_modules/zod/v4/core/util.cjs +30 -54
  46. package/dist/node_modules/zod/v4/core/util.js +32 -55
  47. package/dist/node_modules/zod/v4/core/versions.cjs +2 -2
  48. package/dist/node_modules/zod/v4/core/versions.js +2 -2
  49. package/dist/node_modules/zod/v4/locales/en.cjs +0 -4
  50. package/dist/node_modules/zod/v4/locales/en.js +0 -4
  51. package/dist/node_modules/zod/v4/locales/fr.cjs +7 -24
  52. package/dist/node_modules/zod/v4/locales/fr.js +7 -24
  53. package/dist/node_modules/zod/v4/locales/index.cjs +1 -8
  54. package/dist/node_modules/zod/v4/locales/index.js +0 -3
  55. package/dist/node_modules/zod/v4/locales/it.cjs +1 -1
  56. package/dist/node_modules/zod/v4/locales/it.js +1 -1
  57. package/dist/node_modules/zod/v4/locales/ka.cjs +8 -8
  58. package/dist/node_modules/zod/v4/locales/ka.js +8 -8
  59. package/dist/node_modules/zod/v4/locales/package.json +1 -2
  60. package/dist/node_modules/zod/v4/locales/uz.cjs +0 -1
  61. package/dist/node_modules/zod/v4/locales/uz.js +0 -1
  62. package/dist/node_modules/zod/v4/mini/package.json +1 -2
  63. package/dist/node_modules/zod/v4/mini/schemas.cjs +4 -41
  64. package/dist/node_modules/zod/v4/mini/schemas.js +4 -40
  65. package/dist/node_modules/zod/v4/package.json +1 -2
  66. package/dist/node_modules/zod/v4-mini/package.json +1 -2
  67. package/package.json +20 -20
  68. package/dist/node_modules/zod/v4/locales/el.cjs +0 -136
  69. package/dist/node_modules/zod/v4/locales/el.js +0 -109
  70. package/dist/node_modules/zod/v4/locales/hr.cjs +0 -149
  71. package/dist/node_modules/zod/v4/locales/hr.js +0 -122
  72. package/dist/node_modules/zod/v4/locales/ro.cjs +0 -146
  73. package/dist/node_modules/zod/v4/locales/ro.js +0 -119
@@ -40,17 +40,69 @@ var import_node = require("vscode-jsonrpc/node.js");
40
40
  var import_rpc = require("./generated/rpc.js");
41
41
  var import_sdkProtocolVersion = require("./sdkProtocolVersion.js");
42
42
  var import_session = require("./session.js");
43
+ var import_host = require("./host.js");
43
44
  var import_runtimeArtifacts = require("./runtimeArtifacts.js");
44
45
  var import_cliVersion = require("./cliVersion.js");
45
46
  var import_sessionFsProvider = require("./sessionFsProvider.js");
46
47
  var import_copilotRequestHandler = require("./copilotRequestHandler.js");
48
+ var import_installationConfirmation = require("./installationConfirmation.js");
47
49
  var import_telemetry = require("./telemetry.js");
50
+ var import_schema = require("./schema.js");
48
51
  var import_toolSet = require("./toolSet.js");
49
52
  var import_types = require("./types.js");
50
53
  const MIN_PROTOCOL_VERSION = 3;
51
54
  const RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
52
- function isZodSchema(value) {
53
- return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
55
+ const CLOUD_SESSION_CLEANUP_TIMEOUT_MS = 1e4;
56
+ function createMessageConnection(reader, writer) {
57
+ let dispatch;
58
+ let finishDrain;
59
+ let drained;
60
+ let disposed = false;
61
+ const barrier = { jsonrpc: "2.0", method: "$/sdkDrain" };
62
+ const connection = (0, import_node.createMessageConnection)(
63
+ {
64
+ onError: reader.onError,
65
+ onClose: reader.onClose,
66
+ onPartialMessage: reader.onPartialMessage,
67
+ listen: (callback) => {
68
+ dispatch = callback;
69
+ return reader.listen(callback);
70
+ },
71
+ dispose: () => reader.dispose()
72
+ },
73
+ writer,
74
+ void 0,
75
+ {
76
+ messageStrategy: {
77
+ handleMessage: (message, next) => {
78
+ if (message === barrier) {
79
+ finishDrain?.();
80
+ } else {
81
+ next(message);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ );
87
+ connection.onDispose(() => {
88
+ disposed = true;
89
+ finishDrain?.();
90
+ });
91
+ return Object.assign(connection, {
92
+ drain: () => {
93
+ if (!drained) {
94
+ drained = new Promise((resolve2) => {
95
+ finishDrain = resolve2;
96
+ if (disposed || !dispatch) {
97
+ resolve2();
98
+ } else {
99
+ dispatch(barrier);
100
+ }
101
+ });
102
+ }
103
+ return drained;
104
+ }
105
+ });
54
106
  }
55
107
  async function withTimeout(promise, timeoutMs, message) {
56
108
  let timeout;
@@ -96,13 +148,6 @@ async function waitForChildExit(child, timeoutMs) {
96
148
  }
97
149
  });
98
150
  }
99
- function toJsonSchema(parameters) {
100
- if (!parameters) return void 0;
101
- if (isZodSchema(parameters)) {
102
- return parameters.toJSONSchema();
103
- }
104
- return parameters;
105
- }
106
151
  const DEFAULT_PROVIDER_NAME = "default";
107
152
  function extractBearerTokenProviders(provider, providers) {
108
153
  const callbacks = /* @__PURE__ */ new Map();
@@ -235,8 +280,10 @@ class CopilotClient {
235
280
  cliProcess = null;
236
281
  ffiHost = null;
237
282
  connection = null;
283
+ requestAdapter = null;
238
284
  messageWriter = null;
239
285
  connectionClosed = false;
286
+ connectionEpoch = 0;
240
287
  socket = null;
241
288
  runtimePort = null;
242
289
  actualHost = "localhost";
@@ -244,6 +291,9 @@ class CopilotClient {
244
291
  /** Shared in-flight start; concurrent callers await it instead of spawning another CLI. */
245
292
  startPromise = null;
246
293
  sessions = /* @__PURE__ */ new Map();
294
+ hostExitCallbacks = /* @__PURE__ */ new Map();
295
+ hostSessionFactories = /* @__PURE__ */ new Map();
296
+ hostHandoffs = /* @__PURE__ */ new Map();
247
297
  stderrBuffer = "";
248
298
  // Captures CLI stderr for error messages
249
299
  /** Resolved connection mode chosen in the constructor. */
@@ -272,6 +322,8 @@ class CopilotClient {
272
322
  /** Connection-level session filesystem config, set via constructor option. */
273
323
  sessionFsConfig = null;
274
324
  requestHandler = null;
325
+ extensionLaunchProvider;
326
+ installationConfirmationHandler;
275
327
  builtinPluginDirectories = [];
276
328
  onGitHubTelemetry;
277
329
  clientGlobalHandlers = {};
@@ -429,6 +481,8 @@ class CopilotClient {
429
481
  this.onGetTraceContext = options.onGetTraceContext;
430
482
  this.sessionFsConfig = options.sessionFs ?? null;
431
483
  this.requestHandler = options.requestHandler ?? null;
484
+ this.extensionLaunchProvider = options.extensionLaunchProvider;
485
+ this.installationConfirmationHandler = options.installationConfirmationHandler;
432
486
  this.onGitHubTelemetry = options.onGitHubTelemetry;
433
487
  this.setupClientGlobalHandlers();
434
488
  const connEnv = conn.kind === "stdio" || conn.kind === "tcp" ? conn.env : void 0;
@@ -527,18 +581,30 @@ class CopilotClient {
527
581
  "SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
528
582
  );
529
583
  }
584
+ if (this.sessionFsConfig.capabilities?.binary && (!provider.readFileBytes || !provider.writeFileBytes)) {
585
+ throw new Error(
586
+ "SessionFsConfig declares capabilities.binary but the provider does not implement readFileBytes and writeFileBytes."
587
+ );
588
+ }
530
589
  session.clientSessionApis.sessionFs = (0, import_sessionFsProvider.createSessionFsAdapter)(provider);
531
590
  }
532
591
  setupClientGlobalHandlers() {
533
592
  const handlers = {};
593
+ handlers.host = {
594
+ exited: async (exit) => {
595
+ this.handleHostExit(exit);
596
+ }
597
+ };
598
+ handlers.extensionLaunchProvider = this.extensionLaunchProvider;
534
599
  if (this.requestHandler) {
535
- handlers.llmInference = (0, import_copilotRequestHandler.createCopilotRequestAdapter)(this.requestHandler, () => {
600
+ this.requestAdapter = (0, import_copilotRequestHandler.createCopilotRequestAdapter)(this.requestHandler, () => {
536
601
  if (!this.connection) {
537
602
  return void 0;
538
603
  }
539
604
  this._rpc ??= (0, import_rpc.createServerRpc)(this.connection);
540
605
  return this._rpc;
541
606
  });
607
+ handlers.llmInference = this.requestAdapter;
542
608
  }
543
609
  if (this.onGitHubTelemetry) {
544
610
  const onGitHubTelemetry = this.onGitHubTelemetry;
@@ -632,6 +698,7 @@ class CopilotClient {
632
698
  }
633
699
  async doStart() {
634
700
  this.forceStopping = false;
701
+ this.connectionEpoch++;
635
702
  this.connectionClosed = false;
636
703
  this.processTransportError = null;
637
704
  this.state = "connecting";
@@ -643,6 +710,9 @@ class CopilotClient {
643
710
  }
644
711
  await this.connectToServer();
645
712
  await this.verifyProtocolVersion();
713
+ if (this.extensionLaunchProvider) {
714
+ await this.rpc.registerExtensionLaunchProvider();
715
+ }
646
716
  if (this.builtinPluginDirectories.length > 0) {
647
717
  try {
648
718
  await this.connection.sendRequest("plugins.builtin.set", {
@@ -664,6 +734,9 @@ class CopilotClient {
664
734
  if (this.requestHandler) {
665
735
  await this.connection.sendRequest("llmInference.setProvider", {});
666
736
  }
737
+ if (this.connectionClosed) {
738
+ throw new Error("CLI server connection closed during startup");
739
+ }
667
740
  this.state = "connected";
668
741
  } catch (error) {
669
742
  const startupError = this.processTransportError ?? error;
@@ -679,7 +752,8 @@ class CopilotClient {
679
752
  * 1. Closes all active sessions (releases in-memory resources)
680
753
  * 2. Requests runtime shutdown for SDK-owned CLI processes
681
754
  * 3. Closes the JSON-RPC connection
682
- * 4. Terminates the CLI server process (if spawned by this client)
755
+ * 4. Signals EOF to an owned stdio process and waits for host cleanup, then
756
+ * terminates the process if it does not exit within the shutdown timeout
683
757
  *
684
758
  * Note: session data on disk is preserved, so sessions can be resumed later.
685
759
  * To permanently remove session data before stopping, call
@@ -731,6 +805,7 @@ class CopilotClient {
731
805
  }
732
806
  this.sessions.clear();
733
807
  this.githubTokenProviders.clear();
808
+ this.requestAdapter?.cancelPending();
734
809
  if (this.connection && !this.connectionClosed && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
735
810
  const runtimeShutdownStart = Date.now();
736
811
  const shutdownPromise = this.rpc.runtime.shutdown();
@@ -781,10 +856,23 @@ class CopilotClient {
781
856
  this.socket = null;
782
857
  try {
783
858
  if (!socket.destroyed) {
784
- await new Promise((resolve2) => {
785
- socket.once("close", () => resolve2());
786
- socket.end();
787
- });
859
+ let timeout;
860
+ try {
861
+ await new Promise((resolve2) => {
862
+ socket.once("close", () => resolve2());
863
+ if (this.connectionClosed) {
864
+ socket.destroy();
865
+ } else {
866
+ timeout = setTimeout(
867
+ () => socket.destroy(),
868
+ RUNTIME_SHUTDOWN_TIMEOUT_MS
869
+ );
870
+ socket.end();
871
+ }
872
+ });
873
+ } finally {
874
+ if (timeout !== void 0) clearTimeout(timeout);
875
+ }
788
876
  }
789
877
  } catch (error) {
790
878
  errors.push(
@@ -796,7 +884,23 @@ class CopilotClient {
796
884
  }
797
885
  if (this.cliProcess && !this.isExternalServer) {
798
886
  const child = this.cliProcess;
799
- this.cliProcess = null;
887
+ if (this.connectionConfig.kind === "stdio" && child.stdin && child.exitCode == null && child.signalCode == null) {
888
+ const gracefulExitStart = Date.now();
889
+ try {
890
+ child.stdin.end();
891
+ const exited = await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS);
892
+ this.logDebugTiming(
893
+ exited ? "CopilotClient.stop graceful stdio exit complete" : "CopilotClient.stop graceful stdio exit timed out; terminating child",
894
+ gracefulExitStart
895
+ );
896
+ } catch (error) {
897
+ errors.push(
898
+ new Error(
899
+ `Failed to close CLI stdin: ${error instanceof Error ? error.message : String(error)}`
900
+ )
901
+ );
902
+ }
903
+ }
800
904
  try {
801
905
  if (child.exitCode == null && child.signalCode == null) {
802
906
  child.kill();
@@ -814,6 +918,10 @@ class CopilotClient {
814
918
  `Failed to kill CLI process: ${error instanceof Error ? error.message : String(error)}`
815
919
  )
816
920
  );
921
+ } finally {
922
+ if (this.cliProcess === child) {
923
+ this.cliProcess = null;
924
+ }
817
925
  }
818
926
  }
819
927
  if (this.ffiHost) {
@@ -837,6 +945,7 @@ class CopilotClient {
837
945
  this.runtimePort = null;
838
946
  this.stderrBuffer = "";
839
947
  this.processExitPromise = null;
948
+ this.disconnectHosts();
840
949
  return errors;
841
950
  }
842
951
  /**
@@ -881,11 +990,13 @@ class CopilotClient {
881
990
  */
882
991
  async forceStop() {
883
992
  this.forceStopping = true;
993
+ this.disconnectHosts();
884
994
  for (const session of this.sessions.values()) {
885
995
  session._markDisconnected();
886
996
  }
887
997
  this.sessions.clear();
888
998
  this.githubTokenProviders.clear();
999
+ this.requestAdapter?.cancelPending();
889
1000
  if (this.messageWriter) {
890
1001
  this.messageWriter.suppressWriteErrors = true;
891
1002
  }
@@ -1093,6 +1204,9 @@ class CopilotClient {
1093
1204
  if (config.gitHubToken !== void 0 && config.gitHubTokenProvider !== void 0) {
1094
1205
  throw new Error("gitHubToken and gitHubTokenProvider are mutually exclusive");
1095
1206
  }
1207
+ if (config.cloud != null && config.skillProvider) {
1208
+ throw new Error("Skill providers are not supported for cloud sessions.");
1209
+ }
1096
1210
  if (!this.connection) {
1097
1211
  await this.start();
1098
1212
  }
@@ -1152,18 +1266,22 @@ class CopilotClient {
1152
1266
  if (config.hooks) {
1153
1267
  s.registerHooks(config.hooks);
1154
1268
  }
1269
+ if (config.skillProvider) {
1270
+ s.registerSkillProvider(config.skillProvider);
1271
+ }
1155
1272
  if (transformCallbacks) {
1156
1273
  s.registerTransformCallbacks(transformCallbacks);
1157
1274
  }
1158
1275
  if (config.onEvent) {
1159
1276
  s.on(config.onEvent);
1160
1277
  }
1161
- this.sessions.set(sessionId, s);
1162
1278
  this.setupSessionFs(s, config);
1279
+ this.sessions.set(sessionId, s);
1163
1280
  return s;
1164
1281
  };
1165
1282
  let session;
1166
1283
  let registeredId;
1284
+ let uninitializedCloudSessionId;
1167
1285
  if (localSessionId !== void 0) {
1168
1286
  try {
1169
1287
  session = initializeSession(localSessionId);
@@ -1179,6 +1297,7 @@ class CopilotClient {
1179
1297
  const response = await this.connection.sendRequest("session.create", {
1180
1298
  ...await (0, import_telemetry.getTraceContext)(this.onGetTraceContext),
1181
1299
  model: config.model,
1300
+ allowedModels: config.allowedModels,
1182
1301
  sessionId: localSessionId,
1183
1302
  clientName: config.clientName,
1184
1303
  reasoningEffort: config.reasoningEffort,
@@ -1188,7 +1307,7 @@ class CopilotClient {
1188
1307
  tools: config.tools?.map((tool) => ({
1189
1308
  name: tool.name,
1190
1309
  description: tool.description,
1191
- parameters: toJsonSchema(tool.parameters),
1310
+ parameters: (0, import_schema.toJsonSchema)(tool.parameters),
1192
1311
  overridesBuiltInTool: tool.overridesBuiltInTool,
1193
1312
  skipPermission: tool.skipPermission,
1194
1313
  defer: tool.defer,
@@ -1236,6 +1355,7 @@ class CopilotClient {
1236
1355
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
1237
1356
  ...this.onGitHubTelemetry != null ? { enableGitHubTelemetryForwarding: true } : {},
1238
1357
  mcpServers: toWireMcpServers(config.mcpServers),
1358
+ ...config.diagnostics !== void 0 ? { diagnostics: config.diagnostics } : {},
1239
1359
  mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
1240
1360
  authClientIdMetadataUrl: config.authClientIdMetadataUrl,
1241
1361
  envValueMode: "direct",
@@ -1245,6 +1365,7 @@ class CopilotClient {
1245
1365
  agent: config.agent,
1246
1366
  configDir: config.configDirectory,
1247
1367
  enableConfigDiscovery: config.enableConfigDiscovery,
1368
+ refreshCustomInstructions: config.refreshCustomInstructions,
1248
1369
  skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
1249
1370
  embeddingCacheStorage: config.embeddingCacheStorage,
1250
1371
  organizationCustomInstructions: config.organizationCustomInstructions,
@@ -1254,6 +1375,7 @@ class CopilotClient {
1254
1375
  enableSessionStore: config.enableSessionStore,
1255
1376
  enableSkills: config.enableSkills,
1256
1377
  skillDirectories: config.skillDirectories,
1378
+ ...config.skillProvider ? { hasSkillProvider: true } : {},
1257
1379
  pluginDirectories: config.pluginDirectories,
1258
1380
  instructionDirectories: config.instructionDirectories,
1259
1381
  disabledSkills: config.disabledSkills,
@@ -1267,6 +1389,7 @@ class CopilotClient {
1267
1389
  featureFlags: config.featureFlags,
1268
1390
  expAssignments: config.expAssignments,
1269
1391
  enableManagedSettings: config.enableManagedSettings,
1392
+ enforceManagedModelDefaults: config.enforceManagedModelDefaults,
1270
1393
  managedSettings: config.managedSettings
1271
1394
  });
1272
1395
  const {
@@ -1283,7 +1406,9 @@ class CopilotClient {
1283
1406
  );
1284
1407
  }
1285
1408
  if (session === void 0) {
1409
+ uninitializedCloudSessionId = returnedSessionId;
1286
1410
  session = initializeSession(returnedSessionId);
1411
+ uninitializedCloudSessionId = void 0;
1287
1412
  registeredId = returnedSessionId;
1288
1413
  }
1289
1414
  this.assignGitHubTokenProvider(gitHubTokenProviderRegistrationId, returnedSessionId);
@@ -1305,8 +1430,27 @@ class CopilotClient {
1305
1430
  if (gitHubTokenProviderRegistrationId !== void 0) {
1306
1431
  this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
1307
1432
  }
1433
+ if (uninitializedCloudSessionId !== void 0) {
1434
+ try {
1435
+ await withTimeout(
1436
+ this.deleteSession(uninitializedCloudSessionId),
1437
+ CLOUD_SESSION_CLEANUP_TIMEOUT_MS,
1438
+ `session.delete timed out after ${CLOUD_SESSION_CLEANUP_TIMEOUT_MS}ms`
1439
+ );
1440
+ } catch (cleanupError) {
1441
+ throw new AggregateError(
1442
+ [e, cleanupError],
1443
+ "Failed to initialize and delete cloud session"
1444
+ );
1445
+ }
1446
+ }
1308
1447
  throw e;
1309
1448
  }
1449
+ for (const entry of this.hostHandoffs.values()) {
1450
+ if (entry.requestedSessionId === session.sessionId) {
1451
+ entry.configs.set(session, config);
1452
+ }
1453
+ }
1310
1454
  return session;
1311
1455
  }
1312
1456
  /**
@@ -1337,10 +1481,11 @@ class CopilotClient {
1337
1481
  return this.resumeSessionInternal(sessionId, config);
1338
1482
  }
1339
1483
  /** @internal */
1340
- async resumeSessionForExtension(sessionId, config, factories, extensionOptions) {
1341
- return this.resumeSessionInternal(sessionId, config, factories, extensionOptions);
1484
+ async resumeSessionForExtension(sessionId, config, contributions = {}, extensionOptions) {
1485
+ return this.resumeSessionInternal(sessionId, config, contributions, extensionOptions);
1342
1486
  }
1343
- async resumeSessionInternal(sessionId, config, factories, extensionOptions) {
1487
+ async resumeSessionInternal(sessionId, config, contributions = {}, extensionOptions) {
1488
+ const { workflows } = contributions;
1344
1489
  if (config.gitHubToken !== void 0 && config.gitHubTokenProvider !== void 0) {
1345
1490
  throw new Error("gitHubToken and gitHubTokenProvider are mutually exclusive");
1346
1491
  }
@@ -1360,7 +1505,7 @@ class CopilotClient {
1360
1505
  session.registerTools(config.tools);
1361
1506
  session.registerCanvases(config.canvases);
1362
1507
  session.registerCommands(config.commands);
1363
- session.registerFactories(factories);
1508
+ session.registerWorkflows(workflows);
1364
1509
  const {
1365
1510
  wireProvider: bearerWireProvider,
1366
1511
  wireProviders: bearerWireProviders,
@@ -1385,6 +1530,9 @@ class CopilotClient {
1385
1530
  if (config.hooks) {
1386
1531
  session.registerHooks(config.hooks);
1387
1532
  }
1533
+ if (config.skillProvider) {
1534
+ session.registerSkillProvider(config.skillProvider);
1535
+ }
1388
1536
  const modeDefaults = this.configDefaultsForMode();
1389
1537
  config = { ...modeDefaults, ...config };
1390
1538
  config.customAgentsLocalOnly ??= modeDefaults.customAgentsLocalOnly;
@@ -1398,9 +1546,10 @@ class CopilotClient {
1398
1546
  if (config.onEvent) {
1399
1547
  session.on(config.onEvent);
1400
1548
  }
1401
- this.sessions.set(sessionId, session);
1402
- this.setupSessionFs(session, config);
1403
1549
  const toolFilterOptions = this.resolveToolFilterOptions(config);
1550
+ this.setupSessionFs(session, config);
1551
+ const replacedSession = this.sessions.get(sessionId);
1552
+ this.sessions.set(sessionId, session);
1404
1553
  const gitHubTokenProviderRegistrationId = this.registerGitHubTokenProvider(
1405
1554
  config.gitHubTokenProvider,
1406
1555
  sessionId
@@ -1412,8 +1561,10 @@ class CopilotClient {
1412
1561
  }
1413
1562
  try {
1414
1563
  const response = await this.connection.sendRequest("session.resume", {
1564
+ allowedModels: config.allowedModels,
1415
1565
  ...await (0, import_telemetry.getTraceContext)(this.onGetTraceContext),
1416
1566
  sessionId,
1567
+ allowTranscriptRecovery: config.allowTranscriptRecovery,
1417
1568
  clientName: config.clientName,
1418
1569
  model: config.model,
1419
1570
  reasoningEffort: config.reasoningEffort,
@@ -1432,7 +1583,7 @@ class CopilotClient {
1432
1583
  tools: config.tools?.map((tool) => ({
1433
1584
  name: tool.name,
1434
1585
  description: tool.description,
1435
- parameters: toJsonSchema(tool.parameters),
1586
+ parameters: (0, import_schema.toJsonSchema)(tool.parameters),
1436
1587
  overridesBuiltInTool: tool.overridesBuiltInTool,
1437
1588
  skipPermission: tool.skipPermission,
1438
1589
  defer: tool.defer,
@@ -1441,7 +1592,7 @@ class CopilotClient {
1441
1592
  })),
1442
1593
  toolSearch: config.toolSearch,
1443
1594
  canvases: config.canvases?.map((canvas) => canvas.declaration),
1444
- factories: factories?.map((factory) => factory.meta),
1595
+ workflows: workflows?.map((workflow) => workflow.meta),
1445
1596
  requestCanvasRenderer: config.requestCanvasRenderer,
1446
1597
  requestExtensions: config.requestExtensions,
1447
1598
  extensionSdkPath: config.extensionSdkPath,
@@ -1482,6 +1633,7 @@ class CopilotClient {
1482
1633
  includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
1483
1634
  ...this.onGitHubTelemetry != null ? { enableGitHubTelemetryForwarding: true } : {},
1484
1635
  mcpServers: toWireMcpServers(config.mcpServers),
1636
+ ...config.diagnostics !== void 0 ? { diagnostics: config.diagnostics } : {},
1485
1637
  mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
1486
1638
  authClientIdMetadataUrl: config.authClientIdMetadataUrl,
1487
1639
  envValueMode: "direct",
@@ -1490,6 +1642,7 @@ class CopilotClient {
1490
1642
  defaultAgent: config.defaultAgent,
1491
1643
  agent: config.agent,
1492
1644
  skillDirectories: config.skillDirectories,
1645
+ ...config.skillProvider ? { hasSkillProvider: true } : {},
1493
1646
  pluginDirectories: config.pluginDirectories,
1494
1647
  instructionDirectories: config.instructionDirectories,
1495
1648
  disabledSkills: config.disabledSkills,
@@ -1505,6 +1658,7 @@ class CopilotClient {
1505
1658
  featureFlags: config.featureFlags,
1506
1659
  expAssignments: config.expAssignments,
1507
1660
  enableManagedSettings: config.enableManagedSettings,
1661
+ enforceManagedModelDefaults: config.enforceManagedModelDefaults,
1508
1662
  managedSettings: config.managedSettings,
1509
1663
  ...extensionOptions?.requestedEnvironmentVariables ? {
1510
1664
  requestedEnvironmentVariables: extensionOptions.requestedEnvironmentVariables
@@ -1519,10 +1673,11 @@ class CopilotClient {
1519
1673
  }
1520
1674
  }
1521
1675
  }
1522
- const { workspacePath, capabilities, openCanvases } = response;
1676
+ const { workspacePath, capabilities, openCanvases, transcriptRecovery } = response;
1523
1677
  session["_workspacePath"] = workspacePath;
1524
1678
  session.setCapabilities(capabilities);
1525
1679
  session.setOpenCanvases(openCanvases ?? []);
1680
+ session.setTranscriptRecovery(transcriptRecovery);
1526
1681
  if (config.onMcpAuthRequest) {
1527
1682
  await this.connection.sendRequest("session.eventLog.registerInterest", {
1528
1683
  sessionId,
@@ -1533,14 +1688,220 @@ class CopilotClient {
1533
1688
  this.commitGitHubTokenProvider(sessionId, gitHubTokenProviderRegistrationId);
1534
1689
  } catch (e) {
1535
1690
  session._markDisconnected();
1536
- this.sessions.delete(sessionId);
1691
+ if (this.sessions.get(sessionId) === session) {
1692
+ if (replacedSession) {
1693
+ this.sessions.set(sessionId, replacedSession);
1694
+ } else {
1695
+ this.sessions.delete(sessionId);
1696
+ }
1697
+ }
1537
1698
  if (gitHubTokenProviderRegistrationId !== void 0) {
1538
1699
  this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
1539
1700
  }
1540
1701
  throw e;
1541
1702
  }
1703
+ for (const entry of this.hostHandoffs.values()) {
1704
+ if (entry.requestedSessionId === session.sessionId) {
1705
+ entry.configs.set(session, { ...config, sessionId });
1706
+ }
1707
+ }
1542
1708
  return session;
1543
1709
  }
1710
+ /**
1711
+ * Start a complete AHP listener hosted in-process by this runtime.
1712
+ *
1713
+ * This connection owns the host. Disposing it or disconnecting the client
1714
+ * stops the listener without deleting sessions. The host uses a separate
1715
+ * SDK connection to the same runtime, not another runtime process.
1716
+ * Only one AHP host may own a compute-scoped catalog in an effective Copilot home
1717
+ * at a time. Other SDK clients and sessions remain usable in that home.
1718
+ * Select localServer, githubEnvironment, or both. An empty localServer
1719
+ * selects 127.0.0.1 on an available port. `onExit` runs at most once; owner disconnection cannot
1720
+ * acknowledge listener cleanup over the disconnected transport.
1721
+ *
1722
+ * @experimental
1723
+ */
1724
+ async startAhpHost(options) {
1725
+ if (!options?.localServer && !options?.githubEnvironment) {
1726
+ throw new Error("At least one of localServer or githubEnvironment is required");
1727
+ }
1728
+ if (this.state !== "connected") {
1729
+ await this.start();
1730
+ }
1731
+ const rpc = this.rpc;
1732
+ const hostId = (0, import_node_crypto.randomUUID)();
1733
+ const {
1734
+ computeId,
1735
+ localServer,
1736
+ githubEnvironment,
1737
+ onExit,
1738
+ createSession,
1739
+ resumeSession,
1740
+ onSessionReleased
1741
+ } = options;
1742
+ if (createSession || resumeSession) {
1743
+ this.hostSessionFactories.set(hostId, {
1744
+ createSession,
1745
+ resumeSession,
1746
+ onSessionReleased
1747
+ });
1748
+ }
1749
+ if (onExit) {
1750
+ this.hostExitCallbacks.set(hostId, onExit);
1751
+ }
1752
+ try {
1753
+ const info = await rpc.host.start({
1754
+ hostId,
1755
+ computeId,
1756
+ localServer,
1757
+ githubEnvironment,
1758
+ sessionFactory: createSession ? true : void 0,
1759
+ resumeFactory: resumeSession ? true : void 0
1760
+ });
1761
+ return new import_host.AhpHost(
1762
+ info,
1763
+ async () => {
1764
+ await rpc.host.dispose({ hostId });
1765
+ },
1766
+ (sessionId) => rpc.host.publishSession({ hostId, sessionId }),
1767
+ () => rpc.host.listSessions({ hostId })
1768
+ );
1769
+ } catch (error) {
1770
+ this.hostExitCallbacks.delete(hostId);
1771
+ this.releaseHostSessions(hostId);
1772
+ throw error;
1773
+ }
1774
+ }
1775
+ handleHostExit(exit) {
1776
+ this.releaseHostSessions(exit.hostId);
1777
+ const onExit = this.hostExitCallbacks.get(exit.hostId);
1778
+ if (onExit) {
1779
+ this.hostExitCallbacks.delete(exit.hostId);
1780
+ const reportError = (error) => {
1781
+ console.error("AHP host exit callback failed", { hostId: exit.hostId, error });
1782
+ };
1783
+ try {
1784
+ void Promise.resolve(onExit(exit)).catch(reportError);
1785
+ } catch (error) {
1786
+ reportError(error);
1787
+ }
1788
+ }
1789
+ }
1790
+ disconnectHosts() {
1791
+ for (const hostId of /* @__PURE__ */ new Set([
1792
+ ...this.hostExitCallbacks.keys(),
1793
+ ...this.hostSessionFactories.keys()
1794
+ ])) {
1795
+ this.handleHostExit({
1796
+ hostId,
1797
+ reason: "ownerDisconnected",
1798
+ error: "Owner connection closed; runtime cleanup cannot be acknowledged on this connection."
1799
+ });
1800
+ }
1801
+ }
1802
+ releaseHostSessions(hostId) {
1803
+ this.hostSessionFactories.delete(hostId);
1804
+ for (const [handoffId, entry] of this.hostHandoffs) {
1805
+ if (entry.hostId === hostId) this.releaseHostSession(handoffId);
1806
+ }
1807
+ }
1808
+ releaseHostSession(handoffId) {
1809
+ const entry = this.hostHandoffs.get(handoffId);
1810
+ if (!entry) return;
1811
+ this.hostHandoffs.delete(handoffId);
1812
+ entry.released = true;
1813
+ entry.configs.clear();
1814
+ entry.controller.abort();
1815
+ if (entry.session) this.notifyHostSessionReleased(entry);
1816
+ }
1817
+ notifyHostSessionReleased(entry) {
1818
+ const { session, onReleased } = entry;
1819
+ entry.session = void 0;
1820
+ if (session && onReleased) {
1821
+ try {
1822
+ void Promise.resolve(onReleased(session)).catch(() => {
1823
+ console.error("AHP session release callback failed");
1824
+ });
1825
+ } catch {
1826
+ console.error("AHP session release callback failed");
1827
+ }
1828
+ }
1829
+ }
1830
+ async createHostSession(params) {
1831
+ const options = this.hostSessionFactories.get(params.hostId);
1832
+ if (!(params.resume ? options?.resumeSession : options?.createSession) || this.hostHandoffs.has(params.handoffId)) {
1833
+ throw new Error("AHP session factory is unavailable or handoff already exists");
1834
+ }
1835
+ const entry = {
1836
+ hostId: params.hostId,
1837
+ requestedSessionId: params.config.sessionId,
1838
+ controller: new AbortController(),
1839
+ configs: /* @__PURE__ */ new Map(),
1840
+ released: false,
1841
+ onReleased: options.onSessionReleased
1842
+ };
1843
+ this.hostHandoffs.set(params.handoffId, entry);
1844
+ const { configDir, ...config } = params.config;
1845
+ if (configDir !== void 0) config.configDirectory = configDir;
1846
+ const expected = structuredClone(config);
1847
+ const cancelled = new Promise((_resolve, reject) => {
1848
+ entry.controller.signal.addEventListener(
1849
+ "abort",
1850
+ () => {
1851
+ reject(new Error("AHP session handoff ended"));
1852
+ },
1853
+ { once: true }
1854
+ );
1855
+ });
1856
+ const materialized = Promise.resolve().then(() => {
1857
+ if (params.resume) {
1858
+ const { sessionId, ...resumeConfig } = config;
1859
+ if (!sessionId) throw new Error("AHP resume requires sessionId");
1860
+ return options.resumeSession({
1861
+ sessionId,
1862
+ config: resumeConfig,
1863
+ signal: entry.controller.signal
1864
+ });
1865
+ }
1866
+ return options.createSession({
1867
+ config,
1868
+ signal: entry.controller.signal
1869
+ });
1870
+ }).then((session) => {
1871
+ entry.session = session;
1872
+ const actual = entry.configs.get(session);
1873
+ entry.configs.clear();
1874
+ if (entry.released) {
1875
+ this.notifyHostSessionReleased(entry);
1876
+ throw new Error("AHP session handoff ended");
1877
+ }
1878
+ if (this.sessions.get(session.sessionId) !== session || session.sessionId !== expected.sessionId) {
1879
+ throw new Error(
1880
+ "AHP callback must return the requested session from this client"
1881
+ );
1882
+ }
1883
+ const contains = (value, required) => {
1884
+ if (required && typeof required === "object" && !Array.isArray(required)) {
1885
+ return !!value && typeof value === "object" && Object.entries(required).every(
1886
+ ([key, child]) => contains(value[key], child)
1887
+ );
1888
+ }
1889
+ return JSON.stringify(value) === JSON.stringify(required);
1890
+ };
1891
+ if ((!params.resume || actual !== void 0) && !contains(actual, expected)) {
1892
+ throw new Error(
1893
+ "AHP callback must preserve the supplied session configuration"
1894
+ );
1895
+ }
1896
+ return { sessionId: session.sessionId };
1897
+ });
1898
+ try {
1899
+ return await Promise.race([materialized, cancelled]);
1900
+ } catch (error) {
1901
+ this.releaseHostSession(params.handoffId);
1902
+ throw error;
1903
+ }
1904
+ }
1544
1905
  /**
1545
1906
  * Sends a ping request to the server to verify connectivity.
1546
1907
  *
@@ -1902,6 +2263,9 @@ class CopilotClient {
1902
2263
  if (this.options.mode === "empty") {
1903
2264
  env.COPILOT_DISABLE_KEYTAR = "1";
1904
2265
  }
2266
+ if (this.options.mode !== "empty") {
2267
+ env.COPILOT_RUNTIME_PROCESS_FILE_LOGGING = "1";
2268
+ }
1905
2269
  if (this.options.telemetry) {
1906
2270
  const t = this.options.telemetry;
1907
2271
  env.COPILOT_OTEL_ENABLED = "true";
@@ -2077,8 +2441,13 @@ stderr: ${stderrOutput}`
2077
2441
  case "inprocess":
2078
2442
  return this.connectViaFfi();
2079
2443
  case "tcp":
2080
- case "uri":
2081
2444
  return this.connectViaTcp();
2445
+ case "uri": {
2446
+ const { host, port } = this.parseCliUrl(this.connectionConfig.url);
2447
+ this.actualHost = host;
2448
+ this.runtimePort = port;
2449
+ return this.connectViaTcp();
2450
+ }
2082
2451
  }
2083
2452
  }
2084
2453
  /** Starts the in-process FFI runtime with SDK-managed typed options. */
@@ -2137,7 +2506,7 @@ stderr: ${stderrOutput}`
2137
2506
  throw new Error("In-process FFI runtime host not started");
2138
2507
  }
2139
2508
  this.messageWriter = new TeardownResilientStreamMessageWriter(this.ffiHost.sendStream);
2140
- this.connection = (0, import_node.createMessageConnection)(
2509
+ this.connection = createMessageConnection(
2141
2510
  new import_node.StreamMessageReader(this.ffiHost.receiveStream),
2142
2511
  this.messageWriter
2143
2512
  );
@@ -2191,7 +2560,7 @@ stderr: ${stderrOutput}` : ""}`
2191
2560
  }
2192
2561
  });
2193
2562
  this.messageWriter = new TeardownResilientStreamMessageWriter(this.cliProcess.stdin);
2194
- this.connection = (0, import_node.createMessageConnection)(
2563
+ this.connection = createMessageConnection(
2195
2564
  new import_node.StreamMessageReader(this.cliProcess.stdout),
2196
2565
  this.messageWriter
2197
2566
  );
@@ -2206,7 +2575,7 @@ stderr: ${stderrOutput}` : ""}`
2206
2575
  throw new Error("CLI child process was unexpectedly started in parent process mode");
2207
2576
  }
2208
2577
  this.messageWriter = new TeardownResilientStreamMessageWriter(process.stdout);
2209
- this.connection = (0, import_node.createMessageConnection)(
2578
+ this.connection = createMessageConnection(
2210
2579
  new import_node.StreamMessageReader(process.stdin),
2211
2580
  this.messageWriter
2212
2581
  );
@@ -2229,7 +2598,7 @@ stderr: ${stderrOutput}` : ""}`
2229
2598
  this.socket.connect(this.runtimePort, this.actualHost, () => {
2230
2599
  clearTimeout(connectionTimeout);
2231
2600
  this.messageWriter = new TeardownResilientStreamMessageWriter(this.socket);
2232
- this.connection = (0, import_node.createMessageConnection)(
2601
+ this.connection = createMessageConnection(
2233
2602
  new import_node.StreamMessageReader(this.socket),
2234
2603
  this.messageWriter
2235
2604
  );
@@ -2276,28 +2645,112 @@ stderr: ${stderrOutput}` : ""}`
2276
2645
  return session.clientSessionApis;
2277
2646
  });
2278
2647
  (0, import_rpc.registerClientGlobalApiHandlers)(this.connection, this.clientGlobalHandlers);
2648
+ if (this.installationConfirmationHandler) {
2649
+ const confirmation = (0, import_installationConfirmation.createInstallationConfirmationAdapter)(
2650
+ this.connection,
2651
+ this.installationConfirmationHandler
2652
+ );
2653
+ this.connection.onRequest(
2654
+ "installations.confirm",
2655
+ (params, token) => confirmation.confirm(params, token)
2656
+ );
2657
+ }
2658
+ this.connection.onRequest(
2659
+ "host.materializeSession",
2660
+ (params) => this.createHostSession(params)
2661
+ );
2662
+ this.connection.onNotification(
2663
+ "host.sessionReleased",
2664
+ (params) => {
2665
+ if (this.hostHandoffs.get(params.handoffId)?.hostId === params.hostId) {
2666
+ this.releaseHostSession(params.handoffId);
2667
+ }
2668
+ }
2669
+ );
2279
2670
  this.connection.onRequest(
2280
2671
  "hooks.invoke",
2281
2672
  async (params) => {
2282
2673
  return await this.handleHooksInvoke(params);
2283
2674
  }
2284
2675
  );
2676
+ this.connection.onRequest(
2677
+ "skillProvider.list",
2678
+ async (params, token) => await this.resolveSkillProviderSession(params)._handleSkillProviderList(token)
2679
+ );
2680
+ this.connection.onRequest(
2681
+ "skillProvider.read",
2682
+ async (params, token) => {
2683
+ const session = this.resolveSkillProviderSession(params);
2684
+ if (typeof params.name !== "string") {
2685
+ throw new Error("Invalid skillProvider.read payload");
2686
+ }
2687
+ return await session._handleSkillProviderRead(params.name, token);
2688
+ }
2689
+ );
2285
2690
  const connection = this.connection;
2691
+ const messageWriter = this.messageWriter;
2692
+ const cliProcess = this.isExternalServer ? null : this.cliProcess;
2693
+ const connectionEpoch = this.connectionEpoch;
2694
+ const isCurrentConnection = () => connectionEpoch === this.connectionEpoch && this.connection === connection && (cliProcess === null || this.cliProcess === cliProcess);
2695
+ let disconnecting = false;
2696
+ let exitFallback;
2286
2697
  const markDisconnected = () => {
2287
- if (this.connection !== connection) {
2698
+ if (!isCurrentConnection()) {
2699
+ connection.dispose();
2288
2700
  return;
2289
2701
  }
2290
2702
  this.connectionClosed = true;
2291
2703
  this.state = "disconnected";
2704
+ this.disconnectHosts();
2292
2705
  for (const session of this.sessions.values()) {
2293
2706
  session._markDisconnected();
2294
2707
  }
2295
2708
  this.sessions.clear();
2296
2709
  this.githubTokenProviders.clear();
2710
+ this.requestAdapter?.cancelPending();
2711
+ connection.dispose();
2712
+ this.socket?.destroy();
2713
+ this.connection = null;
2714
+ this.messageWriter = null;
2715
+ this._rpc = null;
2716
+ this._internalRpc = null;
2717
+ this.modelsCache = null;
2297
2718
  };
2298
- this.connection.onClose(markDisconnected);
2719
+ const disconnectAfterDrain = () => {
2720
+ if (exitFallback !== void 0) {
2721
+ clearTimeout(exitFallback);
2722
+ exitFallback = void 0;
2723
+ }
2724
+ if (!isCurrentConnection()) {
2725
+ connection.dispose();
2726
+ return;
2727
+ }
2728
+ if (disconnecting) return;
2729
+ disconnecting = true;
2730
+ this.connectionClosed = true;
2731
+ if (messageWriter) messageWriter.suppressWriteErrors = true;
2732
+ void connection.drain().then(markDisconnected);
2733
+ };
2734
+ this.connection.onClose(disconnectAfterDrain);
2735
+ if (cliProcess) {
2736
+ cliProcess.once("exit", () => {
2737
+ if (!isCurrentConnection()) {
2738
+ connection.dispose();
2739
+ return;
2740
+ }
2741
+ if (disconnecting) return;
2742
+ if (this.socket) {
2743
+ disconnectAfterDrain();
2744
+ return;
2745
+ }
2746
+ this.connectionClosed = true;
2747
+ if (messageWriter) messageWriter.suppressWriteErrors = true;
2748
+ exitFallback = setTimeout(disconnectAfterDrain, RUNTIME_SHUTDOWN_TIMEOUT_MS);
2749
+ exitFallback.unref();
2750
+ });
2751
+ }
2299
2752
  this.connection.onError(() => {
2300
- if (this.connection === connection) {
2753
+ if (connectionEpoch === this.connectionEpoch && this.connection === connection) {
2301
2754
  this.state = "disconnected";
2302
2755
  }
2303
2756
  });
@@ -2390,6 +2843,16 @@ stderr: ${stderrOutput}` : ""}`
2390
2843
  });
2391
2844
  return { response };
2392
2845
  }
2846
+ resolveSkillProviderSession(params) {
2847
+ if (!params || typeof params.sessionId !== "string") {
2848
+ throw new Error("Invalid skillProvider payload");
2849
+ }
2850
+ const session = this.sessions.get(params.sessionId);
2851
+ if (!session) {
2852
+ throw new Error(`Session not found: ${params.sessionId}`);
2853
+ }
2854
+ return session;
2855
+ }
2393
2856
  async handleHooksInvoke(params) {
2394
2857
  if (!params || typeof params.sessionId !== "string" || typeof params.hookType !== "string") {
2395
2858
  throw new Error("Invalid hooks invoke payload");