@github/copilot-sdk 1.0.13-preview.6 → 1.0.14-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/README.md +42 -0
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +44 -9
- package/dist/cjs/ffiRuntimeHost.js +140 -55
- package/dist/cjs/generated/rpc.js +104 -10
- package/dist/cjs/session.js +109 -10
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +4 -0
- package/dist/client.js +44 -9
- package/dist/ffiRuntimeHost.d.ts +8 -2
- package/dist/ffiRuntimeHost.js +140 -55
- package/dist/generated/rpc.d.ts +1399 -60
- package/dist/generated/rpc.js +104 -10
- package/dist/generated/session-events.d.ts +632 -25
- package/dist/index.d.ts +1 -1
- package/dist/session.d.ts +52 -1
- package/dist/session.js +109 -10
- package/dist/types.d.ts +28 -4
- package/package.json +12 -11
|
@@ -266,13 +266,13 @@ function createServerRpc(connection) {
|
|
|
266
266
|
/**
|
|
267
267
|
* Enables installed plugins for new sessions.
|
|
268
268
|
*
|
|
269
|
-
* @param params Plugin names (or specs) to enable.
|
|
269
|
+
* @param params Plugin names (or specs) to enable, plus the optional working directory the repository-controlled guard is evaluated against.
|
|
270
270
|
*/
|
|
271
271
|
enable: async (params) => connection.sendRequest("plugins.enable", params),
|
|
272
272
|
/**
|
|
273
273
|
* Disables installed plugins for new sessions.
|
|
274
274
|
*
|
|
275
|
-
* @param params Plugin names (or specs) to disable.
|
|
275
|
+
* @param params Plugin names (or specs) to disable, plus the optional working directory the repository-controlled guard is evaluated against.
|
|
276
276
|
*/
|
|
277
277
|
disable: async (params) => connection.sendRequest("plugins.disable", params),
|
|
278
278
|
/** @experimental */
|
|
@@ -438,7 +438,11 @@ function createServerRpc(connection) {
|
|
|
438
438
|
*
|
|
439
439
|
* @returns Validated device-managed settings discovered before a session exists.
|
|
440
440
|
*/
|
|
441
|
-
read: async () => connection.sendRequest("managedSettings.read", {})
|
|
441
|
+
read: async () => connection.sendRequest("managedSettings.read", {}),
|
|
442
|
+
/**
|
|
443
|
+
* Force-refreshes enterprise managed settings for every account: wipes the persistent server-policy cache (the whole `<cacheHome>/managed-settings` directory) and drops this runtime process's in-memory retained server policy. It does not itself fetch policy — the effect is that the next time a session resolves managed settings for an account, that resolution re-fetches the account's org policy from the network instead of serving a cached response. Note that `managedSettings.read` returns only device/MDM settings and never triggers the account server-policy fetch, so a host implementing "sync account policy" should start a fresh session resolution rather than treat a subsequent `managedSettings.read` as the refreshed org policy. Mirrors the invalidation a sign-out performs, broadened from the one signing-out account to all of them; device/MDM layers describe the machine, not the account, and are left untouched. Rejects if the on-disk cache cannot be removed.
|
|
444
|
+
*/
|
|
445
|
+
clearCache: async () => connection.sendRequest("managedSettings.clearCache", {})
|
|
442
446
|
},
|
|
443
447
|
/** @experimental */
|
|
444
448
|
runtime: {
|
|
@@ -518,7 +522,15 @@ function createServerRpc(connection) {
|
|
|
518
522
|
*/
|
|
519
523
|
list: async (params) => connection.sendRequest("sessions.list", params),
|
|
520
524
|
/**
|
|
521
|
-
* Reads
|
|
525
|
+
* Reads client-owned metadata for multiple persisted local sessions without opening them. Results preserve request order and report missing, corrupt, unsupported, or temporarily unavailable sessions independently.
|
|
526
|
+
*
|
|
527
|
+
* @param params Bounded batch request for client-owned metadata from persisted local sessions.
|
|
528
|
+
*
|
|
529
|
+
* @returns Ordered client metadata outcomes for the requested local sessions.
|
|
530
|
+
*/
|
|
531
|
+
getClientMetadata: async (params) => connection.sendRequest("sessions.getClientMetadata", params),
|
|
532
|
+
/**
|
|
533
|
+
* Reads a page of durable events directly from a local session's persisted journal without creating, resuming, or activating the session. The first read pins the currently opened journal generation and its byte-length boundary; opaque cursor continuations remain on that generation across runtime-owned compaction, truncation, and rewrite operations, which replace the live path atomically, and events appended after the boundary are excluded. For cold hydration, await the first successful page before activation and establish lossless live-event buffering before resume; merge subsequent live events by ID, preserving persisted order and letting live payloads win. Continuations are process-local, single-use capabilities bound to the originating session and storage context and must be paged sequentially; concurrent or repeated use of the same cursor expires that duplicate read rather than reading the generation twice. A complete snapshot has cursorStatus 'ok' and hasMore false. Snapshots expire after five idle minutes, with at most eight retained per process and idle-only eviction under pressure; completion and cancelled-worker exit release their handles. No transcript copy is created, but retained handles may keep replaced files' disk blocks alive until release. Pages have a soft 1 MiB serialized event-array budget including resolved binary assets; one oversized event is returned alone to guarantee progress. Working memory also includes a record/lookahead and asset resolution; resolving the first binary reference may scan the full pinned generation to build a bounded offset index. If the snapshot expires, is evicted, is cancelled before a continuation is established, or becomes unreadable after an observable unsupported in-place shortening, the continuation returns cursorStatus 'expired' with an empty terminal page and never falls back to a different generation. A missing or initially unreadable journal is an RPC error. Persisted history excludes ephemeral events and may omit payloads that are reconstructed only for an active session; use the active session event stream for post-resume live events.
|
|
522
534
|
*
|
|
523
535
|
* @param params Pagination options for reading an inactive or active local session's persisted event journal.
|
|
524
536
|
*
|
|
@@ -799,7 +811,15 @@ function createSessionRpc(connection, sessionId) {
|
|
|
799
811
|
*
|
|
800
812
|
* @returns Managed sandbox enforcement state for a session.
|
|
801
813
|
*/
|
|
802
|
-
getEnforcementStatus: async () => connection.sendRequest("session.sandbox.getEnforcementStatus", { sessionId })
|
|
814
|
+
getEnforcementStatus: async () => connection.sendRequest("session.sandbox.getEnforcementStatus", { sessionId }),
|
|
815
|
+
/**
|
|
816
|
+
* Disables sandboxing for the remainder of the current session and approves the referenced pending sandbox-bypass permission request. The request is rejected unless the exact request is still pending and the effective sandbox policy permits bypass.
|
|
817
|
+
*
|
|
818
|
+
* @param params Request to disable sandboxing for the current session while resolving an active sandbox-bypass permission prompt.
|
|
819
|
+
*
|
|
820
|
+
* @returns Result of attempting to disable sandboxing for the current session.
|
|
821
|
+
*/
|
|
822
|
+
disableForSession: async (params) => connection.sendRequest("session.sandbox.disableForSession", { sessionId, ...params })
|
|
803
823
|
},
|
|
804
824
|
/**
|
|
805
825
|
* Aborts the current agent turn.
|
|
@@ -963,6 +983,14 @@ function createSessionRpc(connection, sessionId) {
|
|
|
963
983
|
* @returns Complete current or terminal factory run envelope.
|
|
964
984
|
*/
|
|
965
985
|
cancel: async (params) => connection.sendRequest("session.factory.cancel", { sessionId, ...params }),
|
|
986
|
+
/**
|
|
987
|
+
* Pauses a running factory and returns its settled run envelope.
|
|
988
|
+
*
|
|
989
|
+
* @param params Parameters for pausing a running factory.
|
|
990
|
+
*
|
|
991
|
+
* @returns Complete current or terminal factory run envelope.
|
|
992
|
+
*/
|
|
993
|
+
pause: async (params) => connection.sendRequest("session.factory.pause", { sessionId, ...params }),
|
|
966
994
|
/**
|
|
967
995
|
* Records a batch of ordered factory progress lines.
|
|
968
996
|
*
|
|
@@ -1002,9 +1030,9 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1002
1030
|
/** @experimental */
|
|
1003
1031
|
model: {
|
|
1004
1032
|
/**
|
|
1005
|
-
* Gets the
|
|
1033
|
+
* Gets the session's authoritative model snapshot, including the committed Auto preference and any newer unclaimed Auto preference waiting for a future user turn.
|
|
1006
1034
|
*
|
|
1007
|
-
* @returns The
|
|
1035
|
+
* @returns The session's authoritative model snapshot. Auto preference fields are configuration for the virtual `auto` model and do not change the selected model identifier. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume.
|
|
1008
1036
|
*/
|
|
1009
1037
|
getCurrent: async () => connection.sendRequest("session.model.getCurrent", { sessionId }),
|
|
1010
1038
|
/**
|
|
@@ -1015,6 +1043,22 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1015
1043
|
* @returns The model identifier active on the session after the switch.
|
|
1016
1044
|
*/
|
|
1017
1045
|
switchTo: async (params) => connection.sendRequest("session.model.switchTo", { sessionId, ...params }),
|
|
1046
|
+
/**
|
|
1047
|
+
* Requests an Auto preference change without changing the session's selected model. The latest unclaimed request wins; the runtime commits it only after a later prompt using the `auto` model mints a usable model and token pair. A `pending` response confirms that the request was accepted, not that it committed. Observe eventual success through `session.model_change`, failure through the ephemeral `session.auto_tier_switch_failed` event, or current unclaimed state through `session.model.getCurrent`.
|
|
1048
|
+
*
|
|
1049
|
+
* @param params An Auto preference request for the session. This updates Auto configuration only; it does not change the selected model to `auto`.
|
|
1050
|
+
*
|
|
1051
|
+
* @returns Immediate acknowledgement and Auto preference snapshot after a switch request. This result never implies that a pending preference committed.
|
|
1052
|
+
*/
|
|
1053
|
+
switchAutoTier: async (params) => connection.sendRequest("session.model.switchAutoTier", { sessionId, ...params }),
|
|
1054
|
+
/**
|
|
1055
|
+
* Replaces or clears the host-supplied model allowlist for a running session.
|
|
1056
|
+
*
|
|
1057
|
+
* @param params Host-supplied exact model selection IDs to allow for this running session. CAPI IDs are intersected with repository `.github/allowed_models.txt` policy; provider-qualified IDs remain exempt from repository-only policy but are restricted by this host list. Omit or pass null to clear the host restriction; an explicit empty or disjoint list is rejected. Validation and pre-selection fallback failures preserve the previous restriction. Failures after a fallback selection commits retain the new restriction and selected model; callers should inspect current session state after such an error.
|
|
1058
|
+
*
|
|
1059
|
+
* @returns The applied host allowlist and effective session model policy after intersection.
|
|
1060
|
+
*/
|
|
1061
|
+
setAllowedModels: async (params) => connection.sendRequest("session.model.setAllowedModels", { sessionId, ...params }),
|
|
1018
1062
|
/**
|
|
1019
1063
|
* Updates the session's reasoning effort without changing the selected model.
|
|
1020
1064
|
*
|
|
@@ -1221,6 +1265,15 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1221
1265
|
diff: async (params) => connection.sendRequest("session.workspaces.diff", { sessionId, ...params })
|
|
1222
1266
|
},
|
|
1223
1267
|
/** @experimental */
|
|
1268
|
+
autopilotObjective: {
|
|
1269
|
+
/**
|
|
1270
|
+
* Reads the current canonical autopilot objective state for this session.
|
|
1271
|
+
*
|
|
1272
|
+
* @returns Canonical runtime state for the session's current autopilot objective.
|
|
1273
|
+
*/
|
|
1274
|
+
getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId })
|
|
1275
|
+
},
|
|
1276
|
+
/** @experimental */
|
|
1224
1277
|
completions: {
|
|
1225
1278
|
/**
|
|
1226
1279
|
* Gets the characters that should trigger host-driven completions for the session. Empty disables host-driven completions (e.g. local sessions, or a relay host that does not advertise them).
|
|
@@ -1251,7 +1304,7 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1251
1304
|
/**
|
|
1252
1305
|
* Starts fleet mode by submitting the fleet orchestration prompt to the session.
|
|
1253
1306
|
*
|
|
1254
|
-
* @param params
|
|
1307
|
+
* @param params Parameters for starting fleet orchestration: an optional user prompt combined with the fleet instructions, plus the send options forwarded to the resulting turn.
|
|
1255
1308
|
*
|
|
1256
1309
|
* @returns Indicates whether fleet mode was successfully activated.
|
|
1257
1310
|
*/
|
|
@@ -1314,6 +1367,22 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1314
1367
|
* @returns Background tasks currently tracked by the session.
|
|
1315
1368
|
*/
|
|
1316
1369
|
list: async () => connection.sendRequest("session.tasks.list", { sessionId }),
|
|
1370
|
+
/**
|
|
1371
|
+
* Registers a client-owned task, or reclaims an orphaned task belonging to the same extension principal.
|
|
1372
|
+
*
|
|
1373
|
+
* @param params Registers or reclaims a client-owned task.
|
|
1374
|
+
*
|
|
1375
|
+
* @returns Result of registering or reclaiming a client-owned task.
|
|
1376
|
+
*/
|
|
1377
|
+
register: async (params) => connection.sendRequest("session.tasks.register", { sessionId, ...params }),
|
|
1378
|
+
/**
|
|
1379
|
+
* Publishes generic progress or a terminal outcome for a client-owned task.
|
|
1380
|
+
*
|
|
1381
|
+
* @param params Updates a client-owned task.
|
|
1382
|
+
*
|
|
1383
|
+
* @returns Result of publishing a client-owned task update.
|
|
1384
|
+
*/
|
|
1385
|
+
update: async (params) => connection.sendRequest("session.tasks.update", { sessionId, ...params }),
|
|
1317
1386
|
/**
|
|
1318
1387
|
* Refreshes metadata for any detached background shells the runtime knows about.
|
|
1319
1388
|
*
|
|
@@ -1777,7 +1846,7 @@ function createSessionRpc(connection, sessionId) {
|
|
|
1777
1846
|
*/
|
|
1778
1847
|
set: async (params) => connection.sendRequest("session.tools.set", { sessionId, ...params }),
|
|
1779
1848
|
/**
|
|
1780
|
-
*
|
|
1849
|
+
* Sets the current session's live subagent settings override, which takes precedence over persisted user settings until cleared. Persisted user settings remain the source of truth for future sessions.
|
|
1781
1850
|
*
|
|
1782
1851
|
* @param params Subagent settings to apply to the current session
|
|
1783
1852
|
*
|
|
@@ -2127,6 +2196,20 @@ function createSessionRpc(connection, sessionId) {
|
|
|
2127
2196
|
* @returns Point-in-time snapshot of slow-changing session identifier and state fields
|
|
2128
2197
|
*/
|
|
2129
2198
|
snapshot: async () => connection.sendRequest("session.metadata.snapshot", { sessionId }),
|
|
2199
|
+
/**
|
|
2200
|
+
* Returns the client-owned string metadata persisted with this local session. The metadata is not included in model context, events, telemetry, snapshots, or remote exports.
|
|
2201
|
+
*
|
|
2202
|
+
* @returns Client-owned, case-sensitive string metadata persisted with a local session. Clients should namespace keys by owner. Keys must be non-empty and at most 256 UTF-8 bytes; keys under `copilot/` and `github/` are reserved. Values may contain at most 16 KiB of UTF-8 data. A bag may contain at most 128 entries and its serialized sidecar may contain at most 64 KiB. The runtime stores but never interprets these values.
|
|
2203
|
+
*/
|
|
2204
|
+
getClientMetadata: async () => connection.sendRequest("session.metadata.getClientMetadata", { sessionId }),
|
|
2205
|
+
/**
|
|
2206
|
+
* Atomically patches the client-owned string metadata persisted with this local session and returns the committed bag.
|
|
2207
|
+
*
|
|
2208
|
+
* @param params Atomic patch for client-owned session metadata. Operations apply in clear, remove, then set order. The resulting bag must satisfy the ClientMetadata entry and serialized-size limits. Local storage coordinates concurrent runtime processes; custom SessionFs providers must serialize writers that access the same session from multiple processes.
|
|
2209
|
+
*
|
|
2210
|
+
* @returns Client-owned, case-sensitive string metadata persisted with a local session. Clients should namespace keys by owner. Keys must be non-empty and at most 256 UTF-8 bytes; keys under `copilot/` and `github/` are reserved. Values may contain at most 16 KiB of UTF-8 data. A bag may contain at most 128 entries and its serialized sidecar may contain at most 64 KiB. The runtime stores but never interprets these values.
|
|
2211
|
+
*/
|
|
2212
|
+
updateClientMetadata: async (params) => connection.sendRequest("session.metadata.updateClientMetadata", { sessionId, ...params }),
|
|
2130
2213
|
/**
|
|
2131
2214
|
* Reports whether the local session is currently processing user/agent messages.
|
|
2132
2215
|
*
|
|
@@ -2584,7 +2667,13 @@ function createInternalSessionRpc(connection, sessionId) {
|
|
|
2584
2667
|
*
|
|
2585
2668
|
* @returns Resolved persisted factory identity and resumed run envelope.
|
|
2586
2669
|
*/
|
|
2587
|
-
resumeFromTool: async (params) => connection.sendRequest("session.factory.resumeFromTool", { sessionId, ...params })
|
|
2670
|
+
resumeFromTool: async (params) => connection.sendRequest("session.factory.resumeFromTool", { sessionId, ...params }),
|
|
2671
|
+
/**
|
|
2672
|
+
* Atomically pauses an owned factory attempt at a durable checkpoint.
|
|
2673
|
+
*
|
|
2674
|
+
* @param params Parameters for an owned durable pause checkpoint.
|
|
2675
|
+
*/
|
|
2676
|
+
pauseAtCheckpoint: async (params) => connection.sendRequest("session.factory.pauseAtCheckpoint", { sessionId, ...params })
|
|
2588
2677
|
},
|
|
2589
2678
|
/** @experimental */
|
|
2590
2679
|
model: {
|
|
@@ -2782,6 +2871,11 @@ function registerClientSessionApiHandlers(connection, getHandlers) {
|
|
|
2782
2871
|
if (!handler) throw new Error(`No factory handler registered for session: ${params.sessionId}`);
|
|
2783
2872
|
return handler.abort(params);
|
|
2784
2873
|
});
|
|
2874
|
+
connection.onRequest("tasks.cancel", async (params) => {
|
|
2875
|
+
const handler = getHandlers(params.sessionId).tasks;
|
|
2876
|
+
if (!handler) throw new Error(`No tasks handler registered for session: ${params.sessionId}`);
|
|
2877
|
+
return handler.cancel(params);
|
|
2878
|
+
});
|
|
2785
2879
|
connection.onRequest("sessionFs.readFile", async (params) => {
|
|
2786
2880
|
const handler = getHandlers(params.sessionId).sessionFs;
|
|
2787
2881
|
if (!handler) throw new Error(`No sessionFs handler registered for session: ${params.sessionId}`);
|
package/dist/cjs/session.js
CHANGED
|
@@ -249,6 +249,7 @@ class CopilotSession {
|
|
|
249
249
|
eventHandlers = /* @__PURE__ */ new Set();
|
|
250
250
|
typedEventHandlers = /* @__PURE__ */ new Map();
|
|
251
251
|
toolHandlers = /* @__PURE__ */ new Map();
|
|
252
|
+
pendingExternalTools = /* @__PURE__ */ new Map();
|
|
252
253
|
canvases = /* @__PURE__ */ new Map();
|
|
253
254
|
bearerTokenProviders = /* @__PURE__ */ new Map();
|
|
254
255
|
commandHandlers = /* @__PURE__ */ new Map();
|
|
@@ -268,6 +269,7 @@ class CopilotSession {
|
|
|
268
269
|
_capabilities = {};
|
|
269
270
|
openCanvasInstances = [];
|
|
270
271
|
disconnected = false;
|
|
272
|
+
disconnecting = false;
|
|
271
273
|
onDisconnected;
|
|
272
274
|
/** @internal Client session API handlers, populated by CopilotClient during create/resume. */
|
|
273
275
|
clientSessionApis = {};
|
|
@@ -467,6 +469,7 @@ class CopilotSession {
|
|
|
467
469
|
...await (0, import_telemetry.getTraceContext)(this.traceContextProvider),
|
|
468
470
|
sessionId: this.sessionId,
|
|
469
471
|
prompt: options.prompt,
|
|
472
|
+
source: options.source,
|
|
470
473
|
displayPrompt: options.displayPrompt,
|
|
471
474
|
attachments: options.attachments,
|
|
472
475
|
mode: options.mode,
|
|
@@ -525,6 +528,10 @@ class CopilotSession {
|
|
|
525
528
|
return;
|
|
526
529
|
}
|
|
527
530
|
this.disconnected = true;
|
|
531
|
+
for (const controller of this.pendingExternalTools.values()) {
|
|
532
|
+
controller.abort();
|
|
533
|
+
}
|
|
534
|
+
this.pendingExternalTools.clear();
|
|
528
535
|
this._runOnDisconnected();
|
|
529
536
|
this.eventHandlers.clear();
|
|
530
537
|
this.typedEventHandlers.clear();
|
|
@@ -628,6 +635,15 @@ class CopilotSession {
|
|
|
628
635
|
tracestate
|
|
629
636
|
);
|
|
630
637
|
}
|
|
638
|
+
} else if (event.type === "external_tool.completed") {
|
|
639
|
+
const { requestId } = event.data;
|
|
640
|
+
if (requestId) {
|
|
641
|
+
const controller = this.pendingExternalTools.get(requestId);
|
|
642
|
+
if (controller) {
|
|
643
|
+
this.pendingExternalTools.delete(requestId);
|
|
644
|
+
controller.abort();
|
|
645
|
+
}
|
|
646
|
+
}
|
|
631
647
|
} else if (event.type === "permission.requested") {
|
|
632
648
|
const { requestId, permissionRequest, resolvedByHook } = event.data;
|
|
633
649
|
if (resolvedByHook) {
|
|
@@ -708,16 +724,35 @@ class CopilotSession {
|
|
|
708
724
|
* @internal
|
|
709
725
|
*/
|
|
710
726
|
async _executeToolAndRespond(requestId, toolName, toolCallId, args, handler, traceparent, tracestate) {
|
|
727
|
+
const controller = new AbortController();
|
|
728
|
+
if (this.disconnected || this.pendingExternalTools.has(requestId)) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
this.pendingExternalTools.set(requestId, controller);
|
|
711
732
|
try {
|
|
712
733
|
let availableTools;
|
|
713
734
|
if (toolName === TOOL_SEARCH_TOOL_NAME) {
|
|
735
|
+
if (controller.signal.aborted) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const aborted = new Promise((resolve) => {
|
|
739
|
+
controller.signal.addEventListener("abort", () => resolve(void 0), {
|
|
740
|
+
once: true
|
|
741
|
+
});
|
|
742
|
+
});
|
|
714
743
|
try {
|
|
715
|
-
const metadata = await
|
|
716
|
-
|
|
744
|
+
const metadata = await Promise.race([
|
|
745
|
+
this.rpc.tools.getCurrentMetadata(),
|
|
746
|
+
aborted
|
|
747
|
+
]);
|
|
748
|
+
availableTools = metadata?.tools ?? void 0;
|
|
717
749
|
} catch {
|
|
718
750
|
availableTools = void 0;
|
|
719
751
|
}
|
|
720
752
|
}
|
|
753
|
+
if (controller.signal.aborted) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
721
756
|
const rawResult = await handler(args, {
|
|
722
757
|
sessionId: this.sessionId,
|
|
723
758
|
toolCallId,
|
|
@@ -725,7 +760,8 @@ class CopilotSession {
|
|
|
725
760
|
arguments: args,
|
|
726
761
|
availableTools,
|
|
727
762
|
traceparent,
|
|
728
|
-
tracestate
|
|
763
|
+
tracestate,
|
|
764
|
+
signal: controller.signal
|
|
729
765
|
});
|
|
730
766
|
let result;
|
|
731
767
|
if (rawResult == null) {
|
|
@@ -737,12 +773,12 @@ class CopilotSession {
|
|
|
737
773
|
} else {
|
|
738
774
|
result = JSON.stringify(rawResult);
|
|
739
775
|
}
|
|
740
|
-
if (this.
|
|
776
|
+
if (!this._claimExternalTool(requestId, controller)) {
|
|
741
777
|
return;
|
|
742
778
|
}
|
|
743
779
|
await this.rpc.tools.handlePendingToolCall({ requestId, result });
|
|
744
780
|
} catch (error) {
|
|
745
|
-
if (this.
|
|
781
|
+
if (!this._claimExternalTool(requestId, controller)) {
|
|
746
782
|
return;
|
|
747
783
|
}
|
|
748
784
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -753,7 +789,19 @@ class CopilotSession {
|
|
|
753
789
|
throw rpcError;
|
|
754
790
|
}
|
|
755
791
|
}
|
|
792
|
+
} finally {
|
|
793
|
+
if (this.pendingExternalTools.get(requestId) === controller) {
|
|
794
|
+
this.pendingExternalTools.delete(requestId);
|
|
795
|
+
}
|
|
796
|
+
controller.abort();
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
_claimExternalTool(requestId, controller) {
|
|
800
|
+
if (this.disconnected || this.pendingExternalTools.get(requestId) !== controller) {
|
|
801
|
+
return false;
|
|
756
802
|
}
|
|
803
|
+
this.pendingExternalTools.delete(requestId);
|
|
804
|
+
return true;
|
|
757
805
|
}
|
|
758
806
|
/**
|
|
759
807
|
* Executes a permission handler and sends the result back via RPC.
|
|
@@ -1507,13 +1555,27 @@ class CopilotSession {
|
|
|
1507
1555
|
* ```
|
|
1508
1556
|
*/
|
|
1509
1557
|
async disconnect() {
|
|
1510
|
-
if (this.disconnected) {
|
|
1558
|
+
if (this.disconnected || this.disconnecting) {
|
|
1511
1559
|
return;
|
|
1512
1560
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1561
|
+
this.disconnecting = true;
|
|
1562
|
+
try {
|
|
1563
|
+
let response = { success: false };
|
|
1564
|
+
for (let attempt = 0; attempt < 2 && !response.success; attempt++) {
|
|
1565
|
+
response = await this.connection.sendRequest("session.detach", {
|
|
1566
|
+
sessionId: this.sessionId
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
if (!response.success) {
|
|
1570
|
+
throw new Error(
|
|
1571
|
+
`Failed to disconnect session ${this.sessionId}: ${response.error || "Unknown error"}`
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
this._markDisconnected();
|
|
1575
|
+
} catch (error) {
|
|
1576
|
+
this.disconnecting = false;
|
|
1577
|
+
throw error;
|
|
1578
|
+
}
|
|
1517
1579
|
}
|
|
1518
1580
|
/** Enables `await using session = ...` syntax for automatic cleanup. */
|
|
1519
1581
|
async [Symbol.asyncDispose]() {
|
|
@@ -1555,11 +1617,48 @@ class CopilotSession {
|
|
|
1555
1617
|
* ```typescript
|
|
1556
1618
|
* await session.setModel("gpt-5.4");
|
|
1557
1619
|
* await session.setModel("claude-sonnet-4.6", { reasoningEffort: "high" });
|
|
1620
|
+
*
|
|
1621
|
+
* // Select the Auto model and its routing preference in one call.
|
|
1622
|
+
* await session.setModel("auto", { autoTier: "intelligence" });
|
|
1558
1623
|
* ```
|
|
1559
1624
|
*/
|
|
1560
1625
|
async setModel(model, options) {
|
|
1561
1626
|
await this.rpc.model.switchTo({ modelId: model, ...options });
|
|
1562
1627
|
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Change the Auto routing preference without changing the selected model.
|
|
1630
|
+
*
|
|
1631
|
+
* The runtime does not apply the preference immediately. It records the
|
|
1632
|
+
* request and commits it only when a later user turn using the `auto` model
|
|
1633
|
+
* successfully obtains a usable model from the provider. A `pending` status
|
|
1634
|
+
* therefore confirms that the request was accepted, not that it took effect.
|
|
1635
|
+
*
|
|
1636
|
+
* Watch for the outcome through the `session.model_change` event on success,
|
|
1637
|
+
* or the ephemeral `session.auto_tier_switch_failed` event on failure. You
|
|
1638
|
+
* can also read the current committed and in-flight state at any time with
|
|
1639
|
+
* `session.rpc.model.getCurrent()`.
|
|
1640
|
+
*
|
|
1641
|
+
* Only the most recent request survives: issuing a new request replaces any
|
|
1642
|
+
* earlier one that has not yet been claimed by a turn.
|
|
1643
|
+
*
|
|
1644
|
+
* @param autoTier - Routing preference to activate, or `null` to return to
|
|
1645
|
+
* the provider's default Auto routing
|
|
1646
|
+
* @returns The runtime's immediate acknowledgement and Auto preference snapshot
|
|
1647
|
+
*
|
|
1648
|
+
* @experimental Part of an experimental Auto routing surface and may change
|
|
1649
|
+
* or be removed in a future release.
|
|
1650
|
+
*
|
|
1651
|
+
* @example
|
|
1652
|
+
* ```typescript
|
|
1653
|
+
* const result = await session.setAutoTier("intelligence");
|
|
1654
|
+
* if (result.status === "pending") {
|
|
1655
|
+
* // Takes effect on a later turn that uses the `auto` model.
|
|
1656
|
+
* }
|
|
1657
|
+
* ```
|
|
1658
|
+
*/
|
|
1659
|
+
async setAutoTier(autoTier) {
|
|
1660
|
+
return await this.rpc.model.switchAutoTier({ autoTier });
|
|
1661
|
+
}
|
|
1563
1662
|
/**
|
|
1564
1663
|
* Log a message to the session timeline.
|
|
1565
1664
|
* The message appears in the session event stream and is visible to SDK consumers
|
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.84-5";
|
|
2
2
|
export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
package/dist/cliVersion.js
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -7,10 +7,13 @@ export declare class CopilotClient {
|
|
|
7
7
|
private ffiHost;
|
|
8
8
|
private connection;
|
|
9
9
|
private messageWriter;
|
|
10
|
+
private connectionClosed;
|
|
10
11
|
private socket;
|
|
11
12
|
private runtimePort;
|
|
12
13
|
private actualHost;
|
|
13
14
|
private state;
|
|
15
|
+
/** Shared in-flight start; concurrent callers await it instead of spawning another CLI. */
|
|
16
|
+
private startPromise;
|
|
14
17
|
private sessions;
|
|
15
18
|
private stderrBuffer;
|
|
16
19
|
/** Resolved connection mode chosen in the constructor. */
|
|
@@ -121,6 +124,7 @@ export declare class CopilotClient {
|
|
|
121
124
|
* ```
|
|
122
125
|
*/
|
|
123
126
|
start(): Promise<void>;
|
|
127
|
+
private doStart;
|
|
124
128
|
/**
|
|
125
129
|
* Stops the CLI server and closes all active sessions.
|
|
126
130
|
*
|
package/dist/client.js
CHANGED
|
@@ -214,10 +214,13 @@ class CopilotClient {
|
|
|
214
214
|
ffiHost = null;
|
|
215
215
|
connection = null;
|
|
216
216
|
messageWriter = null;
|
|
217
|
+
connectionClosed = false;
|
|
217
218
|
socket = null;
|
|
218
219
|
runtimePort = null;
|
|
219
220
|
actualHost = "localhost";
|
|
220
221
|
state = "disconnected";
|
|
222
|
+
/** Shared in-flight start; concurrent callers await it instead of spawning another CLI. */
|
|
223
|
+
startPromise = null;
|
|
221
224
|
sessions = /* @__PURE__ */ new Map();
|
|
222
225
|
stderrBuffer = "";
|
|
223
226
|
// Captures CLI stderr for error messages
|
|
@@ -595,7 +598,19 @@ class CopilotClient {
|
|
|
595
598
|
if (this.state === "connected") {
|
|
596
599
|
return;
|
|
597
600
|
}
|
|
601
|
+
if (this.startPromise) {
|
|
602
|
+
return this.startPromise;
|
|
603
|
+
}
|
|
604
|
+
this.startPromise = this.doStart();
|
|
605
|
+
try {
|
|
606
|
+
await this.startPromise;
|
|
607
|
+
} finally {
|
|
608
|
+
this.startPromise = null;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async doStart() {
|
|
598
612
|
this.forceStopping = false;
|
|
613
|
+
this.connectionClosed = false;
|
|
599
614
|
this.processTransportError = null;
|
|
600
615
|
this.state = "connecting";
|
|
601
616
|
try {
|
|
@@ -694,7 +709,7 @@ class CopilotClient {
|
|
|
694
709
|
}
|
|
695
710
|
this.sessions.clear();
|
|
696
711
|
this.githubTokenProviders.clear();
|
|
697
|
-
if (this.connection && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
712
|
+
if (this.connection && !this.connectionClosed && (this.cliProcess || this.ffiHost) && !this.isExternalServer) {
|
|
698
713
|
const runtimeShutdownStart = Date.now();
|
|
699
714
|
const shutdownPromise = this.rpc.runtime.shutdown();
|
|
700
715
|
void shutdownPromise.catch(() => void 0);
|
|
@@ -783,7 +798,7 @@ class CopilotClient {
|
|
|
783
798
|
const host = this.ffiHost;
|
|
784
799
|
this.ffiHost = null;
|
|
785
800
|
try {
|
|
786
|
-
host.dispose();
|
|
801
|
+
await host.dispose();
|
|
787
802
|
} catch (error) {
|
|
788
803
|
errors.push(
|
|
789
804
|
new Error(
|
|
@@ -878,11 +893,12 @@ class CopilotClient {
|
|
|
878
893
|
this.cliProcess = null;
|
|
879
894
|
}
|
|
880
895
|
if (this.ffiHost) {
|
|
896
|
+
const host = this.ffiHost;
|
|
897
|
+
this.ffiHost = null;
|
|
881
898
|
try {
|
|
882
|
-
|
|
899
|
+
await host.dispose();
|
|
883
900
|
} catch {
|
|
884
901
|
}
|
|
885
|
-
this.ffiHost = null;
|
|
886
902
|
}
|
|
887
903
|
if (this.cliStartTimeout) {
|
|
888
904
|
clearTimeout(this.cliStartTimeout);
|
|
@@ -1199,6 +1215,7 @@ class CopilotClient {
|
|
|
1199
1215
|
...this.onGitHubTelemetry != null ? { enableGitHubTelemetryForwarding: true } : {},
|
|
1200
1216
|
mcpServers: toWireMcpServers(config.mcpServers),
|
|
1201
1217
|
mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
|
|
1218
|
+
authClientIdMetadataUrl: config.authClientIdMetadataUrl,
|
|
1202
1219
|
envValueMode: "direct",
|
|
1203
1220
|
customAgents: toWireCustomAgents(config.customAgents),
|
|
1204
1221
|
customAgentsLocalOnly: config.customAgentsLocalOnly,
|
|
@@ -1259,6 +1276,7 @@ class CopilotClient {
|
|
|
1259
1276
|
await this.updateSessionOptionsForMode(session, config);
|
|
1260
1277
|
this.commitGitHubTokenProvider(returnedSessionId, gitHubTokenProviderRegistrationId);
|
|
1261
1278
|
} catch (e) {
|
|
1279
|
+
session?._markDisconnected();
|
|
1262
1280
|
if (registeredId !== void 0) {
|
|
1263
1281
|
this.sessions.delete(registeredId);
|
|
1264
1282
|
}
|
|
@@ -1443,6 +1461,7 @@ class CopilotClient {
|
|
|
1443
1461
|
...this.onGitHubTelemetry != null ? { enableGitHubTelemetryForwarding: true } : {},
|
|
1444
1462
|
mcpServers: toWireMcpServers(config.mcpServers),
|
|
1445
1463
|
mcpOAuthTokenStorage: config.mcpOAuthTokenStorage,
|
|
1464
|
+
authClientIdMetadataUrl: config.authClientIdMetadataUrl,
|
|
1446
1465
|
envValueMode: "direct",
|
|
1447
1466
|
customAgents: toWireCustomAgents(config.customAgents),
|
|
1448
1467
|
customAgentsLocalOnly: config.customAgentsLocalOnly,
|
|
@@ -1491,6 +1510,7 @@ class CopilotClient {
|
|
|
1491
1510
|
await this.updateSessionOptionsForMode(session, config);
|
|
1492
1511
|
this.commitGitHubTokenProvider(sessionId, gitHubTokenProviderRegistrationId);
|
|
1493
1512
|
} catch (e) {
|
|
1513
|
+
session._markDisconnected();
|
|
1494
1514
|
this.sessions.delete(sessionId);
|
|
1495
1515
|
if (gitHubTokenProviderRegistrationId !== void 0) {
|
|
1496
1516
|
this.githubTokenProviders.delete(gitHubTokenProviderRegistrationId);
|
|
@@ -1606,7 +1626,10 @@ class CopilotClient {
|
|
|
1606
1626
|
const raceAgainstExit = (p) => this.processExitPromise ? Promise.race([p, this.processExitPromise]) : p;
|
|
1607
1627
|
let serverVersion;
|
|
1608
1628
|
try {
|
|
1609
|
-
const connectParams = {
|
|
1629
|
+
const connectParams = {
|
|
1630
|
+
token: this.effectiveConnectionToken,
|
|
1631
|
+
supportedTaskKinds: ["agent", "client", "shell"]
|
|
1632
|
+
};
|
|
1610
1633
|
if (this.onGitHubTelemetry != null) {
|
|
1611
1634
|
connectParams.enableGitHubTelemetryForwarding = true;
|
|
1612
1635
|
}
|
|
@@ -2237,12 +2260,24 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2237
2260
|
return await this.handleHooksInvoke(params);
|
|
2238
2261
|
}
|
|
2239
2262
|
);
|
|
2240
|
-
this.connection
|
|
2263
|
+
const connection = this.connection;
|
|
2264
|
+
const markDisconnected = () => {
|
|
2265
|
+
if (this.connection !== connection) {
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
this.connectionClosed = true;
|
|
2241
2269
|
this.state = "disconnected";
|
|
2270
|
+
for (const session of this.sessions.values()) {
|
|
2271
|
+
session._markDisconnected();
|
|
2272
|
+
}
|
|
2273
|
+
this.sessions.clear();
|
|
2242
2274
|
this.githubTokenProviders.clear();
|
|
2243
|
-
}
|
|
2244
|
-
this.connection.
|
|
2245
|
-
|
|
2275
|
+
};
|
|
2276
|
+
this.connection.onClose(markDisconnected);
|
|
2277
|
+
this.connection.onError(() => {
|
|
2278
|
+
if (this.connection === connection) {
|
|
2279
|
+
this.state = "disconnected";
|
|
2280
|
+
}
|
|
2246
2281
|
});
|
|
2247
2282
|
}
|
|
2248
2283
|
handleSessionEventNotification(notification) {
|
package/dist/ffiRuntimeHost.d.ts
CHANGED
|
@@ -4,12 +4,16 @@ export declare class FfiRuntimeHost {
|
|
|
4
4
|
private readonly cliEntrypoint;
|
|
5
5
|
private readonly environment;
|
|
6
6
|
private readonly args;
|
|
7
|
+
private static readonly quarantinedHosts;
|
|
7
8
|
private readonly lib;
|
|
8
9
|
private serverId;
|
|
9
10
|
private connectionId;
|
|
10
11
|
private disposed;
|
|
12
|
+
private starting;
|
|
11
13
|
private outboundCallback;
|
|
12
14
|
private keepAliveTimer;
|
|
15
|
+
private cleanupRetryTimer;
|
|
16
|
+
private cleanupInProgress;
|
|
13
17
|
/** The stream JSON-RPC reads server→client frames from. */
|
|
14
18
|
readonly receiveStream: PassThrough;
|
|
15
19
|
/** The stream JSON-RPC writes client→server frames to. */
|
|
@@ -30,6 +34,8 @@ export declare class FfiRuntimeHost {
|
|
|
30
34
|
*/
|
|
31
35
|
private feedInbound;
|
|
32
36
|
private unregisterCallback;
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
private scheduleCleanupRetry;
|
|
38
|
+
private tryFinalizeCleanup;
|
|
39
|
+
/** Awaits the initial cleanup attempt; a non-quiescent close is retried in the background. */
|
|
40
|
+
dispose(): Promise<void>;
|
|
35
41
|
}
|