@github/copilot-sdk 1.0.29-preview.1 → 1.0.29-preview.3
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 +436 -2
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +26 -12
- package/dist/cjs/copilotRequestHandler.js +17 -7
- package/dist/cjs/generated/rpc.js +71 -2
- package/dist/cjs/session.js +48 -0
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.js +26 -12
- package/dist/copilotRequestHandler.js +17 -7
- package/dist/generated/rpc.d.ts +471 -4
- package/dist/generated/rpc.js +71 -2
- package/dist/generated/session-events.d.ts +23 -1
- package/dist/index.d.ts +1 -1
- package/dist/session.d.ts +9 -2
- package/dist/session.js +48 -0
- package/dist/types.d.ts +26 -3
- package/docs/examples.md +7 -7
- package/package.json +13 -12
package/dist/cjs/client.js
CHANGED
|
@@ -336,8 +336,10 @@ class CopilotClient {
|
|
|
336
336
|
effectiveConnectionToken;
|
|
337
337
|
onListModels;
|
|
338
338
|
onGetTraceContext;
|
|
339
|
-
modelsCache =
|
|
340
|
-
|
|
339
|
+
modelsCache = {
|
|
340
|
+
models: null,
|
|
341
|
+
lock: Promise.resolve()
|
|
342
|
+
};
|
|
341
343
|
sessionLifecycleHandlers = /* @__PURE__ */ new Set();
|
|
342
344
|
typedLifecycleHandlers = /* @__PURE__ */ new Map();
|
|
343
345
|
_rpc = null;
|
|
@@ -906,7 +908,7 @@ class CopilotClient {
|
|
|
906
908
|
this._rpc = null;
|
|
907
909
|
this._internalRpc = null;
|
|
908
910
|
}
|
|
909
|
-
this.modelsCache = null;
|
|
911
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
910
912
|
if (this.socket) {
|
|
911
913
|
const socket = this.socket;
|
|
912
914
|
this.socket = null;
|
|
@@ -1068,7 +1070,7 @@ class CopilotClient {
|
|
|
1068
1070
|
this._rpc = null;
|
|
1069
1071
|
this._internalRpc = null;
|
|
1070
1072
|
}
|
|
1071
|
-
this.modelsCache = null;
|
|
1073
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
1072
1074
|
if (this.socket) {
|
|
1073
1075
|
try {
|
|
1074
1076
|
this.socket.destroy();
|
|
@@ -2087,14 +2089,16 @@ class CopilotClient {
|
|
|
2087
2089
|
* @throws Error if not connected (when no custom handler is set)
|
|
2088
2090
|
*/
|
|
2089
2091
|
async listModels() {
|
|
2090
|
-
|
|
2092
|
+
const cache = this.modelsCache;
|
|
2093
|
+
const previousLock = cache.lock;
|
|
2091
2094
|
let resolveLock;
|
|
2092
|
-
|
|
2095
|
+
cache.lock = new Promise((resolve2) => {
|
|
2093
2096
|
resolveLock = resolve2;
|
|
2094
2097
|
});
|
|
2098
|
+
await previousLock;
|
|
2095
2099
|
try {
|
|
2096
|
-
if (
|
|
2097
|
-
return [...
|
|
2100
|
+
if (cache.models !== null) {
|
|
2101
|
+
return [...cache.models];
|
|
2098
2102
|
}
|
|
2099
2103
|
let models;
|
|
2100
2104
|
if (this.onListModels) {
|
|
@@ -2123,7 +2127,7 @@ class CopilotClient {
|
|
|
2123
2127
|
}
|
|
2124
2128
|
}
|
|
2125
2129
|
}
|
|
2126
|
-
|
|
2130
|
+
cache.models = [...models];
|
|
2127
2131
|
return [...models];
|
|
2128
2132
|
} finally {
|
|
2129
2133
|
resolveLock();
|
|
@@ -2888,6 +2892,14 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2888
2892
|
"skillProvider.list",
|
|
2889
2893
|
async (params, token) => await this.resolveSkillProviderSession(params)._handleSkillProviderList(token)
|
|
2890
2894
|
);
|
|
2895
|
+
this.connection.onRequest(
|
|
2896
|
+
"sessionManagement.create",
|
|
2897
|
+
async (params, token) => {
|
|
2898
|
+
const session = this.sessions.get(params.sessionId);
|
|
2899
|
+
if (!session) throw new Error("Session creation owner is unavailable");
|
|
2900
|
+
return await session._handleSessionManagementCreate(params, token);
|
|
2901
|
+
}
|
|
2902
|
+
);
|
|
2891
2903
|
this.connection.onRequest(
|
|
2892
2904
|
"skillProvider.read",
|
|
2893
2905
|
async (params, token) => {
|
|
@@ -2925,7 +2937,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2925
2937
|
this.messageWriter = null;
|
|
2926
2938
|
this._rpc = null;
|
|
2927
2939
|
this._internalRpc = null;
|
|
2928
|
-
this.modelsCache = null;
|
|
2940
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
2929
2941
|
};
|
|
2930
2942
|
const disconnectAfterDrain = () => {
|
|
2931
2943
|
if (exitFallback !== void 0) {
|
|
@@ -3021,7 +3033,8 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
3021
3033
|
const result = await session._handleUserInputRequest({
|
|
3022
3034
|
question: params.question,
|
|
3023
3035
|
choices: params.choices,
|
|
3024
|
-
allowFreeform: params.allowFreeform
|
|
3036
|
+
allowFreeform: params.allowFreeform,
|
|
3037
|
+
requestId: params.requestId
|
|
3025
3038
|
});
|
|
3026
3039
|
return result;
|
|
3027
3040
|
}
|
|
@@ -3037,7 +3050,8 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
3037
3050
|
summary: params.summary,
|
|
3038
3051
|
planContent: params.planContent,
|
|
3039
3052
|
actions: params.actions,
|
|
3040
|
-
recommendedAction: params.recommendedAction
|
|
3053
|
+
recommendedAction: params.recommendedAction,
|
|
3054
|
+
requestId: params.requestId
|
|
3041
3055
|
});
|
|
3042
3056
|
}
|
|
3043
3057
|
async handleAutoModeSwitchRequest(params) {
|
|
@@ -109,7 +109,9 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
109
109
|
if (this.#upstream) {
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
const upstream = new WebSocket(this.context.url
|
|
112
|
+
const upstream = new WebSocket(this.context.url, {
|
|
113
|
+
headers: forwardedRequestHeaders(this.context.headers)
|
|
114
|
+
});
|
|
113
115
|
upstream.binaryType = "arraybuffer";
|
|
114
116
|
this.#upstream = upstream;
|
|
115
117
|
upstream.addEventListener("message", (event) => {
|
|
@@ -149,13 +151,16 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
async close(status = CopilotWebSocketCloseStatus.normalClosure) {
|
|
154
|
+
const upstream = this.#upstream;
|
|
155
|
+
this.#upstream = null;
|
|
156
|
+
const completion = super.close(status);
|
|
152
157
|
try {
|
|
153
|
-
if (
|
|
154
|
-
|
|
158
|
+
if (upstream?.readyState === WebSocket.OPEN || upstream?.readyState === WebSocket.CONNECTING) {
|
|
159
|
+
upstream.close();
|
|
155
160
|
}
|
|
156
161
|
} catch {
|
|
157
162
|
}
|
|
158
|
-
await
|
|
163
|
+
await completion;
|
|
159
164
|
}
|
|
160
165
|
async [Symbol.asyncDispose]() {
|
|
161
166
|
try {
|
|
@@ -494,19 +499,24 @@ const FORBIDDEN_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
|
494
499
|
"te",
|
|
495
500
|
"trailer"
|
|
496
501
|
]);
|
|
497
|
-
|
|
502
|
+
function forwardedRequestHeaders(source) {
|
|
498
503
|
const headers = new Headers();
|
|
499
|
-
for (const [name, values] of Object.entries(
|
|
504
|
+
for (const [name, values] of Object.entries(source)) {
|
|
500
505
|
if (!values) {
|
|
501
506
|
continue;
|
|
502
507
|
}
|
|
503
|
-
|
|
508
|
+
const lower = name.toLowerCase();
|
|
509
|
+
if (FORBIDDEN_REQUEST_HEADERS.has(lower) || lower.startsWith("sec-websocket-")) {
|
|
504
510
|
continue;
|
|
505
511
|
}
|
|
506
512
|
for (const value of values) {
|
|
507
513
|
headers.append(name, value);
|
|
508
514
|
}
|
|
509
515
|
}
|
|
516
|
+
return headers;
|
|
517
|
+
}
|
|
518
|
+
async function buildFetchRequest(exchange) {
|
|
519
|
+
const headers = forwardedRequestHeaders(exchange.headers);
|
|
510
520
|
const method = exchange.method.toUpperCase();
|
|
511
521
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
512
522
|
let body;
|
|
@@ -841,9 +841,17 @@ function createServerRpc(connection) {
|
|
|
841
841
|
*
|
|
842
842
|
* @param params A bounded catalog search. Both the query length and the result count are capped by the schema so a caller cannot request an unbounded scan.
|
|
843
843
|
*
|
|
844
|
-
* @returns Outcome of
|
|
844
|
+
* @returns Outcome of catalog.search or catalog.recommend: either bounded inert candidates, or one typed refusal. Never a partial success.
|
|
845
845
|
*/
|
|
846
846
|
search: async (params) => connection.sendRequest("catalog.search", params),
|
|
847
|
+
/**
|
|
848
|
+
* Requests the initial page of at most ten official-product recommendations for a complete task and product, bound to an existing attached local session. Requires catalog-recommend, catalog-search-session-bound and catalog-search-credential-required. Uses the selected GitHub.com user credential on the fixed Agent Finder recommendations route; successful capability negotiation does not establish service acceptance. Returns the existing inert catalog candidates and retained install references with the typed catalog refusal union. No anonymous retry, unfiltered search fallback or continuation is performed. Server-owned product approvals establish provenance, not task suitability. Read-only: nothing is installed, configured or persisted.
|
|
849
|
+
*
|
|
850
|
+
* @param params Initial-page official-product recommendations for a complete task. The runtime fixes recommendationPolicy to official-product and pageSize to 10; callers cannot override the policy, request pagination or fall back to search.
|
|
851
|
+
*
|
|
852
|
+
* @returns Outcome of catalog.search or catalog.recommend: either bounded inert candidates, or one typed refusal. Never a partial success.
|
|
853
|
+
*/
|
|
854
|
+
recommend: async (params) => connection.sendRequest("catalog.recommend", params),
|
|
847
855
|
/**
|
|
848
856
|
* Retrieves one saved feed by its opaque ID, optionally filtered by trust tier. Requires catalog-feeds and catalog-search-credential-required, and uses the same authority, credential policy, optional session binding and candidate projection as catalog.search, so available entries are the same inert candidates, with the same installability, handles and display metadata, and install through the same confirmed flows. Entries keep the feed's order; an entry the runtime cannot present is returned as unavailable with a reason rather than failing the feed. No anonymous retry. Read-only: nothing is installed, configured, or persisted.
|
|
849
857
|
*
|
|
@@ -2174,6 +2182,49 @@ function createInternalServerRpc(connection) {
|
|
|
2174
2182
|
}
|
|
2175
2183
|
function createSessionRpc(connection, sessionId) {
|
|
2176
2184
|
return {
|
|
2185
|
+
/** @experimental */
|
|
2186
|
+
management: {
|
|
2187
|
+
/**
|
|
2188
|
+
* Updates opt-in session management policy live. Enabling the master enables all tools before applying individual overrides. Opt-in is scoped to the session's configuration directory.
|
|
2189
|
+
*
|
|
2190
|
+
* @param params Updates the session's live policy without changing persistent host settings.
|
|
2191
|
+
*
|
|
2192
|
+
* @returns Opt-in policy for local session management.
|
|
2193
|
+
*/
|
|
2194
|
+
configure: async (params) => connection.sendRequest("session.management.configure", { ...params, sessionId }),
|
|
2195
|
+
/**
|
|
2196
|
+
* Lists other live, opted-in sessions in the same configuration directory. Requires the list tool to be enabled.
|
|
2197
|
+
*
|
|
2198
|
+
* @param params Lists opted-in local peers. The caller is omitted.
|
|
2199
|
+
*
|
|
2200
|
+
* @returns Eligible live peers reported by their owning runtimes.
|
|
2201
|
+
*/
|
|
2202
|
+
list: async (params) => connection.sendRequest("session.management.list", { ...params, sessionId }),
|
|
2203
|
+
/**
|
|
2204
|
+
* Injects peer text into an opted-in session. Wakes an idle agent and safely queues delivery to a busy agent. Acceptance does not imply an answer or completed task.
|
|
2205
|
+
*
|
|
2206
|
+
* @param params Sends peer text, never human approval, to another opted-in session.
|
|
2207
|
+
*
|
|
2208
|
+
* @returns Acceptance is not a completed turn or a reply.
|
|
2209
|
+
*/
|
|
2210
|
+
message: async (params) => connection.sendRequest("session.management.message", { ...params, sessionId }),
|
|
2211
|
+
/**
|
|
2212
|
+
* Asks the owning host to create and supervise a separate session, preserving permissions and model restrictions. Omitted model, reasoning effort, context tier and cwd inherit the caller's current values; explicit overrides use normal model validation and workspace trust. Records durable creation lineage before delivering the initial task as peer text. Returns the new session ID, not task completion. Requires the create tool and a host creation handler.
|
|
2213
|
+
*
|
|
2214
|
+
* @param params Requests a separate session. Omitted launch options inherit the caller's current configuration.
|
|
2215
|
+
*
|
|
2216
|
+
* @returns Identifies a session owned and supervised by the creating host.
|
|
2217
|
+
*/
|
|
2218
|
+
create: async (params) => connection.sendRequest("session.management.create", { ...params, sessionId }),
|
|
2219
|
+
/**
|
|
2220
|
+
* Closes a live opted-in session created by the caller or one of its descendants, preserving saved history and leaving descendants open. Requires the close capability to be enabled. Self, ancestors, siblings and unrelated sessions cannot be closed.
|
|
2221
|
+
*
|
|
2222
|
+
* @param params Closes one live opted-in descendant without deleting its saved history or closing its children.
|
|
2223
|
+
*
|
|
2224
|
+
* @returns Completion of the existing non-deleting close lifecycle.
|
|
2225
|
+
*/
|
|
2226
|
+
close: async (params) => connection.sendRequest("session.management.close", { ...params, sessionId })
|
|
2227
|
+
},
|
|
2177
2228
|
/** @experimental */
|
|
2178
2229
|
providers: {
|
|
2179
2230
|
/**
|
|
@@ -2811,7 +2862,13 @@ function createSessionRpc(connection, sessionId) {
|
|
|
2811
2862
|
*
|
|
2812
2863
|
* @returns Canonical runtime state for the session's current autopilot objective.
|
|
2813
2864
|
*/
|
|
2814
|
-
getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId })
|
|
2865
|
+
getState: async () => connection.sendRequest("session.autopilotObjective.getState", { sessionId }),
|
|
2866
|
+
/**
|
|
2867
|
+
* Sets whether completing or pausing this session's objective preserves autopilot mode. This in-memory preference defaults to false and must be reapplied when attaching a client.
|
|
2868
|
+
*
|
|
2869
|
+
* @param params Client-resolved preference for retaining autopilot mode after objective completion or pause.
|
|
2870
|
+
*/
|
|
2871
|
+
setStayInAutopilot: async (params) => connection.sendRequest("session.autopilotObjective.setStayInAutopilot", { ...params, sessionId })
|
|
2815
2872
|
},
|
|
2816
2873
|
/** @experimental */
|
|
2817
2874
|
completions: {
|
|
@@ -3551,6 +3608,12 @@ function createSessionRpc(connection, sessionId) {
|
|
|
3551
3608
|
* @returns The selectable model entries and selection ids synthesized for the synchronized BYOK models.
|
|
3552
3609
|
*/
|
|
3553
3610
|
sync: async (params) => connection.sendRequest("session.provider.sync", { ...params, sessionId }),
|
|
3611
|
+
/**
|
|
3612
|
+
* Returns credential-free provider configuration status for the selected model. This does not validate provider credentials or contact the provider.
|
|
3613
|
+
*
|
|
3614
|
+
* @returns Credential-free provider configuration status for the selected model.
|
|
3615
|
+
*/
|
|
3616
|
+
getStatus: async () => connection.sendRequest("session.provider.getStatus", { sessionId }),
|
|
3554
3617
|
/**
|
|
3555
3618
|
* 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.
|
|
3556
3619
|
*
|
|
@@ -3891,6 +3954,12 @@ function createSessionRpc(connection, sessionId) {
|
|
|
3891
3954
|
* @returns Current permission mode.
|
|
3892
3955
|
*/
|
|
3893
3956
|
getMode: async () => connection.sendRequest("session.permissions.getMode", { sessionId }),
|
|
3957
|
+
/**
|
|
3958
|
+
* Returns the approval modes currently available under the session's feature and managed permission policy. This read does not change permissions; mutations must still check their authoritative result because policy may change.
|
|
3959
|
+
*
|
|
3960
|
+
* @returns Available permission modes, derived from current session policy.
|
|
3961
|
+
*/
|
|
3962
|
+
getCapabilities: async () => connection.sendRequest("session.permissions.getCapabilities", { sessionId }),
|
|
3894
3963
|
/**
|
|
3895
3964
|
* Adds or removes session-scoped or location-scoped permission rules.
|
|
3896
3965
|
*
|
package/dist/cjs/session.js
CHANGED
|
@@ -170,6 +170,11 @@ class WorkflowProgressBuffer {
|
|
|
170
170
|
if (this.closed) {
|
|
171
171
|
throw new Error("Cannot log after the workflow run has settled");
|
|
172
172
|
}
|
|
173
|
+
if (typeof text !== "string") {
|
|
174
|
+
throw new TypeError(
|
|
175
|
+
`${kind}() expects a string; got ${text === null ? "null" : typeof text}.`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
173
178
|
this.pending.push({ seq: this.nextSeq++, kind, text });
|
|
174
179
|
this.scheduleFlush();
|
|
175
180
|
}
|
|
@@ -297,6 +302,7 @@ class CopilotSession {
|
|
|
297
302
|
/** Settles once every earlier `setTools` call has finished. */
|
|
298
303
|
setToolsQueue = Promise.resolve();
|
|
299
304
|
pendingExternalTools = /* @__PURE__ */ new Map();
|
|
305
|
+
pendingSessionCreations = /* @__PURE__ */ new Set();
|
|
300
306
|
canvases = /* @__PURE__ */ new Map();
|
|
301
307
|
bearerTokenProviders = /* @__PURE__ */ new Map();
|
|
302
308
|
commandHandlers = /* @__PURE__ */ new Map();
|
|
@@ -309,6 +315,7 @@ class CopilotSession {
|
|
|
309
315
|
exitPlanModeHandler;
|
|
310
316
|
autoModeSwitchHandler;
|
|
311
317
|
skillProvider;
|
|
318
|
+
sessionCreationHandler;
|
|
312
319
|
hooks;
|
|
313
320
|
transformCallbacks;
|
|
314
321
|
_rpc = null;
|
|
@@ -896,6 +903,10 @@ class CopilotSession {
|
|
|
896
903
|
controller.abort();
|
|
897
904
|
}
|
|
898
905
|
this.pendingExternalTools.clear();
|
|
906
|
+
for (const controller of this.pendingSessionCreations) {
|
|
907
|
+
controller.abort();
|
|
908
|
+
}
|
|
909
|
+
this.pendingSessionCreations.clear();
|
|
899
910
|
this.eventHandlers.clear();
|
|
900
911
|
this.typedEventHandlers.clear();
|
|
901
912
|
this.toolHandlers.clear();
|
|
@@ -906,6 +917,7 @@ class CopilotSession {
|
|
|
906
917
|
this.exitPlanModeHandler = void 0;
|
|
907
918
|
this.autoModeSwitchHandler = void 0;
|
|
908
919
|
this.skillProvider = void 0;
|
|
920
|
+
this.sessionCreationHandler = void 0;
|
|
909
921
|
this.hooks = void 0;
|
|
910
922
|
this.traceContextProvider = void 0;
|
|
911
923
|
this.bearerTokenProviders.clear();
|
|
@@ -1575,6 +1587,7 @@ class CopilotSession {
|
|
|
1575
1587
|
assertWorkflowResult(result);
|
|
1576
1588
|
return { result };
|
|
1577
1589
|
} finally {
|
|
1590
|
+
controller.abort(new DOMException("Workflow run has settled", "AbortError"));
|
|
1578
1591
|
try {
|
|
1579
1592
|
await progress.close();
|
|
1580
1593
|
} finally {
|
|
@@ -1869,6 +1882,41 @@ class CopilotSession {
|
|
|
1869
1882
|
this.assertConnected();
|
|
1870
1883
|
this.skillProvider = provider;
|
|
1871
1884
|
}
|
|
1885
|
+
/**
|
|
1886
|
+
* Registers the host's creation callback without enabling the tool group.
|
|
1887
|
+
* Enable it separately with `session.rpc.management.configure({ enabled: true })`.
|
|
1888
|
+
*/
|
|
1889
|
+
async setSessionCreationHandler(handler) {
|
|
1890
|
+
this.assertConnected();
|
|
1891
|
+
const previous = this.sessionCreationHandler;
|
|
1892
|
+
this.sessionCreationHandler = handler;
|
|
1893
|
+
try {
|
|
1894
|
+
return await this.rpc.management.configure({ hasCreateHandler: handler !== void 0 });
|
|
1895
|
+
} catch (error) {
|
|
1896
|
+
if (this.sessionCreationHandler === handler) this.sessionCreationHandler = previous;
|
|
1897
|
+
throw error;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
/** @internal */
|
|
1901
|
+
async _handleSessionManagementCreate(request, token) {
|
|
1902
|
+
this.assertConnected();
|
|
1903
|
+
const handler = this.sessionCreationHandler;
|
|
1904
|
+
if (!handler || request.parentSessionId !== this.sessionId || request.sessionId !== this.sessionId) {
|
|
1905
|
+
throw new Error("Session creation handler is unavailable");
|
|
1906
|
+
}
|
|
1907
|
+
const controller = new AbortController();
|
|
1908
|
+
this.pendingSessionCreations.add(controller);
|
|
1909
|
+
const subscription = token.onCancellationRequested(() => controller.abort());
|
|
1910
|
+
if (token.isCancellationRequested) controller.abort();
|
|
1911
|
+
try {
|
|
1912
|
+
return await handler(request, { signal: controller.signal });
|
|
1913
|
+
} catch {
|
|
1914
|
+
throw new Error("Session creation callback failed");
|
|
1915
|
+
} finally {
|
|
1916
|
+
subscription.dispose();
|
|
1917
|
+
this.pendingSessionCreations.delete(controller);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1872
1920
|
/**
|
|
1873
1921
|
* Handles a `skillProvider.list` request from the runtime.
|
|
1874
1922
|
*
|
package/dist/cliVersion.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const COPILOT_CLI_VERSION = "1.0.106-
|
|
1
|
+
export declare const COPILOT_CLI_VERSION = "1.0.106-4";
|
|
2
2
|
export declare const COPILOT_CLI_USE_NPM_PACKAGE = false;
|
package/dist/cliVersion.js
CHANGED
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -318,8 +318,10 @@ class CopilotClient {
|
|
|
318
318
|
effectiveConnectionToken;
|
|
319
319
|
onListModels;
|
|
320
320
|
onGetTraceContext;
|
|
321
|
-
modelsCache =
|
|
322
|
-
|
|
321
|
+
modelsCache = {
|
|
322
|
+
models: null,
|
|
323
|
+
lock: Promise.resolve()
|
|
324
|
+
};
|
|
323
325
|
sessionLifecycleHandlers = /* @__PURE__ */ new Set();
|
|
324
326
|
typedLifecycleHandlers = /* @__PURE__ */ new Map();
|
|
325
327
|
_rpc = null;
|
|
@@ -888,7 +890,7 @@ class CopilotClient {
|
|
|
888
890
|
this._rpc = null;
|
|
889
891
|
this._internalRpc = null;
|
|
890
892
|
}
|
|
891
|
-
this.modelsCache = null;
|
|
893
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
892
894
|
if (this.socket) {
|
|
893
895
|
const socket = this.socket;
|
|
894
896
|
this.socket = null;
|
|
@@ -1050,7 +1052,7 @@ class CopilotClient {
|
|
|
1050
1052
|
this._rpc = null;
|
|
1051
1053
|
this._internalRpc = null;
|
|
1052
1054
|
}
|
|
1053
|
-
this.modelsCache = null;
|
|
1055
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
1054
1056
|
if (this.socket) {
|
|
1055
1057
|
try {
|
|
1056
1058
|
this.socket.destroy();
|
|
@@ -2069,14 +2071,16 @@ class CopilotClient {
|
|
|
2069
2071
|
* @throws Error if not connected (when no custom handler is set)
|
|
2070
2072
|
*/
|
|
2071
2073
|
async listModels() {
|
|
2072
|
-
|
|
2074
|
+
const cache = this.modelsCache;
|
|
2075
|
+
const previousLock = cache.lock;
|
|
2073
2076
|
let resolveLock;
|
|
2074
|
-
|
|
2077
|
+
cache.lock = new Promise((resolve2) => {
|
|
2075
2078
|
resolveLock = resolve2;
|
|
2076
2079
|
});
|
|
2080
|
+
await previousLock;
|
|
2077
2081
|
try {
|
|
2078
|
-
if (
|
|
2079
|
-
return [...
|
|
2082
|
+
if (cache.models !== null) {
|
|
2083
|
+
return [...cache.models];
|
|
2080
2084
|
}
|
|
2081
2085
|
let models;
|
|
2082
2086
|
if (this.onListModels) {
|
|
@@ -2105,7 +2109,7 @@ class CopilotClient {
|
|
|
2105
2109
|
}
|
|
2106
2110
|
}
|
|
2107
2111
|
}
|
|
2108
|
-
|
|
2112
|
+
cache.models = [...models];
|
|
2109
2113
|
return [...models];
|
|
2110
2114
|
} finally {
|
|
2111
2115
|
resolveLock();
|
|
@@ -2870,6 +2874,14 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2870
2874
|
"skillProvider.list",
|
|
2871
2875
|
async (params, token) => await this.resolveSkillProviderSession(params)._handleSkillProviderList(token)
|
|
2872
2876
|
);
|
|
2877
|
+
this.connection.onRequest(
|
|
2878
|
+
"sessionManagement.create",
|
|
2879
|
+
async (params, token) => {
|
|
2880
|
+
const session = this.sessions.get(params.sessionId);
|
|
2881
|
+
if (!session) throw new Error("Session creation owner is unavailable");
|
|
2882
|
+
return await session._handleSessionManagementCreate(params, token);
|
|
2883
|
+
}
|
|
2884
|
+
);
|
|
2873
2885
|
this.connection.onRequest(
|
|
2874
2886
|
"skillProvider.read",
|
|
2875
2887
|
async (params, token) => {
|
|
@@ -2907,7 +2919,7 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
2907
2919
|
this.messageWriter = null;
|
|
2908
2920
|
this._rpc = null;
|
|
2909
2921
|
this._internalRpc = null;
|
|
2910
|
-
this.modelsCache = null;
|
|
2922
|
+
this.modelsCache = { models: null, lock: Promise.resolve() };
|
|
2911
2923
|
};
|
|
2912
2924
|
const disconnectAfterDrain = () => {
|
|
2913
2925
|
if (exitFallback !== void 0) {
|
|
@@ -3003,7 +3015,8 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
3003
3015
|
const result = await session._handleUserInputRequest({
|
|
3004
3016
|
question: params.question,
|
|
3005
3017
|
choices: params.choices,
|
|
3006
|
-
allowFreeform: params.allowFreeform
|
|
3018
|
+
allowFreeform: params.allowFreeform,
|
|
3019
|
+
requestId: params.requestId
|
|
3007
3020
|
});
|
|
3008
3021
|
return result;
|
|
3009
3022
|
}
|
|
@@ -3019,7 +3032,8 @@ stderr: ${stderrOutput}` : ""}`
|
|
|
3019
3032
|
summary: params.summary,
|
|
3020
3033
|
planContent: params.planContent,
|
|
3021
3034
|
actions: params.actions,
|
|
3022
|
-
recommendedAction: params.recommendedAction
|
|
3035
|
+
recommendedAction: params.recommendedAction,
|
|
3036
|
+
requestId: params.requestId
|
|
3023
3037
|
});
|
|
3024
3038
|
}
|
|
3025
3039
|
async handleAutoModeSwitchRequest(params) {
|
|
@@ -82,7 +82,9 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
82
82
|
if (this.#upstream) {
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
const upstream = new WebSocket(this.context.url
|
|
85
|
+
const upstream = new WebSocket(this.context.url, {
|
|
86
|
+
headers: forwardedRequestHeaders(this.context.headers)
|
|
87
|
+
});
|
|
86
88
|
upstream.binaryType = "arraybuffer";
|
|
87
89
|
this.#upstream = upstream;
|
|
88
90
|
upstream.addEventListener("message", (event) => {
|
|
@@ -122,13 +124,16 @@ class CopilotWebSocketForwarder extends CopilotWebSocketHandler {
|
|
|
122
124
|
});
|
|
123
125
|
}
|
|
124
126
|
async close(status = CopilotWebSocketCloseStatus.normalClosure) {
|
|
127
|
+
const upstream = this.#upstream;
|
|
128
|
+
this.#upstream = null;
|
|
129
|
+
const completion = super.close(status);
|
|
125
130
|
try {
|
|
126
|
-
if (
|
|
127
|
-
|
|
131
|
+
if (upstream?.readyState === WebSocket.OPEN || upstream?.readyState === WebSocket.CONNECTING) {
|
|
132
|
+
upstream.close();
|
|
128
133
|
}
|
|
129
134
|
} catch {
|
|
130
135
|
}
|
|
131
|
-
await
|
|
136
|
+
await completion;
|
|
132
137
|
}
|
|
133
138
|
async [Symbol.asyncDispose]() {
|
|
134
139
|
try {
|
|
@@ -467,19 +472,24 @@ const FORBIDDEN_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
|
467
472
|
"te",
|
|
468
473
|
"trailer"
|
|
469
474
|
]);
|
|
470
|
-
|
|
475
|
+
function forwardedRequestHeaders(source) {
|
|
471
476
|
const headers = new Headers();
|
|
472
|
-
for (const [name, values] of Object.entries(
|
|
477
|
+
for (const [name, values] of Object.entries(source)) {
|
|
473
478
|
if (!values) {
|
|
474
479
|
continue;
|
|
475
480
|
}
|
|
476
|
-
|
|
481
|
+
const lower = name.toLowerCase();
|
|
482
|
+
if (FORBIDDEN_REQUEST_HEADERS.has(lower) || lower.startsWith("sec-websocket-")) {
|
|
477
483
|
continue;
|
|
478
484
|
}
|
|
479
485
|
for (const value of values) {
|
|
480
486
|
headers.append(name, value);
|
|
481
487
|
}
|
|
482
488
|
}
|
|
489
|
+
return headers;
|
|
490
|
+
}
|
|
491
|
+
async function buildFetchRequest(exchange) {
|
|
492
|
+
const headers = forwardedRequestHeaders(exchange.headers);
|
|
483
493
|
const method = exchange.method.toUpperCase();
|
|
484
494
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
485
495
|
let body;
|