@github/copilot-sdk 1.0.25 → 1.0.26
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 +15 -23
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +101 -13
- package/dist/cjs/generated/rpc.js +48 -2
- package/dist/cjs/host.js +7 -1
- package/dist/cjs/session.js +140 -14
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.js +104 -14
- package/dist/generated/rpc.d.ts +361 -22
- package/dist/generated/rpc.js +48 -2
- package/dist/generated/session-events.d.ts +90 -1
- package/dist/host.d.ts +41 -1
- package/dist/host.js +7 -1
- package/dist/index.d.ts +2 -2
- package/dist/session.d.ts +10 -7
- package/dist/session.js +146 -15
- package/dist/types.d.ts +18 -16
- package/package.json +12 -12
package/dist/cjs/session.js
CHANGED
|
@@ -311,6 +311,7 @@ class CopilotSession {
|
|
|
311
311
|
disconnected = false;
|
|
312
312
|
pendingResponseWaits = /* @__PURE__ */ new Set();
|
|
313
313
|
pendingStructuredWaits = /* @__PURE__ */ new Set();
|
|
314
|
+
completionRpcUnsupported = false;
|
|
314
315
|
disconnecting = false;
|
|
315
316
|
onDisconnected;
|
|
316
317
|
/** @internal Client session API handlers, populated by CopilotClient during create/resume. */
|
|
@@ -512,9 +513,22 @@ class CopilotSession {
|
|
|
512
513
|
}
|
|
513
514
|
async send(optionsOrPrompt) {
|
|
514
515
|
const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt;
|
|
516
|
+
return this.sendMessage(options);
|
|
517
|
+
}
|
|
518
|
+
async sendMessage(options, cancelled) {
|
|
519
|
+
const message = await this.createSendParams(options);
|
|
520
|
+
if (cancelled?.()) {
|
|
521
|
+
throw new Error("Completion wait cancelled");
|
|
522
|
+
}
|
|
515
523
|
const response = await this.connection.sendRequest("session.send", {
|
|
516
|
-
...await (0, import_telemetry.getTraceContext)(this.traceContextProvider),
|
|
517
524
|
sessionId: this.sessionId,
|
|
525
|
+
...message
|
|
526
|
+
});
|
|
527
|
+
return response.messageId;
|
|
528
|
+
}
|
|
529
|
+
async createSendParams(options) {
|
|
530
|
+
return {
|
|
531
|
+
...await (0, import_telemetry.getTraceContext)(this.traceContextProvider),
|
|
518
532
|
prompt: options.prompt,
|
|
519
533
|
source: options.source,
|
|
520
534
|
displayPrompt: options.displayPrompt,
|
|
@@ -532,8 +546,7 @@ class CopilotSession {
|
|
|
532
546
|
}
|
|
533
547
|
}
|
|
534
548
|
} : {}
|
|
535
|
-
}
|
|
536
|
-
return response.messageId;
|
|
549
|
+
};
|
|
537
550
|
}
|
|
538
551
|
async sendAndWait(optionsOrPrompt, schemaOrTimeout, timeout) {
|
|
539
552
|
const options = typeof optionsOrPrompt === "string" ? { prompt: optionsOrPrompt } : optionsOrPrompt;
|
|
@@ -554,10 +567,39 @@ class CopilotSession {
|
|
|
554
567
|
"Structured output cannot be requested on an immediate steering message."
|
|
555
568
|
);
|
|
556
569
|
}
|
|
570
|
+
const startedAt = Date.now();
|
|
571
|
+
const completion = await this.sendWithCompletion(
|
|
572
|
+
typedSchema ? { ...options, responseSchema: typedSchema } : options,
|
|
573
|
+
effectiveTimeout
|
|
574
|
+
);
|
|
575
|
+
if (completion !== void 0) {
|
|
576
|
+
const message = completion.response;
|
|
577
|
+
if (message !== void 0 && (message.type !== "assistant.message" || message.agentId)) {
|
|
578
|
+
throw new Error("The runtime returned a non-assistant response.");
|
|
579
|
+
}
|
|
580
|
+
if (typedSchema || options.responseSchema) {
|
|
581
|
+
if (completion.aborted) {
|
|
582
|
+
throw new Error(
|
|
583
|
+
"The requested run was aborted before a structured result was completed."
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
if (!message || message.data.toolRequests?.length || !message.data.content.trim()) {
|
|
587
|
+
throw new Error(
|
|
588
|
+
"The requested run completed without a structured assistant response."
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
return typedSchema ? typedSchema.parse(JSON.parse(message.data.content)) : message;
|
|
592
|
+
}
|
|
593
|
+
if (completion.aborted) {
|
|
594
|
+
throw new Error("The requested run was aborted before completion.");
|
|
595
|
+
}
|
|
596
|
+
return message;
|
|
597
|
+
}
|
|
598
|
+
const remainingTimeout = Math.max(0, effectiveTimeout - (Date.now() - startedAt));
|
|
557
599
|
if (typedSchema || options.responseSchema) {
|
|
558
600
|
const message = await this.sendAndWaitForStructuredMessage(
|
|
559
601
|
typedSchema ? { ...options, responseSchema: typedSchema } : options,
|
|
560
|
-
|
|
602
|
+
remainingTimeout
|
|
561
603
|
);
|
|
562
604
|
if (typedSchema) {
|
|
563
605
|
if (!message) {
|
|
@@ -627,14 +669,8 @@ class CopilotSession {
|
|
|
627
669
|
};
|
|
628
670
|
this.pendingResponseWaits.add(fail);
|
|
629
671
|
let timeoutId;
|
|
672
|
+
let waiting = true;
|
|
630
673
|
try {
|
|
631
|
-
messageId = await this.send(options);
|
|
632
|
-
admitted = true;
|
|
633
|
-
for (const event of buffered) {
|
|
634
|
-
if (event instanceof Error) fail(event);
|
|
635
|
-
else observe(event);
|
|
636
|
-
}
|
|
637
|
-
buffered.length = 0;
|
|
638
674
|
const timeoutPromise = new Promise((_, reject) => {
|
|
639
675
|
timeoutId = setTimeout(
|
|
640
676
|
() => reject(
|
|
@@ -642,15 +678,28 @@ class CopilotSession {
|
|
|
642
678
|
`Timeout after ${effectiveTimeout}ms waiting for response completion`
|
|
643
679
|
)
|
|
644
680
|
),
|
|
645
|
-
|
|
681
|
+
remainingTimeout
|
|
646
682
|
);
|
|
647
683
|
});
|
|
648
|
-
const outcome = await Promise.race([
|
|
684
|
+
const outcome = await Promise.race([
|
|
685
|
+
this.sendMessage(options, () => !waiting).then((id) => {
|
|
686
|
+
messageId = id;
|
|
687
|
+
admitted = true;
|
|
688
|
+
for (const event of buffered) {
|
|
689
|
+
if (event instanceof Error) fail(event);
|
|
690
|
+
else observe(event);
|
|
691
|
+
}
|
|
692
|
+
buffered.length = 0;
|
|
693
|
+
return outcomePromise;
|
|
694
|
+
}),
|
|
695
|
+
timeoutPromise
|
|
696
|
+
]);
|
|
649
697
|
if (outcome.kind === "error") {
|
|
650
698
|
throw outcome.error;
|
|
651
699
|
}
|
|
652
700
|
return outcome.message;
|
|
653
701
|
} finally {
|
|
702
|
+
waiting = false;
|
|
654
703
|
if (timeoutId !== void 0) {
|
|
655
704
|
clearTimeout(timeoutId);
|
|
656
705
|
}
|
|
@@ -659,6 +708,81 @@ class CopilotSession {
|
|
|
659
708
|
this.pendingResponseWaits.delete(fail);
|
|
660
709
|
}
|
|
661
710
|
}
|
|
711
|
+
async sendWithCompletion(options, timeout) {
|
|
712
|
+
if (this.completionRpcUnsupported) return void 0;
|
|
713
|
+
if (this.disconnected) throw new Error("Session is disconnected");
|
|
714
|
+
const cancellation = new import_node.CancellationTokenSource();
|
|
715
|
+
const dispatched = /* @__PURE__ */ new Set();
|
|
716
|
+
let completionEventId;
|
|
717
|
+
let resolveDispatched;
|
|
718
|
+
const dispatchCompleted = new Promise((resolve) => {
|
|
719
|
+
resolveDispatched = resolve;
|
|
720
|
+
});
|
|
721
|
+
const unsubscribe = this.on((event) => {
|
|
722
|
+
if (event.agentId || event.type !== "session.idle" && event.type !== "session.autopilot_stopped" && event.type !== "session.error") {
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
dispatched.add(event.id);
|
|
726
|
+
if (event.id === completionEventId) resolveDispatched();
|
|
727
|
+
});
|
|
728
|
+
const drain = async (id) => {
|
|
729
|
+
if (id && !dispatched.has(id)) {
|
|
730
|
+
completionEventId = id;
|
|
731
|
+
await dispatchCompleted;
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
let fail;
|
|
735
|
+
const stopped = new Promise((_, reject) => {
|
|
736
|
+
fail = reject;
|
|
737
|
+
});
|
|
738
|
+
this.pendingResponseWaits.add(fail);
|
|
739
|
+
const timer = setTimeout(
|
|
740
|
+
() => fail(new Error(`Timeout after ${timeout}ms waiting for session.idle`)),
|
|
741
|
+
timeout
|
|
742
|
+
);
|
|
743
|
+
const operation = async () => {
|
|
744
|
+
try {
|
|
745
|
+
const message = await this.createSendParams(options);
|
|
746
|
+
if (cancellation.token.isCancellationRequested) {
|
|
747
|
+
throw new Error("Completion wait cancelled");
|
|
748
|
+
}
|
|
749
|
+
const result = await this.connection.sendRequest(
|
|
750
|
+
"session.sendAndWait",
|
|
751
|
+
{
|
|
752
|
+
sessionId: this.sessionId,
|
|
753
|
+
...message
|
|
754
|
+
},
|
|
755
|
+
cancellation.token
|
|
756
|
+
);
|
|
757
|
+
await drain(result.completionEventId);
|
|
758
|
+
return result;
|
|
759
|
+
} catch (error) {
|
|
760
|
+
if (error instanceof import_node.ResponseError && error.code === import_node.ErrorCodes.MethodNotFound) {
|
|
761
|
+
this.completionRpcUnsupported = true;
|
|
762
|
+
return void 0;
|
|
763
|
+
}
|
|
764
|
+
if (error instanceof import_node.ResponseError && typeof error.data === "object" && error.data !== null) {
|
|
765
|
+
if ("stack" in error.data && typeof error.data.stack === "string") {
|
|
766
|
+
error.stack = error.data.stack;
|
|
767
|
+
}
|
|
768
|
+
if ("completionEventId" in error.data && typeof error.data.completionEventId === "string") {
|
|
769
|
+
await drain(error.data.completionEventId);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
throw error;
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
try {
|
|
776
|
+
return await Promise.race([operation(), stopped]);
|
|
777
|
+
} finally {
|
|
778
|
+
clearTimeout(timer);
|
|
779
|
+
unsubscribe();
|
|
780
|
+
this.pendingResponseWaits.delete(fail);
|
|
781
|
+
resolveDispatched();
|
|
782
|
+
cancellation.cancel();
|
|
783
|
+
cancellation.dispose();
|
|
784
|
+
}
|
|
785
|
+
}
|
|
662
786
|
async sendAndWaitForStructuredMessage(options, timeout) {
|
|
663
787
|
if (this.disconnected) {
|
|
664
788
|
throw new Error("Session is disconnected");
|
|
@@ -708,12 +832,13 @@ class CopilotSession {
|
|
|
708
832
|
}
|
|
709
833
|
});
|
|
710
834
|
this.pendingStructuredWaits.add(fail);
|
|
835
|
+
let waiting = true;
|
|
711
836
|
const timer = setTimeout(
|
|
712
837
|
() => fail(new Error(`Timeout after ${timeout}ms waiting for the structured response`)),
|
|
713
838
|
timeout
|
|
714
839
|
);
|
|
715
840
|
try {
|
|
716
|
-
const sendOutcome = this.
|
|
841
|
+
const sendOutcome = this.sendMessage(options, () => !waiting).then(
|
|
717
842
|
(id) => {
|
|
718
843
|
if (!id) {
|
|
719
844
|
throw new Error(
|
|
@@ -734,6 +859,7 @@ class CopilotSession {
|
|
|
734
859
|
if (outcome.kind === "error") throw outcome.error;
|
|
735
860
|
return outcome.message;
|
|
736
861
|
} finally {
|
|
862
|
+
waiting = false;
|
|
737
863
|
clearTimeout(timer);
|
|
738
864
|
buffered.length = 0;
|
|
739
865
|
unsubscribe();
|
package/dist/cliVersion.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const COPILOT_CLI_VERSION = "1.0.
|
|
1
|
+
export declare const COPILOT_CLI_VERSION = "1.0.103";
|
|
2
2
|
export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
package/dist/cliVersion.js
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare class CopilotClient {
|
|
|
20
20
|
private sessions;
|
|
21
21
|
private hostExitCallbacks;
|
|
22
22
|
private hostSessionFactories;
|
|
23
|
+
private hostAuthenticators;
|
|
24
|
+
private hostAuthentications;
|
|
23
25
|
private hostHandoffs;
|
|
24
26
|
private stderrBuffer;
|
|
25
27
|
/** Resolved connection mode chosen in the constructor. */
|
package/dist/client.js
CHANGED
|
@@ -18,7 +18,9 @@ import {
|
|
|
18
18
|
} from "./generated/rpc.js";
|
|
19
19
|
import { getSdkProtocolVersion } from "./sdkProtocolVersion.js";
|
|
20
20
|
import { CopilotSession } from "./session.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
AhpHost
|
|
23
|
+
} from "./host.js";
|
|
22
24
|
import { ensureRuntimeBundle } from "./runtimeArtifacts.js";
|
|
23
25
|
import { COPILOT_CLI_VERSION } from "./cliVersion.js";
|
|
24
26
|
import { createSessionFsAdapter } from "./sessionFsProvider.js";
|
|
@@ -273,6 +275,8 @@ class CopilotClient {
|
|
|
273
275
|
sessions = /* @__PURE__ */ new Map();
|
|
274
276
|
hostExitCallbacks = /* @__PURE__ */ new Map();
|
|
275
277
|
hostSessionFactories = /* @__PURE__ */ new Map();
|
|
278
|
+
hostAuthenticators = /* @__PURE__ */ new Map();
|
|
279
|
+
hostAuthentications = /* @__PURE__ */ new Map();
|
|
276
280
|
hostHandoffs = /* @__PURE__ */ new Map();
|
|
277
281
|
stderrBuffer = "";
|
|
278
282
|
// Captures CLI stderr for error messages
|
|
@@ -477,6 +481,7 @@ class CopilotClient {
|
|
|
477
481
|
const connArgs = conn.kind === "stdio" || conn.kind === "tcp" ? conn.args ?? [] : [];
|
|
478
482
|
this.connectionExtraArgs = [...connArgs];
|
|
479
483
|
this.options = {
|
|
484
|
+
entra: options.entra ? { ...options.entra } : void 0,
|
|
480
485
|
workingDirectory: options.workingDirectory ?? process.cwd(),
|
|
481
486
|
logLevel: options.logLevel,
|
|
482
487
|
gitHubToken: options.gitHubToken,
|
|
@@ -485,7 +490,6 @@ class CopilotClient {
|
|
|
485
490
|
telemetry: options.telemetry,
|
|
486
491
|
baseDirectory: options.baseDirectory,
|
|
487
492
|
sessionIdleTimeoutSeconds: options.sessionIdleTimeoutSeconds ?? 0,
|
|
488
|
-
enableRemoteSessions: options.enableRemoteSessions ?? false,
|
|
489
493
|
mode: options.mode ?? "copilot-cli",
|
|
490
494
|
clientInfo: options.clientInfo
|
|
491
495
|
};
|
|
@@ -1399,7 +1403,6 @@ class CopilotClient {
|
|
|
1399
1403
|
memory: config.memory,
|
|
1400
1404
|
gitHubToken: config.gitHubToken,
|
|
1401
1405
|
gitHubTokenProviderRegistrationId,
|
|
1402
|
-
remoteSession: config.remoteSession,
|
|
1403
1406
|
cloud: config.cloud,
|
|
1404
1407
|
featureFlags: config.featureFlags,
|
|
1405
1408
|
expAssignments: config.expAssignments,
|
|
@@ -1675,7 +1678,6 @@ class CopilotClient {
|
|
|
1675
1678
|
continuePendingWork: config.continuePendingWork,
|
|
1676
1679
|
gitHubToken: config.gitHubToken,
|
|
1677
1680
|
gitHubTokenProviderRegistrationId,
|
|
1678
|
-
remoteSession: config.remoteSession,
|
|
1679
1681
|
openCanvases: config.openCanvases,
|
|
1680
1682
|
featureFlags: config.featureFlags,
|
|
1681
1683
|
expAssignments: config.expAssignments,
|
|
@@ -1745,6 +1747,18 @@ class CopilotClient {
|
|
|
1745
1747
|
* @experimental
|
|
1746
1748
|
*/
|
|
1747
1749
|
async startAhpHost(options) {
|
|
1750
|
+
const authentication = options?.authentication;
|
|
1751
|
+
if (!authentication || !["github", "none", "custom"].includes(authentication.mode)) {
|
|
1752
|
+
throw new Error("An explicit authentication mode is required");
|
|
1753
|
+
}
|
|
1754
|
+
if (authentication.mode === "custom" && (typeof authentication.requireIdentity !== "string" || !authentication.requireIdentity.trim() || typeof authentication.authenticate !== "function")) {
|
|
1755
|
+
throw new Error(
|
|
1756
|
+
"Custom authentication requires a nonempty requireIdentity and authenticate callback"
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
if (authentication.mode !== "github" && options.githubEnvironment) {
|
|
1760
|
+
throw new Error("githubEnvironment requires github authentication");
|
|
1761
|
+
}
|
|
1748
1762
|
if (!options?.localServer && !options?.githubEnvironment) {
|
|
1749
1763
|
throw new Error("At least one of localServer or githubEnvironment is required");
|
|
1750
1764
|
}
|
|
@@ -1753,8 +1767,12 @@ class CopilotClient {
|
|
|
1753
1767
|
}
|
|
1754
1768
|
const rpc = this.rpc;
|
|
1755
1769
|
const hostId = randomUUID();
|
|
1770
|
+
if (authentication.mode === "custom") {
|
|
1771
|
+
this.hostAuthenticators.set(hostId, { ...authentication });
|
|
1772
|
+
}
|
|
1756
1773
|
const {
|
|
1757
1774
|
computeId,
|
|
1775
|
+
allowCreatingNewSessions,
|
|
1758
1776
|
localServer,
|
|
1759
1777
|
githubEnvironment,
|
|
1760
1778
|
onExit,
|
|
@@ -1766,7 +1784,11 @@ class CopilotClient {
|
|
|
1766
1784
|
this.hostSessionFactories.set(hostId, {
|
|
1767
1785
|
createSession,
|
|
1768
1786
|
resumeSession,
|
|
1769
|
-
onSessionReleased
|
|
1787
|
+
onSessionReleased,
|
|
1788
|
+
policy: {
|
|
1789
|
+
mode: authentication.mode,
|
|
1790
|
+
requireIdentity: authentication.mode === "custom" ? authentication.requireIdentity : void 0
|
|
1791
|
+
}
|
|
1770
1792
|
});
|
|
1771
1793
|
}
|
|
1772
1794
|
if (onExit) {
|
|
@@ -1775,11 +1797,13 @@ class CopilotClient {
|
|
|
1775
1797
|
try {
|
|
1776
1798
|
const info = await rpc.host.start({
|
|
1777
1799
|
hostId,
|
|
1800
|
+
authentication: authentication.mode === "custom" ? { mode: "custom", requireIdentity: authentication.requireIdentity } : { mode: authentication.mode },
|
|
1778
1801
|
computeId,
|
|
1779
1802
|
localServer,
|
|
1780
1803
|
githubEnvironment,
|
|
1781
1804
|
sessionFactory: createSession ? true : void 0,
|
|
1782
|
-
resumeFactory: resumeSession ? true : void 0
|
|
1805
|
+
resumeFactory: resumeSession ? true : void 0,
|
|
1806
|
+
allowCreatingNewSessions
|
|
1783
1807
|
});
|
|
1784
1808
|
return new AhpHost(
|
|
1785
1809
|
info,
|
|
@@ -1788,7 +1812,13 @@ class CopilotClient {
|
|
|
1788
1812
|
},
|
|
1789
1813
|
(sessionId) => rpc.host.publishSession({ hostId, sessionId }),
|
|
1790
1814
|
() => rpc.host.listSessions({ hostId }),
|
|
1791
|
-
(sessionId) => rpc.host.unpublishSession({ hostId, sessionId })
|
|
1815
|
+
(sessionId) => rpc.host.unpublishSession({ hostId, sessionId }),
|
|
1816
|
+
async (allowed) => {
|
|
1817
|
+
await rpc.host.setSessionCreationPolicy({
|
|
1818
|
+
hostId,
|
|
1819
|
+
allowCreatingNewSessions: allowed
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1792
1822
|
);
|
|
1793
1823
|
} catch (error) {
|
|
1794
1824
|
this.hostExitCallbacks.delete(hostId);
|
|
@@ -1814,7 +1844,8 @@ class CopilotClient {
|
|
|
1814
1844
|
disconnectHosts() {
|
|
1815
1845
|
for (const hostId of /* @__PURE__ */ new Set([
|
|
1816
1846
|
...this.hostExitCallbacks.keys(),
|
|
1817
|
-
...this.hostSessionFactories.keys()
|
|
1847
|
+
...this.hostSessionFactories.keys(),
|
|
1848
|
+
...this.hostAuthenticators.keys()
|
|
1818
1849
|
])) {
|
|
1819
1850
|
this.handleHostExit({
|
|
1820
1851
|
hostId,
|
|
@@ -1824,6 +1855,13 @@ class CopilotClient {
|
|
|
1824
1855
|
}
|
|
1825
1856
|
}
|
|
1826
1857
|
releaseHostSessions(hostId) {
|
|
1858
|
+
this.hostAuthenticators.delete(hostId);
|
|
1859
|
+
for (const [requestId, entry] of this.hostAuthentications) {
|
|
1860
|
+
if (entry.hostId === hostId) {
|
|
1861
|
+
this.hostAuthentications.delete(requestId);
|
|
1862
|
+
entry.controller.abort();
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1827
1865
|
this.hostSessionFactories.delete(hostId);
|
|
1828
1866
|
for (const [handoffId, entry] of this.hostHandoffs) {
|
|
1829
1867
|
if (entry.hostId === hostId) this.releaseHostSession(handoffId);
|
|
@@ -1852,10 +1890,19 @@ class CopilotClient {
|
|
|
1852
1890
|
}
|
|
1853
1891
|
}
|
|
1854
1892
|
async createHostSession(params) {
|
|
1893
|
+
const authentication = params.authentication;
|
|
1894
|
+
if (!authentication) {
|
|
1895
|
+
throw new Error("AHP session handoff authentication is required");
|
|
1896
|
+
}
|
|
1855
1897
|
const options = this.hostSessionFactories.get(params.hostId);
|
|
1856
1898
|
if (!(params.resume ? options?.resumeSession : options?.createSession) || this.hostHandoffs.has(params.handoffId)) {
|
|
1857
1899
|
throw new Error("AHP session factory is unavailable or handoff already exists");
|
|
1858
1900
|
}
|
|
1901
|
+
const policy = options.policy;
|
|
1902
|
+
const identity = authentication.identity;
|
|
1903
|
+
if (authentication.mode !== policy.mode || (authentication.mode === "none" ? identity !== void 0 : typeof identity !== "string" || !identity.trim()) || policy.mode === "custom" && identity !== policy.requireIdentity) {
|
|
1904
|
+
throw new Error("AHP trusted authentication does not match host policy");
|
|
1905
|
+
}
|
|
1859
1906
|
const entry = {
|
|
1860
1907
|
hostId: params.hostId,
|
|
1861
1908
|
requestedSessionId: params.config.sessionId,
|
|
@@ -1882,12 +1929,14 @@ class CopilotClient {
|
|
|
1882
1929
|
const { sessionId, ...resumeConfig } = config;
|
|
1883
1930
|
if (!sessionId) throw new Error("AHP resume requires sessionId");
|
|
1884
1931
|
return options.resumeSession({
|
|
1932
|
+
authentication,
|
|
1885
1933
|
sessionId,
|
|
1886
1934
|
config: resumeConfig,
|
|
1887
1935
|
signal: entry.controller.signal
|
|
1888
1936
|
});
|
|
1889
1937
|
}
|
|
1890
1938
|
return options.createSession({
|
|
1939
|
+
authentication,
|
|
1891
1940
|
config,
|
|
1892
1941
|
signal: entry.controller.signal
|
|
1893
1942
|
});
|
|
@@ -2034,6 +2083,7 @@ class CopilotClient {
|
|
|
2034
2083
|
let serverVersion;
|
|
2035
2084
|
try {
|
|
2036
2085
|
const connectParams = {
|
|
2086
|
+
entra: this.options.entra,
|
|
2037
2087
|
token: this.effectiveConnectionToken,
|
|
2038
2088
|
supportedTaskKinds: ["agent", "client", "shell"]
|
|
2039
2089
|
};
|
|
@@ -2048,6 +2098,9 @@ class CopilotClient {
|
|
|
2048
2098
|
serverVersion = result.protocolVersion;
|
|
2049
2099
|
} catch (err) {
|
|
2050
2100
|
if (err instanceof ResponseError && (err.code === ErrorCodes.MethodNotFound || err.message === "Unhandled method connect")) {
|
|
2101
|
+
if (this.options.entra) {
|
|
2102
|
+
throw new Error("This runtime does not support Entra client configuration.");
|
|
2103
|
+
}
|
|
2051
2104
|
serverVersion = (await raceAgainstExit(this.ping())).protocolVersion;
|
|
2052
2105
|
} else {
|
|
2053
2106
|
throw err;
|
|
@@ -2334,9 +2387,6 @@ class CopilotClient {
|
|
|
2334
2387
|
this.options.sessionIdleTimeoutSeconds.toString()
|
|
2335
2388
|
);
|
|
2336
2389
|
}
|
|
2337
|
-
if (this.options.enableRemoteSessions) {
|
|
2338
|
-
args.push("--remote");
|
|
2339
|
-
}
|
|
2340
2390
|
const envWithoutNodeDebug = this.buildRuntimeEnv();
|
|
2341
2391
|
if (!this.resolvedCliPath) {
|
|
2342
2392
|
throw new Error(
|
|
@@ -2522,9 +2572,6 @@ stderr: ${this.stderrBuffer.trim().slice(-8192) || "(empty)"}`
|
|
|
2522
2572
|
if (this.options.sessionIdleTimeoutSeconds > 0) {
|
|
2523
2573
|
args.push("--session-idle-timeout", this.options.sessionIdleTimeoutSeconds.toString());
|
|
2524
2574
|
}
|
|
2525
|
-
if (this.options.enableRemoteSessions) {
|
|
2526
|
-
args.push("--remote");
|
|
2527
|
-
}
|
|
2528
2575
|
if (cliLoginSyncIntegrationId) {
|
|
2529
2576
|
args.push(`--cli-login-sync-integration-id=${cliLoginSyncIntegrationId}`);
|
|
2530
2577
|
}
|
|
@@ -2700,6 +2747,49 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2700
2747
|
"host.materializeSession",
|
|
2701
2748
|
(params) => this.createHostSession(params)
|
|
2702
2749
|
);
|
|
2750
|
+
this.connection.onRequest(
|
|
2751
|
+
"host.validateAuthentication",
|
|
2752
|
+
async (params) => {
|
|
2753
|
+
const authenticator = this.hostAuthenticators.get(params.hostId);
|
|
2754
|
+
if (!authenticator || this.hostAuthentications.has(params.requestId)) {
|
|
2755
|
+
throw new Error("AHP authenticator is unavailable or request already exists");
|
|
2756
|
+
}
|
|
2757
|
+
const entry = { hostId: params.hostId, controller: new AbortController() };
|
|
2758
|
+
this.hostAuthentications.set(params.requestId, entry);
|
|
2759
|
+
const signal = entry.controller.signal;
|
|
2760
|
+
const cancelled = new Promise((_resolve, reject) => {
|
|
2761
|
+
signal.addEventListener(
|
|
2762
|
+
"abort",
|
|
2763
|
+
() => reject(new Error("AHP authentication ended")),
|
|
2764
|
+
{ once: true }
|
|
2765
|
+
);
|
|
2766
|
+
});
|
|
2767
|
+
try {
|
|
2768
|
+
const result = await Promise.race([
|
|
2769
|
+
Promise.resolve().then(
|
|
2770
|
+
() => authenticator.authenticate({ token: params.token, signal })
|
|
2771
|
+
),
|
|
2772
|
+
cancelled
|
|
2773
|
+
]);
|
|
2774
|
+
if (signal.aborted || this.hostAuthenticators.get(params.hostId) !== authenticator) {
|
|
2775
|
+
throw new Error("AHP authentication ended");
|
|
2776
|
+
}
|
|
2777
|
+
return result;
|
|
2778
|
+
} finally {
|
|
2779
|
+
if (this.hostAuthentications.get(params.requestId) === entry) {
|
|
2780
|
+
this.hostAuthentications.delete(params.requestId);
|
|
2781
|
+
}
|
|
2782
|
+
entry.controller.abort();
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
);
|
|
2786
|
+
this.connection.onNotification(
|
|
2787
|
+
"host.authenticationCancelled",
|
|
2788
|
+
(params) => {
|
|
2789
|
+
const entry = this.hostAuthentications.get(params.requestId);
|
|
2790
|
+
if (entry?.hostId === params.hostId) entry.controller.abort();
|
|
2791
|
+
}
|
|
2792
|
+
);
|
|
2703
2793
|
this.connection.onNotification(
|
|
2704
2794
|
"host.sessionReleased",
|
|
2705
2795
|
(params) => {
|