@github/copilot-sdk 1.0.0-beta.5 → 1.0.0-beta.7
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 +25 -30
- package/dist/canvas.d.ts +163 -0
- package/dist/canvas.js +92 -0
- package/dist/cjs/canvas.js +119 -0
- package/dist/cjs/client.js +243 -251
- package/dist/cjs/extension.js +9 -2
- package/dist/cjs/generated/rpc.js +97 -1
- package/dist/cjs/index.js +17 -7
- package/dist/cjs/session.js +64 -90
- package/dist/cjs/types.js +36 -3
- package/dist/client.d.ts +46 -49
- package/dist/client.js +246 -252
- package/dist/extension.d.ts +3 -1
- package/dist/extension.js +10 -2
- package/dist/generated/rpc.d.ts +796 -63
- package/dist/generated/rpc.js +97 -1
- package/dist/generated/session-events.d.ts +491 -78
- package/dist/index.d.ts +4 -2
- package/dist/index.js +12 -2
- package/dist/session.d.ts +13 -210
- package/dist/session.js +63 -88
- package/dist/types.d.ts +291 -121
- package/dist/types.js +34 -2
- package/package.json +2 -2
package/dist/cjs/client.js
CHANGED
|
@@ -30,18 +30,14 @@ var import_node_path = require("node:path");
|
|
|
30
30
|
var import_node_url = require("node:url");
|
|
31
31
|
var import_node = require("vscode-jsonrpc/node.js");
|
|
32
32
|
var import_rpc = require("./generated/rpc.js");
|
|
33
|
+
var import_canvas = require("./canvas.js");
|
|
33
34
|
var import_sdkProtocolVersion = require("./sdkProtocolVersion.js");
|
|
34
35
|
var import_session = require("./session.js");
|
|
35
36
|
var import_sessionFsProvider = require("./sessionFsProvider.js");
|
|
36
37
|
var import_telemetry = require("./telemetry.js");
|
|
37
38
|
var import_types = require("./types.js");
|
|
38
39
|
const import_meta = {};
|
|
39
|
-
|
|
40
|
-
const { maxInputTokens, ...rest } = provider;
|
|
41
|
-
if (maxInputTokens === void 0) return rest;
|
|
42
|
-
return { ...rest, maxPromptTokens: maxInputTokens };
|
|
43
|
-
}
|
|
44
|
-
const MIN_PROTOCOL_VERSION = 2;
|
|
40
|
+
const MIN_PROTOCOL_VERSION = 3;
|
|
45
41
|
function isZodSchema(value) {
|
|
46
42
|
return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
|
|
47
43
|
}
|
|
@@ -52,6 +48,36 @@ function toJsonSchema(parameters) {
|
|
|
52
48
|
}
|
|
53
49
|
return parameters;
|
|
54
50
|
}
|
|
51
|
+
function toWireMcpServers(mcpServers) {
|
|
52
|
+
if (!mcpServers) return void 0;
|
|
53
|
+
return Object.fromEntries(
|
|
54
|
+
Object.entries(mcpServers).map(([name, server]) => {
|
|
55
|
+
if ("workingDirectory" in server) {
|
|
56
|
+
const { workingDirectory, ...rest } = server;
|
|
57
|
+
return [name, { ...rest, cwd: workingDirectory }];
|
|
58
|
+
}
|
|
59
|
+
return [name, server];
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function toWireCustomAgents(agents) {
|
|
64
|
+
if (!agents) return void 0;
|
|
65
|
+
return agents.map((agent) => {
|
|
66
|
+
if (!agent.mcpServers) return agent;
|
|
67
|
+
const { mcpServers, ...rest } = agent;
|
|
68
|
+
return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function isCanvasProviderRequestParams(params) {
|
|
72
|
+
if (!params || typeof params !== "object") {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const request = params;
|
|
76
|
+
return typeof request.sessionId === "string" && typeof request.extensionId === "string" && typeof request.canvasId === "string" && typeof request.instanceId === "string";
|
|
77
|
+
}
|
|
78
|
+
function isCanvasActionInvokeParams(params) {
|
|
79
|
+
return isCanvasProviderRequestParams(params) && typeof params.actionName === "string";
|
|
80
|
+
}
|
|
55
81
|
function extractTransformCallbacks(systemMessage) {
|
|
56
82
|
if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
|
|
57
83
|
return { wirePayload: systemMessage, transformCallbacks: void 0 };
|
|
@@ -105,12 +131,18 @@ class CopilotClient {
|
|
|
105
131
|
cliProcess = null;
|
|
106
132
|
connection = null;
|
|
107
133
|
socket = null;
|
|
108
|
-
|
|
134
|
+
runtimePort = null;
|
|
109
135
|
actualHost = "localhost";
|
|
110
136
|
state = "disconnected";
|
|
111
137
|
sessions = /* @__PURE__ */ new Map();
|
|
112
138
|
stderrBuffer = "";
|
|
113
139
|
// Captures CLI stderr for error messages
|
|
140
|
+
/** Resolved connection mode chosen in the constructor. */
|
|
141
|
+
connectionConfig;
|
|
142
|
+
/** Resolved path to the runtime executable (only used for child-process kinds). */
|
|
143
|
+
resolvedCliPath;
|
|
144
|
+
/** Resolved environment passed to the spawned runtime. */
|
|
145
|
+
resolvedEnv;
|
|
114
146
|
options;
|
|
115
147
|
isExternalServer = false;
|
|
116
148
|
forceStopping = false;
|
|
@@ -159,86 +191,79 @@ class CopilotClient {
|
|
|
159
191
|
* Creates a new CopilotClient instance.
|
|
160
192
|
*
|
|
161
193
|
* @param options - Configuration options for the client
|
|
162
|
-
* @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath)
|
|
163
194
|
*
|
|
164
195
|
* @example
|
|
165
196
|
* ```typescript
|
|
166
|
-
* // Default
|
|
197
|
+
* // Default: spawns the bundled runtime over stdio
|
|
167
198
|
* const client = new CopilotClient();
|
|
168
199
|
*
|
|
169
|
-
* // Connect to an existing
|
|
170
|
-
* const client = new CopilotClient({
|
|
200
|
+
* // Connect to an existing runtime
|
|
201
|
+
* const client = new CopilotClient({
|
|
202
|
+
* connection: RuntimeConnection.forUri("localhost:3000"),
|
|
203
|
+
* });
|
|
204
|
+
*
|
|
205
|
+
* // Spawn the runtime over TCP on a chosen port
|
|
206
|
+
* const client = new CopilotClient({
|
|
207
|
+
* connection: RuntimeConnection.forTcp({ port: 9001 }),
|
|
208
|
+
* });
|
|
171
209
|
*
|
|
172
|
-
* //
|
|
210
|
+
* // Use a custom runtime binary
|
|
173
211
|
* const client = new CopilotClient({
|
|
174
|
-
*
|
|
175
|
-
* logLevel: "debug"
|
|
212
|
+
* connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }),
|
|
213
|
+
* logLevel: "debug",
|
|
176
214
|
* });
|
|
177
215
|
* ```
|
|
178
216
|
*/
|
|
179
217
|
constructor(options = {}) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) {
|
|
184
|
-
throw new Error(
|
|
185
|
-
"isChildProcess must be used in conjunction with useStdio and not with cliUrl"
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
if (options.cliUrl && (options.gitHubToken || options.useLoggedInUser !== void 0)) {
|
|
218
|
+
const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" };
|
|
219
|
+
if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
|
|
189
220
|
throw new Error(
|
|
190
|
-
"gitHubToken and useLoggedInUser cannot be used with
|
|
221
|
+
"gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
|
|
191
222
|
);
|
|
192
223
|
}
|
|
193
|
-
if (
|
|
194
|
-
if (typeof
|
|
195
|
-
throw new Error("
|
|
196
|
-
}
|
|
197
|
-
if (options.useStdio === true) {
|
|
198
|
-
throw new Error("tcpConnectionToken cannot be used with useStdio: true");
|
|
224
|
+
if (conn.kind === "tcp" && conn.connectionToken !== void 0) {
|
|
225
|
+
if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) {
|
|
226
|
+
throw new Error("connectionToken must be a non-empty string");
|
|
199
227
|
}
|
|
200
228
|
}
|
|
201
|
-
|
|
202
|
-
const sdkSpawnsCli = !willUseStdio && !options.cliUrl && !options.isChildProcess;
|
|
203
|
-
this.effectiveConnectionToken = options.tcpConnectionToken ?? (sdkSpawnsCli ? (0, import_node_crypto.randomUUID)() : void 0);
|
|
229
|
+
this.connectionConfig = conn;
|
|
204
230
|
if (options.sessionFs) {
|
|
205
231
|
this.validateSessionFsConfig(options.sessionFs);
|
|
206
232
|
}
|
|
207
|
-
if (
|
|
208
|
-
const { host, port } = this.parseCliUrl(
|
|
233
|
+
if (conn.kind === "uri") {
|
|
234
|
+
const { host, port } = this.parseCliUrl(conn.url);
|
|
209
235
|
this.actualHost = host;
|
|
210
|
-
this.
|
|
236
|
+
this.runtimePort = port;
|
|
211
237
|
this.isExternalServer = true;
|
|
212
|
-
}
|
|
213
|
-
if (options.isChildProcess) {
|
|
238
|
+
} else if (conn.kind === "parent-process") {
|
|
214
239
|
this.isExternalServer = true;
|
|
215
240
|
}
|
|
241
|
+
if (conn.kind === "tcp") {
|
|
242
|
+
this.effectiveConnectionToken = conn.connectionToken ?? (0, import_node_crypto.randomUUID)();
|
|
243
|
+
} else if (conn.kind === "uri") {
|
|
244
|
+
this.effectiveConnectionToken = conn.connectionToken;
|
|
245
|
+
}
|
|
216
246
|
this.onListModels = options.onListModels;
|
|
217
247
|
this.onGetTraceContext = options.onGetTraceContext;
|
|
218
248
|
this.sessionFsConfig = options.sessionFs ?? null;
|
|
219
249
|
const effectiveEnv = options.env ?? process.env;
|
|
250
|
+
this.resolvedEnv = effectiveEnv;
|
|
251
|
+
this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0;
|
|
252
|
+
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
253
|
+
this.connectionExtraArgs = [...connArgs];
|
|
220
254
|
this.options = {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
cwd: options.cwd ?? process.cwd(),
|
|
224
|
-
port: options.port || 0,
|
|
225
|
-
useStdio: options.cliUrl ? false : options.useStdio ?? true,
|
|
226
|
-
// Default to stdio unless cliUrl is provided
|
|
227
|
-
isChildProcess: options.isChildProcess ?? false,
|
|
228
|
-
cliUrl: options.cliUrl,
|
|
229
|
-
logLevel: options.logLevel || "debug",
|
|
230
|
-
autoStart: options.autoStart ?? true,
|
|
231
|
-
autoRestart: false,
|
|
232
|
-
env: effectiveEnv,
|
|
255
|
+
workingDirectory: options.workingDirectory ?? process.cwd(),
|
|
256
|
+
logLevel: options.logLevel,
|
|
233
257
|
gitHubToken: options.gitHubToken,
|
|
234
|
-
// Default useLoggedInUser to false when gitHubToken is provided, otherwise true
|
|
258
|
+
// Default useLoggedInUser to false when gitHubToken is provided, otherwise true.
|
|
235
259
|
useLoggedInUser: options.useLoggedInUser ?? (options.gitHubToken ? false : true),
|
|
236
260
|
telemetry: options.telemetry,
|
|
237
|
-
|
|
261
|
+
baseDirectory: options.baseDirectory,
|
|
238
262
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
239
|
-
|
|
263
|
+
enableRemoteSessions: options.enableRemoteSessions ?? false
|
|
240
264
|
};
|
|
241
265
|
}
|
|
266
|
+
connectionExtraArgs = [];
|
|
242
267
|
/**
|
|
243
268
|
* Parse CLI URL into host and port
|
|
244
269
|
* Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
|
|
@@ -276,12 +301,12 @@ class CopilotClient {
|
|
|
276
301
|
if (!this.sessionFsConfig) {
|
|
277
302
|
return;
|
|
278
303
|
}
|
|
279
|
-
if (!config.
|
|
304
|
+
if (!config.createSessionFsProvider) {
|
|
280
305
|
throw new Error(
|
|
281
|
-
"
|
|
306
|
+
"createSessionFsProvider is required in session config when sessionFs is enabled in client options."
|
|
282
307
|
);
|
|
283
308
|
}
|
|
284
|
-
const provider = config.
|
|
309
|
+
const provider = config.createSessionFsProvider(session);
|
|
285
310
|
if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) {
|
|
286
311
|
throw new Error(
|
|
287
312
|
"SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
|
|
@@ -295,14 +320,14 @@ class CopilotClient {
|
|
|
295
320
|
* If connecting to an external server (via cliUrl), only establishes the connection.
|
|
296
321
|
* Otherwise, spawns the CLI server process and then connects.
|
|
297
322
|
*
|
|
298
|
-
* This method is called automatically
|
|
323
|
+
* This method is called automatically the first time you create or resume a session.
|
|
299
324
|
*
|
|
300
325
|
* @returns A promise that resolves when the connection is established
|
|
301
326
|
* @throws Error if the server fails to start or the connection fails
|
|
302
327
|
*
|
|
303
328
|
* @example
|
|
304
329
|
* ```typescript
|
|
305
|
-
* const client = new CopilotClient(
|
|
330
|
+
* const client = new CopilotClient();
|
|
306
331
|
* await client.start();
|
|
307
332
|
* // Now ready to create sessions
|
|
308
333
|
* ```
|
|
@@ -397,8 +422,15 @@ class CopilotClient {
|
|
|
397
422
|
}
|
|
398
423
|
this.modelsCache = null;
|
|
399
424
|
if (this.socket) {
|
|
425
|
+
const socket = this.socket;
|
|
426
|
+
this.socket = null;
|
|
400
427
|
try {
|
|
401
|
-
|
|
428
|
+
if (!socket.destroyed) {
|
|
429
|
+
await new Promise((resolve) => {
|
|
430
|
+
socket.once("close", () => resolve());
|
|
431
|
+
socket.end();
|
|
432
|
+
});
|
|
433
|
+
}
|
|
402
434
|
} catch (error) {
|
|
403
435
|
errors.push(
|
|
404
436
|
new Error(
|
|
@@ -406,11 +438,18 @@ class CopilotClient {
|
|
|
406
438
|
)
|
|
407
439
|
);
|
|
408
440
|
}
|
|
409
|
-
this.socket = null;
|
|
410
441
|
}
|
|
411
442
|
if (this.cliProcess && !this.isExternalServer) {
|
|
443
|
+
const child = this.cliProcess;
|
|
444
|
+
this.cliProcess = null;
|
|
412
445
|
try {
|
|
413
|
-
|
|
446
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
447
|
+
const exited = new Promise((resolve) => {
|
|
448
|
+
child.once("exit", () => resolve());
|
|
449
|
+
});
|
|
450
|
+
child.kill();
|
|
451
|
+
await exited;
|
|
452
|
+
}
|
|
414
453
|
} catch (error) {
|
|
415
454
|
errors.push(
|
|
416
455
|
new Error(
|
|
@@ -418,18 +457,32 @@ class CopilotClient {
|
|
|
418
457
|
)
|
|
419
458
|
);
|
|
420
459
|
}
|
|
421
|
-
this.cliProcess = null;
|
|
422
460
|
}
|
|
423
461
|
if (this.cliStartTimeout) {
|
|
424
462
|
clearTimeout(this.cliStartTimeout);
|
|
425
463
|
this.cliStartTimeout = null;
|
|
426
464
|
}
|
|
427
465
|
this.state = "disconnected";
|
|
428
|
-
this.
|
|
466
|
+
this.runtimePort = null;
|
|
429
467
|
this.stderrBuffer = "";
|
|
430
468
|
this.processExitPromise = null;
|
|
431
469
|
return errors;
|
|
432
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Alias for {@link stop} that lets `CopilotClient` participate in `await using`
|
|
473
|
+
* blocks for automatic cleanup.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```typescript
|
|
477
|
+
* await using client = new CopilotClient();
|
|
478
|
+
* const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
479
|
+
* await session.sendAndWait("Hello");
|
|
480
|
+
* // client.stop() is called automatically when the block exits.
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
async [Symbol.asyncDispose]() {
|
|
484
|
+
await this.stop();
|
|
485
|
+
}
|
|
433
486
|
/**
|
|
434
487
|
* Forcefully stops the CLI server without graceful cleanup.
|
|
435
488
|
*
|
|
@@ -486,7 +539,7 @@ class CopilotClient {
|
|
|
486
539
|
this.cliStartTimeout = null;
|
|
487
540
|
}
|
|
488
541
|
this.state = "disconnected";
|
|
489
|
-
this.
|
|
542
|
+
this.runtimePort = null;
|
|
490
543
|
this.stderrBuffer = "";
|
|
491
544
|
this.processExitPromise = null;
|
|
492
545
|
}
|
|
@@ -494,12 +547,11 @@ class CopilotClient {
|
|
|
494
547
|
* Creates a new conversation session with the Copilot CLI.
|
|
495
548
|
*
|
|
496
549
|
* Sessions maintain conversation state, handle events, and manage tool execution.
|
|
497
|
-
* If the client is not connected
|
|
498
|
-
* start the connection.
|
|
550
|
+
* If the client is not connected, this method automatically starts the connection.
|
|
499
551
|
*
|
|
500
552
|
* @param config - Optional configuration for the session
|
|
501
553
|
* @returns A promise that resolves with the created session
|
|
502
|
-
* @throws Error if the client
|
|
554
|
+
* @throws Error if the client fails to start
|
|
503
555
|
*
|
|
504
556
|
* @example
|
|
505
557
|
* ```typescript
|
|
@@ -521,11 +573,7 @@ class CopilotClient {
|
|
|
521
573
|
*/
|
|
522
574
|
async createSession(config) {
|
|
523
575
|
if (!this.connection) {
|
|
524
|
-
|
|
525
|
-
await this.start();
|
|
526
|
-
} else {
|
|
527
|
-
throw new Error("Client not connected. Call start() first.");
|
|
528
|
-
}
|
|
576
|
+
await this.start();
|
|
529
577
|
}
|
|
530
578
|
const sessionId = config.sessionId ?? (0, import_node_crypto.randomUUID)();
|
|
531
579
|
const session = new import_session.CopilotSession(
|
|
@@ -535,6 +583,7 @@ class CopilotClient {
|
|
|
535
583
|
this.onGetTraceContext
|
|
536
584
|
);
|
|
537
585
|
session.registerTools(config.tools);
|
|
586
|
+
session.registerCanvases(config.canvases);
|
|
538
587
|
session.registerCommands(config.commands);
|
|
539
588
|
session.registerPermissionHandler(config.onPermissionRequest);
|
|
540
589
|
if (config.onUserInputRequest) {
|
|
@@ -543,11 +592,11 @@ class CopilotClient {
|
|
|
543
592
|
if (config.onElicitationRequest) {
|
|
544
593
|
session.registerElicitationHandler(config.onElicitationRequest);
|
|
545
594
|
}
|
|
546
|
-
if (config.
|
|
547
|
-
session.registerExitPlanModeHandler(config.
|
|
595
|
+
if (config.onExitPlanModeRequest) {
|
|
596
|
+
session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
548
597
|
}
|
|
549
|
-
if (config.
|
|
550
|
-
session.registerAutoModeSwitchHandler(config.
|
|
598
|
+
if (config.onAutoModeSwitchRequest) {
|
|
599
|
+
session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
|
|
551
600
|
}
|
|
552
601
|
if (config.hooks) {
|
|
553
602
|
session.registerHooks(config.hooks);
|
|
@@ -577,6 +626,10 @@ class CopilotClient {
|
|
|
577
626
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
578
627
|
skipPermission: tool.skipPermission
|
|
579
628
|
})),
|
|
629
|
+
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
630
|
+
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
631
|
+
requestExtensions: config.requestExtensions,
|
|
632
|
+
extensionInfo: config.extensionInfo,
|
|
580
633
|
commands: config.commands?.map((cmd) => ({
|
|
581
634
|
name: cmd.name,
|
|
582
635
|
description: cmd.description
|
|
@@ -584,21 +637,21 @@ class CopilotClient {
|
|
|
584
637
|
systemMessage: wireSystemMessage,
|
|
585
638
|
availableTools: config.availableTools,
|
|
586
639
|
excludedTools: config.excludedTools,
|
|
587
|
-
provider: config.provider
|
|
640
|
+
provider: config.provider,
|
|
588
641
|
enableSessionTelemetry: config.enableSessionTelemetry,
|
|
589
642
|
modelCapabilities: config.modelCapabilities,
|
|
590
|
-
requestPermission:
|
|
643
|
+
requestPermission: !!config.onPermissionRequest,
|
|
591
644
|
requestUserInput: !!config.onUserInputRequest,
|
|
592
645
|
requestElicitation: !!config.onElicitationRequest,
|
|
593
|
-
requestExitPlanMode: !!config.
|
|
594
|
-
requestAutoModeSwitch: !!config.
|
|
646
|
+
requestExitPlanMode: !!config.onExitPlanModeRequest,
|
|
647
|
+
requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
|
|
595
648
|
hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
|
|
596
649
|
workingDirectory: config.workingDirectory,
|
|
597
650
|
streaming: config.streaming,
|
|
598
651
|
includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
|
|
599
|
-
mcpServers: config.mcpServers,
|
|
652
|
+
mcpServers: toWireMcpServers(config.mcpServers),
|
|
600
653
|
envValueMode: "direct",
|
|
601
|
-
customAgents: config.customAgents,
|
|
654
|
+
customAgents: toWireCustomAgents(config.customAgents),
|
|
602
655
|
defaultAgent: config.defaultAgent,
|
|
603
656
|
agent: config.agent,
|
|
604
657
|
configDir: config.configDir,
|
|
@@ -646,11 +699,7 @@ class CopilotClient {
|
|
|
646
699
|
*/
|
|
647
700
|
async resumeSession(sessionId, config) {
|
|
648
701
|
if (!this.connection) {
|
|
649
|
-
|
|
650
|
-
await this.start();
|
|
651
|
-
} else {
|
|
652
|
-
throw new Error("Client not connected. Call start() first.");
|
|
653
|
-
}
|
|
702
|
+
await this.start();
|
|
654
703
|
}
|
|
655
704
|
const session = new import_session.CopilotSession(
|
|
656
705
|
sessionId,
|
|
@@ -659,6 +708,7 @@ class CopilotClient {
|
|
|
659
708
|
this.onGetTraceContext
|
|
660
709
|
);
|
|
661
710
|
session.registerTools(config.tools);
|
|
711
|
+
session.registerCanvases(config.canvases);
|
|
662
712
|
session.registerCommands(config.commands);
|
|
663
713
|
session.registerPermissionHandler(config.onPermissionRequest);
|
|
664
714
|
if (config.onUserInputRequest) {
|
|
@@ -667,11 +717,11 @@ class CopilotClient {
|
|
|
667
717
|
if (config.onElicitationRequest) {
|
|
668
718
|
session.registerElicitationHandler(config.onElicitationRequest);
|
|
669
719
|
}
|
|
670
|
-
if (config.
|
|
671
|
-
session.registerExitPlanModeHandler(config.
|
|
720
|
+
if (config.onExitPlanModeRequest) {
|
|
721
|
+
session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
672
722
|
}
|
|
673
|
-
if (config.
|
|
674
|
-
session.registerAutoModeSwitchHandler(config.
|
|
723
|
+
if (config.onAutoModeSwitchRequest) {
|
|
724
|
+
session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
|
|
675
725
|
}
|
|
676
726
|
if (config.hooks) {
|
|
677
727
|
session.registerHooks(config.hooks);
|
|
@@ -705,61 +755,52 @@ class CopilotClient {
|
|
|
705
755
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
706
756
|
skipPermission: tool.skipPermission
|
|
707
757
|
})),
|
|
758
|
+
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
759
|
+
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
760
|
+
requestExtensions: config.requestExtensions,
|
|
761
|
+
extensionInfo: config.extensionInfo,
|
|
708
762
|
commands: config.commands?.map((cmd) => ({
|
|
709
763
|
name: cmd.name,
|
|
710
764
|
description: cmd.description
|
|
711
765
|
})),
|
|
712
|
-
provider: config.provider
|
|
766
|
+
provider: config.provider,
|
|
713
767
|
modelCapabilities: config.modelCapabilities,
|
|
714
768
|
requestPermission: config.onPermissionRequest !== import_types.defaultJoinSessionPermissionHandler,
|
|
715
769
|
requestUserInput: !!config.onUserInputRequest,
|
|
716
770
|
requestElicitation: !!config.onElicitationRequest,
|
|
717
|
-
requestExitPlanMode: !!config.
|
|
718
|
-
requestAutoModeSwitch: !!config.
|
|
771
|
+
requestExitPlanMode: !!config.onExitPlanModeRequest,
|
|
772
|
+
requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
|
|
719
773
|
hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
|
|
720
774
|
workingDirectory: config.workingDirectory,
|
|
721
775
|
configDir: config.configDir,
|
|
722
776
|
enableConfigDiscovery: config.enableConfigDiscovery,
|
|
723
777
|
streaming: config.streaming,
|
|
724
778
|
includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
|
|
725
|
-
mcpServers: config.mcpServers,
|
|
779
|
+
mcpServers: toWireMcpServers(config.mcpServers),
|
|
726
780
|
envValueMode: "direct",
|
|
727
|
-
customAgents: config.customAgents,
|
|
781
|
+
customAgents: toWireCustomAgents(config.customAgents),
|
|
728
782
|
defaultAgent: config.defaultAgent,
|
|
729
783
|
agent: config.agent,
|
|
730
784
|
skillDirectories: config.skillDirectories,
|
|
731
785
|
instructionDirectories: config.instructionDirectories,
|
|
732
786
|
disabledSkills: config.disabledSkills,
|
|
733
787
|
infiniteSessions: config.infiniteSessions,
|
|
734
|
-
|
|
788
|
+
suppressResumeEvent: config.suppressResumeEvent,
|
|
735
789
|
continuePendingWork: config.continuePendingWork,
|
|
736
790
|
gitHubToken: config.gitHubToken,
|
|
737
|
-
remoteSession: config.remoteSession
|
|
791
|
+
remoteSession: config.remoteSession,
|
|
792
|
+
openCanvases: config.openCanvases
|
|
738
793
|
});
|
|
739
|
-
const { workspacePath, capabilities } = response;
|
|
794
|
+
const { workspacePath, capabilities, openCanvases } = response;
|
|
740
795
|
session["_workspacePath"] = workspacePath;
|
|
741
796
|
session.setCapabilities(capabilities);
|
|
797
|
+
session.setOpenCanvases(openCanvases ?? []);
|
|
742
798
|
} catch (e) {
|
|
743
799
|
this.sessions.delete(sessionId);
|
|
744
800
|
throw e;
|
|
745
801
|
}
|
|
746
802
|
return session;
|
|
747
803
|
}
|
|
748
|
-
/**
|
|
749
|
-
* Gets the current connection state of the client.
|
|
750
|
-
*
|
|
751
|
-
* @returns The current connection state: "disconnected", "connecting", "connected", or "error"
|
|
752
|
-
*
|
|
753
|
-
* @example
|
|
754
|
-
* ```typescript
|
|
755
|
-
* if (client.getState() === "connected") {
|
|
756
|
-
* const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
757
|
-
* }
|
|
758
|
-
* ```
|
|
759
|
-
*/
|
|
760
|
-
getState() {
|
|
761
|
-
return this.state;
|
|
762
|
-
}
|
|
763
804
|
/**
|
|
764
805
|
* Sends a ping request to the server to verify connectivity.
|
|
765
806
|
*
|
|
@@ -961,8 +1002,13 @@ class CopilotClient {
|
|
|
961
1002
|
if (!this.connection) {
|
|
962
1003
|
throw new Error("Client not connected");
|
|
963
1004
|
}
|
|
1005
|
+
let wireFilter;
|
|
1006
|
+
if (filter) {
|
|
1007
|
+
const { workingDirectory, ...rest } = filter;
|
|
1008
|
+
wireFilter = { ...rest, cwd: workingDirectory };
|
|
1009
|
+
}
|
|
964
1010
|
const response = await this.connection.sendRequest("session.list", {
|
|
965
|
-
filter
|
|
1011
|
+
filter: wireFilter
|
|
966
1012
|
});
|
|
967
1013
|
const { sessions } = response;
|
|
968
1014
|
return sessions.map(CopilotClient.toSessionMetadata);
|
|
@@ -997,13 +1043,19 @@ class CopilotClient {
|
|
|
997
1043
|
return CopilotClient.toSessionMetadata(session);
|
|
998
1044
|
}
|
|
999
1045
|
static toSessionMetadata(raw) {
|
|
1046
|
+
const { context } = raw;
|
|
1000
1047
|
return {
|
|
1001
1048
|
sessionId: raw.sessionId,
|
|
1002
1049
|
startTime: new Date(raw.startTime),
|
|
1003
1050
|
modifiedTime: new Date(raw.modifiedTime),
|
|
1004
1051
|
summary: raw.summary,
|
|
1005
1052
|
isRemote: raw.isRemote,
|
|
1006
|
-
context:
|
|
1053
|
+
context: context ? {
|
|
1054
|
+
workingDirectory: context.cwd,
|
|
1055
|
+
gitRoot: context.gitRoot,
|
|
1056
|
+
repository: context.repository,
|
|
1057
|
+
branch: context.branch
|
|
1058
|
+
} : void 0
|
|
1007
1059
|
};
|
|
1008
1060
|
}
|
|
1009
1061
|
/**
|
|
@@ -1056,7 +1108,7 @@ class CopilotClient {
|
|
|
1056
1108
|
throw new Error(result.error || "Failed to set foreground session");
|
|
1057
1109
|
}
|
|
1058
1110
|
}
|
|
1059
|
-
|
|
1111
|
+
onLifecycle(eventTypeOrHandler, handler) {
|
|
1060
1112
|
if (typeof eventTypeOrHandler === "string" && handler) {
|
|
1061
1113
|
const eventType = eventTypeOrHandler;
|
|
1062
1114
|
if (!this.typedLifecycleHandlers.has(eventType)) {
|
|
@@ -1083,17 +1135,17 @@ class CopilotClient {
|
|
|
1083
1135
|
async startCLIServer() {
|
|
1084
1136
|
return new Promise((resolve, reject) => {
|
|
1085
1137
|
this.stderrBuffer = "";
|
|
1086
|
-
const args = [
|
|
1087
|
-
|
|
1088
|
-
"--
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
this.options.logLevel
|
|
1092
|
-
];
|
|
1093
|
-
if (this.options.useStdio) {
|
|
1138
|
+
const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
|
|
1139
|
+
if (this.options.logLevel) {
|
|
1140
|
+
args.push("--log-level", this.options.logLevel);
|
|
1141
|
+
}
|
|
1142
|
+
if (this.connectionConfig.kind === "stdio") {
|
|
1094
1143
|
args.push("--stdio");
|
|
1095
|
-
} else if (this.
|
|
1096
|
-
|
|
1144
|
+
} else if (this.connectionConfig.kind === "tcp") {
|
|
1145
|
+
const requestedPort = this.connectionConfig.port ?? 0;
|
|
1146
|
+
if (requestedPort > 0) {
|
|
1147
|
+
args.push("--port", requestedPort.toString());
|
|
1148
|
+
}
|
|
1097
1149
|
}
|
|
1098
1150
|
if (this.options.gitHubToken) {
|
|
1099
1151
|
args.push("--auth-token-env", "COPILOT_SDK_AUTH_TOKEN");
|
|
@@ -1107,10 +1159,10 @@ class CopilotClient {
|
|
|
1107
1159
|
this.options.sessionIdleTimeoutSeconds.toString()
|
|
1108
1160
|
);
|
|
1109
1161
|
}
|
|
1110
|
-
if (this.options.
|
|
1162
|
+
if (this.options.enableRemoteSessions) {
|
|
1111
1163
|
args.push("--remote");
|
|
1112
1164
|
}
|
|
1113
|
-
const envWithoutNodeDebug = { ...this.
|
|
1165
|
+
const envWithoutNodeDebug = { ...this.resolvedEnv };
|
|
1114
1166
|
delete envWithoutNodeDebug.NODE_DEBUG;
|
|
1115
1167
|
if (this.options.gitHubToken) {
|
|
1116
1168
|
envWithoutNodeDebug.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
@@ -1118,12 +1170,12 @@ class CopilotClient {
|
|
|
1118
1170
|
if (this.effectiveConnectionToken) {
|
|
1119
1171
|
envWithoutNodeDebug.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
|
|
1120
1172
|
}
|
|
1121
|
-
if (this.options.
|
|
1122
|
-
envWithoutNodeDebug.COPILOT_HOME = this.options.
|
|
1173
|
+
if (this.options.baseDirectory) {
|
|
1174
|
+
envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
|
|
1123
1175
|
}
|
|
1124
|
-
if (!this.
|
|
1176
|
+
if (!this.resolvedCliPath) {
|
|
1125
1177
|
throw new Error(
|
|
1126
|
-
"Path to Copilot CLI is required. Please
|
|
1178
|
+
"Path to Copilot CLI is required. Please supply it via `RuntimeConnection.forStdio({ path })` or `RuntimeConnection.forTcp({ path })`, set the COPILOT_CLI_PATH environment variable, or use `RuntimeConnection.forUri(...)` to connect to an already-running runtime."
|
|
1127
1179
|
);
|
|
1128
1180
|
}
|
|
1129
1181
|
if (this.options.telemetry) {
|
|
@@ -1142,31 +1194,31 @@ class CopilotClient {
|
|
|
1142
1194
|
t.captureContent
|
|
1143
1195
|
);
|
|
1144
1196
|
}
|
|
1145
|
-
if (!(0, import_node_fs.existsSync)(this.
|
|
1197
|
+
if (!(0, import_node_fs.existsSync)(this.resolvedCliPath)) {
|
|
1146
1198
|
throw new Error(
|
|
1147
|
-
`Copilot CLI not found at ${this.
|
|
1199
|
+
`Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
|
|
1148
1200
|
);
|
|
1149
1201
|
}
|
|
1150
|
-
const stdioConfig = this.
|
|
1151
|
-
const isJsFile = this.
|
|
1202
|
+
const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
|
|
1203
|
+
const isJsFile = this.resolvedCliPath.endsWith(".js");
|
|
1152
1204
|
if (isJsFile) {
|
|
1153
|
-
this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.
|
|
1205
|
+
this.cliProcess = (0, import_node_child_process.spawn)(getNodeExecPath(), [this.resolvedCliPath, ...args], {
|
|
1154
1206
|
stdio: stdioConfig,
|
|
1155
|
-
cwd: this.options.
|
|
1207
|
+
cwd: this.options.workingDirectory,
|
|
1156
1208
|
env: envWithoutNodeDebug,
|
|
1157
1209
|
windowsHide: true
|
|
1158
1210
|
});
|
|
1159
1211
|
} else {
|
|
1160
|
-
this.cliProcess = (0, import_node_child_process.spawn)(this.
|
|
1212
|
+
this.cliProcess = (0, import_node_child_process.spawn)(this.resolvedCliPath, args, {
|
|
1161
1213
|
stdio: stdioConfig,
|
|
1162
|
-
cwd: this.options.
|
|
1214
|
+
cwd: this.options.workingDirectory,
|
|
1163
1215
|
env: envWithoutNodeDebug,
|
|
1164
1216
|
windowsHide: true
|
|
1165
1217
|
});
|
|
1166
1218
|
}
|
|
1167
1219
|
let stdout = "";
|
|
1168
1220
|
let resolved = false;
|
|
1169
|
-
if (this.
|
|
1221
|
+
if (this.connectionConfig.kind === "stdio") {
|
|
1170
1222
|
resolved = true;
|
|
1171
1223
|
resolve();
|
|
1172
1224
|
} else {
|
|
@@ -1174,7 +1226,7 @@ class CopilotClient {
|
|
|
1174
1226
|
stdout += data.toString();
|
|
1175
1227
|
const match = stdout.match(/listening on port (\d+)/i);
|
|
1176
1228
|
if (match && !resolved) {
|
|
1177
|
-
this.
|
|
1229
|
+
this.runtimePort = parseInt(match[1], 10);
|
|
1178
1230
|
resolved = true;
|
|
1179
1231
|
resolve();
|
|
1180
1232
|
}
|
|
@@ -1248,19 +1300,21 @@ stderr: ${stderrOutput}`
|
|
|
1248
1300
|
resolved = true;
|
|
1249
1301
|
reject(new Error("Timeout waiting for CLI server to start"));
|
|
1250
1302
|
}
|
|
1251
|
-
},
|
|
1303
|
+
}, 3e4);
|
|
1252
1304
|
});
|
|
1253
1305
|
}
|
|
1254
1306
|
/**
|
|
1255
1307
|
* Connect to the CLI server (via socket or stdio)
|
|
1256
1308
|
*/
|
|
1257
1309
|
async connectToServer() {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1310
|
+
switch (this.connectionConfig.kind) {
|
|
1311
|
+
case "parent-process":
|
|
1312
|
+
return this.connectToParentProcessViaStdio();
|
|
1313
|
+
case "stdio":
|
|
1314
|
+
return this.connectToChildProcessViaStdio();
|
|
1315
|
+
case "tcp":
|
|
1316
|
+
case "uri":
|
|
1317
|
+
return this.connectViaTcp();
|
|
1264
1318
|
}
|
|
1265
1319
|
}
|
|
1266
1320
|
/**
|
|
@@ -1300,7 +1354,7 @@ stderr: ${stderrOutput}`
|
|
|
1300
1354
|
* Connect to the CLI server via TCP socket
|
|
1301
1355
|
*/
|
|
1302
1356
|
async connectViaTcp() {
|
|
1303
|
-
if (!this.
|
|
1357
|
+
if (!this.runtimePort) {
|
|
1304
1358
|
throw new Error("Server port not available");
|
|
1305
1359
|
}
|
|
1306
1360
|
return new Promise((resolve, reject) => {
|
|
@@ -1309,7 +1363,7 @@ stderr: ${stderrOutput}`
|
|
|
1309
1363
|
this.socket?.destroy();
|
|
1310
1364
|
reject(new Error("Timeout connecting to CLI server"));
|
|
1311
1365
|
}, 1e4);
|
|
1312
|
-
this.socket.connect(this.
|
|
1366
|
+
this.socket.connect(this.runtimePort, this.actualHost, () => {
|
|
1313
1367
|
clearTimeout(connectionTimeout);
|
|
1314
1368
|
this.connection = (0, import_node.createMessageConnection)(
|
|
1315
1369
|
new import_node.StreamMessageReader(this.socket),
|
|
@@ -1335,14 +1389,6 @@ stderr: ${stderrOutput}`
|
|
|
1335
1389
|
this.connection.onNotification("session.lifecycle", (notification) => {
|
|
1336
1390
|
this.handleSessionLifecycleNotification(notification);
|
|
1337
1391
|
});
|
|
1338
|
-
this.connection.onRequest(
|
|
1339
|
-
"tool.call",
|
|
1340
|
-
async (params) => await this.handleToolCallRequestV2(params)
|
|
1341
|
-
);
|
|
1342
|
-
this.connection.onRequest(
|
|
1343
|
-
"permission.request",
|
|
1344
|
-
async (params) => await this.handlePermissionRequestV2(params)
|
|
1345
|
-
);
|
|
1346
1392
|
this.connection.onRequest(
|
|
1347
1393
|
"userInput.request",
|
|
1348
1394
|
async (params) => await this.handleUserInputRequest(params)
|
|
@@ -1363,6 +1409,18 @@ stderr: ${stderrOutput}`
|
|
|
1363
1409
|
"systemMessage.transform",
|
|
1364
1410
|
async (params) => await this.handleSystemMessageTransform(params)
|
|
1365
1411
|
);
|
|
1412
|
+
this.connection.onRequest(
|
|
1413
|
+
"canvas.open",
|
|
1414
|
+
async (params) => this.handleCanvasProviderRequest("canvas.open", params)
|
|
1415
|
+
);
|
|
1416
|
+
this.connection.onRequest(
|
|
1417
|
+
"canvas.close",
|
|
1418
|
+
async (params) => this.handleCanvasProviderRequest("canvas.close", params)
|
|
1419
|
+
);
|
|
1420
|
+
this.connection.onRequest(
|
|
1421
|
+
"canvas.action.invoke",
|
|
1422
|
+
async (params) => this.handleCanvasActionInvokeRequest(params)
|
|
1423
|
+
);
|
|
1366
1424
|
const sessions = this.sessions;
|
|
1367
1425
|
(0, import_rpc.registerClientSessionApiHandlers)(this.connection, (sessionId) => {
|
|
1368
1426
|
const session = sessions.get(sessionId);
|
|
@@ -1389,7 +1447,20 @@ stderr: ${stderrOutput}`
|
|
|
1389
1447
|
if (typeof notification !== "object" || !notification || !("type" in notification) || typeof notification.type !== "string" || !("sessionId" in notification) || typeof notification.sessionId !== "string") {
|
|
1390
1448
|
return;
|
|
1391
1449
|
}
|
|
1392
|
-
const
|
|
1450
|
+
const raw = notification;
|
|
1451
|
+
let metadata;
|
|
1452
|
+
if (raw.metadata && raw.metadata.startTime && raw.metadata.modifiedTime) {
|
|
1453
|
+
metadata = {
|
|
1454
|
+
startTime: new Date(raw.metadata.startTime),
|
|
1455
|
+
modifiedTime: new Date(raw.metadata.modifiedTime),
|
|
1456
|
+
summary: raw.metadata.summary
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
const event = {
|
|
1460
|
+
type: raw.type,
|
|
1461
|
+
sessionId: raw.sessionId,
|
|
1462
|
+
metadata
|
|
1463
|
+
};
|
|
1393
1464
|
const typedHandlers = this.typedLifecycleHandlers.get(event.type);
|
|
1394
1465
|
if (typedHandlers) {
|
|
1395
1466
|
for (const handler of typedHandlers) {
|
|
@@ -1471,104 +1542,25 @@ stderr: ${stderrOutput}`
|
|
|
1471
1542
|
}
|
|
1472
1543
|
return await session._handleSystemMessageTransform(params.sections);
|
|
1473
1544
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
/**
|
|
1478
|
-
* Handles a v2-style tool.call RPC request from the server.
|
|
1479
|
-
* Looks up the session and tool handler, executes it, and returns the result
|
|
1480
|
-
* in the v2 response format.
|
|
1481
|
-
*/
|
|
1482
|
-
async handleToolCallRequestV2(params) {
|
|
1483
|
-
if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") {
|
|
1484
|
-
throw new Error("Invalid tool call payload");
|
|
1485
|
-
}
|
|
1486
|
-
const session = this.sessions.get(params.sessionId);
|
|
1487
|
-
if (!session) {
|
|
1488
|
-
throw new Error(`Unknown session ${params.sessionId}`);
|
|
1489
|
-
}
|
|
1490
|
-
const handler = session.getToolHandler(params.toolName);
|
|
1491
|
-
if (!handler) {
|
|
1492
|
-
return {
|
|
1493
|
-
result: {
|
|
1494
|
-
textResultForLlm: `Tool '${params.toolName}' is not supported by this client instance.`,
|
|
1495
|
-
resultType: "failure",
|
|
1496
|
-
error: `tool '${params.toolName}' not supported`,
|
|
1497
|
-
toolTelemetry: {}
|
|
1498
|
-
}
|
|
1499
|
-
};
|
|
1500
|
-
}
|
|
1501
|
-
try {
|
|
1502
|
-
const traceparent = params.traceparent;
|
|
1503
|
-
const tracestate = params.tracestate;
|
|
1504
|
-
const invocation = {
|
|
1505
|
-
sessionId: params.sessionId,
|
|
1506
|
-
toolCallId: params.toolCallId,
|
|
1507
|
-
toolName: params.toolName,
|
|
1508
|
-
arguments: params.arguments,
|
|
1509
|
-
traceparent,
|
|
1510
|
-
tracestate
|
|
1511
|
-
};
|
|
1512
|
-
const result = await handler(params.arguments, invocation);
|
|
1513
|
-
return { result: this.normalizeToolResultV2(result) };
|
|
1514
|
-
} catch (error) {
|
|
1515
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1516
|
-
return {
|
|
1517
|
-
result: {
|
|
1518
|
-
textResultForLlm: "Invoking this tool produced an error. Detailed information is not available.",
|
|
1519
|
-
resultType: "failure",
|
|
1520
|
-
error: message,
|
|
1521
|
-
toolTelemetry: {}
|
|
1522
|
-
}
|
|
1523
|
-
};
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
/**
|
|
1527
|
-
* Handles a v2-style permission.request RPC request from the server.
|
|
1528
|
-
*/
|
|
1529
|
-
async handlePermissionRequestV2(params) {
|
|
1530
|
-
if (!params || typeof params.sessionId !== "string" || !params.permissionRequest) {
|
|
1531
|
-
throw new Error("Invalid permission request payload");
|
|
1545
|
+
async handleCanvasProviderRequest(actionName, params) {
|
|
1546
|
+
if (!isCanvasProviderRequestParams(params)) {
|
|
1547
|
+
throw new Error("Invalid canvas provider request payload");
|
|
1532
1548
|
}
|
|
1533
1549
|
const session = this.sessions.get(params.sessionId);
|
|
1534
1550
|
if (!session) {
|
|
1535
1551
|
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1536
1552
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
} catch (error) {
|
|
1541
|
-
if (error instanceof Error && error.message === import_session.NO_RESULT_PERMISSION_V2_ERROR) {
|
|
1542
|
-
throw error;
|
|
1543
|
-
}
|
|
1544
|
-
return {
|
|
1545
|
-
result: {
|
|
1546
|
-
kind: "user-not-available"
|
|
1547
|
-
}
|
|
1548
|
-
};
|
|
1553
|
+
const canvas = session.getCanvas(params.canvasId);
|
|
1554
|
+
if (!canvas) {
|
|
1555
|
+
throw new Error(`No canvas registered with id "${params.canvasId}"`);
|
|
1549
1556
|
}
|
|
1557
|
+
return (0, import_canvas.dispatchCanvasProviderRequest)(canvas, actionName, params);
|
|
1550
1558
|
}
|
|
1551
|
-
|
|
1552
|
-
if (
|
|
1553
|
-
|
|
1554
|
-
textResultForLlm: "Tool returned no result",
|
|
1555
|
-
resultType: "failure",
|
|
1556
|
-
error: "tool returned no result",
|
|
1557
|
-
toolTelemetry: {}
|
|
1558
|
-
};
|
|
1559
|
-
}
|
|
1560
|
-
if (this.isToolResultObject(result)) {
|
|
1561
|
-
return result;
|
|
1559
|
+
async handleCanvasActionInvokeRequest(params) {
|
|
1560
|
+
if (!isCanvasActionInvokeParams(params)) {
|
|
1561
|
+
throw new Error("Invalid canvas provider request payload");
|
|
1562
1562
|
}
|
|
1563
|
-
|
|
1564
|
-
return {
|
|
1565
|
-
textResultForLlm: textResult,
|
|
1566
|
-
resultType: "success",
|
|
1567
|
-
toolTelemetry: {}
|
|
1568
|
-
};
|
|
1569
|
-
}
|
|
1570
|
-
isToolResultObject(value) {
|
|
1571
|
-
return typeof value === "object" && value !== null && "textResultForLlm" in value && typeof value.textResultForLlm === "string" && "resultType" in value;
|
|
1563
|
+
return this.handleCanvasProviderRequest(params.actionName, params);
|
|
1572
1564
|
}
|
|
1573
1565
|
}
|
|
1574
1566
|
// Annotate the CommonJS export names for ESM import in node:
|