@github/copilot-sdk 1.0.29-preview.7 → 1.0.29-preview.9
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 +172 -5
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +89 -25
- package/dist/cjs/generated/rpc.js +17 -2
- package/dist/cjs/session.js +7 -0
- package/dist/cjs/types.js +3 -5
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +8 -6
- package/dist/client.js +91 -27
- package/dist/generated/lifecycle-diagnostics.d.ts +4 -0
- package/dist/generated/rpc.d.ts +146 -9
- package/dist/generated/rpc.js +17 -2
- package/dist/generated/session-events.d.ts +13 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +7 -0
- package/dist/types.d.ts +9 -13
- package/dist/types.js +3 -5
- package/docs/agent-author.md +49 -2
- package/docs/examples.md +14 -9
- package/docs/workflows.md +2 -3
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -286,7 +286,7 @@ new CopilotClient(options?: CopilotClientOptions)
|
|
|
286
286
|
- `RuntimeConnection.forStdio({ path?, args?, env? })` (default) — spawn the runtime and communicate over its stdin/stdout.
|
|
287
287
|
- `RuntimeConnection.forTcp({ port?, connectionToken?, path?, args?, env? })` — spawn the runtime as a TCP server.
|
|
288
288
|
- `RuntimeConnection.forUri(url, { connectionToken? })` — connect to an already-running runtime (mutually exclusive with `gitHubToken`/`useLoggedInUser`). There is no top-level `cliUrl` shortcut; use this factory for URL-based connections.
|
|
289
|
-
- `RuntimeConnection.forInProcess()` — host the runtime in-process over its native C ABI (FFI). **Experimental.**
|
|
289
|
+
- `RuntimeConnection.forInProcess()` — host the runtime in-process over its native C ABI (FFI). **Experimental.** Client-level `env`, `telemetry`, and `workingDirectory` are rejected; use supported typed options and configure working directories per session.
|
|
290
290
|
- The child-process transports (`forStdio`/`forTcp`) also accept a per-connection `env`. Set it there or via the top-level `env` option — not both (setting both throws).
|
|
291
291
|
- Managed child-process connections materialize the bundled `copilot-runtime` and adjacent `runtime.node`, then launch the wrapper by default. An explicit connection `path` or `COPILOT_CLI_PATH` overrides the bundled runtime.
|
|
292
292
|
- `mode?: "empty" | "copilot-cli"` - Defaulting strategy. Use `"empty"` for multi-user server mode; defaults to `"copilot-cli"`.
|
|
@@ -421,6 +421,20 @@ Create a new conversation session.
|
|
|
421
421
|
- `hooks?: SessionHooks` - Hook handlers for session lifecycle events. See [Session Hooks](#session-hooks) section.
|
|
422
422
|
- `skillProvider?: SkillProvider` - **Experimental.** Serves skills from host storage instead of skill directories. Not persisted; pass it again on resume. See [Skill providers](#skill-providers-experimental).
|
|
423
423
|
|
|
424
|
+
<!-- docs-validate: strict -->
|
|
425
|
+
<!-- docs-validate: hidden -->
|
|
426
|
+
```typescript
|
|
427
|
+
declare function acquireTokenForHost(host: string): Promise<string>;
|
|
428
|
+
|
|
429
|
+
const session = await client.createSession({
|
|
430
|
+
gitHubTokenProvider: async ({ host }) => ({
|
|
431
|
+
kind: "token",
|
|
432
|
+
accessToken: await acquireTokenForHost(host),
|
|
433
|
+
expiresIn: 8 * 60 * 60,
|
|
434
|
+
}),
|
|
435
|
+
});
|
|
436
|
+
```
|
|
437
|
+
<!-- /docs-validate: hidden -->
|
|
424
438
|
```typescript
|
|
425
439
|
const session = await client.createSession({
|
|
426
440
|
gitHubTokenProvider: async ({ host }) => ({
|
|
@@ -495,6 +509,7 @@ Request the TUI to switch to displaying the specified session. Only available in
|
|
|
495
509
|
|
|
496
510
|
Subscribe to a specific session lifecycle event type. Returns an unsubscribe function.
|
|
497
511
|
|
|
512
|
+
<!-- docs-validate: strict -->
|
|
498
513
|
```typescript
|
|
499
514
|
const unsubscribe = client.onLifecycle("session.foreground", (event) => {
|
|
500
515
|
console.log(`Session ${event.sessionId} is now in foreground`);
|
|
@@ -505,6 +520,7 @@ const unsubscribe = client.onLifecycle("session.foreground", (event) => {
|
|
|
505
520
|
|
|
506
521
|
Subscribe to all session lifecycle events. Returns an unsubscribe function.
|
|
507
522
|
|
|
523
|
+
<!-- docs-validate: strict -->
|
|
508
524
|
```typescript
|
|
509
525
|
const unsubscribe = client.onLifecycle((event) => {
|
|
510
526
|
console.log(`${event.type}: ${event.sessionId}`);
|
|
@@ -552,12 +568,32 @@ Returns the message ID.
|
|
|
552
568
|
|
|
553
569
|
Use `source: "system"` for automated messages from your application:
|
|
554
570
|
|
|
571
|
+
<!-- docs-validate: strict -->
|
|
572
|
+
<!-- docs-validate: hidden -->
|
|
573
|
+
```typescript
|
|
574
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
575
|
+
|
|
576
|
+
declare const session: CopilotSession;
|
|
577
|
+
|
|
578
|
+
await session.send({ prompt: "Context updated", source: "system" });
|
|
579
|
+
```
|
|
580
|
+
<!-- /docs-validate: hidden -->
|
|
555
581
|
```typescript
|
|
556
582
|
await session.send({ prompt: "Context updated", source: "system" });
|
|
557
583
|
```
|
|
558
584
|
|
|
559
585
|
For a message from another agent, use its trusted sender ID:
|
|
560
586
|
|
|
587
|
+
<!-- docs-validate: strict -->
|
|
588
|
+
<!-- docs-validate: hidden -->
|
|
589
|
+
```typescript
|
|
590
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
591
|
+
|
|
592
|
+
declare const session: CopilotSession;
|
|
593
|
+
|
|
594
|
+
await session.send({ prompt: "Review complete", source: "agent-reviewer-id" });
|
|
595
|
+
```
|
|
596
|
+
<!-- /docs-validate: hidden -->
|
|
561
597
|
```typescript
|
|
562
598
|
await session.send({ prompt: "Review complete", source: "agent-reviewer-id" });
|
|
563
599
|
```
|
|
@@ -590,6 +626,23 @@ Pass a raw JSON Schema or a Zod schema as `responseSchema` to `send` or
|
|
|
590
626
|
`sendAndWait`. As with custom tool parameters, the SDK converts Zod schemas to
|
|
591
627
|
JSON Schema before sending them:
|
|
592
628
|
|
|
629
|
+
<!-- docs-validate: strict -->
|
|
630
|
+
<!-- docs-validate: hidden -->
|
|
631
|
+
```typescript
|
|
632
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
633
|
+
|
|
634
|
+
declare const session: CopilotSession;
|
|
635
|
+
|
|
636
|
+
import { z } from "zod";
|
|
637
|
+
|
|
638
|
+
const answerSchema = z.object({ answer: z.number().int() });
|
|
639
|
+
const message = await session.sendAndWait({
|
|
640
|
+
prompt: "What is 19 + 23?",
|
|
641
|
+
responseSchema: answerSchema,
|
|
642
|
+
});
|
|
643
|
+
console.log(message?.data.content); // JSON text
|
|
644
|
+
```
|
|
645
|
+
<!-- /docs-validate: hidden -->
|
|
593
646
|
```typescript
|
|
594
647
|
import { z } from "zod";
|
|
595
648
|
|
|
@@ -603,6 +656,20 @@ console.log(message?.data.content); // JSON text
|
|
|
603
656
|
|
|
604
657
|
For a typed result, pass the Zod schema as the **second argument** instead:
|
|
605
658
|
|
|
659
|
+
<!-- docs-validate: strict -->
|
|
660
|
+
<!-- docs-validate: hidden -->
|
|
661
|
+
```typescript
|
|
662
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
663
|
+
|
|
664
|
+
declare const session: CopilotSession;
|
|
665
|
+
import { z } from "zod";
|
|
666
|
+
|
|
667
|
+
const answerSchema = z.object({ answer: z.number().int() });
|
|
668
|
+
|
|
669
|
+
const answer = await session.sendAndWait("What is 19 + 23?", answerSchema);
|
|
670
|
+
console.log(answer.answer); // number; TResult is inferred from answerSchema
|
|
671
|
+
```
|
|
672
|
+
<!-- /docs-validate: hidden -->
|
|
606
673
|
```typescript
|
|
607
674
|
const answer = await session.sendAndWait("What is 19 + 23?", answerSchema);
|
|
608
675
|
console.log(answer.answer); // number; TResult is inferred from answerSchema
|
|
@@ -675,6 +742,28 @@ native `output_config.format` endpoint.
|
|
|
675
742
|
|
|
676
743
|
Subscribe to a specific event type. The handler receives properly typed events.
|
|
677
744
|
|
|
745
|
+
<!-- docs-validate: strict -->
|
|
746
|
+
<!-- docs-validate: hidden -->
|
|
747
|
+
```typescript
|
|
748
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
749
|
+
|
|
750
|
+
declare const session: CopilotSession;
|
|
751
|
+
|
|
752
|
+
// Listen for specific event types with full type inference
|
|
753
|
+
session.on("assistant.message", (event) => {
|
|
754
|
+
console.log(event.data.content); // TypeScript knows about event.data.content
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
session.on("session.idle", () => {
|
|
758
|
+
console.log("Session is idle");
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// Listen to streaming events
|
|
762
|
+
session.on("assistant.message_delta", (event) => {
|
|
763
|
+
process.stdout.write(event.data.deltaContent);
|
|
764
|
+
});
|
|
765
|
+
```
|
|
766
|
+
<!-- /docs-validate: hidden -->
|
|
678
767
|
```typescript
|
|
679
768
|
// Listen for specific event types with full type inference
|
|
680
769
|
session.on("assistant.message", (event) => {
|
|
@@ -695,6 +784,22 @@ session.on("assistant.message_delta", (event) => {
|
|
|
695
784
|
|
|
696
785
|
Subscribe to all session events. Returns an unsubscribe function.
|
|
697
786
|
|
|
787
|
+
<!-- docs-validate: strict -->
|
|
788
|
+
<!-- docs-validate: hidden -->
|
|
789
|
+
```typescript
|
|
790
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
791
|
+
|
|
792
|
+
declare const session: CopilotSession;
|
|
793
|
+
|
|
794
|
+
const unsubscribe = session.on((event) => {
|
|
795
|
+
// Handle any event type
|
|
796
|
+
console.log(event.type, event);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
// Later...
|
|
800
|
+
unsubscribe();
|
|
801
|
+
```
|
|
802
|
+
<!-- /docs-validate: hidden -->
|
|
698
803
|
```typescript
|
|
699
804
|
const unsubscribe = session.on((event) => {
|
|
700
805
|
// Handle any event type
|
|
@@ -722,6 +827,19 @@ The runtime does not apply the preference immediately. It records the request an
|
|
|
722
827
|
|
|
723
828
|
Watch for the outcome through the `session.model_change` event on success or the ephemeral `session.auto_tier_switch_failed` event on failure. A failed activation leaves the incumbent effective tier unchanged. Read the authoritative state at any time with `session.rpc.model.getCurrent()`.
|
|
724
829
|
|
|
830
|
+
<!-- docs-validate: strict -->
|
|
831
|
+
<!-- docs-validate: hidden -->
|
|
832
|
+
```typescript
|
|
833
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
834
|
+
|
|
835
|
+
declare const session: CopilotSession;
|
|
836
|
+
|
|
837
|
+
const result = await session.setAutoTier("intelligence");
|
|
838
|
+
if (result.status === "pending") {
|
|
839
|
+
// Accepted, but not yet in effect.
|
|
840
|
+
}
|
|
841
|
+
```
|
|
842
|
+
<!-- /docs-validate: hidden -->
|
|
725
843
|
```typescript
|
|
726
844
|
const result = await session.setAutoTier("intelligence");
|
|
727
845
|
if (result.status === "pending") {
|
|
@@ -735,6 +853,23 @@ See [Auto tier persistence](../docs/features/session-persistence.md#auto-tier-pe
|
|
|
735
853
|
|
|
736
854
|
Read the current model's reasoning-summary presentation policy without changing session state. Call `session.rpc.model.list()` first to load the model catalog; otherwise the result may have `ready: false`. The request and result types are exported from `@github/copilot-sdk`.
|
|
737
855
|
|
|
856
|
+
<!-- docs-validate: strict -->
|
|
857
|
+
<!-- docs-validate: hidden -->
|
|
858
|
+
```typescript
|
|
859
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
860
|
+
|
|
861
|
+
declare const session: CopilotSession;
|
|
862
|
+
|
|
863
|
+
import type {
|
|
864
|
+
ModelGetReasoningSummariesRequest,
|
|
865
|
+
ModelGetReasoningSummariesResult,
|
|
866
|
+
} from "@github/copilot-sdk";
|
|
867
|
+
|
|
868
|
+
const presentation: ModelGetReasoningSummariesRequest = { summariesVisible: false };
|
|
869
|
+
const policy: ModelGetReasoningSummariesResult =
|
|
870
|
+
await session.rpc.model.getReasoningSummaries(presentation);
|
|
871
|
+
```
|
|
872
|
+
<!-- /docs-validate: hidden -->
|
|
738
873
|
```typescript
|
|
739
874
|
import type {
|
|
740
875
|
ModelGetReasoningSummariesRequest,
|
|
@@ -754,6 +889,26 @@ Replace the tools this client supplies to the session, together with the handler
|
|
|
754
889
|
|
|
755
890
|
Once the runtime accepts the replacement, every tool call this session dispatches uses the new handlers; calls already running finish on their original handlers. If the runtime rejects it, the promise rejects and the previous tools and handlers stay in place. Concurrent calls are applied one at a time, in call order.
|
|
756
891
|
|
|
892
|
+
<!-- docs-validate: strict -->
|
|
893
|
+
<!-- docs-validate: hidden -->
|
|
894
|
+
```typescript
|
|
895
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
896
|
+
|
|
897
|
+
declare const session: CopilotSession;
|
|
898
|
+
import { defineTool } from "@github/copilot-sdk";
|
|
899
|
+
import { z } from "zod";
|
|
900
|
+
|
|
901
|
+
declare function searchIssues(query: string): Promise<string>;
|
|
902
|
+
|
|
903
|
+
await session.setTools([
|
|
904
|
+
defineTool("search_issues", {
|
|
905
|
+
description: "Search the issues shown on the current page",
|
|
906
|
+
parameters: z.object({ query: z.string() }),
|
|
907
|
+
handler: async ({ query }) => searchIssues(query),
|
|
908
|
+
}),
|
|
909
|
+
]);
|
|
910
|
+
```
|
|
911
|
+
<!-- /docs-validate: hidden -->
|
|
757
912
|
```typescript
|
|
758
913
|
await session.setTools([
|
|
759
914
|
defineTool("search_issues", {
|
|
@@ -782,6 +937,18 @@ Disconnect the session and free resources. Session data on disk is preserved for
|
|
|
782
937
|
|
|
783
938
|
Host capabilities reported when the session was created or resumed. Use this to check feature support before calling capability-gated APIs.
|
|
784
939
|
|
|
940
|
+
<!-- docs-validate: strict -->
|
|
941
|
+
<!-- docs-validate: hidden -->
|
|
942
|
+
```typescript
|
|
943
|
+
import type { CopilotSession } from "@github/copilot-sdk";
|
|
944
|
+
|
|
945
|
+
declare const session: CopilotSession;
|
|
946
|
+
|
|
947
|
+
if (session.capabilities.ui?.elicitation) {
|
|
948
|
+
const ok = await session.ui.confirm("Deploy?");
|
|
949
|
+
}
|
|
950
|
+
```
|
|
951
|
+
<!-- /docs-validate: hidden -->
|
|
785
952
|
```typescript
|
|
786
953
|
if (session.capabilities.ui?.elicitation) {
|
|
787
954
|
const ok = await session.ui.confirm("Deploy?");
|
|
@@ -1427,7 +1594,7 @@ console.log(session.workspacePath);
|
|
|
1427
1594
|
// => ~/.copilot/session-state/{sessionId}/
|
|
1428
1595
|
|
|
1429
1596
|
// Custom thresholds
|
|
1430
|
-
const
|
|
1597
|
+
const tuned = await client.createSession({
|
|
1431
1598
|
model: "gpt-5",
|
|
1432
1599
|
infiniteSessions: {
|
|
1433
1600
|
enabled: true,
|
|
@@ -1437,7 +1604,7 @@ const session = await client.createSession({
|
|
|
1437
1604
|
});
|
|
1438
1605
|
|
|
1439
1606
|
// Disable infinite sessions
|
|
1440
|
-
const
|
|
1607
|
+
const disabled = await client.createSession({
|
|
1441
1608
|
model: "gpt-5",
|
|
1442
1609
|
infiniteSessions: { enabled: false },
|
|
1443
1610
|
});
|
|
@@ -1475,13 +1642,13 @@ const disabled = await client.createSession({
|
|
|
1475
1642
|
<!-- /docs-validate: hidden -->
|
|
1476
1643
|
```typescript
|
|
1477
1644
|
// Enable memory for a session
|
|
1478
|
-
const
|
|
1645
|
+
const enabled = await client.createSession({
|
|
1479
1646
|
model: "gpt-5",
|
|
1480
1647
|
memory: { enabled: true },
|
|
1481
1648
|
});
|
|
1482
1649
|
|
|
1483
1650
|
// Disable memory for a session
|
|
1484
|
-
const
|
|
1651
|
+
const disabled = await client.createSession({
|
|
1485
1652
|
model: "gpt-5",
|
|
1486
1653
|
memory: { enabled: false },
|
|
1487
1654
|
});
|
package/dist/cjs/cliVersion.js
CHANGED
|
@@ -22,7 +22,7 @@ __export(cliVersion_exports, {
|
|
|
22
22
|
COPILOT_CLI_VERSION: () => COPILOT_CLI_VERSION
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(cliVersion_exports);
|
|
25
|
-
const COPILOT_CLI_VERSION = "1.0.106-
|
|
25
|
+
const COPILOT_CLI_VERSION = "1.0.106-10";
|
|
26
26
|
const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
|
27
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
28
|
0 && (module.exports = {
|
package/dist/cjs/client.js
CHANGED
|
@@ -301,6 +301,10 @@ function getNodeExecPath() {
|
|
|
301
301
|
function getBundledRuntimePath() {
|
|
302
302
|
return (0, import_runtimeArtifacts.ensureRuntimeBundle)(import_cliVersion.COPILOT_CLI_VERSION);
|
|
303
303
|
}
|
|
304
|
+
async function getSpawnableBundledRuntimePath() {
|
|
305
|
+
const runtimePath = await getBundledRuntimePath();
|
|
306
|
+
return process.platform === "win32" ? import_node_path.win32.toNamespacedPath(runtimePath) : runtimePath;
|
|
307
|
+
}
|
|
304
308
|
class TeardownResilientStreamMessageWriter extends import_node.StreamMessageWriter {
|
|
305
309
|
suppressWriteErrors = false;
|
|
306
310
|
constructor(writable) {
|
|
@@ -466,19 +470,22 @@ class CopilotClient {
|
|
|
466
470
|
*/
|
|
467
471
|
constructor(options = {}) {
|
|
468
472
|
const conn = options._internalConnection ?? options.connection ?? CopilotClient.resolveDefaultConnection();
|
|
473
|
+
if ((conn.kind === "uri" || conn.kind === "parent-process") && options.internalTestOptions !== void 0) {
|
|
474
|
+
throw new Error("internalTestOptions requires a runtime owned by this client");
|
|
475
|
+
}
|
|
469
476
|
if (conn.kind === "uri" && (options.gitHubToken !== void 0 || options.useLoggedInUser !== void 0)) {
|
|
470
477
|
throw new Error(
|
|
471
478
|
"gitHubToken and useLoggedInUser cannot be used with RuntimeConnection.forUri (external server manages its own auth)"
|
|
472
479
|
);
|
|
473
480
|
}
|
|
474
|
-
if (conn.kind === "inprocess" && options.
|
|
481
|
+
if (conn.kind === "inprocess" && options.env !== void 0) {
|
|
475
482
|
throw new Error(
|
|
476
|
-
"
|
|
483
|
+
"env is not supported with RuntimeConnection.forInProcess(): environment variables belong to the shared host process. Use typed client/session options or a child-process transport."
|
|
477
484
|
);
|
|
478
485
|
}
|
|
479
|
-
if (conn.kind === "inprocess" && options.
|
|
486
|
+
if (conn.kind === "inprocess" && options.workingDirectory !== void 0) {
|
|
480
487
|
throw new Error(
|
|
481
|
-
"
|
|
488
|
+
"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. Set SessionConfig.workingDirectory instead."
|
|
482
489
|
);
|
|
483
490
|
}
|
|
484
491
|
if (conn.kind === "inprocess" && options.telemetry !== void 0) {
|
|
@@ -544,6 +551,7 @@ class CopilotClient {
|
|
|
544
551
|
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
545
552
|
this.connectionExtraArgs = [...connArgs];
|
|
546
553
|
this.options = {
|
|
554
|
+
internalTestOptions: options.internalTestOptions,
|
|
547
555
|
entra: options.entra ? { ...options.entra, tokenProvider: options.entra.tokenProvider } : void 0,
|
|
548
556
|
workingDirectory: options.workingDirectory ?? process.cwd(),
|
|
549
557
|
logLevel: options.logLevel,
|
|
@@ -815,12 +823,17 @@ class CopilotClient {
|
|
|
815
823
|
* Stops the CLI server and closes all active sessions.
|
|
816
824
|
*
|
|
817
825
|
* This method performs graceful cleanup:
|
|
818
|
-
* 1. Closes all active sessions (releases in-memory resources)
|
|
826
|
+
* 1. Closes all active sessions (releases in-memory resources); detach
|
|
827
|
+
* requests share one shutdown timeout
|
|
819
828
|
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
820
829
|
* 3. Closes the JSON-RPC connection
|
|
821
830
|
* 4. Signals EOF to an owned stdio process and waits for host cleanup, then
|
|
822
831
|
* terminates the process if it does not exit within the shutdown timeout
|
|
823
832
|
*
|
|
833
|
+
* In-process connections first abort active turns without a timeout. That
|
|
834
|
+
* step is outside the detach deadline, so in-process stop() can still wait
|
|
835
|
+
* indefinitely if the runtime stops answering abort requests.
|
|
836
|
+
*
|
|
824
837
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
825
838
|
* To permanently remove session data before stopping, call
|
|
826
839
|
* {@link deleteSession} for each session first.
|
|
@@ -842,16 +855,31 @@ class CopilotClient {
|
|
|
842
855
|
if (this.connectionConfig.kind === "inprocess") {
|
|
843
856
|
await Promise.allSettled(activeSessions.map((session) => session.abort()));
|
|
844
857
|
}
|
|
858
|
+
let detachDeadlineTimer;
|
|
859
|
+
const detachDeadline = new Promise((resolve2) => {
|
|
860
|
+
detachDeadlineTimer = setTimeout(() => resolve2("timeout"), RUNTIME_SHUTDOWN_TIMEOUT_MS);
|
|
861
|
+
});
|
|
845
862
|
for (const session of activeSessions) {
|
|
846
863
|
const sessionId = session.sessionId;
|
|
847
864
|
let lastError = null;
|
|
865
|
+
let attempts = 0;
|
|
848
866
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
849
867
|
if (this.connectionClosed) {
|
|
850
868
|
lastError = null;
|
|
851
869
|
break;
|
|
852
870
|
}
|
|
871
|
+
attempts = attempt;
|
|
853
872
|
try {
|
|
854
|
-
await
|
|
873
|
+
const outcome = await Promise.race([
|
|
874
|
+
session.disconnect().then(() => "disconnected"),
|
|
875
|
+
detachDeadline
|
|
876
|
+
]);
|
|
877
|
+
if (outcome === "timeout") {
|
|
878
|
+
lastError = new Error(
|
|
879
|
+
`session.detach did not complete within the ${RUNTIME_SHUTDOWN_TIMEOUT_MS}ms shutdown timeout`
|
|
880
|
+
);
|
|
881
|
+
break;
|
|
882
|
+
}
|
|
855
883
|
lastError = null;
|
|
856
884
|
break;
|
|
857
885
|
} catch (error) {
|
|
@@ -869,11 +897,12 @@ class CopilotClient {
|
|
|
869
897
|
if (lastError) {
|
|
870
898
|
errors.push(
|
|
871
899
|
new Error(
|
|
872
|
-
`Failed to disconnect session ${sessionId} after
|
|
900
|
+
`Failed to disconnect session ${sessionId} after ${attempts} ${attempts === 1 ? "attempt" : "attempts"}: ${lastError.message}`
|
|
873
901
|
)
|
|
874
902
|
);
|
|
875
903
|
}
|
|
876
904
|
}
|
|
905
|
+
clearTimeout(detachDeadlineTimer);
|
|
877
906
|
for (const session of activeSessions) {
|
|
878
907
|
session._markDisconnected();
|
|
879
908
|
}
|
|
@@ -1143,7 +1172,7 @@ class CopilotClient {
|
|
|
1143
1172
|
* // Session with model and tools
|
|
1144
1173
|
* const session = await client.createSession({
|
|
1145
1174
|
* onPermissionRequest: approveAll,
|
|
1146
|
-
* model: "gpt-4",
|
|
1175
|
+
* model: "gpt-5.4",
|
|
1147
1176
|
* tools: [{
|
|
1148
1177
|
* name: "get_weather",
|
|
1149
1178
|
* description: "Get weather for a location",
|
|
@@ -2408,15 +2437,40 @@ class CopilotClient {
|
|
|
2408
2437
|
};
|
|
2409
2438
|
}
|
|
2410
2439
|
/**
|
|
2411
|
-
* Builds
|
|
2412
|
-
*
|
|
2413
|
-
* variables on top of the effective env. Not used by the in-process (FFI) transport,
|
|
2414
|
-
* whose worker inherits the host process's ambient environment
|
|
2415
|
-
* (see {@link CopilotClient.startInProcessFfi}).
|
|
2440
|
+
* Builds runtime configuration for child processes and the per-host FFI snapshot.
|
|
2441
|
+
* Typed auth, home, keychain, and telemetry options override the effective env.
|
|
2416
2442
|
*/
|
|
2417
2443
|
buildRuntimeEnv() {
|
|
2418
|
-
const env =
|
|
2444
|
+
const env = process.platform === "win32" ? Object.fromEntries(
|
|
2445
|
+
Object.entries(this.resolvedEnv).map(([key, value]) => [
|
|
2446
|
+
key.toUpperCase(),
|
|
2447
|
+
value
|
|
2448
|
+
])
|
|
2449
|
+
) : { ...this.resolvedEnv };
|
|
2419
2450
|
delete env.NODE_DEBUG;
|
|
2451
|
+
const test = this.options.internalTestOptions;
|
|
2452
|
+
if (test) {
|
|
2453
|
+
const overrides = {
|
|
2454
|
+
COPILOT_API_URL: test.copilotApiUrl,
|
|
2455
|
+
COPILOT_DEBUG_GITHUB_API_URL: test.githubApiUrl,
|
|
2456
|
+
HTTP_PROXY: test.proxyUrl,
|
|
2457
|
+
HTTPS_PROXY: test.proxyUrl,
|
|
2458
|
+
http_proxy: test.proxyUrl,
|
|
2459
|
+
https_proxy: test.proxyUrl,
|
|
2460
|
+
NO_PROXY: test.noProxy,
|
|
2461
|
+
no_proxy: test.noProxy,
|
|
2462
|
+
NODE_EXTRA_CA_CERTS: test.caCertificatePath,
|
|
2463
|
+
SSL_CERT_FILE: test.caCertificatePath,
|
|
2464
|
+
REQUESTS_CA_BUNDLE: test.caCertificatePath,
|
|
2465
|
+
CURL_CA_BUNDLE: test.caCertificatePath,
|
|
2466
|
+
GIT_SSL_CAINFO: test.caCertificatePath
|
|
2467
|
+
};
|
|
2468
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
2469
|
+
if (value !== void 0) {
|
|
2470
|
+
env[process.platform === "win32" ? key.toUpperCase() : key] = value;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2420
2474
|
if (this.options.gitHubToken) {
|
|
2421
2475
|
env.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
2422
2476
|
}
|
|
@@ -2425,6 +2479,9 @@ class CopilotClient {
|
|
|
2425
2479
|
}
|
|
2426
2480
|
if (this.options.baseDirectory) {
|
|
2427
2481
|
env.COPILOT_HOME = this.options.baseDirectory;
|
|
2482
|
+
if (this.connectionConfig.kind === "inprocess") {
|
|
2483
|
+
env.COPILOT_CACHE_HOME = (0, import_node_path.join)(this.options.baseDirectory, "cache");
|
|
2484
|
+
}
|
|
2428
2485
|
}
|
|
2429
2486
|
if (this.options.mode === "empty") {
|
|
2430
2487
|
env.COPILOT_DISABLE_KEYTAR = "1";
|
|
@@ -2451,7 +2508,7 @@ class CopilotClient {
|
|
|
2451
2508
|
* Start the CLI server process
|
|
2452
2509
|
*/
|
|
2453
2510
|
async startCLIServer() {
|
|
2454
|
-
this.resolvedCliPath ??= await
|
|
2511
|
+
this.resolvedCliPath ??= await getSpawnableBundledRuntimePath();
|
|
2455
2512
|
return new Promise((resolve2, reject) => {
|
|
2456
2513
|
this.stderrBuffer = "";
|
|
2457
2514
|
const args = [...this.connectionExtraArgs, "--headless", "--no-auto-update"];
|
|
@@ -2489,6 +2546,22 @@ class CopilotClient {
|
|
|
2489
2546
|
`Copilot CLI not found at ${this.resolvedCliPath}. Set COPILOT_CLI_PATH to use a custom installation.`
|
|
2490
2547
|
);
|
|
2491
2548
|
}
|
|
2549
|
+
const workingDirectory = this.options.workingDirectory;
|
|
2550
|
+
let workingDirectoryProblem;
|
|
2551
|
+
try {
|
|
2552
|
+
workingDirectoryProblem = (0, import_node_fs.statSync)(workingDirectory).isDirectory() ? void 0 : "does not exist or is not a directory";
|
|
2553
|
+
if (!workingDirectoryProblem) {
|
|
2554
|
+
(0, import_node_fs.accessSync)(workingDirectory, import_node_fs.constants.X_OK);
|
|
2555
|
+
}
|
|
2556
|
+
} catch (error) {
|
|
2557
|
+
const code = error.code;
|
|
2558
|
+
workingDirectoryProblem = code === "ENOENT" || code === "ENOTDIR" ? "does not exist or is not a directory" : `cannot be entered: ${error instanceof Error ? error.message : String(error)}`;
|
|
2559
|
+
}
|
|
2560
|
+
if (workingDirectoryProblem) {
|
|
2561
|
+
throw new Error(
|
|
2562
|
+
`Working directory ${workingDirectory} ${workingDirectoryProblem}.`
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2492
2565
|
const stdioConfig = this.connectionConfig.kind === "stdio" ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
|
|
2493
2566
|
const isJsFile = this.resolvedCliPath.endsWith(".js");
|
|
2494
2567
|
if (isJsFile) {
|
|
@@ -2640,16 +2713,7 @@ stderr: ${this.stderrBuffer.trim().slice(-8192) || "(empty)"}`
|
|
|
2640
2713
|
runtimeLibrary = (0, import_node_path.join)((0, import_node_path.dirname)(bundledRuntimePath), "runtime.node");
|
|
2641
2714
|
}
|
|
2642
2715
|
const { FfiRuntimeHost } = await import("./ffiRuntimeHost.js");
|
|
2643
|
-
const environment =
|
|
2644
|
-
if (this.options.gitHubToken) {
|
|
2645
|
-
environment.COPILOT_SDK_AUTH_TOKEN = this.options.gitHubToken;
|
|
2646
|
-
}
|
|
2647
|
-
if (this.options.baseDirectory) {
|
|
2648
|
-
environment.COPILOT_HOME = this.options.baseDirectory;
|
|
2649
|
-
}
|
|
2650
|
-
if (this.options.mode === "empty") {
|
|
2651
|
-
environment.COPILOT_DISABLE_KEYTAR = "1";
|
|
2652
|
-
}
|
|
2716
|
+
const environment = this.buildRuntimeEnv();
|
|
2653
2717
|
const args = [];
|
|
2654
2718
|
if (this.options.logLevel) {
|
|
2655
2719
|
args.push("--log-level", this.options.logLevel);
|
|
@@ -2628,7 +2628,7 @@ function createSessionRpc(connection, sessionId) {
|
|
|
2628
2628
|
/** @experimental */
|
|
2629
2629
|
login: {
|
|
2630
2630
|
/**
|
|
2631
|
-
* Begin an interactive login flow for a provider kind (
|
|
2631
|
+
* Begin an interactive login flow for a provider kind, optionally selecting how to authorize (`method`: `web` by default, or `device-code`), and return its opaque flow id and first step.
|
|
2632
2632
|
*
|
|
2633
2633
|
* @param params Begin an interactive login flow for a provider kind, optionally reusing a cached base identity or explicitly requesting provider account selection.
|
|
2634
2634
|
*
|
|
@@ -2640,7 +2640,7 @@ function createSessionRpc(connection, sessionId) {
|
|
|
2640
2640
|
*
|
|
2641
2641
|
* @param params Advance an in-flight login flow, optionally fulfilling an input-required step.
|
|
2642
2642
|
*
|
|
2643
|
-
* @returns One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra).
|
|
2643
|
+
* @returns One step in an interactive login flow. The consumer acts on the step and calls advance to proceed. Browser-open is encoded as two distinct steps by design: `open-url` is CONSUMER-driven (the provider surfaces the authorize URL and the consumer opens it — github.com/GHEC web), while `needs-interaction` is PROVIDER-driven (the provider opens the browser or broker UI itself and does not surface a URL — Entra). A device-code flow surfaces its one-time code as `device-code`; the consumer shows the code, may open the verification URI, and calls advance, which resolves once the user has authorized the device.
|
|
2644
2644
|
*/
|
|
2645
2645
|
advance: async (params) => connection.sendRequest("session.accounts.login.advance", { ...params, sessionId }),
|
|
2646
2646
|
/**
|
|
@@ -4500,6 +4500,12 @@ function createSessionRpc(connection, sessionId) {
|
|
|
4500
4500
|
* @returns Indicates whether an in-progress background compaction was cancelled.
|
|
4501
4501
|
*/
|
|
4502
4502
|
cancelBackgroundCompaction: async () => connection.sendRequest("session.history.cancelBackgroundCompaction", { sessionId }),
|
|
4503
|
+
/**
|
|
4504
|
+
* Replaces this local session's compaction settings: the model, prompt and reasoning effort its automatic and manual compactions use. Each call replaces all three: an omitted field returns to its default. Settings are held in memory only, so re-apply them after resuming the session in a new process. A change applies to compactions that start afterwards, except that automatic compactions keep the model the running turn already chose for them until that turn ends; a compaction already in progress may still pick up a new reasoning effort. Rejects on a remote session.
|
|
4505
|
+
*
|
|
4506
|
+
* @param params Compaction settings for this session. Each call replaces the previous settings: an omitted field returns to its default. Settings live in memory until the session ends; re-apply them after resuming a session in a new process.
|
|
4507
|
+
*/
|
|
4508
|
+
setCompactionConfig: async (params) => connection.sendRequest("session.history.setCompactionConfig", { ...params, sessionId }),
|
|
4503
4509
|
/**
|
|
4504
4510
|
* Aborts any in-progress manual compaction on a local session.
|
|
4505
4511
|
*
|
|
@@ -4837,6 +4843,15 @@ function createInternalSessionRpc(connection, sessionId) {
|
|
|
4837
4843
|
}
|
|
4838
4844
|
},
|
|
4839
4845
|
/** @experimental */
|
|
4846
|
+
canvasSource: {
|
|
4847
|
+
/**
|
|
4848
|
+
* Closes a canvas through its original session source. Requires the privately admitted in-process CLI host.
|
|
4849
|
+
*
|
|
4850
|
+
* @param params Closes a canvas through its original owned or attached session namespace.
|
|
4851
|
+
*/
|
|
4852
|
+
close: async (params) => connection.sendRequest("session.canvasSource.close", { ...params, sessionId })
|
|
4853
|
+
},
|
|
4854
|
+
/** @experimental */
|
|
4840
4855
|
workflow: {
|
|
4841
4856
|
/**
|
|
4842
4857
|
* Internal tool-originated dynamic workflow invocation.
|
package/dist/cjs/session.js
CHANGED
|
@@ -1177,6 +1177,13 @@ class CopilotSession {
|
|
|
1177
1177
|
} else if (typeof rawResult === "string") {
|
|
1178
1178
|
result = rawResult;
|
|
1179
1179
|
} else if (isToolResultObject(rawResult)) {
|
|
1180
|
+
try {
|
|
1181
|
+
JSON.stringify(rawResult.toolTelemetry);
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1184
|
+
throw new Error(`failed to serialize tool telemetry: ${message}`);
|
|
1185
|
+
}
|
|
1186
|
+
JSON.stringify(rawResult);
|
|
1180
1187
|
result = rawResult;
|
|
1181
1188
|
} else {
|
|
1182
1189
|
result = JSON.stringify(rawResult);
|
package/dist/cjs/types.js
CHANGED
|
@@ -71,11 +71,9 @@ const RuntimeConnection = {
|
|
|
71
71
|
/**
|
|
72
72
|
* Host the runtime in-process over the native runtime library's C ABI (FFI).
|
|
73
73
|
*
|
|
74
|
-
* @experimental
|
|
75
|
-
* `
|
|
76
|
-
*
|
|
77
|
-
* corresponding environment variables on the host process instead. See
|
|
78
|
-
* https://github.com/github/copilot-sdk/issues/1934.
|
|
74
|
+
* @experimental Runtime configuration from `gitHubToken` and
|
|
75
|
+
* `baseDirectory` is scoped to this host, not the process environment.
|
|
76
|
+
* Client-level `env`, `telemetry` and `workingDirectory` are unsupported.
|
|
79
77
|
*/
|
|
80
78
|
forInProcess(options = {}) {
|
|
81
79
|
return { kind: "inprocess", ...options };
|
package/dist/cliVersion.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const COPILOT_CLI_VERSION = "1.0.106-
|
|
1
|
+
export declare const COPILOT_CLI_VERSION = "1.0.106-10";
|
|
2
2
|
export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
package/dist/cliVersion.js
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -139,12 +139,17 @@ export declare class CopilotClient {
|
|
|
139
139
|
* Stops the CLI server and closes all active sessions.
|
|
140
140
|
*
|
|
141
141
|
* This method performs graceful cleanup:
|
|
142
|
-
* 1. Closes all active sessions (releases in-memory resources)
|
|
142
|
+
* 1. Closes all active sessions (releases in-memory resources); detach
|
|
143
|
+
* requests share one shutdown timeout
|
|
143
144
|
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
144
145
|
* 3. Closes the JSON-RPC connection
|
|
145
146
|
* 4. Signals EOF to an owned stdio process and waits for host cleanup, then
|
|
146
147
|
* terminates the process if it does not exit within the shutdown timeout
|
|
147
148
|
*
|
|
149
|
+
* In-process connections first abort active turns without a timeout. That
|
|
150
|
+
* step is outside the detach deadline, so in-process stop() can still wait
|
|
151
|
+
* indefinitely if the runtime stops answering abort requests.
|
|
152
|
+
*
|
|
148
153
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
149
154
|
* To permanently remove session data before stopping, call
|
|
150
155
|
* {@link deleteSession} for each session first.
|
|
@@ -469,11 +474,8 @@ export declare class CopilotClient {
|
|
|
469
474
|
*/
|
|
470
475
|
onLifecycle(handler: SessionLifecycleHandler): () => void;
|
|
471
476
|
/**
|
|
472
|
-
* Builds
|
|
473
|
-
*
|
|
474
|
-
* variables on top of the effective env. Not used by the in-process (FFI) transport,
|
|
475
|
-
* whose worker inherits the host process's ambient environment
|
|
476
|
-
* (see {@link CopilotClient.startInProcessFfi}).
|
|
477
|
+
* Builds runtime configuration for child processes and the per-host FFI snapshot.
|
|
478
|
+
* Typed auth, home, keychain, and telemetry options override the effective env.
|
|
477
479
|
*/
|
|
478
480
|
private buildRuntimeEnv;
|
|
479
481
|
/**
|