@github/copilot-sdk-win32-x64 1.0.15 → 1.0.16-preview.0
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/copilot-sdk/client.d.ts +27 -1
- package/copilot-sdk/extension.js +470 -10
- package/copilot-sdk/generated/rpc.d.ts +997 -14
- package/copilot-sdk/generated/session-events.d.ts +81 -1
- package/copilot-sdk/host.d.ts +86 -0
- package/copilot-sdk/index.d.ts +3 -1
- package/copilot-sdk/index.js +471 -10
- package/copilot-sdk/types.d.ts +3 -0
- package/package.json +1 -1
- package/prebuilds/win32-x64/OneAuthInterop.dll +0 -0
- package/prebuilds/win32-x64/copilot-runtime.exe +0 -0
- package/prebuilds/win32-x64/runtime.node +2 -2
- package/ripgrep/bin/win32-x64/rg.exe +0 -0
- package/schemas/api.schema.json +1093 -8
- package/schemas/session-events.schema.json +305 -3
- package/tgrep/bin/win32-x64/tgrep.exe +0 -0
package/copilot-sdk/index.js
CHANGED
|
@@ -4041,6 +4041,60 @@ import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2 } f
|
|
|
4041
4041
|
// src/sdk/nodejs/dist/generated/rpc.js
|
|
4042
4042
|
function createServerRpc(connection) {
|
|
4043
4043
|
return {
|
|
4044
|
+
/** @experimental */
|
|
4045
|
+
environments: {
|
|
4046
|
+
/**
|
|
4047
|
+
* Lists GitHub Mission Control environments visible to the authenticated identity. Does not require a running host and excludes host relay credentials.
|
|
4048
|
+
*
|
|
4049
|
+
* @param params Optional discovery filters supported by GitHub Mission Control.
|
|
4050
|
+
*
|
|
4051
|
+
* @returns Environments visible to the authenticated caller and matching the supplied filters.
|
|
4052
|
+
*/
|
|
4053
|
+
list: async (params) => connection.sendRequest("environments.list", params),
|
|
4054
|
+
/**
|
|
4055
|
+
* Gets safe discovery information for a GitHub Mission Control environment without requiring a running host.
|
|
4056
|
+
*
|
|
4057
|
+
* @param params Identify a Mission Control environment to retrieve.
|
|
4058
|
+
*
|
|
4059
|
+
* @returns Safe discovery information for the requested environment.
|
|
4060
|
+
*/
|
|
4061
|
+
get: async (params) => connection.sendRequest("environments.get", params),
|
|
4062
|
+
/**
|
|
4063
|
+
* Deletes a user-managed GitHub Mission Control environment. GitHub-managed environments cannot be deleted. Does not stop a running host, which may register again.
|
|
4064
|
+
*
|
|
4065
|
+
* @param params Identify a user-managed Mission Control environment to delete.
|
|
4066
|
+
*
|
|
4067
|
+
* @returns Acknowledgement that the requested environment was deleted.
|
|
4068
|
+
*/
|
|
4069
|
+
delete: async (params) => connection.sendRequest("environments.delete", params)
|
|
4070
|
+
},
|
|
4071
|
+
/** @experimental */
|
|
4072
|
+
host: {
|
|
4073
|
+
/**
|
|
4074
|
+
* Publishes an attached resident session for this listener's lifetime without copying it.
|
|
4075
|
+
*
|
|
4076
|
+
* @param params Publishes a resident session attached to the listener's owning connection.
|
|
4077
|
+
*
|
|
4078
|
+
* @returns The existing runtime identity and its resource on the listener.
|
|
4079
|
+
*/
|
|
4080
|
+
publishSession: async (params) => connection.sendRequest("host.publishSession", params),
|
|
4081
|
+
/**
|
|
4082
|
+
* Starts a connection-owned AHP host with explicit localServer and/or githubEnvironment transports as a supervised SDK participant.
|
|
4083
|
+
*
|
|
4084
|
+
* @param params Starts a supervised AHP host with at least one explicitly selected transport.
|
|
4085
|
+
*
|
|
4086
|
+
* @returns Listener readiness, returned only after binding and the supervised participant's SDK handshake.
|
|
4087
|
+
*/
|
|
4088
|
+
start: async (params) => connection.sendRequest("host.start", params),
|
|
4089
|
+
/**
|
|
4090
|
+
* Stops a listener owned by this SDK connection and joins its cleanup without deleting sessions.
|
|
4091
|
+
*
|
|
4092
|
+
* @param params Stops a connection-owned listener and joins its teardown.
|
|
4093
|
+
*
|
|
4094
|
+
* @returns Empty acknowledgement for a completed host lifecycle operation.
|
|
4095
|
+
*/
|
|
4096
|
+
dispose: async (params) => connection.sendRequest("host.dispose", params)
|
|
4097
|
+
},
|
|
4044
4098
|
/**
|
|
4045
4099
|
* Checks server responsiveness and returns protocol information.
|
|
4046
4100
|
*
|
|
@@ -4873,6 +4927,45 @@ function createServerRpc(connection) {
|
|
|
4873
4927
|
}
|
|
4874
4928
|
function createInternalServerRpc(connection) {
|
|
4875
4929
|
return {
|
|
4930
|
+
/** @experimental */
|
|
4931
|
+
host: {
|
|
4932
|
+
/**
|
|
4933
|
+
* Requests app-owned materialization over the owning SDK participant.
|
|
4934
|
+
*
|
|
4935
|
+
* @param params One application-owned session handoff, requested by the supervised hosting participant.
|
|
4936
|
+
*
|
|
4937
|
+
* @returns The resident session the application has materialized on its own connection.
|
|
4938
|
+
*/
|
|
4939
|
+
createSession: async (params) => connection.sendRequest("host.createSession", params),
|
|
4940
|
+
/**
|
|
4941
|
+
* Releases app ownership retention after AHP detaches.
|
|
4942
|
+
*
|
|
4943
|
+
* @param params Ends one participation, not the application's session lifetime.
|
|
4944
|
+
*
|
|
4945
|
+
* @returns Empty acknowledgement for a completed host lifecycle operation.
|
|
4946
|
+
*/
|
|
4947
|
+
releaseSession: async (params) => connection.sendRequest("host.releaseSession", params),
|
|
4948
|
+
/**
|
|
4949
|
+
* Resolves current authenticated credentials and remote-control policy only for the runtime-owned Mission Control hosting participant.
|
|
4950
|
+
*
|
|
4951
|
+
* @returns Private credentials delivered only to a runtime-owned Mission Control hosting participant.
|
|
4952
|
+
*/
|
|
4953
|
+
getEnvironmentCredentials: async () => connection.sendRequest("host.getEnvironmentCredentials", {}),
|
|
4954
|
+
/**
|
|
4955
|
+
* Returns listener settings only to the supervised hosting participant over its SDK connection.
|
|
4956
|
+
*
|
|
4957
|
+
* @returns Normalized listener settings delivered only to the supervised hosting participant.
|
|
4958
|
+
*/
|
|
4959
|
+
getConfiguration: async () => connection.sendRequest("host.getConfiguration", {}),
|
|
4960
|
+
/**
|
|
4961
|
+
* Reports a supervised hosting participant's bound AHP endpoint after its SDK handshake.
|
|
4962
|
+
*
|
|
4963
|
+
* @param params Readiness reported by the supervised hosting participant on its own SDK connection.
|
|
4964
|
+
*
|
|
4965
|
+
* @returns Empty acknowledgement for a completed host lifecycle operation.
|
|
4966
|
+
*/
|
|
4967
|
+
ready: async (params) => connection.sendRequest("host.ready", params)
|
|
4968
|
+
},
|
|
4876
4969
|
/**
|
|
4877
4970
|
* Performs the SDK server connection handshake and validates the optional connection token. Marked internal because this is JSON-RPC transport plumbing invoked automatically by an SDK client's own `connect()` wrapper, not a user-facing method. Stays internal as long as the SDK client owns the handshake; would only become public if the SDK ever exposed the raw schema surface to consumers without a connection wrapper.
|
|
4878
4971
|
*
|
|
@@ -4994,7 +5087,15 @@ function createSessionRpc(connection, sessionId) {
|
|
|
4994
5087
|
*
|
|
4995
5088
|
* @returns Result of attempting to disable sandboxing for the current session.
|
|
4996
5089
|
*/
|
|
4997
|
-
disableForSession: async (params) => connection.sendRequest("session.sandbox.disableForSession", { sessionId, ...params })
|
|
5090
|
+
disableForSession: async (params) => connection.sendRequest("session.sandbox.disableForSession", { sessionId, ...params }),
|
|
5091
|
+
/**
|
|
5092
|
+
* Adds the path offered by a pending sandbox escalation permission request's sandboxPathGrant to the session's sandbox policy and approves the request, so the blocked operation re-runs inside the sandbox rather than outside it. The request is rejected unless the exact request is still pending, carries a sandboxPathGrant, and the grant still takes effect under the current managed policy. Does not persist the path; hosts that store sandbox settings save it themselves.
|
|
5093
|
+
*
|
|
5094
|
+
* @param params Request to accept the sandbox path grant offered on an active sandbox escalation permission prompt.
|
|
5095
|
+
*
|
|
5096
|
+
* @returns Result of accepting a sandbox path grant.
|
|
5097
|
+
*/
|
|
5098
|
+
grantPathForRequest: async (params) => connection.sendRequest("session.sandbox.grantPathForRequest", { sessionId, ...params })
|
|
4998
5099
|
},
|
|
4999
5100
|
/**
|
|
5000
5101
|
* Aborts the current agent turn.
|
|
@@ -6202,7 +6303,15 @@ function createSessionRpc(connection, sessionId) {
|
|
|
6202
6303
|
*
|
|
6203
6304
|
* @returns The selectable model entries and selection ids synthesized for the synchronized BYOK models.
|
|
6204
6305
|
*/
|
|
6205
|
-
sync: async (params) => connection.sendRequest("session.provider.sync", { sessionId, ...params })
|
|
6306
|
+
sync: async (params) => connection.sendRequest("session.provider.sync", { sessionId, ...params }),
|
|
6307
|
+
/**
|
|
6308
|
+
* Withdraws named host-managed models from the session's BYOK registry, leaving every other entry untouched. The scoped counterpart to `provider.sync`: a snapshot can only describe entries the caller knows about, so using it to remove one model silently withdraws rows registered by another source, such as a plugin calling `provider.add` at runtime. Naming what to remove leaves unrelated entries alone. Selection ids that are not registered are ignored, so withdrawal is idempotent. A provider is removed only when one of the withdrawn models was the last entry referencing it; a provider that simply has no models, which is the normal state while its rows are supplied by catalog discovery, is left in place.
|
|
6309
|
+
*
|
|
6310
|
+
* @param params Host-managed model selection ids to withdraw from the session's BYOK registry.
|
|
6311
|
+
*
|
|
6312
|
+
* @returns What the withdrawal actually removed from the registry.
|
|
6313
|
+
*/
|
|
6314
|
+
withdraw: async (params) => connection.sendRequest("session.provider.withdraw", { sessionId, ...params })
|
|
6206
6315
|
},
|
|
6207
6316
|
/** @experimental */
|
|
6208
6317
|
options: {
|
|
@@ -7455,6 +7564,11 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
|
|
|
7455
7564
|
});
|
|
7456
7565
|
}
|
|
7457
7566
|
function registerClientGlobalApiHandlers(connection, handlers) {
|
|
7567
|
+
connection.onNotification("host.exited", async (params) => {
|
|
7568
|
+
const handler = handlers.host;
|
|
7569
|
+
if (!handler) return;
|
|
7570
|
+
await handler.exited(params);
|
|
7571
|
+
});
|
|
7458
7572
|
connection.onRequest("extensionLaunchProvider.resolve", async (params) => {
|
|
7459
7573
|
const handler = handlers.extensionLaunchProvider;
|
|
7460
7574
|
if (!handler) throw new Error("No extensionLaunchProvider client-global handler registered");
|
|
@@ -10696,6 +10810,42 @@ function assertWorkflowStepResult(value, key) {
|
|
|
10696
10810
|
});
|
|
10697
10811
|
}
|
|
10698
10812
|
|
|
10813
|
+
// src/sdk/nodejs/dist/host.js
|
|
10814
|
+
var AhpHost = class {
|
|
10815
|
+
/** @internal */
|
|
10816
|
+
constructor(info, disposeHost, publishHostSession) {
|
|
10817
|
+
this.disposeHost = disposeHost;
|
|
10818
|
+
this.publishHostSession = publishHostSession;
|
|
10819
|
+
this.hostId = info.hostId;
|
|
10820
|
+
this.url = info.url;
|
|
10821
|
+
this.environmentId = info.environmentId;
|
|
10822
|
+
this.token = info.token;
|
|
10823
|
+
this.pid = info.pid;
|
|
10824
|
+
}
|
|
10825
|
+
disposeHost;
|
|
10826
|
+
publishHostSession;
|
|
10827
|
+
hostId;
|
|
10828
|
+
/** Local WebSocket URL. Absent when only the GitHub environment is enabled. */
|
|
10829
|
+
url;
|
|
10830
|
+
/** Mission Control environment ID, when GitHub hosting is enabled. */
|
|
10831
|
+
environmentId;
|
|
10832
|
+
/** Connection token, when required by the listener. Treat this value as a secret. */
|
|
10833
|
+
token;
|
|
10834
|
+
/** Legacy separate host process ID. Absent for in-process listeners; use dispose() to stop. */
|
|
10835
|
+
pid;
|
|
10836
|
+
/** Ask the runtime to stop the listener and await its cleanup, on every call. */
|
|
10837
|
+
dispose() {
|
|
10838
|
+
return this.disposeHost();
|
|
10839
|
+
}
|
|
10840
|
+
/** Publish an existing session attached to this client, until this listener stops. */
|
|
10841
|
+
publishSession(sessionId) {
|
|
10842
|
+
return this.publishHostSession(sessionId);
|
|
10843
|
+
}
|
|
10844
|
+
async [Symbol.asyncDispose]() {
|
|
10845
|
+
await this.dispose();
|
|
10846
|
+
}
|
|
10847
|
+
};
|
|
10848
|
+
|
|
10699
10849
|
// src/sdk/nodejs/dist/runtimeArtifacts.js
|
|
10700
10850
|
import {
|
|
10701
10851
|
chmodSync,
|
|
@@ -11067,6 +11217,57 @@ var BuiltInTools = {
|
|
|
11067
11217
|
// src/sdk/nodejs/dist/client.js
|
|
11068
11218
|
var MIN_PROTOCOL_VERSION = 3;
|
|
11069
11219
|
var RUNTIME_SHUTDOWN_TIMEOUT_MS = 1e4;
|
|
11220
|
+
function createMessageConnection(reader, writer) {
|
|
11221
|
+
let dispatch;
|
|
11222
|
+
let finishDrain;
|
|
11223
|
+
let drained;
|
|
11224
|
+
let disposed = false;
|
|
11225
|
+
const barrier = { jsonrpc: "2.0", method: "$/sdkDrain" };
|
|
11226
|
+
const connection = (0, import_node3.createMessageConnection)(
|
|
11227
|
+
{
|
|
11228
|
+
onError: reader.onError,
|
|
11229
|
+
onClose: reader.onClose,
|
|
11230
|
+
onPartialMessage: reader.onPartialMessage,
|
|
11231
|
+
listen: (callback) => {
|
|
11232
|
+
dispatch = callback;
|
|
11233
|
+
return reader.listen(callback);
|
|
11234
|
+
},
|
|
11235
|
+
dispose: () => reader.dispose()
|
|
11236
|
+
},
|
|
11237
|
+
writer,
|
|
11238
|
+
void 0,
|
|
11239
|
+
{
|
|
11240
|
+
messageStrategy: {
|
|
11241
|
+
handleMessage: (message, next) => {
|
|
11242
|
+
if (message === barrier) {
|
|
11243
|
+
finishDrain?.();
|
|
11244
|
+
} else {
|
|
11245
|
+
next(message);
|
|
11246
|
+
}
|
|
11247
|
+
}
|
|
11248
|
+
}
|
|
11249
|
+
}
|
|
11250
|
+
);
|
|
11251
|
+
connection.onDispose(() => {
|
|
11252
|
+
disposed = true;
|
|
11253
|
+
finishDrain?.();
|
|
11254
|
+
});
|
|
11255
|
+
return Object.assign(connection, {
|
|
11256
|
+
drain: () => {
|
|
11257
|
+
if (!drained) {
|
|
11258
|
+
drained = new Promise((resolve22) => {
|
|
11259
|
+
finishDrain = resolve22;
|
|
11260
|
+
if (disposed || !dispatch) {
|
|
11261
|
+
resolve22();
|
|
11262
|
+
} else {
|
|
11263
|
+
dispatch(barrier);
|
|
11264
|
+
}
|
|
11265
|
+
});
|
|
11266
|
+
}
|
|
11267
|
+
return drained;
|
|
11268
|
+
}
|
|
11269
|
+
});
|
|
11270
|
+
}
|
|
11070
11271
|
async function withTimeout(promise, timeoutMs, message) {
|
|
11071
11272
|
let timeout;
|
|
11072
11273
|
try {
|
|
@@ -11253,6 +11454,9 @@ var CopilotClient = class _CopilotClient {
|
|
|
11253
11454
|
/** Shared in-flight start; concurrent callers await it instead of spawning another CLI. */
|
|
11254
11455
|
startPromise = null;
|
|
11255
11456
|
sessions = /* @__PURE__ */ new Map();
|
|
11457
|
+
hostExitCallbacks = /* @__PURE__ */ new Map();
|
|
11458
|
+
hostSessionFactories = /* @__PURE__ */ new Map();
|
|
11459
|
+
hostHandoffs = /* @__PURE__ */ new Map();
|
|
11256
11460
|
stderrBuffer = "";
|
|
11257
11461
|
// Captures CLI stderr for error messages
|
|
11258
11462
|
/** Resolved connection mode chosen in the constructor. */
|
|
@@ -11544,6 +11748,11 @@ var CopilotClient = class _CopilotClient {
|
|
|
11544
11748
|
}
|
|
11545
11749
|
setupClientGlobalHandlers() {
|
|
11546
11750
|
const handlers = {};
|
|
11751
|
+
handlers.host = {
|
|
11752
|
+
exited: async (exit) => {
|
|
11753
|
+
this.handleHostExit(exit);
|
|
11754
|
+
}
|
|
11755
|
+
};
|
|
11547
11756
|
handlers.extensionLaunchProvider = this.extensionLaunchProvider;
|
|
11548
11757
|
if (this.requestHandler) {
|
|
11549
11758
|
this.requestAdapter = createCopilotRequestAdapter(this.requestHandler, () => {
|
|
@@ -11697,7 +11906,8 @@ var CopilotClient = class _CopilotClient {
|
|
|
11697
11906
|
* 1. Closes all active sessions (releases in-memory resources)
|
|
11698
11907
|
* 2. Requests runtime shutdown for SDK-owned CLI processes
|
|
11699
11908
|
* 3. Closes the JSON-RPC connection
|
|
11700
|
-
* 4.
|
|
11909
|
+
* 4. Signals EOF to an owned stdio process and waits for host cleanup, then
|
|
11910
|
+
* terminates the process if it does not exit within the shutdown timeout
|
|
11701
11911
|
*
|
|
11702
11912
|
* Note: session data on disk is preserved, so sessions can be resumed later.
|
|
11703
11913
|
* To permanently remove session data before stopping, call
|
|
@@ -11815,7 +12025,23 @@ var CopilotClient = class _CopilotClient {
|
|
|
11815
12025
|
}
|
|
11816
12026
|
if (this.cliProcess && !this.isExternalServer) {
|
|
11817
12027
|
const child = this.cliProcess;
|
|
11818
|
-
this.
|
|
12028
|
+
if (this.connectionConfig.kind === "stdio" && child.stdin && child.exitCode == null && child.signalCode == null) {
|
|
12029
|
+
const gracefulExitStart = Date.now();
|
|
12030
|
+
try {
|
|
12031
|
+
child.stdin.end();
|
|
12032
|
+
const exited = await waitForChildExit(child, RUNTIME_SHUTDOWN_TIMEOUT_MS);
|
|
12033
|
+
this.logDebugTiming(
|
|
12034
|
+
exited ? "CopilotClient.stop graceful stdio exit complete" : "CopilotClient.stop graceful stdio exit timed out; terminating child",
|
|
12035
|
+
gracefulExitStart
|
|
12036
|
+
);
|
|
12037
|
+
} catch (error) {
|
|
12038
|
+
errors.push(
|
|
12039
|
+
new Error(
|
|
12040
|
+
`Failed to close CLI stdin: ${error instanceof Error ? error.message : String(error)}`
|
|
12041
|
+
)
|
|
12042
|
+
);
|
|
12043
|
+
}
|
|
12044
|
+
}
|
|
11819
12045
|
try {
|
|
11820
12046
|
if (child.exitCode == null && child.signalCode == null) {
|
|
11821
12047
|
child.kill();
|
|
@@ -11833,6 +12059,10 @@ var CopilotClient = class _CopilotClient {
|
|
|
11833
12059
|
`Failed to kill CLI process: ${error instanceof Error ? error.message : String(error)}`
|
|
11834
12060
|
)
|
|
11835
12061
|
);
|
|
12062
|
+
} finally {
|
|
12063
|
+
if (this.cliProcess === child) {
|
|
12064
|
+
this.cliProcess = null;
|
|
12065
|
+
}
|
|
11836
12066
|
}
|
|
11837
12067
|
}
|
|
11838
12068
|
if (this.ffiHost) {
|
|
@@ -11856,6 +12086,7 @@ var CopilotClient = class _CopilotClient {
|
|
|
11856
12086
|
this.runtimePort = null;
|
|
11857
12087
|
this.stderrBuffer = "";
|
|
11858
12088
|
this.processExitPromise = null;
|
|
12089
|
+
this.disconnectHosts();
|
|
11859
12090
|
return errors;
|
|
11860
12091
|
}
|
|
11861
12092
|
/**
|
|
@@ -11900,6 +12131,7 @@ var CopilotClient = class _CopilotClient {
|
|
|
11900
12131
|
*/
|
|
11901
12132
|
async forceStop() {
|
|
11902
12133
|
this.forceStopping = true;
|
|
12134
|
+
this.disconnectHosts();
|
|
11903
12135
|
for (const session of this.sessions.values()) {
|
|
11904
12136
|
session._markDisconnected();
|
|
11905
12137
|
}
|
|
@@ -12199,6 +12431,7 @@ var CopilotClient = class _CopilotClient {
|
|
|
12199
12431
|
const response = await this.connection.sendRequest("session.create", {
|
|
12200
12432
|
...await getTraceContext(this.onGetTraceContext),
|
|
12201
12433
|
model: config.model,
|
|
12434
|
+
allowedModels: config.allowedModels,
|
|
12202
12435
|
sessionId: localSessionId,
|
|
12203
12436
|
clientName: config.clientName,
|
|
12204
12437
|
reasoningEffort: config.reasoningEffort,
|
|
@@ -12329,6 +12562,11 @@ var CopilotClient = class _CopilotClient {
|
|
|
12329
12562
|
}
|
|
12330
12563
|
throw e;
|
|
12331
12564
|
}
|
|
12565
|
+
for (const entry of this.hostHandoffs.values()) {
|
|
12566
|
+
if (entry.requestedSessionId === session.sessionId) {
|
|
12567
|
+
entry.configs.set(session, config);
|
|
12568
|
+
}
|
|
12569
|
+
}
|
|
12332
12570
|
return session;
|
|
12333
12571
|
}
|
|
12334
12572
|
/**
|
|
@@ -12435,6 +12673,7 @@ var CopilotClient = class _CopilotClient {
|
|
|
12435
12673
|
}
|
|
12436
12674
|
try {
|
|
12437
12675
|
const response = await this.connection.sendRequest("session.resume", {
|
|
12676
|
+
allowedModels: config.allowedModels,
|
|
12438
12677
|
...await getTraceContext(this.onGetTraceContext),
|
|
12439
12678
|
sessionId,
|
|
12440
12679
|
clientName: config.clientName,
|
|
@@ -12563,8 +12802,205 @@ var CopilotClient = class _CopilotClient {
|
|
|
12563
12802
|
}
|
|
12564
12803
|
throw e;
|
|
12565
12804
|
}
|
|
12805
|
+
for (const entry of this.hostHandoffs.values()) {
|
|
12806
|
+
if (entry.requestedSessionId === session.sessionId) {
|
|
12807
|
+
entry.configs.set(session, { ...config, sessionId });
|
|
12808
|
+
}
|
|
12809
|
+
}
|
|
12566
12810
|
return session;
|
|
12567
12811
|
}
|
|
12812
|
+
/**
|
|
12813
|
+
* Start a complete AHP listener hosted in-process by this runtime.
|
|
12814
|
+
*
|
|
12815
|
+
* This connection owns the host. Disposing it or disconnecting the client
|
|
12816
|
+
* stops the listener without deleting sessions. The host uses a separate
|
|
12817
|
+
* SDK connection to the same runtime, not another runtime process.
|
|
12818
|
+
* Only one AHP host may own the catalog in an effective Copilot home
|
|
12819
|
+
* at a time. Other SDK clients and sessions remain usable in that home.
|
|
12820
|
+
* Select localServer, githubEnvironment, or both. An empty localServer
|
|
12821
|
+
* selects 127.0.0.1 on an available port. `onExit` runs at most once; owner disconnection cannot
|
|
12822
|
+
* acknowledge listener cleanup over the disconnected transport.
|
|
12823
|
+
*
|
|
12824
|
+
* @experimental
|
|
12825
|
+
*/
|
|
12826
|
+
async startAhpHost(options) {
|
|
12827
|
+
if (!options?.localServer && !options?.githubEnvironment) {
|
|
12828
|
+
throw new Error("At least one of localServer or githubEnvironment is required");
|
|
12829
|
+
}
|
|
12830
|
+
if (this.state !== "connected") {
|
|
12831
|
+
await this.start();
|
|
12832
|
+
}
|
|
12833
|
+
const rpc = this.rpc;
|
|
12834
|
+
const hostId = randomUUID();
|
|
12835
|
+
const {
|
|
12836
|
+
localServer,
|
|
12837
|
+
githubEnvironment,
|
|
12838
|
+
onExit,
|
|
12839
|
+
createSession,
|
|
12840
|
+
resumeSession,
|
|
12841
|
+
onSessionReleased
|
|
12842
|
+
} = options;
|
|
12843
|
+
if (createSession || resumeSession) {
|
|
12844
|
+
this.hostSessionFactories.set(hostId, {
|
|
12845
|
+
createSession,
|
|
12846
|
+
resumeSession,
|
|
12847
|
+
onSessionReleased
|
|
12848
|
+
});
|
|
12849
|
+
}
|
|
12850
|
+
if (onExit) {
|
|
12851
|
+
this.hostExitCallbacks.set(hostId, onExit);
|
|
12852
|
+
}
|
|
12853
|
+
try {
|
|
12854
|
+
const info = await rpc.host.start({
|
|
12855
|
+
hostId,
|
|
12856
|
+
localServer,
|
|
12857
|
+
githubEnvironment,
|
|
12858
|
+
sessionFactory: createSession ? true : void 0,
|
|
12859
|
+
resumeFactory: resumeSession ? true : void 0
|
|
12860
|
+
});
|
|
12861
|
+
return new AhpHost(
|
|
12862
|
+
info,
|
|
12863
|
+
async () => {
|
|
12864
|
+
await rpc.host.dispose({ hostId });
|
|
12865
|
+
},
|
|
12866
|
+
(sessionId) => rpc.host.publishSession({ hostId, sessionId })
|
|
12867
|
+
);
|
|
12868
|
+
} catch (error) {
|
|
12869
|
+
this.hostExitCallbacks.delete(hostId);
|
|
12870
|
+
this.releaseHostSessions(hostId);
|
|
12871
|
+
throw error;
|
|
12872
|
+
}
|
|
12873
|
+
}
|
|
12874
|
+
handleHostExit(exit) {
|
|
12875
|
+
this.releaseHostSessions(exit.hostId);
|
|
12876
|
+
const onExit = this.hostExitCallbacks.get(exit.hostId);
|
|
12877
|
+
if (onExit) {
|
|
12878
|
+
this.hostExitCallbacks.delete(exit.hostId);
|
|
12879
|
+
const reportError = (error) => {
|
|
12880
|
+
console.error("AHP host exit callback failed", { hostId: exit.hostId, error });
|
|
12881
|
+
};
|
|
12882
|
+
try {
|
|
12883
|
+
void Promise.resolve(onExit(exit)).catch(reportError);
|
|
12884
|
+
} catch (error) {
|
|
12885
|
+
reportError(error);
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12888
|
+
}
|
|
12889
|
+
disconnectHosts() {
|
|
12890
|
+
for (const hostId of /* @__PURE__ */ new Set([
|
|
12891
|
+
...this.hostExitCallbacks.keys(),
|
|
12892
|
+
...this.hostSessionFactories.keys()
|
|
12893
|
+
])) {
|
|
12894
|
+
this.handleHostExit({
|
|
12895
|
+
hostId,
|
|
12896
|
+
reason: "ownerDisconnected",
|
|
12897
|
+
error: "Owner connection closed; runtime cleanup cannot be acknowledged on this connection."
|
|
12898
|
+
});
|
|
12899
|
+
}
|
|
12900
|
+
}
|
|
12901
|
+
releaseHostSessions(hostId) {
|
|
12902
|
+
this.hostSessionFactories.delete(hostId);
|
|
12903
|
+
for (const [handoffId, entry] of this.hostHandoffs) {
|
|
12904
|
+
if (entry.hostId === hostId) this.releaseHostSession(handoffId);
|
|
12905
|
+
}
|
|
12906
|
+
}
|
|
12907
|
+
releaseHostSession(handoffId) {
|
|
12908
|
+
const entry = this.hostHandoffs.get(handoffId);
|
|
12909
|
+
if (!entry) return;
|
|
12910
|
+
this.hostHandoffs.delete(handoffId);
|
|
12911
|
+
entry.released = true;
|
|
12912
|
+
entry.configs.clear();
|
|
12913
|
+
entry.controller.abort();
|
|
12914
|
+
if (entry.session) this.notifyHostSessionReleased(entry);
|
|
12915
|
+
}
|
|
12916
|
+
notifyHostSessionReleased(entry) {
|
|
12917
|
+
const { session, onReleased } = entry;
|
|
12918
|
+
entry.session = void 0;
|
|
12919
|
+
if (session && onReleased) {
|
|
12920
|
+
try {
|
|
12921
|
+
void Promise.resolve(onReleased(session)).catch(() => {
|
|
12922
|
+
console.error("AHP session release callback failed");
|
|
12923
|
+
});
|
|
12924
|
+
} catch {
|
|
12925
|
+
console.error("AHP session release callback failed");
|
|
12926
|
+
}
|
|
12927
|
+
}
|
|
12928
|
+
}
|
|
12929
|
+
async createHostSession(params) {
|
|
12930
|
+
const options = this.hostSessionFactories.get(params.hostId);
|
|
12931
|
+
if (!(params.resume ? options?.resumeSession : options?.createSession) || this.hostHandoffs.has(params.handoffId)) {
|
|
12932
|
+
throw new Error("AHP session factory is unavailable or handoff already exists");
|
|
12933
|
+
}
|
|
12934
|
+
const entry = {
|
|
12935
|
+
hostId: params.hostId,
|
|
12936
|
+
requestedSessionId: params.config.sessionId,
|
|
12937
|
+
controller: new AbortController(),
|
|
12938
|
+
configs: /* @__PURE__ */ new Map(),
|
|
12939
|
+
released: false,
|
|
12940
|
+
onReleased: options.onSessionReleased
|
|
12941
|
+
};
|
|
12942
|
+
this.hostHandoffs.set(params.handoffId, entry);
|
|
12943
|
+
const { configDir, ...config } = params.config;
|
|
12944
|
+
if (configDir !== void 0) config.configDirectory = configDir;
|
|
12945
|
+
const expected = structuredClone(config);
|
|
12946
|
+
const cancelled = new Promise((_resolve, reject) => {
|
|
12947
|
+
entry.controller.signal.addEventListener(
|
|
12948
|
+
"abort",
|
|
12949
|
+
() => {
|
|
12950
|
+
reject(new Error("AHP session handoff ended"));
|
|
12951
|
+
},
|
|
12952
|
+
{ once: true }
|
|
12953
|
+
);
|
|
12954
|
+
});
|
|
12955
|
+
const materialized = Promise.resolve().then(() => {
|
|
12956
|
+
if (params.resume) {
|
|
12957
|
+
const { sessionId, ...resumeConfig } = config;
|
|
12958
|
+
if (!sessionId) throw new Error("AHP resume requires sessionId");
|
|
12959
|
+
return options.resumeSession({
|
|
12960
|
+
sessionId,
|
|
12961
|
+
config: resumeConfig,
|
|
12962
|
+
signal: entry.controller.signal
|
|
12963
|
+
});
|
|
12964
|
+
}
|
|
12965
|
+
return options.createSession({
|
|
12966
|
+
config,
|
|
12967
|
+
signal: entry.controller.signal
|
|
12968
|
+
});
|
|
12969
|
+
}).then((session) => {
|
|
12970
|
+
entry.session = session;
|
|
12971
|
+
const actual = entry.configs.get(session);
|
|
12972
|
+
entry.configs.clear();
|
|
12973
|
+
if (entry.released) {
|
|
12974
|
+
this.notifyHostSessionReleased(entry);
|
|
12975
|
+
throw new Error("AHP session handoff ended");
|
|
12976
|
+
}
|
|
12977
|
+
if (this.sessions.get(session.sessionId) !== session || session.sessionId !== expected.sessionId) {
|
|
12978
|
+
throw new Error(
|
|
12979
|
+
"AHP callback must return the requested session from this client"
|
|
12980
|
+
);
|
|
12981
|
+
}
|
|
12982
|
+
const contains = (value, required) => {
|
|
12983
|
+
if (required && typeof required === "object" && !Array.isArray(required)) {
|
|
12984
|
+
return !!value && typeof value === "object" && Object.entries(required).every(
|
|
12985
|
+
([key, child]) => contains(value[key], child)
|
|
12986
|
+
);
|
|
12987
|
+
}
|
|
12988
|
+
return JSON.stringify(value) === JSON.stringify(required);
|
|
12989
|
+
};
|
|
12990
|
+
if ((!params.resume || actual !== void 0) && !contains(actual, expected)) {
|
|
12991
|
+
throw new Error(
|
|
12992
|
+
"AHP callback must preserve the supplied session configuration"
|
|
12993
|
+
);
|
|
12994
|
+
}
|
|
12995
|
+
return { sessionId: session.sessionId };
|
|
12996
|
+
});
|
|
12997
|
+
try {
|
|
12998
|
+
return await Promise.race([materialized, cancelled]);
|
|
12999
|
+
} catch (error) {
|
|
13000
|
+
this.releaseHostSession(params.handoffId);
|
|
13001
|
+
throw error;
|
|
13002
|
+
}
|
|
13003
|
+
}
|
|
12568
13004
|
/**
|
|
12569
13005
|
* Sends a ping request to the server to verify connectivity.
|
|
12570
13006
|
*
|
|
@@ -13104,8 +13540,13 @@ stderr: ${stderrOutput}`
|
|
|
13104
13540
|
case "inprocess":
|
|
13105
13541
|
return this.connectViaFfi();
|
|
13106
13542
|
case "tcp":
|
|
13107
|
-
case "uri":
|
|
13108
13543
|
return this.connectViaTcp();
|
|
13544
|
+
case "uri": {
|
|
13545
|
+
const { host, port } = this.parseCliUrl(this.connectionConfig.url);
|
|
13546
|
+
this.actualHost = host;
|
|
13547
|
+
this.runtimePort = port;
|
|
13548
|
+
return this.connectViaTcp();
|
|
13549
|
+
}
|
|
13109
13550
|
}
|
|
13110
13551
|
}
|
|
13111
13552
|
/** Starts the in-process FFI runtime with SDK-managed typed options. */
|
|
@@ -13164,7 +13605,7 @@ stderr: ${stderrOutput}`
|
|
|
13164
13605
|
throw new Error("In-process FFI runtime host not started");
|
|
13165
13606
|
}
|
|
13166
13607
|
this.messageWriter = new TeardownResilientStreamMessageWriter(this.ffiHost.sendStream);
|
|
13167
|
-
this.connection =
|
|
13608
|
+
this.connection = createMessageConnection(
|
|
13168
13609
|
new import_node3.StreamMessageReader(this.ffiHost.receiveStream),
|
|
13169
13610
|
this.messageWriter
|
|
13170
13611
|
);
|
|
@@ -13218,7 +13659,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13218
13659
|
}
|
|
13219
13660
|
});
|
|
13220
13661
|
this.messageWriter = new TeardownResilientStreamMessageWriter(this.cliProcess.stdin);
|
|
13221
|
-
this.connection =
|
|
13662
|
+
this.connection = createMessageConnection(
|
|
13222
13663
|
new import_node3.StreamMessageReader(this.cliProcess.stdout),
|
|
13223
13664
|
this.messageWriter
|
|
13224
13665
|
);
|
|
@@ -13233,7 +13674,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13233
13674
|
throw new Error("CLI child process was unexpectedly started in parent process mode");
|
|
13234
13675
|
}
|
|
13235
13676
|
this.messageWriter = new TeardownResilientStreamMessageWriter(process.stdout);
|
|
13236
|
-
this.connection =
|
|
13677
|
+
this.connection = createMessageConnection(
|
|
13237
13678
|
new import_node3.StreamMessageReader(process.stdin),
|
|
13238
13679
|
this.messageWriter
|
|
13239
13680
|
);
|
|
@@ -13256,7 +13697,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13256
13697
|
this.socket.connect(this.runtimePort, this.actualHost, () => {
|
|
13257
13698
|
clearTimeout(connectionTimeout);
|
|
13258
13699
|
this.messageWriter = new TeardownResilientStreamMessageWriter(this.socket);
|
|
13259
|
-
this.connection =
|
|
13700
|
+
this.connection = createMessageConnection(
|
|
13260
13701
|
new import_node3.StreamMessageReader(this.socket),
|
|
13261
13702
|
this.messageWriter
|
|
13262
13703
|
);
|
|
@@ -13313,6 +13754,18 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13313
13754
|
(params, token) => confirmation.confirm(params, token)
|
|
13314
13755
|
);
|
|
13315
13756
|
}
|
|
13757
|
+
this.connection.onRequest(
|
|
13758
|
+
"host.materializeSession",
|
|
13759
|
+
(params) => this.createHostSession(params)
|
|
13760
|
+
);
|
|
13761
|
+
this.connection.onNotification(
|
|
13762
|
+
"host.sessionReleased",
|
|
13763
|
+
(params) => {
|
|
13764
|
+
if (this.hostHandoffs.get(params.handoffId)?.hostId === params.hostId) {
|
|
13765
|
+
this.releaseHostSession(params.handoffId);
|
|
13766
|
+
}
|
|
13767
|
+
}
|
|
13768
|
+
);
|
|
13316
13769
|
this.connection.onRequest(
|
|
13317
13770
|
"hooks.invoke",
|
|
13318
13771
|
async (params) => {
|
|
@@ -13320,20 +13773,27 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13320
13773
|
}
|
|
13321
13774
|
);
|
|
13322
13775
|
const connection = this.connection;
|
|
13776
|
+
const messageWriter = this.messageWriter;
|
|
13323
13777
|
const markDisconnected = () => {
|
|
13324
13778
|
if (this.connection !== connection) {
|
|
13779
|
+
connection.dispose();
|
|
13325
13780
|
return;
|
|
13326
13781
|
}
|
|
13327
13782
|
this.connectionClosed = true;
|
|
13328
13783
|
this.state = "disconnected";
|
|
13784
|
+
this.disconnectHosts();
|
|
13329
13785
|
for (const session of this.sessions.values()) {
|
|
13330
13786
|
session._markDisconnected();
|
|
13331
13787
|
}
|
|
13332
13788
|
this.sessions.clear();
|
|
13333
13789
|
this.githubTokenProviders.clear();
|
|
13334
13790
|
this.requestAdapter?.cancelPending();
|
|
13791
|
+
connection.dispose();
|
|
13335
13792
|
};
|
|
13336
|
-
this.connection.onClose(
|
|
13793
|
+
this.connection.onClose(() => {
|
|
13794
|
+
if (messageWriter) messageWriter.suppressWriteErrors = true;
|
|
13795
|
+
void connection.drain().then(markDisconnected);
|
|
13796
|
+
});
|
|
13337
13797
|
this.connection.onError(() => {
|
|
13338
13798
|
if (this.connection === connection) {
|
|
13339
13799
|
this.state = "disconnected";
|
|
@@ -13451,6 +13911,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
13451
13911
|
}
|
|
13452
13912
|
};
|
|
13453
13913
|
export {
|
|
13914
|
+
AhpHost,
|
|
13454
13915
|
BuiltInTools,
|
|
13455
13916
|
Canvas,
|
|
13456
13917
|
CanvasError,
|
package/copilot-sdk/types.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { ExtensionLaunchProviderHandler as GeneratedExtensionLaunchProvider
|
|
|
13
13
|
import type { ToolSet } from "./toolSet.js";
|
|
14
14
|
export type { RemoteSessionMode } from "./generated/rpc.js";
|
|
15
15
|
export type { CurrentToolMetadata } from "./generated/rpc.js";
|
|
16
|
+
export type { SandboxConfigSource } from "./generated/rpc.js";
|
|
16
17
|
export type { ConnectorAccountRequest, ConnectorAvailability, ConnectorCapabilities, ConnectorCatalogEntry, ConnectorCatalogResult, ConnectorCatalogStatus, ConnectorConnectRequest, ConnectorConnectResult, ConnectorContinueRequest, ConnectorDisconnectResult, ConnectorMcpStatus, ConnectorReconcileRequest, ConnectorRuntimeStatus, ConnectorStatus, ExtensionLaunchProfile, ExtensionLaunchProviderResolveRequest, ExtensionLaunchProviderResolveResult, GitHubTokenAcquireReason, GitHubTokenAcquireResult, GitHubTelemetryNotification, GitHubTelemetryEvent, GitHubTelemetryClientInfo, InstallationConfirmationRequest, InstallationConfirmationResponse, InstallationDecision, InstallationReview, McpInstallationReview, } from "./generated/rpc.js";
|
|
17
18
|
/**
|
|
18
19
|
* Arguments passed to a session's {@link GitHubTokenProvider}.
|
|
@@ -1839,6 +1840,8 @@ export type AskUserVariant = "legacy" | "elicitation";
|
|
|
1839
1840
|
* an existing one).
|
|
1840
1841
|
*/
|
|
1841
1842
|
export interface SessionConfigBase {
|
|
1843
|
+
/** Exact model IDs allowed by the host. Omission preserves runtime policy. */
|
|
1844
|
+
allowedModels?: string[];
|
|
1842
1845
|
/**
|
|
1843
1846
|
* Client name to identify the application using the SDK.
|
|
1844
1847
|
* Included in the User-Agent header for API requests.
|