@github/copilot-sdk 1.0.7-preview.0 → 1.0.7-preview.1
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/dist/cjs/client.js +162 -36
- package/dist/cjs/copilotRequestHandler.js +9 -0
- package/dist/cjs/ffiRuntimeHost.js +282 -0
- package/dist/cjs/generated/rpc.js +32 -3
- package/dist/cjs/types.js +12 -0
- package/dist/client.d.ts +49 -0
- package/dist/client.js +152 -36
- package/dist/copilotRequestHandler.d.ts +3 -0
- package/dist/copilotRequestHandler.js +9 -0
- package/dist/ffiRuntimeHost.d.ts +40 -0
- package/dist/ffiRuntimeHost.js +248 -0
- package/dist/generated/rpc.d.ts +325 -9
- package/dist/generated/rpc.js +32 -3
- package/dist/generated/session-events.d.ts +100 -1
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +53 -1
- package/dist/types.js +12 -0
- package/package.json +3 -2
package/dist/cjs/types.js
CHANGED
|
@@ -59,6 +59,18 @@ const RuntimeConnection = {
|
|
|
59
59
|
*/
|
|
60
60
|
forUri(url, opts = {}) {
|
|
61
61
|
return { kind: "uri", url, connectionToken: opts.connectionToken };
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Host the runtime in-process over the native runtime library's C ABI (FFI).
|
|
65
|
+
*
|
|
66
|
+
* @experimental Per-client options lowered to environment variables (`env`,
|
|
67
|
+
* `telemetry`, `gitHubToken`, `baseDirectory`) are **not** honored in-process;
|
|
68
|
+
* the worker inherits the host process's ambient environment. Set the
|
|
69
|
+
* corresponding environment variables on the host process instead. See
|
|
70
|
+
* https://github.com/github/copilot-sdk/issues/1934.
|
|
71
|
+
*/
|
|
72
|
+
forInProcess() {
|
|
73
|
+
return { kind: "inprocess" };
|
|
62
74
|
}
|
|
63
75
|
};
|
|
64
76
|
function convertMcpCallToolResult(callResult) {
|
package/dist/client.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { CopilotClientOptions, GetAuthStatusResponse, GetStatusResponse, Mo
|
|
|
4
4
|
export declare class CopilotClient {
|
|
5
5
|
private cliStartTimeout;
|
|
6
6
|
private cliProcess;
|
|
7
|
+
private ffiHost;
|
|
7
8
|
private connection;
|
|
8
9
|
private messageWriter;
|
|
9
10
|
private socket;
|
|
@@ -45,6 +46,18 @@ export declare class CopilotClient {
|
|
|
45
46
|
get rpc(): ReturnType<typeof createServerRpc>;
|
|
46
47
|
private logDebugTiming;
|
|
47
48
|
private logDebug;
|
|
49
|
+
/**
|
|
50
|
+
* Environment variable that overrides the transport when the caller does not set
|
|
51
|
+
* {@link CopilotClientOptions.connection}. Accepts `"inprocess"` or `"stdio"`
|
|
52
|
+
* (case-insensitive); unset preserves the default stdio transport. Any other value
|
|
53
|
+
* is an error.
|
|
54
|
+
*/
|
|
55
|
+
private static readonly DEFAULT_CONNECTION_ENV_VAR;
|
|
56
|
+
/**
|
|
57
|
+
* Resolves the default {@link RuntimeConnection} for the no-connection case,
|
|
58
|
+
* honoring {@link CopilotClient.DEFAULT_CONNECTION_ENV_VAR}.
|
|
59
|
+
*/
|
|
60
|
+
private static resolveDefaultConnection;
|
|
48
61
|
/**
|
|
49
62
|
* Creates a new CopilotClient instance.
|
|
50
63
|
*
|
|
@@ -406,6 +419,14 @@ export declare class CopilotClient {
|
|
|
406
419
|
* ```
|
|
407
420
|
*/
|
|
408
421
|
onLifecycle(handler: SessionLifecycleHandler): () => void;
|
|
422
|
+
/**
|
|
423
|
+
* Builds the environment for the spawned runtime child process (stdio/TCP): applies
|
|
424
|
+
* the auth token, connection token, `COPILOT_HOME`, keychain setting, and telemetry
|
|
425
|
+
* variables on top of the effective env. Not used by the in-process (FFI) transport,
|
|
426
|
+
* whose worker inherits the host process's ambient environment
|
|
427
|
+
* (see {@link CopilotClient.startInProcessFfi}).
|
|
428
|
+
*/
|
|
429
|
+
private buildRuntimeEnv;
|
|
409
430
|
/**
|
|
410
431
|
* Start the CLI server process
|
|
411
432
|
*/
|
|
@@ -414,6 +435,34 @@ export declare class CopilotClient {
|
|
|
414
435
|
* Connect to the CLI server (via socket or stdio)
|
|
415
436
|
*/
|
|
416
437
|
private connectToServer;
|
|
438
|
+
/**
|
|
439
|
+
* Start the in-process FFI runtime host: resolve the CLI entrypoint and native
|
|
440
|
+
* runtime library, then let the native host spawn the CLI worker.
|
|
441
|
+
*
|
|
442
|
+
* The worker inherits this host process's ambient environment; per-client options
|
|
443
|
+
* that lower to environment variables (`env`, `telemetry`, `gitHubToken`,
|
|
444
|
+
* `baseDirectory`) are intentionally not applied here, because the native runtime
|
|
445
|
+
* loads into the shared host process and a single env block cannot carry per-client
|
|
446
|
+
* values. Configure the in-process runtime via the host process environment instead.
|
|
447
|
+
* See https://github.com/github/copilot-sdk/issues/1934.
|
|
448
|
+
*/
|
|
449
|
+
private startInProcessFfi;
|
|
450
|
+
/**
|
|
451
|
+
* Connect to the in-process FFI runtime host over its receive/send streams,
|
|
452
|
+
* reusing the same `vscode-jsonrpc` framing as the stdio transport.
|
|
453
|
+
*/
|
|
454
|
+
private connectViaFfi;
|
|
455
|
+
/**
|
|
456
|
+
* Resolves the CLI entrypoint used for in-process FFI hosting: `COPILOT_CLI_PATH`
|
|
457
|
+
* when set, otherwise the bundled platform-package entrypoint.
|
|
458
|
+
*/
|
|
459
|
+
private resolveCliPathForFfi;
|
|
460
|
+
/**
|
|
461
|
+
* Returns the napi prebuilds folder name for the current host — the
|
|
462
|
+
* `<node-platform>-<arch>` convention (e.g. `win32-x64`, `darwin-arm64`,
|
|
463
|
+
* `linux-x64`) under which the runtime ships `prebuilds/<folder>/runtime.node`.
|
|
464
|
+
*/
|
|
465
|
+
private static getNapiPrebuildsFolder;
|
|
417
466
|
/**
|
|
418
467
|
* Connect to child via stdio pipes
|
|
419
468
|
*/
|
package/dist/client.js
CHANGED
|
@@ -233,6 +233,7 @@ class TeardownResilientStreamMessageWriter extends StreamMessageWriter {
|
|
|
233
233
|
class CopilotClient {
|
|
234
234
|
cliStartTimeout = null;
|
|
235
235
|
cliProcess = null;
|
|
236
|
+
ffiHost = null;
|
|
236
237
|
connection = null;
|
|
237
238
|
messageWriter = null;
|
|
238
239
|
socket = null;
|
|
@@ -309,6 +310,29 @@ class CopilotClient {
|
|
|
309
310
|
`);
|
|
310
311
|
}
|
|
311
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Environment variable that overrides the transport when the caller does not set
|
|
315
|
+
* {@link CopilotClientOptions.connection}. Accepts `"inprocess"` or `"stdio"`
|
|
316
|
+
* (case-insensitive); unset preserves the default stdio transport. Any other value
|
|
317
|
+
* is an error.
|
|
318
|
+
*/
|
|
319
|
+
static DEFAULT_CONNECTION_ENV_VAR = "COPILOT_SDK_DEFAULT_CONNECTION";
|
|
320
|
+
/**
|
|
321
|
+
* Resolves the default {@link RuntimeConnection} for the no-connection case,
|
|
322
|
+
* honoring {@link CopilotClient.DEFAULT_CONNECTION_ENV_VAR}.
|
|
323
|
+
*/
|
|
324
|
+
static resolveDefaultConnection() {
|
|
325
|
+
const value = process.env[CopilotClient.DEFAULT_CONNECTION_ENV_VAR];
|
|
326
|
+
if (!value || value.toLowerCase() === "stdio") {
|
|
327
|
+
return { kind: "stdio" };
|
|
328
|
+
}
|
|
329
|
+
if (value.toLowerCase() === "inprocess") {
|
|
330
|
+
return { kind: "inprocess" };
|
|
331
|
+
}
|
|
332
|
+
throw new Error(
|
|
333
|
+
`Invalid ${CopilotClient.DEFAULT_CONNECTION_ENV_VAR} value '${value}'. Expected 'inprocess', 'stdio', or unset.`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
312
336
|
/**
|
|
313
337
|
* Creates a new CopilotClient instance.
|
|
314
338
|
*
|
|
@@ -337,12 +361,17 @@ class CopilotClient {
|
|
|
337
361
|
* ```
|
|
338
362
|
*/
|
|
339
363
|
constructor(options = {}) {
|
|
340
|
-
const conn = options._internalConnection ?? options.connection ??
|
|
364
|
+
const conn = options._internalConnection ?? options.connection ?? CopilotClient.resolveDefaultConnection();
|
|
341
365
|
if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
|
|
342
366
|
throw new Error(
|
|
343
367
|
"gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
|
|
344
368
|
);
|
|
345
369
|
}
|
|
370
|
+
if (conn.kind === "inprocess" && options.workingDirectory !== void 0) {
|
|
371
|
+
throw new Error(
|
|
372
|
+
"workingDirectory is not supported with RuntimeConnection.forInProcess(): the in-process transport hosts the runtime in this process, so honoring it would require mutating the shared process-global cwd. Change the host process's working directory before constructing the client instead."
|
|
373
|
+
);
|
|
374
|
+
}
|
|
346
375
|
if (conn.kind === "tcp" && conn.connectionToken !== void 0) {
|
|
347
376
|
if (typeof conn.connectionToken !== "string" || conn.connectionToken.length === 0) {
|
|
348
377
|
throw new Error("connectionToken must be a non-empty string");
|
|
@@ -498,7 +527,9 @@ class CopilotClient {
|
|
|
498
527
|
}
|
|
499
528
|
this.state = "connecting";
|
|
500
529
|
try {
|
|
501
|
-
if (
|
|
530
|
+
if (this.connectionConfig.kind === "inprocess") {
|
|
531
|
+
await this.startInProcessFfi();
|
|
532
|
+
} else if (!this.isExternalServer) {
|
|
502
533
|
await this.startCLIServer();
|
|
503
534
|
}
|
|
504
535
|
await this.connectToServer();
|
|
@@ -547,6 +578,9 @@ class CopilotClient {
|
|
|
547
578
|
async stop() {
|
|
548
579
|
const errors = [];
|
|
549
580
|
const activeSessions = [...this.sessions.values()];
|
|
581
|
+
if (this.connectionConfig.kind === "inprocess") {
|
|
582
|
+
await Promise.allSettled(activeSessions.map((session) => session.abort()));
|
|
583
|
+
}
|
|
550
584
|
for (const session of activeSessions) {
|
|
551
585
|
const sessionId = session.sessionId;
|
|
552
586
|
let lastError = null;
|
|
@@ -575,7 +609,7 @@ class CopilotClient {
|
|
|
575
609
|
session._markDisconnected();
|
|
576
610
|
}
|
|
577
611
|
this.sessions.clear();
|
|
578
|
-
if (this.connection && this.cliProcess && !this.isExternalServer) {
|
|
612
|
+
if (this.connection && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
579
613
|
const runtimeShutdownStart = Date.now();
|
|
580
614
|
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
581
615
|
void shutdownPromise.catch(() => void 0);
|
|
@@ -660,6 +694,19 @@ class CopilotClient {
|
|
|
660
694
|
);
|
|
661
695
|
}
|
|
662
696
|
}
|
|
697
|
+
if (this.ffiHost) {
|
|
698
|
+
const host = this.ffiHost;
|
|
699
|
+
this.ffiHost = null;
|
|
700
|
+
try {
|
|
701
|
+
host.dispose();
|
|
702
|
+
} catch (error) {
|
|
703
|
+
errors.push(
|
|
704
|
+
new Error(
|
|
705
|
+
`Failed to dispose in-process runtime host: ${error instanceof Error ? error.message : String(error)}`
|
|
706
|
+
)
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
663
710
|
if (this.cliStartTimeout) {
|
|
664
711
|
clearTimeout(this.cliStartTimeout);
|
|
665
712
|
this.cliStartTimeout = null;
|
|
@@ -744,6 +791,13 @@ class CopilotClient {
|
|
|
744
791
|
}
|
|
745
792
|
this.cliProcess = null;
|
|
746
793
|
}
|
|
794
|
+
if (this.ffiHost) {
|
|
795
|
+
try {
|
|
796
|
+
this.ffiHost.dispose();
|
|
797
|
+
} catch {
|
|
798
|
+
}
|
|
799
|
+
this.ffiHost = null;
|
|
800
|
+
}
|
|
747
801
|
if (this.cliStartTimeout) {
|
|
748
802
|
clearTimeout(this.cliStartTimeout);
|
|
749
803
|
this.cliStartTimeout = null;
|
|
@@ -988,6 +1042,7 @@ class CopilotClient {
|
|
|
988
1042
|
requestExtensions: config.requestExtensions,
|
|
989
1043
|
extensionSdkPath: config.extensionSdkPath,
|
|
990
1044
|
extensionInfo: config.extensionInfo,
|
|
1045
|
+
canvasProvider: config.canvasProvider,
|
|
991
1046
|
commands: config.commands?.map((cmd) => ({
|
|
992
1047
|
name: cmd.name,
|
|
993
1048
|
description: cmd.description
|
|
@@ -1185,6 +1240,7 @@ class CopilotClient {
|
|
|
1185
1240
|
requestExtensions: config.requestExtensions,
|
|
1186
1241
|
extensionSdkPath: config.extensionSdkPath,
|
|
1187
1242
|
extensionInfo: config.extensionInfo,
|
|
1243
|
+
canvasProvider: config.canvasProvider,
|
|
1188
1244
|
commands: config.commands?.map((cmd) => ({
|
|
1189
1245
|
name: cmd.name,
|
|
1190
1246
|
description: cmd.description
|
|
@@ -1583,6 +1639,41 @@ class CopilotClient {
|
|
|
1583
1639
|
this.sessionLifecycleHandlers.delete(wildcardHandler);
|
|
1584
1640
|
};
|
|
1585
1641
|
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Builds the environment for the spawned runtime child process (stdio/TCP): applies
|
|
1644
|
+
* the auth token, connection token, `COPILOT_HOME`, keychain setting, and telemetry
|
|
1645
|
+
* variables on top of the effective env. Not used by the in-process (FFI) transport,
|
|
1646
|
+
* whose worker inherits the host process's ambient environment
|
|
1647
|
+
* (see {@link CopilotClient.startInProcessFfi}).
|
|
1648
|
+
*/
|
|
1649
|
+
buildRuntimeEnv() {
|
|
1650
|
+
const env = { ...this.resolvedEnv };
|
|
1651
|
+
delete env.NODE_DEBUG;
|
|
1652
|
+
if (this.options.gitHubToken) {
|
|
1653
|
+
env.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
1654
|
+
}
|
|
1655
|
+
if (this.effectiveConnectionToken) {
|
|
1656
|
+
env.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
|
|
1657
|
+
}
|
|
1658
|
+
if (this.options.baseDirectory) {
|
|
1659
|
+
env.COPILOT_HOME = this.options.baseDirectory;
|
|
1660
|
+
}
|
|
1661
|
+
if (this.options.mode === "empty") {
|
|
1662
|
+
env.COPILOT_DISABLE_KEYTAR = "1";
|
|
1663
|
+
}
|
|
1664
|
+
if (this.options.telemetry) {
|
|
1665
|
+
const t = this.options.telemetry;
|
|
1666
|
+
env.COPILOT_OTEL_ENABLED = "true";
|
|
1667
|
+
if (t.otlpEndpoint !== void 0) env.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
|
|
1668
|
+
if (t.otlpProtocol !== void 0) env.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
|
|
1669
|
+
if (t.filePath !== void 0) env.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
|
|
1670
|
+
if (t.exporterType !== void 0) env.COPILOT_OTEL_EXPORTER_TYPE = t.exporterType;
|
|
1671
|
+
if (t.sourceName !== void 0) env.COPILOT_OTEL_SOURCE_NAME = t.sourceName;
|
|
1672
|
+
if (t.captureContent !== void 0)
|
|
1673
|
+
env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = String(t.captureContent);
|
|
1674
|
+
}
|
|
1675
|
+
return env;
|
|
1676
|
+
}
|
|
1586
1677
|
/**
|
|
1587
1678
|
* Start the CLI server process
|
|
1588
1679
|
*/
|
|
@@ -1616,43 +1707,12 @@ class CopilotClient {
|
|
|
1616
1707
|
if (this.options.enableRemoteSessions) {
|
|
1617
1708
|
args.push("--remote");
|
|
1618
1709
|
}
|
|
1619
|
-
const envWithoutNodeDebug =
|
|
1620
|
-
delete envWithoutNodeDebug.NODE_DEBUG;
|
|
1621
|
-
if (this.options.gitHubToken) {
|
|
1622
|
-
envWithoutNodeDebug.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
1623
|
-
}
|
|
1624
|
-
if (this.effectiveConnectionToken) {
|
|
1625
|
-
envWithoutNodeDebug.COPILOT_CONNECTION_TOKEN = this.effectiveConnectionToken;
|
|
1626
|
-
}
|
|
1627
|
-
if (this.options.baseDirectory) {
|
|
1628
|
-
envWithoutNodeDebug.COPILOT_HOME = this.options.baseDirectory;
|
|
1629
|
-
}
|
|
1630
|
-
if (this.options.mode === "empty") {
|
|
1631
|
-
envWithoutNodeDebug.COPILOT_DISABLE_KEYTAR = "1";
|
|
1632
|
-
}
|
|
1710
|
+
const envWithoutNodeDebug = this.buildRuntimeEnv();
|
|
1633
1711
|
if (!this.resolvedCliPath) {
|
|
1634
1712
|
throw new Error(
|
|
1635
1713
|
"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."
|
|
1636
1714
|
);
|
|
1637
1715
|
}
|
|
1638
|
-
if (this.options.telemetry) {
|
|
1639
|
-
const t = this.options.telemetry;
|
|
1640
|
-
envWithoutNodeDebug.COPILOT_OTEL_ENABLED = "true";
|
|
1641
|
-
if (t.otlpEndpoint !== void 0)
|
|
1642
|
-
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_ENDPOINT = t.otlpEndpoint;
|
|
1643
|
-
if (t.otlpProtocol !== void 0)
|
|
1644
|
-
envWithoutNodeDebug.OTEL_EXPORTER_OTLP_PROTOCOL = t.otlpProtocol;
|
|
1645
|
-
if (t.filePath !== void 0)
|
|
1646
|
-
envWithoutNodeDebug.COPILOT_OTEL_FILE_EXPORTER_PATH = t.filePath;
|
|
1647
|
-
if (t.exporterType !== void 0)
|
|
1648
|
-
envWithoutNodeDebug.COPILOT_OTEL_EXPORTER_TYPE = t.exporterType;
|
|
1649
|
-
if (t.sourceName !== void 0)
|
|
1650
|
-
envWithoutNodeDebug.COPILOT_OTEL_SOURCE_NAME = t.sourceName;
|
|
1651
|
-
if (t.captureContent !== void 0)
|
|
1652
|
-
envWithoutNodeDebug.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = String(
|
|
1653
|
-
t.captureContent
|
|
1654
|
-
);
|
|
1655
|
-
}
|
|
1656
1716
|
if (!existsSync(this.resolvedCliPath)) {
|
|
1657
1717
|
throw new Error(
|
|
1658
1718
|
`Copilot CLI not found at ${this.resolvedCliPath}. Ensure @github/copilot is installed.`
|
|
@@ -1771,11 +1831,66 @@ stderr: ${stderrOutput}`
|
|
|
1771
1831
|
return this.connectToParentProcessViaStdio();
|
|
1772
1832
|
case "stdio":
|
|
1773
1833
|
return this.connectToChildProcessViaStdio();
|
|
1834
|
+
case "inprocess":
|
|
1835
|
+
return this.connectViaFfi();
|
|
1774
1836
|
case "tcp":
|
|
1775
1837
|
case "uri":
|
|
1776
1838
|
return this.connectViaTcp();
|
|
1777
1839
|
}
|
|
1778
1840
|
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Start the in-process FFI runtime host: resolve the CLI entrypoint and native
|
|
1843
|
+
* runtime library, then let the native host spawn the CLI worker.
|
|
1844
|
+
*
|
|
1845
|
+
* The worker inherits this host process's ambient environment; per-client options
|
|
1846
|
+
* that lower to environment variables (`env`, `telemetry`, `gitHubToken`,
|
|
1847
|
+
* `baseDirectory`) are intentionally not applied here, because the native runtime
|
|
1848
|
+
* loads into the shared host process and a single env block cannot carry per-client
|
|
1849
|
+
* values. Configure the in-process runtime via the host process environment instead.
|
|
1850
|
+
* See https://github.com/github/copilot-sdk/issues/1934.
|
|
1851
|
+
*/
|
|
1852
|
+
async startInProcessFfi() {
|
|
1853
|
+
const entrypoint = this.resolveCliPathForFfi();
|
|
1854
|
+
const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
|
|
1855
|
+
const host = FfiRuntimeHost.create(entrypoint, CopilotClient.getNapiPrebuildsFolder());
|
|
1856
|
+
this.ffiHost = host;
|
|
1857
|
+
await host.start();
|
|
1858
|
+
}
|
|
1859
|
+
/**
|
|
1860
|
+
* Connect to the in-process FFI runtime host over its receive/send streams,
|
|
1861
|
+
* reusing the same `vscode-jsonrpc` framing as the stdio transport.
|
|
1862
|
+
*/
|
|
1863
|
+
async connectViaFfi() {
|
|
1864
|
+
if (!this.ffiHost) {
|
|
1865
|
+
throw new Error("In-process FFI runtime host not started");
|
|
1866
|
+
}
|
|
1867
|
+
this.messageWriter = new TeardownResilientStreamMessageWriter(this.ffiHost.sendStream);
|
|
1868
|
+
this.connection = createMessageConnection(
|
|
1869
|
+
new StreamMessageReader(this.ffiHost.receiveStream),
|
|
1870
|
+
this.messageWriter
|
|
1871
|
+
);
|
|
1872
|
+
this.attachConnectionHandlers();
|
|
1873
|
+
this.connection.listen();
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Resolves the CLI entrypoint used for in-process FFI hosting: `COPILOT_CLI_PATH`
|
|
1877
|
+
* when set, otherwise the bundled platform-package entrypoint.
|
|
1878
|
+
*/
|
|
1879
|
+
resolveCliPathForFfi() {
|
|
1880
|
+
return this.resolvedEnv.COPILOT_CLI_PATH ?? getBundledCliPath();
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Returns the napi prebuilds folder name for the current host — the
|
|
1884
|
+
* `<node-platform>-<arch>` convention (e.g. `win32-x64`, `darwin-arm64`,
|
|
1885
|
+
* `linux-x64`) under which the runtime ships `prebuilds/<folder>/runtime.node`.
|
|
1886
|
+
*/
|
|
1887
|
+
static getNapiPrebuildsFolder() {
|
|
1888
|
+
const arch = process.arch;
|
|
1889
|
+
if (arch !== "x64" && arch !== "arm64") {
|
|
1890
|
+
throw new Error(`Unsupported architecture '${arch}' for in-process FFI hosting.`);
|
|
1891
|
+
}
|
|
1892
|
+
return `${process.platform}-${arch}`;
|
|
1893
|
+
}
|
|
1779
1894
|
/**
|
|
1780
1895
|
* Connect to child via stdio pipes
|
|
1781
1896
|
*/
|
|
@@ -1897,8 +2012,9 @@ stderr: ${stderrOutput}`
|
|
|
1897
2012
|
return;
|
|
1898
2013
|
}
|
|
1899
2014
|
const session = this.sessions.get(notification.sessionId);
|
|
2015
|
+
const event = notification.event;
|
|
1900
2016
|
if (session) {
|
|
1901
|
-
session._dispatchEvent(
|
|
2017
|
+
session._dispatchEvent(event);
|
|
1902
2018
|
}
|
|
1903
2019
|
}
|
|
1904
2020
|
handleSessionLifecycleNotification(notification) {
|
|
@@ -8,6 +8,9 @@ declare const kSuppressCloseOnDispose: unique symbol;
|
|
|
8
8
|
export interface CopilotRequestContext {
|
|
9
9
|
readonly requestId: string;
|
|
10
10
|
readonly sessionId?: string;
|
|
11
|
+
readonly agentId?: string;
|
|
12
|
+
readonly parentAgentId?: string;
|
|
13
|
+
readonly interactionType?: string;
|
|
11
14
|
readonly transport: "http" | "websocket";
|
|
12
15
|
url: string;
|
|
13
16
|
headers: LlmInferenceHeaders;
|
|
@@ -153,6 +153,9 @@ class CopilotRequestHandler {
|
|
|
153
153
|
const ctx = {
|
|
154
154
|
requestId: exchange.requestId,
|
|
155
155
|
sessionId: exchange.sessionId,
|
|
156
|
+
agentId: exchange.agentId,
|
|
157
|
+
parentAgentId: exchange.parentAgentId,
|
|
158
|
+
interactionType: exchange.interactionType,
|
|
156
159
|
transport: exchange.transport,
|
|
157
160
|
url: exchange.url,
|
|
158
161
|
headers: exchange.headers,
|
|
@@ -278,6 +281,9 @@ function routeChunk(exchange, params) {
|
|
|
278
281
|
class CopilotRequestExchange {
|
|
279
282
|
requestId;
|
|
280
283
|
sessionId;
|
|
284
|
+
agentId;
|
|
285
|
+
parentAgentId;
|
|
286
|
+
interactionType;
|
|
281
287
|
method = "GET";
|
|
282
288
|
url = "";
|
|
283
289
|
headers = {};
|
|
@@ -297,6 +303,9 @@ class CopilotRequestExchange {
|
|
|
297
303
|
/** Fill in the request context once the matching start frame arrives. */
|
|
298
304
|
setContext(params) {
|
|
299
305
|
this.sessionId = params.sessionId;
|
|
306
|
+
this.agentId = params.agentId;
|
|
307
|
+
this.parentAgentId = params.parentAgentId;
|
|
308
|
+
this.interactionType = params.interactionType;
|
|
300
309
|
this.method = params.method;
|
|
301
310
|
this.url = params.url;
|
|
302
311
|
this.headers = params.headers;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PassThrough, Writable } from "node:stream";
|
|
2
|
+
export declare class FfiRuntimeHost {
|
|
3
|
+
private readonly libraryPath;
|
|
4
|
+
private readonly cliEntrypoint;
|
|
5
|
+
private readonly environment?;
|
|
6
|
+
private readonly lib;
|
|
7
|
+
private serverId;
|
|
8
|
+
private connectionId;
|
|
9
|
+
private disposed;
|
|
10
|
+
private outboundCallback;
|
|
11
|
+
private keepAliveTimer;
|
|
12
|
+
/** The stream JSON-RPC reads server→client frames from. */
|
|
13
|
+
readonly receiveStream: PassThrough;
|
|
14
|
+
/** The stream JSON-RPC writes client→server frames to. */
|
|
15
|
+
readonly sendStream: Writable;
|
|
16
|
+
private constructor();
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the cdylib next to the given CLI entrypoint and prepares the FFI host.
|
|
19
|
+
* The cdylib is resolved as `prebuilds/<prebuildsFolder>/runtime.node` relative to
|
|
20
|
+
* the entrypoint directory (the napi-rs `<node-platform>-<arch>` layout, e.g.
|
|
21
|
+
* `linux-x64`). Throws if it cannot be found.
|
|
22
|
+
*/
|
|
23
|
+
static create(cliEntrypoint: string, prebuildsFolder: string, environment?: Record<string, string | undefined>): FfiRuntimeHost;
|
|
24
|
+
/**
|
|
25
|
+
* Starts the in-process runtime: spawns the CLI worker via the native host,
|
|
26
|
+
* waits for readiness, and opens the FFI JSON-RPC connection.
|
|
27
|
+
*/
|
|
28
|
+
start(): Promise<void>;
|
|
29
|
+
private writeFrame;
|
|
30
|
+
/**
|
|
31
|
+
* Native outbound (server→client) callback. koffi delivers it on the JS event loop
|
|
32
|
+
* via a threadsafe function, so the frame is decoded and written straight to
|
|
33
|
+
* {@link receiveStream}. The native pointer is only valid for this call, so the
|
|
34
|
+
* bytes are copied out before returning.
|
|
35
|
+
*/
|
|
36
|
+
private feedInbound;
|
|
37
|
+
private unregisterCallback;
|
|
38
|
+
/** Closes the FFI connection, shuts down the native host, and releases resources. */
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|