@github/copilot-sdk 1.0.0-beta.1 → 1.0.0-beta.11
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 +61 -48
- package/dist/canvas.d.ts +126 -0
- package/dist/canvas.js +49 -0
- package/dist/cjs/canvas.js +75 -0
- package/dist/cjs/client.js +540 -299
- package/dist/cjs/extension.js +12 -3
- package/dist/cjs/generated/rpc.js +1332 -15
- package/dist/cjs/index.js +22 -7
- package/dist/cjs/session.js +179 -93
- package/dist/cjs/sessionFsProvider.js +34 -0
- package/dist/cjs/toolSet.js +107 -0
- package/dist/cjs/types.js +38 -4
- package/dist/client.d.ts +63 -73
- package/dist/client.js +541 -300
- package/dist/extension.d.ts +4 -2
- package/dist/extension.js +13 -3
- package/dist/generated/rpc.d.ts +10205 -994
- package/dist/generated/rpc.js +1332 -15
- package/dist/generated/session-events.d.ts +2061 -194
- package/dist/index.d.ts +6 -2
- package/dist/index.js +15 -2
- package/dist/session.d.ts +19 -186
- package/dist/session.js +179 -92
- package/dist/sessionFsProvider.d.ts +29 -2
- package/dist/sessionFsProvider.js +34 -0
- package/dist/toolSet.d.ts +75 -0
- package/dist/toolSet.js +82 -0
- package/dist/types.d.ts +753 -123
- package/dist/types.js +36 -3
- package/docs/agent-author.md +31 -7
- package/docs/examples.md +29 -19
- package/package.json +4 -4
package/dist/client.js
CHANGED
|
@@ -18,11 +18,12 @@ import {
|
|
|
18
18
|
registerClientSessionApiHandlers
|
|
19
19
|
} from "./generated/rpc.js";
|
|
20
20
|
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
|
|
21
|
-
import { CopilotSession
|
|
21
|
+
import { CopilotSession } from "./session.js";
|
|
22
22
|
import { createSessionFsAdapter } from "./sessionFsProvider.js";
|
|
23
23
|
import { getTraceContext } from "./telemetry.js";
|
|
24
|
+
import { ToolSet } from "./toolSet.js";
|
|
24
25
|
import { defaultJoinSessionPermissionHandler } from "./types.js";
|
|
25
|
-
const MIN_PROTOCOL_VERSION =
|
|
26
|
+
const MIN_PROTOCOL_VERSION = 3;
|
|
26
27
|
function isZodSchema(value) {
|
|
27
28
|
return value != null && typeof value === "object" && "toJSONSchema" in value && typeof value.toJSONSchema === "function";
|
|
28
29
|
}
|
|
@@ -33,6 +34,53 @@ function toJsonSchema(parameters) {
|
|
|
33
34
|
}
|
|
34
35
|
return parameters;
|
|
35
36
|
}
|
|
37
|
+
function toWireMcpServers(mcpServers) {
|
|
38
|
+
if (!mcpServers) return void 0;
|
|
39
|
+
return Object.fromEntries(
|
|
40
|
+
Object.entries(mcpServers).map(([name, server]) => {
|
|
41
|
+
if ("workingDirectory" in server) {
|
|
42
|
+
const { workingDirectory, ...rest } = server;
|
|
43
|
+
return [name, { ...rest, cwd: workingDirectory }];
|
|
44
|
+
}
|
|
45
|
+
return [name, server];
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
function toWireCustomAgents(agents) {
|
|
50
|
+
if (!agents) return void 0;
|
|
51
|
+
return agents.map((agent) => {
|
|
52
|
+
if (!agent.mcpServers) return agent;
|
|
53
|
+
const { mcpServers, ...rest } = agent;
|
|
54
|
+
return { ...rest, mcpServers: toWireMcpServers(mcpServers) };
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function toWireLargeOutput(config) {
|
|
58
|
+
if (!config) return void 0;
|
|
59
|
+
const { outputDirectory, ...rest } = config;
|
|
60
|
+
const wire = { ...rest };
|
|
61
|
+
if (outputDirectory !== void 0) {
|
|
62
|
+
wire.outputDir = outputDirectory;
|
|
63
|
+
}
|
|
64
|
+
return wire;
|
|
65
|
+
}
|
|
66
|
+
function toolFilterListToArray(value) {
|
|
67
|
+
if (value === void 0) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
return value instanceof ToolSet ? value.toArray() : value;
|
|
71
|
+
}
|
|
72
|
+
function validateToolFilterList(field, list) {
|
|
73
|
+
if (!list) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (const entry of list) {
|
|
77
|
+
if (entry === "*") {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Invalid ${field} entry '*': there is no bare wildcard. Use one or more of \`new ToolSet().addBuiltIn('*')\`, \`.addMcp('*')\`, or \`.addCustom('*')\` to target a specific source.`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
36
84
|
function extractTransformCallbacks(systemMessage) {
|
|
37
85
|
if (!systemMessage || systemMessage.mode !== "customize" || !systemMessage.sections) {
|
|
38
86
|
return { wirePayload: systemMessage, transformCallbacks: void 0 };
|
|
@@ -86,12 +134,18 @@ class CopilotClient {
|
|
|
86
134
|
cliProcess = null;
|
|
87
135
|
connection = null;
|
|
88
136
|
socket = null;
|
|
89
|
-
|
|
137
|
+
runtimePort = null;
|
|
90
138
|
actualHost = "localhost";
|
|
91
139
|
state = "disconnected";
|
|
92
140
|
sessions = /* @__PURE__ */ new Map();
|
|
93
141
|
stderrBuffer = "";
|
|
94
142
|
// Captures CLI stderr for error messages
|
|
143
|
+
/** Resolved connection mode chosen in the constructor. */
|
|
144
|
+
connectionConfig;
|
|
145
|
+
/** Resolved path to the runtime executable (only used for child-process kinds). */
|
|
146
|
+
resolvedCliPath;
|
|
147
|
+
/** Resolved environment passed to the spawned runtime. */
|
|
148
|
+
resolvedEnv;
|
|
95
149
|
options;
|
|
96
150
|
isExternalServer = false;
|
|
97
151
|
forceStopping = false;
|
|
@@ -140,85 +194,90 @@ class CopilotClient {
|
|
|
140
194
|
* Creates a new CopilotClient instance.
|
|
141
195
|
*
|
|
142
196
|
* @param options - Configuration options for the client
|
|
143
|
-
* @throws Error if mutually exclusive options are provided (e.g., cliUrl with useStdio or cliPath)
|
|
144
197
|
*
|
|
145
198
|
* @example
|
|
146
199
|
* ```typescript
|
|
147
|
-
* // Default
|
|
200
|
+
* // Default: spawns the bundled runtime over stdio
|
|
148
201
|
* const client = new CopilotClient();
|
|
149
202
|
*
|
|
150
|
-
* // Connect to an existing
|
|
151
|
-
* const client = new CopilotClient({
|
|
203
|
+
* // Connect to an existing runtime
|
|
204
|
+
* const client = new CopilotClient({
|
|
205
|
+
* connection: RuntimeConnection.forUri("localhost:3000"),
|
|
206
|
+
* });
|
|
207
|
+
*
|
|
208
|
+
* // Spawn the runtime over TCP on a chosen port
|
|
209
|
+
* const client = new CopilotClient({
|
|
210
|
+
* connection: RuntimeConnection.forTcp({ port: 9001 }),
|
|
211
|
+
* });
|
|
152
212
|
*
|
|
153
|
-
* //
|
|
213
|
+
* // Use a custom runtime binary
|
|
154
214
|
* const client = new CopilotClient({
|
|
155
|
-
*
|
|
156
|
-
* logLevel: "debug"
|
|
215
|
+
* connection: RuntimeConnection.forStdio({ path: "/usr/local/bin/copilot" }),
|
|
216
|
+
* logLevel: "debug",
|
|
157
217
|
* });
|
|
158
218
|
* ```
|
|
159
219
|
*/
|
|
160
220
|
constructor(options = {}) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) {
|
|
165
|
-
throw new Error(
|
|
166
|
-
"isChildProcess must be used in conjunction with useStdio and not with cliUrl"
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
if (options.cliUrl && (options.gitHubToken || options.useLoggedInUser !== void 0)) {
|
|
221
|
+
const conn = options._internalConnection ?? options.connection ?? { kind: "stdio" };
|
|
222
|
+
if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
|
|
170
223
|
throw new Error(
|
|
171
|
-
"gitHubToken and useLoggedInUser cannot be used with
|
|
224
|
+
"gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
|
|
172
225
|
);
|
|
173
226
|
}
|
|
174
|
-
if (
|
|
175
|
-
if (typeof
|
|
176
|
-
throw new Error("
|
|
177
|
-
}
|
|
178
|
-
if (options.useStdio === true) {
|
|
179
|
-
throw new Error("tcpConnectionToken cannot be used with useStdio: true");
|
|
227
|
+
if (conn.kind === "tcp" && conn.connectionToken !== void 0) {
|
|
228
|
+
if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) {
|
|
229
|
+
throw new Error("connectionToken must be a non-empty string");
|
|
180
230
|
}
|
|
181
231
|
}
|
|
182
|
-
|
|
183
|
-
const sdkSpawnsCli = !willUseStdio && !options.cliUrl && !options.isChildProcess;
|
|
184
|
-
this.effectiveConnectionToken = options.tcpConnectionToken ?? (sdkSpawnsCli ? randomUUID() : void 0);
|
|
232
|
+
this.connectionConfig = conn;
|
|
185
233
|
if (options.sessionFs) {
|
|
186
234
|
this.validateSessionFsConfig(options.sessionFs);
|
|
187
235
|
}
|
|
188
|
-
if (
|
|
189
|
-
const { host, port } = this.parseCliUrl(
|
|
236
|
+
if (conn.kind === "uri") {
|
|
237
|
+
const { host, port } = this.parseCliUrl(conn.url);
|
|
190
238
|
this.actualHost = host;
|
|
191
|
-
this.
|
|
239
|
+
this.runtimePort = port;
|
|
192
240
|
this.isExternalServer = true;
|
|
193
|
-
}
|
|
194
|
-
if (options.isChildProcess) {
|
|
241
|
+
} else if (conn.kind === "parent-process") {
|
|
195
242
|
this.isExternalServer = true;
|
|
196
243
|
}
|
|
244
|
+
if (conn.kind === "tcp") {
|
|
245
|
+
this.effectiveConnectionToken = conn.connectionToken ?? randomUUID();
|
|
246
|
+
} else if (conn.kind === "uri") {
|
|
247
|
+
this.effectiveConnectionToken = conn.connectionToken;
|
|
248
|
+
}
|
|
197
249
|
this.onListModels = options.onListModels;
|
|
198
250
|
this.onGetTraceContext = options.onGetTraceContext;
|
|
199
251
|
this.sessionFsConfig = options.sessionFs ?? null;
|
|
200
252
|
const effectiveEnv = options.env ?? process.env;
|
|
253
|
+
this.resolvedEnv = effectiveEnv;
|
|
254
|
+
this.resolvedCliPath = conn.kind === "stdio" || conn.kind === "tcp" ? conn.path ?? effectiveEnv.COPILOT_CLI_PATH ?? getBundledCliPath() : void 0;
|
|
255
|
+
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
256
|
+
this.connectionExtraArgs = [...connArgs];
|
|
201
257
|
this.options = {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
cwd: options.cwd ?? process.cwd(),
|
|
205
|
-
port: options.port || 0,
|
|
206
|
-
useStdio: options.cliUrl ? false : options.useStdio ?? true,
|
|
207
|
-
// Default to stdio unless cliUrl is provided
|
|
208
|
-
isChildProcess: options.isChildProcess ?? false,
|
|
209
|
-
cliUrl: options.cliUrl,
|
|
210
|
-
logLevel: options.logLevel || "debug",
|
|
211
|
-
autoStart: options.autoStart ?? true,
|
|
212
|
-
autoRestart: false,
|
|
213
|
-
env: effectiveEnv,
|
|
258
|
+
workingDirectory: options.workingDirectory ?? process.cwd(),
|
|
259
|
+
logLevel: options.logLevel,
|
|
214
260
|
gitHubToken: options.gitHubToken,
|
|
215
|
-
// Default useLoggedInUser to false when gitHubToken is provided, otherwise true
|
|
261
|
+
// Default useLoggedInUser to false when gitHubToken is provided, otherwise true.
|
|
216
262
|
useLoggedInUser: options.useLoggedInUser ?? (options.gitHubToken ? false : true),
|
|
217
263
|
telemetry: options.telemetry,
|
|
218
|
-
|
|
219
|
-
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0
|
|
264
|
+
baseDirectory: options.baseDirectory,
|
|
265
|
+
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
266
|
+
enableRemoteSessions: options.enableRemoteSessions ?? false,
|
|
267
|
+
mode: options.mode ?? "copilot-cli"
|
|
220
268
|
};
|
|
269
|
+
if (this.options.mode === "empty") {
|
|
270
|
+
const hasPersistence = this.options.baseDirectory !== void 0 || this.sessionFsConfig !== null || // External runtimes manage their own persistence layer; the SDK
|
|
271
|
+
// can't enforce it from here.
|
|
272
|
+
conn.kind === "uri" || conn.kind === "parent-process";
|
|
273
|
+
if (!hasPersistence) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
"CopilotClient was created with mode: 'empty' but neither 'baseDirectory' nor 'sessionFs' was set. Empty mode requires an explicit per-session persistence location; pick one."
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
221
279
|
}
|
|
280
|
+
connectionExtraArgs = [];
|
|
222
281
|
/**
|
|
223
282
|
* Parse CLI URL into host and port
|
|
224
283
|
* Supports formats: "host:port", "http://host:port", "https://host:port", or just "port"
|
|
@@ -252,20 +311,37 @@ class CopilotClient {
|
|
|
252
311
|
throw new Error("sessionFs.conventions must be either 'windows' or 'posix'");
|
|
253
312
|
}
|
|
254
313
|
}
|
|
314
|
+
setupSessionFs(session, config) {
|
|
315
|
+
if (!this.sessionFsConfig) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (!config.createSessionFsProvider) {
|
|
319
|
+
throw new Error(
|
|
320
|
+
"createSessionFsProvider is required in session config when sessionFs is enabled in client options."
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
const provider = config.createSessionFsProvider(session);
|
|
324
|
+
if (this.sessionFsConfig.capabilities?.sqlite && !provider.sqlite) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
"SessionFsConfig declares capabilities.sqlite but the provider does not implement sqlite."
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
session.clientSessionApis.sessionFs = createSessionFsAdapter(provider);
|
|
330
|
+
}
|
|
255
331
|
/**
|
|
256
332
|
* Starts the CLI server and establishes a connection.
|
|
257
333
|
*
|
|
258
334
|
* If connecting to an external server (via cliUrl), only establishes the connection.
|
|
259
335
|
* Otherwise, spawns the CLI server process and then connects.
|
|
260
336
|
*
|
|
261
|
-
* This method is called automatically
|
|
337
|
+
* This method is called automatically the first time you create or resume a session.
|
|
262
338
|
*
|
|
263
339
|
* @returns A promise that resolves when the connection is established
|
|
264
340
|
* @throws Error if the server fails to start or the connection fails
|
|
265
341
|
*
|
|
266
342
|
* @example
|
|
267
343
|
* ```typescript
|
|
268
|
-
* const client = new CopilotClient(
|
|
344
|
+
* const client = new CopilotClient();
|
|
269
345
|
* await client.start();
|
|
270
346
|
* // Now ready to create sessions
|
|
271
347
|
* ```
|
|
@@ -285,7 +361,8 @@ class CopilotClient {
|
|
|
285
361
|
await this.connection.sendRequest("sessionFs.setProvider", {
|
|
286
362
|
initialCwd: this.sessionFsConfig.initialCwd,
|
|
287
363
|
sessionStatePath: this.sessionFsConfig.sessionStatePath,
|
|
288
|
-
conventions: this.sessionFsConfig.conventions
|
|
364
|
+
conventions: this.sessionFsConfig.conventions,
|
|
365
|
+
capabilities: this.sessionFsConfig.capabilities
|
|
289
366
|
});
|
|
290
367
|
}
|
|
291
368
|
this.state = "connected";
|
|
@@ -359,8 +436,15 @@ class CopilotClient {
|
|
|
359
436
|
}
|
|
360
437
|
this.modelsCache = null;
|
|
361
438
|
if (this.socket) {
|
|
439
|
+
const socket = this.socket;
|
|
440
|
+
this.socket = null;
|
|
362
441
|
try {
|
|
363
|
-
|
|
442
|
+
if (!socket.destroyed) {
|
|
443
|
+
await new Promise((resolve) => {
|
|
444
|
+
socket.once("close", () => resolve());
|
|
445
|
+
socket.end();
|
|
446
|
+
});
|
|
447
|
+
}
|
|
364
448
|
} catch (error) {
|
|
365
449
|
errors.push(
|
|
366
450
|
new Error(
|
|
@@ -368,11 +452,18 @@ class CopilotClient {
|
|
|
368
452
|
)
|
|
369
453
|
);
|
|
370
454
|
}
|
|
371
|
-
this.socket = null;
|
|
372
455
|
}
|
|
373
456
|
if (this.cliProcess && !this.isExternalServer) {
|
|
457
|
+
const child = this.cliProcess;
|
|
458
|
+
this.cliProcess = null;
|
|
374
459
|
try {
|
|
375
|
-
|
|
460
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
461
|
+
const exited = new Promise((resolve) => {
|
|
462
|
+
child.once("exit", () => resolve());
|
|
463
|
+
});
|
|
464
|
+
child.kill();
|
|
465
|
+
await exited;
|
|
466
|
+
}
|
|
376
467
|
} catch (error) {
|
|
377
468
|
errors.push(
|
|
378
469
|
new Error(
|
|
@@ -380,18 +471,32 @@ class CopilotClient {
|
|
|
380
471
|
)
|
|
381
472
|
);
|
|
382
473
|
}
|
|
383
|
-
this.cliProcess = null;
|
|
384
474
|
}
|
|
385
475
|
if (this.cliStartTimeout) {
|
|
386
476
|
clearTimeout(this.cliStartTimeout);
|
|
387
477
|
this.cliStartTimeout = null;
|
|
388
478
|
}
|
|
389
479
|
this.state = "disconnected";
|
|
390
|
-
this.
|
|
480
|
+
this.runtimePort = null;
|
|
391
481
|
this.stderrBuffer = "";
|
|
392
482
|
this.processExitPromise = null;
|
|
393
483
|
return errors;
|
|
394
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Alias for {@link stop} that lets `CopilotClient` participate in `await using`
|
|
487
|
+
* blocks for automatic cleanup.
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* await using client = new CopilotClient();
|
|
492
|
+
* const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
493
|
+
* await session.sendAndWait("Hello");
|
|
494
|
+
* // client.stop() is called automatically when the block exits.
|
|
495
|
+
* ```
|
|
496
|
+
*/
|
|
497
|
+
async [Symbol.asyncDispose]() {
|
|
498
|
+
await this.stop();
|
|
499
|
+
}
|
|
395
500
|
/**
|
|
396
501
|
* Forcefully stops the CLI server without graceful cleanup.
|
|
397
502
|
*
|
|
@@ -448,7 +553,7 @@ class CopilotClient {
|
|
|
448
553
|
this.cliStartTimeout = null;
|
|
449
554
|
}
|
|
450
555
|
this.state = "disconnected";
|
|
451
|
-
this.
|
|
556
|
+
this.runtimePort = null;
|
|
452
557
|
this.stderrBuffer = "";
|
|
453
558
|
this.processExitPromise = null;
|
|
454
559
|
}
|
|
@@ -456,12 +561,11 @@ class CopilotClient {
|
|
|
456
561
|
* Creates a new conversation session with the Copilot CLI.
|
|
457
562
|
*
|
|
458
563
|
* Sessions maintain conversation state, handle events, and manage tool execution.
|
|
459
|
-
* If the client is not connected
|
|
460
|
-
* start the connection.
|
|
564
|
+
* If the client is not connected, this method automatically starts the connection.
|
|
461
565
|
*
|
|
462
566
|
* @param config - Optional configuration for the session
|
|
463
567
|
* @returns A promise that resolves with the created session
|
|
464
|
-
* @throws Error if the client
|
|
568
|
+
* @throws Error if the client fails to start
|
|
465
569
|
*
|
|
466
570
|
* @example
|
|
467
571
|
* ```typescript
|
|
@@ -481,66 +585,190 @@ class CopilotClient {
|
|
|
481
585
|
* });
|
|
482
586
|
* ```
|
|
483
587
|
*/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
588
|
+
/**
|
|
589
|
+
* Normalizes session-level tool filter options. Converts {@link ToolSet}
|
|
590
|
+
* instances to plain string arrays, rejects misuse (bare `"*"`) and the
|
|
591
|
+
* missing-availableTools case in `mode = "empty"`.
|
|
592
|
+
*
|
|
593
|
+
* The SDK always sends `toolFilterPrecedence: "excluded"` so callers can
|
|
594
|
+
* compose include + exclude lists naturally (e.g. "everything matching X
|
|
595
|
+
* except Y") regardless of mode. Allowlist-precedence is intentionally not
|
|
596
|
+
* exposed — it's available on the runtime side as a CLI-only concession to
|
|
597
|
+
* legacy behavior, but SDK consumers always get the composable semantics.
|
|
598
|
+
*
|
|
599
|
+
* @internal
|
|
600
|
+
*/
|
|
601
|
+
resolveToolFilterOptions(config) {
|
|
602
|
+
const availableTools = toolFilterListToArray(config.availableTools);
|
|
603
|
+
const excludedTools = toolFilterListToArray(config.excludedTools);
|
|
604
|
+
validateToolFilterList("availableTools", availableTools);
|
|
605
|
+
validateToolFilterList("excludedTools", excludedTools);
|
|
606
|
+
if (this.options.mode === "empty") {
|
|
607
|
+
if (availableTools === void 0) {
|
|
608
|
+
throw new Error(
|
|
609
|
+
"CopilotClient is in mode: 'empty' but the session config did not specify 'availableTools'. Empty mode requires every session to explicitly opt into the tools it wants \u2014 e.g. `new ToolSet().addBuiltIn(BuiltInTools.Isolated)`."
|
|
610
|
+
);
|
|
495
611
|
}
|
|
496
612
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
613
|
+
return { availableTools, excludedTools, toolFilterPrecedence: "excluded" };
|
|
614
|
+
}
|
|
615
|
+
/** Mode-specific defaults spread under the caller's config (app values win). */
|
|
616
|
+
configDefaultsForMode() {
|
|
617
|
+
if (this.options.mode === "empty") {
|
|
618
|
+
return {
|
|
619
|
+
enableSessionTelemetry: false,
|
|
620
|
+
mcpOAuthTokenStorage: "in-memory",
|
|
621
|
+
skipEmbeddingRetrieval: true,
|
|
622
|
+
embeddingCacheStorage: "in-memory",
|
|
623
|
+
enableOnDemandInstructionDiscovery: false,
|
|
624
|
+
enableFileHooks: false,
|
|
625
|
+
enableHostGitOperations: false,
|
|
626
|
+
enableSessionStore: false,
|
|
627
|
+
enableSkills: false
|
|
628
|
+
};
|
|
509
629
|
}
|
|
510
|
-
|
|
511
|
-
|
|
630
|
+
return {};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Returns the systemMessage config to use, adjusted for the current mode.
|
|
634
|
+
* In empty mode we ensure the environment_context section is removed
|
|
635
|
+
* unless the app has already taken control of it. `append` (and
|
|
636
|
+
* unspecified) mode is promoted to `customize` so we can also strip
|
|
637
|
+
* environment_context; the caller's `content` is preserved verbatim
|
|
638
|
+
* because the runtime appends it as additional instructions in both
|
|
639
|
+
* customize and append modes.
|
|
640
|
+
*/
|
|
641
|
+
getSystemMessageConfigForMode(supplied) {
|
|
642
|
+
if (this.options.mode !== "empty") return supplied;
|
|
643
|
+
if (!supplied) {
|
|
644
|
+
return {
|
|
645
|
+
mode: "customize",
|
|
646
|
+
sections: { environment_context: { action: "remove" } }
|
|
647
|
+
};
|
|
512
648
|
}
|
|
513
|
-
|
|
514
|
-
|
|
649
|
+
switch (supplied.mode) {
|
|
650
|
+
case "replace":
|
|
651
|
+
return supplied;
|
|
652
|
+
case "customize":
|
|
653
|
+
if (supplied.sections?.environment_context) return supplied;
|
|
654
|
+
return {
|
|
655
|
+
...supplied,
|
|
656
|
+
sections: {
|
|
657
|
+
...supplied.sections,
|
|
658
|
+
environment_context: { action: "remove" }
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
case "append":
|
|
662
|
+
case void 0:
|
|
663
|
+
return {
|
|
664
|
+
mode: "customize",
|
|
665
|
+
content: supplied.content,
|
|
666
|
+
sections: { environment_context: { action: "remove" } }
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Mode-specific options applied via session.options.update after create/resume.
|
|
672
|
+
*
|
|
673
|
+
* In empty mode, defaults the four overridable feature flags to safe values
|
|
674
|
+
* (caller values from `config` win). `installedPlugins=[]` is unconditional
|
|
675
|
+
* in empty mode — apps that need custom plugins should switch modes.
|
|
676
|
+
*/
|
|
677
|
+
async updateSessionOptionsForMode(session, config) {
|
|
678
|
+
const patch = {};
|
|
679
|
+
if (this.options.mode === "empty") {
|
|
680
|
+
patch.skipCustomInstructions = config.skipCustomInstructions ?? true;
|
|
681
|
+
patch.customAgentsLocalOnly = config.customAgentsLocalOnly ?? true;
|
|
682
|
+
patch.coauthorEnabled = config.coauthorEnabled ?? false;
|
|
683
|
+
patch.manageScheduleEnabled = config.manageScheduleEnabled ?? false;
|
|
684
|
+
patch.installedPlugins = [];
|
|
685
|
+
} else {
|
|
686
|
+
if (config.skipCustomInstructions !== void 0)
|
|
687
|
+
patch.skipCustomInstructions = config.skipCustomInstructions;
|
|
688
|
+
if (config.customAgentsLocalOnly !== void 0)
|
|
689
|
+
patch.customAgentsLocalOnly = config.customAgentsLocalOnly;
|
|
690
|
+
if (config.coauthorEnabled !== void 0)
|
|
691
|
+
patch.coauthorEnabled = config.coauthorEnabled;
|
|
692
|
+
if (config.manageScheduleEnabled !== void 0)
|
|
693
|
+
patch.manageScheduleEnabled = config.manageScheduleEnabled;
|
|
694
|
+
}
|
|
695
|
+
if (Object.keys(patch).length === 0) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
try {
|
|
699
|
+
await session.rpc.options.update(patch);
|
|
700
|
+
} catch (e) {
|
|
701
|
+
try {
|
|
702
|
+
await session.disconnect();
|
|
703
|
+
} catch {
|
|
704
|
+
}
|
|
705
|
+
throw e;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async createSession(config) {
|
|
709
|
+
if (!this.connection) {
|
|
710
|
+
await this.start();
|
|
515
711
|
}
|
|
712
|
+
config = { ...this.configDefaultsForMode(), ...config };
|
|
713
|
+
config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
|
|
714
|
+
const callerSessionId = config.sessionId;
|
|
715
|
+
const useServerGeneratedId = config.cloud != null && callerSessionId == null;
|
|
716
|
+
const localSessionId = useServerGeneratedId ? void 0 : callerSessionId ?? randomUUID();
|
|
516
717
|
const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
|
|
517
718
|
config.systemMessage
|
|
518
719
|
);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
);
|
|
720
|
+
const initializeSession = (sessionId) => {
|
|
721
|
+
const s = new CopilotSession(
|
|
722
|
+
sessionId,
|
|
723
|
+
this.connection,
|
|
724
|
+
void 0,
|
|
725
|
+
this.onGetTraceContext
|
|
726
|
+
);
|
|
727
|
+
s.registerTools(config.tools);
|
|
728
|
+
s.registerCanvases(config.canvases);
|
|
729
|
+
s.registerCommands(config.commands);
|
|
730
|
+
s.registerPermissionHandler(config.onPermissionRequest);
|
|
731
|
+
if (config.onUserInputRequest) {
|
|
732
|
+
s.registerUserInputHandler(config.onUserInputRequest);
|
|
733
|
+
}
|
|
734
|
+
if (config.onElicitationRequest) {
|
|
735
|
+
s.registerElicitationHandler(config.onElicitationRequest);
|
|
736
|
+
}
|
|
737
|
+
if (config.onExitPlanModeRequest) {
|
|
738
|
+
s.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
739
|
+
}
|
|
740
|
+
if (config.onAutoModeSwitchRequest) {
|
|
741
|
+
s.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
|
|
742
|
+
}
|
|
743
|
+
if (config.hooks) {
|
|
744
|
+
s.registerHooks(config.hooks);
|
|
745
|
+
}
|
|
746
|
+
if (transformCallbacks) {
|
|
747
|
+
s.registerTransformCallbacks(transformCallbacks);
|
|
748
|
+
}
|
|
749
|
+
if (config.onEvent) {
|
|
750
|
+
s.on(config.onEvent);
|
|
535
751
|
}
|
|
752
|
+
this.sessions.set(sessionId, s);
|
|
753
|
+
this.setupSessionFs(s, config);
|
|
754
|
+
return s;
|
|
755
|
+
};
|
|
756
|
+
let session;
|
|
757
|
+
let registeredId;
|
|
758
|
+
if (localSessionId !== void 0) {
|
|
759
|
+
session = initializeSession(localSessionId);
|
|
760
|
+
registeredId = localSessionId;
|
|
536
761
|
}
|
|
762
|
+
const toolFilterOptions = this.resolveToolFilterOptions(config);
|
|
537
763
|
try {
|
|
538
764
|
const response = await this.connection.sendRequest("session.create", {
|
|
539
765
|
...await getTraceContext(this.onGetTraceContext),
|
|
540
766
|
model: config.model,
|
|
541
|
-
sessionId,
|
|
767
|
+
sessionId: localSessionId,
|
|
542
768
|
clientName: config.clientName,
|
|
543
769
|
reasoningEffort: config.reasoningEffort,
|
|
770
|
+
reasoningSummary: config.reasoningSummary,
|
|
771
|
+
contextTier: config.contextTier,
|
|
544
772
|
tools: config.tools?.map((tool) => ({
|
|
545
773
|
name: tool.name,
|
|
546
774
|
description: tool.description,
|
|
@@ -548,40 +776,82 @@ class CopilotClient {
|
|
|
548
776
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
549
777
|
skipPermission: tool.skipPermission
|
|
550
778
|
})),
|
|
779
|
+
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
780
|
+
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
781
|
+
requestExtensions: config.requestExtensions,
|
|
782
|
+
extensionSdkPath: config.extensionSdkPath,
|
|
783
|
+
extensionInfo: config.extensionInfo,
|
|
551
784
|
commands: config.commands?.map((cmd) => ({
|
|
552
785
|
name: cmd.name,
|
|
553
786
|
description: cmd.description
|
|
554
787
|
})),
|
|
555
788
|
systemMessage: wireSystemMessage,
|
|
556
|
-
availableTools:
|
|
557
|
-
excludedTools:
|
|
789
|
+
availableTools: toolFilterOptions.availableTools,
|
|
790
|
+
excludedTools: toolFilterOptions.excludedTools,
|
|
791
|
+
toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
|
|
558
792
|
provider: config.provider,
|
|
793
|
+
enableSessionTelemetry: config.enableSessionTelemetry,
|
|
559
794
|
modelCapabilities: config.modelCapabilities,
|
|
560
|
-
|
|
795
|
+
largeOutput: toWireLargeOutput(config.largeOutput),
|
|
796
|
+
requestPermission: !!config.onPermissionRequest,
|
|
561
797
|
requestUserInput: !!config.onUserInputRequest,
|
|
562
798
|
requestElicitation: !!config.onElicitationRequest,
|
|
799
|
+
...config.enableMcpApps ? { requestMcpApps: true } : {},
|
|
800
|
+
requestExitPlanMode: !!config.onExitPlanModeRequest,
|
|
801
|
+
requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
|
|
563
802
|
hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
|
|
564
803
|
workingDirectory: config.workingDirectory,
|
|
565
804
|
streaming: config.streaming,
|
|
566
805
|
includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
|
|
567
|
-
mcpServers: config.mcpServers,
|
|
806
|
+
mcpServers: toWireMcpServers(config.mcpServers),
|
|
807
|
+
mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
|
|
568
808
|
envValueMode: "direct",
|
|
569
|
-
customAgents: config.customAgents,
|
|
809
|
+
customAgents: toWireCustomAgents(config.customAgents),
|
|
570
810
|
defaultAgent: config.defaultAgent,
|
|
571
811
|
agent: config.agent,
|
|
572
|
-
configDir: config.
|
|
812
|
+
configDir: config.configDirectory,
|
|
573
813
|
enableConfigDiscovery: config.enableConfigDiscovery,
|
|
814
|
+
skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
|
|
815
|
+
embeddingCacheStorage: config.embeddingCacheStorage,
|
|
816
|
+
organizationCustomInstructions: config.organizationCustomInstructions,
|
|
817
|
+
enableOnDemandInstructionDiscovery: config.enableOnDemandInstructionDiscovery,
|
|
818
|
+
enableFileHooks: config.enableFileHooks,
|
|
819
|
+
enableHostGitOperations: config.enableHostGitOperations,
|
|
820
|
+
enableSessionStore: config.enableSessionStore,
|
|
821
|
+
enableSkills: config.enableSkills,
|
|
574
822
|
skillDirectories: config.skillDirectories,
|
|
823
|
+
pluginDirectories: config.pluginDirectories,
|
|
575
824
|
instructionDirectories: config.instructionDirectories,
|
|
576
825
|
disabledSkills: config.disabledSkills,
|
|
577
826
|
infiniteSessions: config.infiniteSessions,
|
|
578
|
-
gitHubToken: config.gitHubToken
|
|
827
|
+
gitHubToken: config.gitHubToken,
|
|
828
|
+
remoteSession: config.remoteSession,
|
|
829
|
+
cloud: config.cloud
|
|
579
830
|
});
|
|
580
|
-
const {
|
|
831
|
+
const {
|
|
832
|
+
sessionId: returnedSessionId,
|
|
833
|
+
workspacePath,
|
|
834
|
+
capabilities
|
|
835
|
+
} = response;
|
|
836
|
+
if (!returnedSessionId) {
|
|
837
|
+
throw new Error("session.create response did not include a sessionId");
|
|
838
|
+
}
|
|
839
|
+
if (localSessionId !== void 0 && localSessionId !== returnedSessionId) {
|
|
840
|
+
throw new Error(
|
|
841
|
+
`session.create returned sessionId ${returnedSessionId} but the caller requested ${localSessionId}`
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
if (session === void 0) {
|
|
845
|
+
session = initializeSession(returnedSessionId);
|
|
846
|
+
registeredId = returnedSessionId;
|
|
847
|
+
}
|
|
581
848
|
session["_workspacePath"] = workspacePath;
|
|
582
849
|
session.setCapabilities(capabilities);
|
|
850
|
+
await this.updateSessionOptionsForMode(session, config);
|
|
583
851
|
} catch (e) {
|
|
584
|
-
|
|
852
|
+
if (registeredId !== void 0) {
|
|
853
|
+
this.sessions.delete(registeredId);
|
|
854
|
+
}
|
|
585
855
|
throw e;
|
|
586
856
|
}
|
|
587
857
|
return session;
|
|
@@ -611,17 +881,8 @@ class CopilotClient {
|
|
|
611
881
|
* ```
|
|
612
882
|
*/
|
|
613
883
|
async resumeSession(sessionId, config) {
|
|
614
|
-
if (!config?.onPermissionRequest) {
|
|
615
|
-
throw new Error(
|
|
616
|
-
"An onPermissionRequest handler is required when resuming a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }."
|
|
617
|
-
);
|
|
618
|
-
}
|
|
619
884
|
if (!this.connection) {
|
|
620
|
-
|
|
621
|
-
await this.start();
|
|
622
|
-
} else {
|
|
623
|
-
throw new Error("Client not connected. Call start() first.");
|
|
624
|
-
}
|
|
885
|
+
await this.start();
|
|
625
886
|
}
|
|
626
887
|
const session = new CopilotSession(
|
|
627
888
|
sessionId,
|
|
@@ -630,6 +891,7 @@ class CopilotClient {
|
|
|
630
891
|
this.onGetTraceContext
|
|
631
892
|
);
|
|
632
893
|
session.registerTools(config.tools);
|
|
894
|
+
session.registerCanvases(config.canvases);
|
|
633
895
|
session.registerCommands(config.commands);
|
|
634
896
|
session.registerPermissionHandler(config.onPermissionRequest);
|
|
635
897
|
if (config.onUserInputRequest) {
|
|
@@ -638,9 +900,17 @@ class CopilotClient {
|
|
|
638
900
|
if (config.onElicitationRequest) {
|
|
639
901
|
session.registerElicitationHandler(config.onElicitationRequest);
|
|
640
902
|
}
|
|
903
|
+
if (config.onExitPlanModeRequest) {
|
|
904
|
+
session.registerExitPlanModeHandler(config.onExitPlanModeRequest);
|
|
905
|
+
}
|
|
906
|
+
if (config.onAutoModeSwitchRequest) {
|
|
907
|
+
session.registerAutoModeSwitchHandler(config.onAutoModeSwitchRequest);
|
|
908
|
+
}
|
|
641
909
|
if (config.hooks) {
|
|
642
910
|
session.registerHooks(config.hooks);
|
|
643
911
|
}
|
|
912
|
+
config = { ...this.configDefaultsForMode(), ...config };
|
|
913
|
+
config.systemMessage = this.getSystemMessageConfigForMode(config.systemMessage);
|
|
644
914
|
const { wirePayload: wireSystemMessage, transformCallbacks } = extractTransformCallbacks(
|
|
645
915
|
config.systemMessage
|
|
646
916
|
);
|
|
@@ -651,17 +921,8 @@ class CopilotClient {
|
|
|
651
921
|
session.on(config.onEvent);
|
|
652
922
|
}
|
|
653
923
|
this.sessions.set(sessionId, session);
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
session.clientSessionApis.sessionFs = createSessionFsAdapter(
|
|
657
|
-
config.createSessionFsHandler(session)
|
|
658
|
-
);
|
|
659
|
-
} else {
|
|
660
|
-
throw new Error(
|
|
661
|
-
"createSessionFsHandler is required in session config when sessionFs is enabled in client options."
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
924
|
+
this.setupSessionFs(session, config);
|
|
925
|
+
const toolFilterOptions = this.resolveToolFilterOptions(config);
|
|
665
926
|
try {
|
|
666
927
|
const response = await this.connection.sendRequest("session.resume", {
|
|
667
928
|
...await getTraceContext(this.onGetTraceContext),
|
|
@@ -669,9 +930,13 @@ class CopilotClient {
|
|
|
669
930
|
clientName: config.clientName,
|
|
670
931
|
model: config.model,
|
|
671
932
|
reasoningEffort: config.reasoningEffort,
|
|
933
|
+
reasoningSummary: config.reasoningSummary,
|
|
934
|
+
contextTier: config.contextTier,
|
|
672
935
|
systemMessage: wireSystemMessage,
|
|
673
|
-
availableTools:
|
|
674
|
-
excludedTools:
|
|
936
|
+
availableTools: toolFilterOptions.availableTools,
|
|
937
|
+
excludedTools: toolFilterOptions.excludedTools,
|
|
938
|
+
toolFilterPrecedence: toolFilterOptions.toolFilterPrecedence,
|
|
939
|
+
enableSessionTelemetry: config.enableSessionTelemetry,
|
|
675
940
|
tools: config.tools?.map((tool) => ({
|
|
676
941
|
name: tool.name,
|
|
677
942
|
description: tool.description,
|
|
@@ -679,58 +944,66 @@ class CopilotClient {
|
|
|
679
944
|
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
680
945
|
skipPermission: tool.skipPermission
|
|
681
946
|
})),
|
|
947
|
+
canvases: config.canvases?.map((canvas) => canvas.declaration),
|
|
948
|
+
requestCanvasRenderer: config.requestCanvasRenderer,
|
|
949
|
+
requestExtensions: config.requestExtensions,
|
|
950
|
+
extensionSdkPath: config.extensionSdkPath,
|
|
951
|
+
extensionInfo: config.extensionInfo,
|
|
682
952
|
commands: config.commands?.map((cmd) => ({
|
|
683
953
|
name: cmd.name,
|
|
684
954
|
description: cmd.description
|
|
685
955
|
})),
|
|
686
956
|
provider: config.provider,
|
|
687
957
|
modelCapabilities: config.modelCapabilities,
|
|
958
|
+
largeOutput: toWireLargeOutput(config.largeOutput),
|
|
688
959
|
requestPermission: config.onPermissionRequest !== defaultJoinSessionPermissionHandler,
|
|
689
960
|
requestUserInput: !!config.onUserInputRequest,
|
|
690
961
|
requestElicitation: !!config.onElicitationRequest,
|
|
962
|
+
...config.enableMcpApps ? { requestMcpApps: true } : {},
|
|
963
|
+
requestExitPlanMode: !!config.onExitPlanModeRequest,
|
|
964
|
+
requestAutoModeSwitch: !!config.onAutoModeSwitchRequest,
|
|
691
965
|
hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)),
|
|
692
966
|
workingDirectory: config.workingDirectory,
|
|
693
|
-
configDir: config.
|
|
967
|
+
configDir: config.configDirectory,
|
|
694
968
|
enableConfigDiscovery: config.enableConfigDiscovery,
|
|
969
|
+
skipEmbeddingRetrieval: config.skipEmbeddingRetrieval,
|
|
970
|
+
embeddingCacheStorage: config.embeddingCacheStorage,
|
|
971
|
+
organizationCustomInstructions: config.organizationCustomInstructions,
|
|
972
|
+
enableOnDemandInstructionDiscovery: config.enableOnDemandInstructionDiscovery,
|
|
973
|
+
enableFileHooks: config.enableFileHooks,
|
|
974
|
+
enableHostGitOperations: config.enableHostGitOperations,
|
|
975
|
+
enableSessionStore: config.enableSessionStore,
|
|
976
|
+
enableSkills: config.enableSkills,
|
|
695
977
|
streaming: config.streaming,
|
|
696
978
|
includeSubAgentStreamingEvents: config.includeSubAgentStreamingEvents ?? true,
|
|
697
|
-
mcpServers: config.mcpServers,
|
|
979
|
+
mcpServers: toWireMcpServers(config.mcpServers),
|
|
980
|
+
mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
|
|
698
981
|
envValueMode: "direct",
|
|
699
|
-
customAgents: config.customAgents,
|
|
982
|
+
customAgents: toWireCustomAgents(config.customAgents),
|
|
700
983
|
defaultAgent: config.defaultAgent,
|
|
701
984
|
agent: config.agent,
|
|
702
985
|
skillDirectories: config.skillDirectories,
|
|
986
|
+
pluginDirectories: config.pluginDirectories,
|
|
703
987
|
instructionDirectories: config.instructionDirectories,
|
|
704
988
|
disabledSkills: config.disabledSkills,
|
|
705
989
|
infiniteSessions: config.infiniteSessions,
|
|
706
|
-
disableResume: config.
|
|
990
|
+
disableResume: config.suppressResumeEvent,
|
|
707
991
|
continuePendingWork: config.continuePendingWork,
|
|
708
|
-
gitHubToken: config.gitHubToken
|
|
992
|
+
gitHubToken: config.gitHubToken,
|
|
993
|
+
remoteSession: config.remoteSession,
|
|
994
|
+
openCanvases: config.openCanvases
|
|
709
995
|
});
|
|
710
|
-
const { workspacePath, capabilities } = response;
|
|
996
|
+
const { workspacePath, capabilities, openCanvases } = response;
|
|
711
997
|
session["_workspacePath"] = workspacePath;
|
|
712
998
|
session.setCapabilities(capabilities);
|
|
999
|
+
session.setOpenCanvases(openCanvases ?? []);
|
|
1000
|
+
await this.updateSessionOptionsForMode(session, config);
|
|
713
1001
|
} catch (e) {
|
|
714
1002
|
this.sessions.delete(sessionId);
|
|
715
1003
|
throw e;
|
|
716
1004
|
}
|
|
717
1005
|
return session;
|
|
718
1006
|
}
|
|
719
|
-
/**
|
|
720
|
-
* Gets the current connection state of the client.
|
|
721
|
-
*
|
|
722
|
-
* @returns The current connection state: "disconnected", "connecting", "connected", or "error"
|
|
723
|
-
*
|
|
724
|
-
* @example
|
|
725
|
-
* ```typescript
|
|
726
|
-
* if (client.getState() === "connected") {
|
|
727
|
-
* const session = await client.createSession({ onPermissionRequest: approveAll });
|
|
728
|
-
* }
|
|
729
|
-
* ```
|
|
730
|
-
*/
|
|
731
|
-
getState() {
|
|
732
|
-
return this.state;
|
|
733
|
-
}
|
|
734
1007
|
/**
|
|
735
1008
|
* Sends a ping request to the server to verify connectivity.
|
|
736
1009
|
*
|
|
@@ -843,7 +1116,7 @@ class CopilotClient {
|
|
|
843
1116
|
);
|
|
844
1117
|
serverVersion = result.protocolVersion;
|
|
845
1118
|
} catch (err) {
|
|
846
|
-
if (err instanceof ResponseError && err.code === ErrorCodes.MethodNotFound) {
|
|
1119
|
+
if (err instanceof ResponseError && (err.code === ErrorCodes.MethodNotFound || err.message === "Unhandled method connect")) {
|
|
847
1120
|
serverVersion = (await raceAgainstExit(this.ping())).protocolVersion;
|
|
848
1121
|
} else {
|
|
849
1122
|
throw err;
|
|
@@ -932,8 +1205,13 @@ class CopilotClient {
|
|
|
932
1205
|
if (!this.connection) {
|
|
933
1206
|
throw new Error("Client not connected");
|
|
934
1207
|
}
|
|
1208
|
+
let wireFilter;
|
|
1209
|
+
if (filter) {
|
|
1210
|
+
const { workingDirectory, ...rest } = filter;
|
|
1211
|
+
wireFilter = { ...rest, cwd: workingDirectory };
|
|
1212
|
+
}
|
|
935
1213
|
const response = await this.connection.sendRequest("session.list", {
|
|
936
|
-
filter
|
|
1214
|
+
filter: wireFilter
|
|
937
1215
|
});
|
|
938
1216
|
const { sessions } = response;
|
|
939
1217
|
return sessions.map(CopilotClient.toSessionMetadata);
|
|
@@ -968,13 +1246,19 @@ class CopilotClient {
|
|
|
968
1246
|
return CopilotClient.toSessionMetadata(session);
|
|
969
1247
|
}
|
|
970
1248
|
static toSessionMetadata(raw) {
|
|
1249
|
+
const { context } = raw;
|
|
971
1250
|
return {
|
|
972
1251
|
sessionId: raw.sessionId,
|
|
973
1252
|
startTime: new Date(raw.startTime),
|
|
974
1253
|
modifiedTime: new Date(raw.modifiedTime),
|
|
975
1254
|
summary: raw.summary,
|
|
976
1255
|
isRemote: raw.isRemote,
|
|
977
|
-
context:
|
|
1256
|
+
context: context ? {
|
|
1257
|
+
workingDirectory: context.cwd,
|
|
1258
|
+
gitRoot: context.gitRoot,
|
|
1259
|
+
repository: context.repository,
|
|
1260
|
+
branch: context.branch
|
|
1261
|
+
} : void 0
|
|
978
1262
|
};
|
|
979
1263
|
}
|
|
980
1264
|
/**
|
|
@@ -1027,7 +1311,7 @@ class CopilotClient {
|
|
|
1027
1311
|
throw new Error(result.error || "Failed to set foreground session");
|
|
1028
1312
|
}
|
|
1029
1313
|
}
|
|
1030
|
-
|
|
1314
|
+
onLifecycle(eventTypeOrHandler, handler) {
|
|
1031
1315
|
if (typeof eventTypeOrHandler === "string" && handler) {
|
|
1032
1316
|
const eventType = eventTypeOrHandler;
|
|
1033
1317
|
if (!this.typedLifecycleHandlers.has(eventType)) {
|
|
@@ -1054,17 +1338,17 @@ class CopilotClient {
|
|
|
1054
1338
|
async startCLIServer() {
|
|
1055
1339
|
return new Promise((resolve, reject) => {
|
|
1056
1340
|
this.stderrBuffer = "";
|
|
1057
|
-
const args = [
|
|
1058
|
-
|
|
1059
|
-
"--
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
this.options.logLevel
|
|
1063
|
-
];
|
|
1064
|
-
if (this.options.useStdio) {
|
|
1341
|
+
const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
|
|
1342
|
+
if (this.options.logLevel) {
|
|
1343
|
+
args.push("--log-level", this.options.logLevel);
|
|
1344
|
+
}
|
|
1345
|
+
if (this.connectionConfig.kind === "stdio") {
|
|
1065
1346
|
args.push("--stdio");
|
|
1066
|
-
} else if (this.
|
|
1067
|
-
|
|
1347
|
+
} else if (this.connectionConfig.kind === "tcp") {
|
|
1348
|
+
const requestedPort = this.connectionConfig.port ?? 0;
|
|
1349
|
+
if (requestedPort > 0) {
|
|
1350
|
+
args.push("--port", requestedPort.toString());
|
|
1351
|
+
}
|
|
1068
1352
|
}
|
|
1069
1353
|
if (this.options.gitHubToken) {
|
|
1070
1354
|
args.push("--auth-token-env", "COPILOT_SDK_AUTH_TOKEN");
|
|
@@ -1078,7 +1362,10 @@ class CopilotClient {
|
|
|
1078
1362
|
this.options.sessionIdleTimeoutSeconds.toString()
|
|
1079
1363
|
);
|
|
1080
1364
|
}
|
|
1081
|
-
|
|
1365
|
+
if (this.options.enableRemoteSessions) {
|
|
1366
|
+
args.push("--remote");
|
|
1367
|
+
}
|
|
1368
|
+
const envWithoutNodeDebug = { ...this.resolvedEnv };
|
|
1082
1369
|
delete envWithoutNodeDebug.NODE_DEBUG;
|
|
1083
1370
|
if (this.options.gitHubToken) {
|
|
1084
1371
|
envWithoutNodeDebug.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
@@ -1086,12 +1373,15 @@ class CopilotClient {
|
|
|
1086
1373
|
if (this.effectiveConnectionToken) {
|
|
1087
1374
|
envWithoutNodeDebug.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
|
|
1088
1375
|
}
|
|
1089
|
-
if (this.options.
|
|
1090
|
-
envWithoutNodeDebug.COPILOT_HOME = this.options.
|
|
1376
|
+
if (this.options.baseDirectory) {
|
|
1377
|
+
envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
|
|
1091
1378
|
}
|
|
1092
|
-
if (
|
|
1379
|
+
if (this.options.mode === "empty") {
|
|
1380
|
+
envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
|
|
1381
|
+
}
|
|
1382
|
+
if (!this.resolvedCliPath) {
|
|
1093
1383
|
throw new Error(
|
|
1094
|
-
"Path to Copilot CLI is required. Please
|
|
1384
|
+
"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."
|
|
1095
1385
|
);
|
|
1096
1386
|
}
|
|
1097
1387
|
if (this.options.telemetry) {
|
|
@@ -1110,31 +1400,31 @@ class CopilotClient {
|
|
|
1110
1400
|
t.captureContent
|
|
1111
1401
|
);
|
|
1112
1402
|
}
|
|
1113
|
-
if (!existsSync(this.
|
|
1403
|
+
if (!existsSync(this.resolvedCliPath)) {
|
|
1114
1404
|
throw new Error(
|
|
1115
|
-
`Copilot CLI not found at ${this.
|
|
1405
|
+
`Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
|
|
1116
1406
|
);
|
|
1117
1407
|
}
|
|
1118
|
-
const stdioConfig = this.
|
|
1119
|
-
const isJsFile = this.
|
|
1408
|
+
const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
|
|
1409
|
+
const isJsFile = this.resolvedCliPath.endsWith(".js");
|
|
1120
1410
|
if (isJsFile) {
|
|
1121
|
-
this.cliProcess = spawn(getNodeExecPath(), [this.
|
|
1411
|
+
this.cliProcess = spawn(getNodeExecPath(), [this.resolvedCliPath, ...args], {
|
|
1122
1412
|
stdio: stdioConfig,
|
|
1123
|
-
cwd: this.options.
|
|
1413
|
+
cwd: this.options.workingDirectory,
|
|
1124
1414
|
env: envWithoutNodeDebug,
|
|
1125
1415
|
windowsHide: true
|
|
1126
1416
|
});
|
|
1127
1417
|
} else {
|
|
1128
|
-
this.cliProcess = spawn(this.
|
|
1418
|
+
this.cliProcess = spawn(this.resolvedCliPath, args, {
|
|
1129
1419
|
stdio: stdioConfig,
|
|
1130
|
-
cwd: this.options.
|
|
1420
|
+
cwd: this.options.workingDirectory,
|
|
1131
1421
|
env: envWithoutNodeDebug,
|
|
1132
1422
|
windowsHide: true
|
|
1133
1423
|
});
|
|
1134
1424
|
}
|
|
1135
1425
|
let stdout = "";
|
|
1136
1426
|
let resolved = false;
|
|
1137
|
-
if (this.
|
|
1427
|
+
if (this.connectionConfig.kind === "stdio") {
|
|
1138
1428
|
resolved = true;
|
|
1139
1429
|
resolve();
|
|
1140
1430
|
} else {
|
|
@@ -1142,7 +1432,7 @@ class CopilotClient {
|
|
|
1142
1432
|
stdout += data.toString();
|
|
1143
1433
|
const match = stdout.match(/listening on port (\d+)/i);
|
|
1144
1434
|
if (match && !resolved) {
|
|
1145
|
-
this.
|
|
1435
|
+
this.runtimePort = parseInt(match[1], 10);
|
|
1146
1436
|
resolved = true;
|
|
1147
1437
|
resolve();
|
|
1148
1438
|
}
|
|
@@ -1216,19 +1506,21 @@ stderr: ${stderrOutput}`
|
|
|
1216
1506
|
resolved = true;
|
|
1217
1507
|
reject(new Error("Timeout waiting for CLI server to start"));
|
|
1218
1508
|
}
|
|
1219
|
-
},
|
|
1509
|
+
}, 3e4);
|
|
1220
1510
|
});
|
|
1221
1511
|
}
|
|
1222
1512
|
/**
|
|
1223
1513
|
* Connect to the CLI server (via socket or stdio)
|
|
1224
1514
|
*/
|
|
1225
1515
|
async connectToServer() {
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1516
|
+
switch (this.connectionConfig.kind) {
|
|
1517
|
+
case "parent-process":
|
|
1518
|
+
return this.connectToParentProcessViaStdio();
|
|
1519
|
+
case "stdio":
|
|
1520
|
+
return this.connectToChildProcessViaStdio();
|
|
1521
|
+
case "tcp":
|
|
1522
|
+
case "uri":
|
|
1523
|
+
return this.connectViaTcp();
|
|
1232
1524
|
}
|
|
1233
1525
|
}
|
|
1234
1526
|
/**
|
|
@@ -1268,12 +1560,17 @@ stderr: ${stderrOutput}`
|
|
|
1268
1560
|
* Connect to the CLI server via TCP socket
|
|
1269
1561
|
*/
|
|
1270
1562
|
async connectViaTcp() {
|
|
1271
|
-
if (!this.
|
|
1563
|
+
if (!this.runtimePort) {
|
|
1272
1564
|
throw new Error("Server port not available");
|
|
1273
1565
|
}
|
|
1274
1566
|
return new Promise((resolve, reject) => {
|
|
1275
1567
|
this.socket = new Socket();
|
|
1276
|
-
|
|
1568
|
+
const connectionTimeout = setTimeout(() => {
|
|
1569
|
+
this.socket?.destroy();
|
|
1570
|
+
reject(new Error("Timeout connecting to CLI server"));
|
|
1571
|
+
}, 1e4);
|
|
1572
|
+
this.socket.connect(this.runtimePort, this.actualHost, () => {
|
|
1573
|
+
clearTimeout(connectionTimeout);
|
|
1277
1574
|
this.connection = createMessageConnection(
|
|
1278
1575
|
new StreamMessageReader(this.socket),
|
|
1279
1576
|
new StreamMessageWriter(this.socket)
|
|
@@ -1283,6 +1580,7 @@ stderr: ${stderrOutput}`
|
|
|
1283
1580
|
resolve();
|
|
1284
1581
|
});
|
|
1285
1582
|
this.socket.on("error", (error) => {
|
|
1583
|
+
clearTimeout(connectionTimeout);
|
|
1286
1584
|
reject(new Error(`Failed to connect to CLI server: ${error.message}`));
|
|
1287
1585
|
});
|
|
1288
1586
|
});
|
|
@@ -1298,16 +1596,16 @@ stderr: ${stderrOutput}`
|
|
|
1298
1596
|
this.handleSessionLifecycleNotification(notification);
|
|
1299
1597
|
});
|
|
1300
1598
|
this.connection.onRequest(
|
|
1301
|
-
"
|
|
1302
|
-
async (params) => await this.
|
|
1599
|
+
"userInput.request",
|
|
1600
|
+
async (params) => await this.handleUserInputRequest(params)
|
|
1303
1601
|
);
|
|
1304
1602
|
this.connection.onRequest(
|
|
1305
|
-
"
|
|
1306
|
-
async (params) => await this.
|
|
1603
|
+
"exitPlanMode.request",
|
|
1604
|
+
async (params) => await this.handleExitPlanModeRequest(params)
|
|
1307
1605
|
);
|
|
1308
1606
|
this.connection.onRequest(
|
|
1309
|
-
"
|
|
1310
|
-
async (params) => await this.
|
|
1607
|
+
"autoModeSwitch.request",
|
|
1608
|
+
async (params) => await this.handleAutoModeSwitchRequest(params)
|
|
1311
1609
|
);
|
|
1312
1610
|
this.connection.onRequest(
|
|
1313
1611
|
"hooks.invoke",
|
|
@@ -1343,7 +1641,20 @@ stderr: ${stderrOutput}`
|
|
|
1343
1641
|
if (typeof notification !== "object" || !notification || !("type" in notification) || typeof notification.type !== "string" || !("sessionId" in notification) || typeof notification.sessionId !== "string") {
|
|
1344
1642
|
return;
|
|
1345
1643
|
}
|
|
1346
|
-
const
|
|
1644
|
+
const raw = notification;
|
|
1645
|
+
let metadata;
|
|
1646
|
+
if (raw.metadata && raw.metadata.startTime && raw.metadata.modifiedTime) {
|
|
1647
|
+
metadata = {
|
|
1648
|
+
startTime: new Date(raw.metadata.startTime),
|
|
1649
|
+
modifiedTime: new Date(raw.metadata.modifiedTime),
|
|
1650
|
+
summary: raw.metadata.summary
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
const event = {
|
|
1654
|
+
type: raw.type,
|
|
1655
|
+
sessionId: raw.sessionId,
|
|
1656
|
+
metadata
|
|
1657
|
+
};
|
|
1347
1658
|
const typedHandlers = this.typedLifecycleHandlers.get(event.type);
|
|
1348
1659
|
if (typedHandlers) {
|
|
1349
1660
|
for (const handler of typedHandlers) {
|
|
@@ -1375,125 +1686,55 @@ stderr: ${stderrOutput}`
|
|
|
1375
1686
|
});
|
|
1376
1687
|
return result;
|
|
1377
1688
|
}
|
|
1378
|
-
async
|
|
1379
|
-
if (!params || typeof params.sessionId !== "string" || typeof params.
|
|
1380
|
-
throw new Error("Invalid
|
|
1689
|
+
async handleExitPlanModeRequest(params) {
|
|
1690
|
+
if (!params || typeof params.sessionId !== "string" || typeof params.summary !== "string" || !Array.isArray(params.actions) || typeof params.recommendedAction !== "string") {
|
|
1691
|
+
throw new Error("Invalid exit plan mode request payload");
|
|
1381
1692
|
}
|
|
1382
1693
|
const session = this.sessions.get(params.sessionId);
|
|
1383
1694
|
if (!session) {
|
|
1384
1695
|
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1385
1696
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1697
|
+
return await session._handleExitPlanModeRequest({
|
|
1698
|
+
summary: params.summary,
|
|
1699
|
+
planContent: params.planContent,
|
|
1700
|
+
actions: params.actions,
|
|
1701
|
+
recommendedAction: params.recommendedAction
|
|
1702
|
+
});
|
|
1388
1703
|
}
|
|
1389
|
-
async
|
|
1390
|
-
if (!params || typeof params.sessionId !== "string"
|
|
1391
|
-
throw new Error("Invalid
|
|
1704
|
+
async handleAutoModeSwitchRequest(params) {
|
|
1705
|
+
if (!params || typeof params.sessionId !== "string") {
|
|
1706
|
+
throw new Error("Invalid auto mode switch request payload");
|
|
1392
1707
|
}
|
|
1393
1708
|
const session = this.sessions.get(params.sessionId);
|
|
1394
1709
|
if (!session) {
|
|
1395
1710
|
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1396
1711
|
}
|
|
1397
|
-
|
|
1712
|
+
const response = await session._handleAutoModeSwitchRequest({
|
|
1713
|
+
errorCode: params.errorCode,
|
|
1714
|
+
retryAfterSeconds: params.retryAfterSeconds
|
|
1715
|
+
});
|
|
1716
|
+
return { response };
|
|
1398
1717
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
/**
|
|
1403
|
-
* Handles a v2-style tool.call RPC request from the server.
|
|
1404
|
-
* Looks up the session and tool handler, executes it, and returns the result
|
|
1405
|
-
* in the v2 response format.
|
|
1406
|
-
*/
|
|
1407
|
-
async handleToolCallRequestV2(params) {
|
|
1408
|
-
if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") {
|
|
1409
|
-
throw new Error("Invalid tool call payload");
|
|
1718
|
+
async handleHooksInvoke(params) {
|
|
1719
|
+
if (!params || typeof params.sessionId !== "string" || typeof params.hookType !== "string") {
|
|
1720
|
+
throw new Error("Invalid hooks invoke payload");
|
|
1410
1721
|
}
|
|
1411
1722
|
const session = this.sessions.get(params.sessionId);
|
|
1412
1723
|
if (!session) {
|
|
1413
|
-
throw new Error(`
|
|
1414
|
-
}
|
|
1415
|
-
const handler = session.getToolHandler(params.toolName);
|
|
1416
|
-
if (!handler) {
|
|
1417
|
-
return {
|
|
1418
|
-
result: {
|
|
1419
|
-
textResultForLlm: `Tool '${params.toolName}' is not supported by this client instance.`,
|
|
1420
|
-
resultType: "failure",
|
|
1421
|
-
error: `tool '${params.toolName}' not supported`,
|
|
1422
|
-
toolTelemetry: {}
|
|
1423
|
-
}
|
|
1424
|
-
};
|
|
1425
|
-
}
|
|
1426
|
-
try {
|
|
1427
|
-
const traceparent = params.traceparent;
|
|
1428
|
-
const tracestate = params.tracestate;
|
|
1429
|
-
const invocation = {
|
|
1430
|
-
sessionId: params.sessionId,
|
|
1431
|
-
toolCallId: params.toolCallId,
|
|
1432
|
-
toolName: params.toolName,
|
|
1433
|
-
arguments: params.arguments,
|
|
1434
|
-
traceparent,
|
|
1435
|
-
tracestate
|
|
1436
|
-
};
|
|
1437
|
-
const result = await handler(params.arguments, invocation);
|
|
1438
|
-
return { result: this.normalizeToolResultV2(result) };
|
|
1439
|
-
} catch (error) {
|
|
1440
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1441
|
-
return {
|
|
1442
|
-
result: {
|
|
1443
|
-
textResultForLlm: "Invoking this tool produced an error. Detailed information is not available.",
|
|
1444
|
-
resultType: "failure",
|
|
1445
|
-
error: message,
|
|
1446
|
-
toolTelemetry: {}
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1724
|
+
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1449
1725
|
}
|
|
1726
|
+
const output = await session._handleHooksInvoke(params.hookType, params.input);
|
|
1727
|
+
return { output };
|
|
1450
1728
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
async handlePermissionRequestV2(params) {
|
|
1455
|
-
if (!params || typeof params.sessionId !== "string" || !params.permissionRequest) {
|
|
1456
|
-
throw new Error("Invalid permission request payload");
|
|
1729
|
+
async handleSystemMessageTransform(params) {
|
|
1730
|
+
if (!params || typeof params.sessionId !== "string" || !params.sections || typeof params.sections !== "object") {
|
|
1731
|
+
throw new Error("Invalid systemMessage.transform payload");
|
|
1457
1732
|
}
|
|
1458
1733
|
const session = this.sessions.get(params.sessionId);
|
|
1459
1734
|
if (!session) {
|
|
1460
1735
|
throw new Error(`Session not found: ${params.sessionId}`);
|
|
1461
1736
|
}
|
|
1462
|
-
|
|
1463
|
-
const result = await session._handlePermissionRequestV2(params.permissionRequest);
|
|
1464
|
-
return { result };
|
|
1465
|
-
} catch (error) {
|
|
1466
|
-
if (error instanceof Error && error.message === NO_RESULT_PERMISSION_V2_ERROR) {
|
|
1467
|
-
throw error;
|
|
1468
|
-
}
|
|
1469
|
-
return {
|
|
1470
|
-
result: {
|
|
1471
|
-
kind: "user-not-available"
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
normalizeToolResultV2(result) {
|
|
1477
|
-
if (result === void 0 || result === null) {
|
|
1478
|
-
return {
|
|
1479
|
-
textResultForLlm: "Tool returned no result",
|
|
1480
|
-
resultType: "failure",
|
|
1481
|
-
error: "tool returned no result",
|
|
1482
|
-
toolTelemetry: {}
|
|
1483
|
-
};
|
|
1484
|
-
}
|
|
1485
|
-
if (this.isToolResultObject(result)) {
|
|
1486
|
-
return result;
|
|
1487
|
-
}
|
|
1488
|
-
const textResult = typeof result === "string" ? result : JSON.stringify(result);
|
|
1489
|
-
return {
|
|
1490
|
-
textResultForLlm: textResult,
|
|
1491
|
-
resultType: "success",
|
|
1492
|
-
toolTelemetry: {}
|
|
1493
|
-
};
|
|
1494
|
-
}
|
|
1495
|
-
isToolResultObject(value) {
|
|
1496
|
-
return typeof value === "object" && value !== null && "textResultForLlm" in value && typeof value.textResultForLlm === "string" && "resultType" in value;
|
|
1737
|
+
return await session._handleSystemMessageTransform(params.sections);
|
|
1497
1738
|
}
|
|
1498
1739
|
}
|
|
1499
1740
|
export {
|