@github/copilot-sdk 1.0.9-preview.0 → 1.0.9-preview.1

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.
@@ -25,6 +25,10 @@ var import_node = require("vscode-jsonrpc/node.js");
25
25
  var import_rpc = require("./generated/rpc.js");
26
26
  var import_canvas = require("./canvas.js");
27
27
  var import_telemetry = require("./telemetry.js");
28
+ var import_factory = require("./factory.js");
29
+ function isFactoryResumeErrorCode(value) {
30
+ return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "reapproval_declined" || value === "no_approval_provider";
31
+ }
28
32
  function deserializeHookInput(raw) {
29
33
  if (!raw || typeof raw !== "object" || typeof raw.timestamp !== "number") {
30
34
  return raw;
@@ -45,6 +49,164 @@ function isOpenCanvasInstance(value) {
45
49
  const instance = value;
46
50
  return typeof instance.instanceId === "string" && instance.instanceId.length > 0 && typeof instance.extensionId === "string" && instance.extensionId.length > 0 && typeof instance.canvasId === "string" && instance.canvasId.length > 0;
47
51
  }
52
+ const FACTORY_LOG_FLUSH_DELAY_MS = 10;
53
+ const MAX_FACTORY_FANOUT_ITEMS = 4096;
54
+ function assertFactoryFanoutSize(kind, size) {
55
+ if (size > MAX_FACTORY_FANOUT_ITEMS) {
56
+ throw new Error(
57
+ `${kind}() accepts at most ${MAX_FACTORY_FANOUT_ITEMS} items; got ${size}.`
58
+ );
59
+ }
60
+ }
61
+ async function runFactoryParallel(thunks) {
62
+ if (!Array.isArray(thunks)) {
63
+ throw new Error(
64
+ "parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
65
+ );
66
+ }
67
+ assertFactoryFanoutSize("parallel", thunks.length);
68
+ if (thunks.some((thunk) => typeof thunk !== "function")) {
69
+ throw new Error(
70
+ "parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
71
+ );
72
+ }
73
+ return Promise.all(
74
+ thunks.map(
75
+ (thunk) => Promise.resolve().then(() => thunk()).catch((error) => {
76
+ if (isFactoryFatalError(error)) {
77
+ throw error;
78
+ }
79
+ return null;
80
+ })
81
+ )
82
+ );
83
+ }
84
+ async function runFactoryPipeline(items, ...stages) {
85
+ if (!Array.isArray(items)) {
86
+ throw new Error("pipeline(items, ...stages): items must be an array");
87
+ }
88
+ assertFactoryFanoutSize("pipeline", items.length);
89
+ return Promise.all(
90
+ items.map(async (item, index) => {
91
+ let previous = item;
92
+ for (const stage of stages) {
93
+ try {
94
+ previous = await stage(previous, item, index);
95
+ } catch (error) {
96
+ if (isFactoryFatalError(error)) {
97
+ throw error;
98
+ }
99
+ return null;
100
+ }
101
+ }
102
+ return previous;
103
+ })
104
+ );
105
+ }
106
+ class FactoryProgressBuffer {
107
+ constructor(send) {
108
+ this.send = send;
109
+ }
110
+ send;
111
+ nextSeq = 0;
112
+ pending = [];
113
+ flushTimer;
114
+ flushTail = Promise.resolve();
115
+ flushError;
116
+ flushFailed = false;
117
+ closed = false;
118
+ enqueue(kind, text) {
119
+ if (this.closed) {
120
+ throw new Error("Cannot log after the factory run has settled");
121
+ }
122
+ this.pending.push({ seq: this.nextSeq++, kind, text });
123
+ this.scheduleFlush();
124
+ }
125
+ async flush() {
126
+ this.clearFlushTimer();
127
+ const lines = this.pending.splice(0);
128
+ if (lines.length > 0) {
129
+ this.flushTail = this.flushTail.then(async () => {
130
+ try {
131
+ await this.send(lines);
132
+ } catch (error) {
133
+ if (!this.flushFailed) {
134
+ this.flushFailed = true;
135
+ this.flushError = error;
136
+ }
137
+ }
138
+ });
139
+ }
140
+ await this.flushTail;
141
+ if (this.flushFailed) {
142
+ throw this.flushError;
143
+ }
144
+ }
145
+ async close() {
146
+ this.closed = true;
147
+ this.clearFlushTimer();
148
+ const lines = this.pending.splice(0);
149
+ await this.flushTail;
150
+ if (this.flushFailed) {
151
+ throw this.flushError;
152
+ }
153
+ if (lines.length > 0) {
154
+ try {
155
+ await this.send(lines);
156
+ } catch (error) {
157
+ console.warn(
158
+ "Failed to flush final factory progress after the factory body settled",
159
+ error
160
+ );
161
+ }
162
+ }
163
+ }
164
+ scheduleFlush() {
165
+ if (this.flushTimer !== void 0) {
166
+ return;
167
+ }
168
+ this.flushTimer = setTimeout(() => {
169
+ this.flushTimer = void 0;
170
+ void this.flush().catch(() => {
171
+ });
172
+ }, FACTORY_LOG_FLUSH_DELAY_MS);
173
+ this.flushTimer.unref?.();
174
+ }
175
+ clearFlushTimer() {
176
+ if (this.flushTimer !== void 0) {
177
+ clearTimeout(this.flushTimer);
178
+ this.flushTimer = void 0;
179
+ }
180
+ }
181
+ }
182
+ function toPublicFactoryRunResult(envelope) {
183
+ return envelope;
184
+ }
185
+ async function awaitFactoryOperation(operation, signal) {
186
+ let rejectAbort;
187
+ const abortPromise = new Promise((_resolve, reject) => {
188
+ rejectAbort = reject;
189
+ });
190
+ const onAbort = () => rejectAbort?.(signal.reason ?? new DOMException("Factory run was aborted", "AbortError"));
191
+ signal.addEventListener("abort", onAbort, { once: true });
192
+ try {
193
+ throwIfFactoryAborted(signal);
194
+ return await Promise.race([operation(), abortPromise]);
195
+ } finally {
196
+ signal.removeEventListener("abort", onAbort);
197
+ }
198
+ }
199
+ function throwIfFactoryAborted(signal) {
200
+ if (signal.aborted) {
201
+ throw signal.reason ?? new DOMException("Factory run was aborted", "AbortError");
202
+ }
203
+ }
204
+ function isFactoryAbortError(error) {
205
+ return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
206
+ }
207
+ function isFactoryFatalError(error) {
208
+ return isFactoryAbortError(error) || error instanceof import_node.ResponseError || error instanceof import_node.ConnectionError;
209
+ }
48
210
  const TOOL_SEARCH_TOOL_NAME = "tool_search_tool";
49
211
  class CopilotSession {
50
212
  /**
@@ -72,6 +234,8 @@ class CopilotSession {
72
234
  canvases = /* @__PURE__ */ new Map();
73
235
  bearerTokenProviders = /* @__PURE__ */ new Map();
74
236
  commandHandlers = /* @__PURE__ */ new Map();
237
+ factories = /* @__PURE__ */ new Map();
238
+ factoryAbortControllers = /* @__PURE__ */ new Map();
75
239
  permissionHandler;
76
240
  mcpAuthHandler;
77
241
  userInputHandler;
@@ -87,6 +251,128 @@ class CopilotSession {
87
251
  disconnected = false;
88
252
  /** @internal Client session API handlers, populated by CopilotClient during create/resume. */
89
253
  clientSessionApis = {};
254
+ /**
255
+ * Friendly factory API for running registered factories by name or handle.
256
+ *
257
+ * @experimental Part of the experimental Agent Factories surface and may
258
+ * change or be removed in future SDK or CLI releases.
259
+ */
260
+ factory = {
261
+ run: (async (nameOrHandle, options) => {
262
+ const name = typeof nameOrHandle === "string" ? nameOrHandle : (0, import_factory.getFactoryDefinition)(nameOrHandle).meta.name;
263
+ if (options?.resumeFromRunId !== void 0) {
264
+ return this.factory.resume(options.resumeFromRunId, {
265
+ limits: options.limits
266
+ });
267
+ }
268
+ const envelope = await this.rpc.factory.run({
269
+ name,
270
+ args: options?.args === void 0 ? {} : options.args,
271
+ options: {
272
+ limits: options?.limits
273
+ }
274
+ });
275
+ return toPublicFactoryRunResult(envelope);
276
+ }),
277
+ resume: (async (runId, options) => {
278
+ let response;
279
+ try {
280
+ response = await this.rpc.factory.resume({
281
+ runId,
282
+ limits: options?.limits
283
+ });
284
+ } catch (error) {
285
+ if (error instanceof import_node.ResponseError && typeof error.data === "object" && error.data !== null) {
286
+ const code = error.data.code;
287
+ if (isFactoryResumeErrorCode(code)) {
288
+ throw new import_factory.FactoryResumeError(code, error.message);
289
+ }
290
+ }
291
+ throw error;
292
+ }
293
+ return toPublicFactoryRunResult(response.run);
294
+ }),
295
+ getRun: async (runId) => toPublicFactoryRunResult(await this.rpc.factory.getRun({ runId })),
296
+ waitForRun: (runId, options) => this.waitForFactoryRun(runId, options?.signal),
297
+ listRuns: async () => (await this.rpc.factory.listRuns()).runs,
298
+ getRunDetail: (runId) => this.rpc.factory.getRunDetail({ runId }),
299
+ getRunProgress: (runId, options = {}) => this.rpc.factory.getRunProgress({ runId, ...options }),
300
+ cancel: async (runId) => toPublicFactoryRunResult(await this.rpc.factory.cancel({ runId }))
301
+ };
302
+ /**
303
+ * Resolve when a factory run reaches a terminal status.
304
+ *
305
+ * The subscription is installed *before* the first read so a transition
306
+ * landing between the two cannot be missed, and re-reads are serialized so
307
+ * overlapping invalidation events cannot interleave — the run's revision
308
+ * advances once per operation, so a burst of events is common and must
309
+ * collapse into a single in-flight read. A bounded periodic re-read keeps a
310
+ * dropped invalidation from leaving the wait pending forever.
311
+ */
312
+ waitForFactoryRun(runId, signal) {
313
+ const abortError = () => signal?.reason ?? new DOMException("Factory run wait was aborted", "AbortError");
314
+ if (signal?.aborted === true) {
315
+ return Promise.reject(abortError());
316
+ }
317
+ return new Promise((resolve, reject) => {
318
+ let settled = false;
319
+ let reading = false;
320
+ let rereadRequested = false;
321
+ let pollHandle;
322
+ let unsubscribe;
323
+ let onAbort;
324
+ const finish = (complete) => {
325
+ if (settled) {
326
+ return;
327
+ }
328
+ settled = true;
329
+ if (pollHandle !== void 0) {
330
+ clearInterval(pollHandle);
331
+ }
332
+ unsubscribe?.();
333
+ if (onAbort !== void 0) {
334
+ signal?.removeEventListener("abort", onAbort);
335
+ }
336
+ complete();
337
+ };
338
+ const read = async () => {
339
+ if (settled) {
340
+ return;
341
+ }
342
+ if (reading) {
343
+ rereadRequested = true;
344
+ return;
345
+ }
346
+ reading = true;
347
+ try {
348
+ do {
349
+ rereadRequested = false;
350
+ const envelope = await this.rpc.factory.getRun({ runId });
351
+ if ((0, import_factory.isFactoryRunTerminal)(envelope.status)) {
352
+ finish(() => resolve(toPublicFactoryRunResult(envelope)));
353
+ return;
354
+ }
355
+ } while (rereadRequested && !settled);
356
+ } catch (error) {
357
+ finish(() => reject(error));
358
+ } finally {
359
+ reading = false;
360
+ }
361
+ };
362
+ if (signal !== void 0) {
363
+ onAbort = () => finish(() => reject(abortError()));
364
+ signal.addEventListener("abort", onAbort, { once: true });
365
+ }
366
+ unsubscribe = this.on("factory.run_updated", (event) => {
367
+ if (event.data.runId === runId) {
368
+ void read();
369
+ }
370
+ });
371
+ pollHandle = setInterval(() => void read(), 5e3);
372
+ pollHandle.unref?.();
373
+ void read();
374
+ });
375
+ }
90
376
  /**
91
377
  * Typed session-scoped RPC methods.
92
378
  */
@@ -201,6 +487,13 @@ class CopilotSession {
201
487
  this.autoModeSwitchHandler = void 0;
202
488
  this.commandHandlers.clear();
203
489
  this.canvases.clear();
490
+ this.factories.clear();
491
+ for (const controllersForRun of this.factoryAbortControllers.values()) {
492
+ for (const controller of controllersForRun.values()) {
493
+ controller.abort();
494
+ }
495
+ }
496
+ this.factoryAbortControllers.clear();
204
497
  this.transformCallbacks?.clear();
205
498
  }
206
499
  on(eventTypeOrHandler, handler) {
@@ -587,6 +880,157 @@ class CopilotSession {
587
880
  }
588
881
  };
589
882
  }
883
+ /**
884
+ * Registers factory closures and reverse-RPC handlers for this session.
885
+ *
886
+ * @param factories - Factory handles declared by the joining extension.
887
+ * @internal Called by the SDK when an extension joins a session.
888
+ */
889
+ registerFactories(factories) {
890
+ this.factories.clear();
891
+ if (!factories || factories.length === 0) {
892
+ delete this.clientSessionApis.factory;
893
+ return;
894
+ }
895
+ for (const handle of factories) {
896
+ const definition = (0, import_factory.getFactoryDefinition)(handle);
897
+ if (this.factories.has(definition.meta.name)) {
898
+ throw new Error(
899
+ `Duplicate factory name "${definition.meta.name}". Factory names must be unique within a joinSession call.`
900
+ );
901
+ }
902
+ this.factories.set(definition.meta.name, definition);
903
+ }
904
+ const self = this;
905
+ this.clientSessionApis.factory = {
906
+ async execute(params) {
907
+ const definition = self.factories.get(params.name);
908
+ if (!definition) {
909
+ const message = `No factory registered with name "${params.name}"`;
910
+ throw new import_node.ResponseError(import_node.ErrorCodes.InvalidParams, message, {
911
+ code: "factory_not_found",
912
+ name: params.name
913
+ });
914
+ }
915
+ const controller = new AbortController();
916
+ let controllersForRun = self.factoryAbortControllers.get(params.runId);
917
+ if (controllersForRun === void 0) {
918
+ controllersForRun = /* @__PURE__ */ new Map();
919
+ self.factoryAbortControllers.set(params.runId, controllersForRun);
920
+ }
921
+ controllersForRun.set(params.executionToken, controller);
922
+ const progress = new FactoryProgressBuffer(async (lines) => {
923
+ await self.rpc.factory.log({
924
+ runId: params.runId,
925
+ executionToken: params.executionToken,
926
+ lines
927
+ });
928
+ });
929
+ try {
930
+ const context = {
931
+ runId: params.runId,
932
+ args: params.args,
933
+ session: self,
934
+ signal: controller.signal,
935
+ phase: (title) => {
936
+ throwIfFactoryAborted(controller.signal);
937
+ progress.enqueue("phase", title);
938
+ },
939
+ log: (message) => {
940
+ throwIfFactoryAborted(controller.signal);
941
+ progress.enqueue("log", message);
942
+ },
943
+ agent: async (prompt, options = {}) => {
944
+ await progress.flush();
945
+ const response = await awaitFactoryOperation(
946
+ () => self.rpc.factory.agent({
947
+ factoryRunId: params.runId,
948
+ executionToken: params.executionToken,
949
+ prompt,
950
+ opts: {
951
+ label: options.label,
952
+ schema: options.schema,
953
+ model: options.model
954
+ }
955
+ }),
956
+ controller.signal
957
+ );
958
+ return response.result ?? null;
959
+ },
960
+ step: async (key, producer, options = {}) => {
961
+ await progress.flush();
962
+ if (options.volatile) {
963
+ throwIfFactoryAborted(controller.signal);
964
+ return producer();
965
+ }
966
+ const cached = await awaitFactoryOperation(
967
+ () => self.rpc.factory.journal.get({
968
+ runId: params.runId,
969
+ executionToken: params.executionToken,
970
+ key
971
+ }),
972
+ controller.signal
973
+ );
974
+ if (cached.hit) {
975
+ if (cached.resultJson === void 0) {
976
+ throw new Error(
977
+ `step("${key}") journal returned a hit without a result`
978
+ );
979
+ }
980
+ assertFactoryStepResult(cached.resultJson, key);
981
+ return cached.resultJson;
982
+ }
983
+ const result2 = await producer();
984
+ assertFactoryStepResult(result2, key);
985
+ await awaitFactoryOperation(
986
+ () => self.rpc.factory.journal.put({
987
+ runId: params.runId,
988
+ executionToken: params.executionToken,
989
+ key,
990
+ resultJson: result2
991
+ }),
992
+ controller.signal
993
+ );
994
+ return result2;
995
+ },
996
+ parallel: runFactoryParallel,
997
+ pipeline: runFactoryPipeline,
998
+ factory: async () => {
999
+ throw new Error("nested factories are not supported");
1000
+ }
1001
+ };
1002
+ const result = await definition.run(context);
1003
+ if (result === void 0) {
1004
+ return {};
1005
+ }
1006
+ assertFactoryResult(result);
1007
+ return { result };
1008
+ } finally {
1009
+ try {
1010
+ await progress.close();
1011
+ } finally {
1012
+ const controllersForRun2 = self.factoryAbortControllers.get(params.runId);
1013
+ if (controllersForRun2?.get(params.executionToken) === controller) {
1014
+ controllersForRun2.delete(params.executionToken);
1015
+ if (controllersForRun2.size === 0) {
1016
+ self.factoryAbortControllers.delete(params.runId);
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ },
1022
+ async abort(params) {
1023
+ const controllersForRun = self.factoryAbortControllers.get(params.runId);
1024
+ if (controllersForRun !== void 0) {
1025
+ const reason = new DOMException("Factory run was aborted", "AbortError");
1026
+ for (const controller of controllersForRun.values()) {
1027
+ controller.abort(reason);
1028
+ }
1029
+ }
1030
+ return {};
1031
+ }
1032
+ };
1033
+ }
590
1034
  /**
591
1035
  * Registers per-provider {@link BearerTokenProvider} callbacks for BYOK providers
592
1036
  * configured with managed-identity / on-demand bearer-token auth.
@@ -1078,6 +1522,151 @@ function toCanvasRpcError(error) {
1078
1522
  const message = error instanceof Error ? error.message : String(error);
1079
1523
  return new import_node.ResponseError(import_node.ErrorCodes.InternalError, message, { code, message });
1080
1524
  }
1525
+ function strictJsonValidationError(context, category, message, path) {
1526
+ return new import_node.ResponseError(import_node.ErrorCodes.InternalError, message, {
1527
+ code: context.code,
1528
+ category,
1529
+ path
1530
+ });
1531
+ }
1532
+ function assertStrictJson(value, context) {
1533
+ const ancestors = /* @__PURE__ */ new Set();
1534
+ const visit = (current, path, allowUndefined) => {
1535
+ if (current === void 0) {
1536
+ if (allowUndefined) {
1537
+ return;
1538
+ }
1539
+ throw strictJsonValidationError(
1540
+ context,
1541
+ "nested_undefined",
1542
+ `${context.label} contains nested undefined at ${path}`,
1543
+ path
1544
+ );
1545
+ }
1546
+ if (current === null || typeof current === "boolean" || typeof current === "string") {
1547
+ return;
1548
+ }
1549
+ if (typeof current === "number") {
1550
+ if (!Number.isFinite(current)) {
1551
+ throw strictJsonValidationError(
1552
+ context,
1553
+ "non_finite_number",
1554
+ `${context.label} contains a non-finite number at ${path}`,
1555
+ path
1556
+ );
1557
+ }
1558
+ if (Object.is(current, -0)) {
1559
+ throw strictJsonValidationError(
1560
+ context,
1561
+ "negative_zero",
1562
+ `${context.label} contains negative zero at ${path}; normalize it to 0`,
1563
+ path
1564
+ );
1565
+ }
1566
+ return;
1567
+ }
1568
+ if (typeof current === "function" || typeof current === "symbol" || typeof current === "bigint") {
1569
+ throw strictJsonValidationError(
1570
+ context,
1571
+ "unsupported_type",
1572
+ `${context.label} contains a function, symbol, or BigInt at ${path}`,
1573
+ path
1574
+ );
1575
+ }
1576
+ if (typeof current !== "object") {
1577
+ throw strictJsonValidationError(
1578
+ context,
1579
+ "unsupported_type",
1580
+ `${context.label} contains a function, symbol, or BigInt at ${path}`,
1581
+ path
1582
+ );
1583
+ }
1584
+ if (ancestors.has(current)) {
1585
+ throw strictJsonValidationError(
1586
+ context,
1587
+ "cyclic_value",
1588
+ `${context.label} contains a cyclic reference at ${path}`,
1589
+ path
1590
+ );
1591
+ }
1592
+ ancestors.add(current);
1593
+ try {
1594
+ if (Array.isArray(current)) {
1595
+ const keys = Reflect.ownKeys(current);
1596
+ if (keys.length !== current.length + 1 || keys.some(
1597
+ (key) => key !== "length" && (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= current.length)
1598
+ )) {
1599
+ throw strictJsonValidationError(
1600
+ context,
1601
+ "unsupported_object",
1602
+ `${context.label} contains a non-JSON array property at ${path}`,
1603
+ path
1604
+ );
1605
+ }
1606
+ for (let index = 0; index < current.length; index++) {
1607
+ const descriptor = Object.getOwnPropertyDescriptor(current, String(index));
1608
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor)) {
1609
+ throw strictJsonValidationError(
1610
+ context,
1611
+ "unsupported_object",
1612
+ `${context.label} contains a non-JSON array property at ${path}[${index}]`,
1613
+ `${path}[${index}]`
1614
+ );
1615
+ }
1616
+ visit(descriptor.value, `${path}[${index}]`, false);
1617
+ }
1618
+ return;
1619
+ }
1620
+ const prototype = Object.getPrototypeOf(current);
1621
+ if (prototype !== Object.prototype && prototype !== null) {
1622
+ throw strictJsonValidationError(
1623
+ context,
1624
+ "unsupported_object",
1625
+ `${context.label} contains a non-JSON object at ${path}`,
1626
+ path
1627
+ );
1628
+ }
1629
+ for (const key of Reflect.ownKeys(current)) {
1630
+ if (typeof key === "symbol") {
1631
+ throw strictJsonValidationError(
1632
+ context,
1633
+ "unsupported_type",
1634
+ `${context.label} contains a function, symbol, or BigInt at ${path}`,
1635
+ path
1636
+ );
1637
+ }
1638
+ const propertyPath = /^[A-Za-z_$][\w$]*$/.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
1639
+ const descriptor = Object.getOwnPropertyDescriptor(current, key);
1640
+ if (descriptor === void 0 || !descriptor.enumerable || !("value" in descriptor)) {
1641
+ throw strictJsonValidationError(
1642
+ context,
1643
+ "unsupported_object",
1644
+ `${context.label} contains a non-JSON property at ${propertyPath}`,
1645
+ propertyPath
1646
+ );
1647
+ }
1648
+ visit(descriptor.value, propertyPath, false);
1649
+ }
1650
+ } finally {
1651
+ ancestors.delete(current);
1652
+ }
1653
+ };
1654
+ visit(value, "$", context.allowTopLevelUndefined);
1655
+ }
1656
+ function assertFactoryResult(value) {
1657
+ assertStrictJson(value, {
1658
+ code: "factory_result_not_json",
1659
+ label: "Factory result",
1660
+ allowTopLevelUndefined: true
1661
+ });
1662
+ }
1663
+ function assertFactoryStepResult(value, key) {
1664
+ assertStrictJson(value, {
1665
+ code: "factory_step_not_json",
1666
+ label: `Factory step "${key}" result`,
1667
+ allowTopLevelUndefined: false
1668
+ });
1669
+ }
1081
1670
  // Annotate the CommonJS export names for ESM import in node:
1082
1671
  0 && (module.exports = {
1083
1672
  CopilotSession
package/dist/client.d.ts CHANGED
@@ -224,6 +224,7 @@ export declare class CopilotClient {
224
224
  * ```
225
225
  */
226
226
  resumeSession(sessionId: string, config: ResumeSessionConfig): Promise<CopilotSession>;
227
+ private resumeSessionInternal;
227
228
  /**
228
229
  * Sends a ping request to the server to verify connectivity.
229
230
  *
package/dist/client.js CHANGED
@@ -1180,6 +1180,13 @@ class CopilotClient {
1180
1180
  * ```
1181
1181
  */
1182
1182
  async resumeSession(sessionId, config) {
1183
+ return this.resumeSessionInternal(sessionId, config);
1184
+ }
1185
+ /** @internal */
1186
+ async resumeSessionForExtension(sessionId, config, factories) {
1187
+ return this.resumeSessionInternal(sessionId, config, factories);
1188
+ }
1189
+ async resumeSessionInternal(sessionId, config, factories) {
1183
1190
  if (!this.connection) {
1184
1191
  await this.start();
1185
1192
  }
@@ -1193,6 +1200,7 @@ class CopilotClient {
1193
1200
  session.registerTools(config.tools);
1194
1201
  session.registerCanvases(config.canvases);
1195
1202
  session.registerCommands(config.commands);
1203
+ session.registerFactories(factories);
1196
1204
  const {
1197
1205
  wireProvider: bearerWireProvider,
1198
1206
  wireProviders: bearerWireProviders,
@@ -1259,6 +1267,7 @@ class CopilotClient {
1259
1267
  })),
1260
1268
  toolSearch: config.toolSearch,
1261
1269
  canvases: config.canvases?.map((canvas) => canvas.declaration),
1270
+ factories: factories?.map((factory) => factory.meta),
1262
1271
  requestCanvasRenderer: config.requestCanvasRenderer,
1263
1272
  requestExtensions: config.requestExtensions,
1264
1273
  extensionSdkPath: config.extensionSdkPath,
@@ -1,10 +1,19 @@
1
1
  import type { CopilotSession } from "./session.js";
2
- import { type ExtensionInfo, type PermissionHandler, type ResumeSessionConfig } from "./types.js";
2
+ import { type PermissionHandler, type ResumeSessionConfig } from "./types.js";
3
+ import type { FactoryHandle } from "./factory.js";
3
4
  export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js";
4
5
  export type JoinSessionConfig = Omit<ResumeSessionConfig, "onPermissionRequest" | "extensionSdkPath"> & {
5
6
  onPermissionRequest?: PermissionHandler;
7
+ /**
8
+ * Factory handles to register when the extension joins the session.
9
+ *
10
+ * @experimental Part of the experimental Agent Factories surface and may
11
+ * change or be removed in future SDK or CLI releases.
12
+ */
13
+ factories?: FactoryHandle[];
6
14
  };
7
- export type { ExtensionInfo };
15
+ export type { ExtensionInfo, FactoryLimits, FactoryMeta } from "./types.js";
16
+ export { defineFactory, FactoryResumeError, isFactoryRunTerminal, type RunOptions, type ResumeOptions, type FactoryResumeErrorCode, type SessionFactoryApi, type FactoryAgentOptions, type FactoryContext, type FactoryDefinition, type FactoryHandle, type FactoryJsonSchema, type JsonValue, type FactoryPipelineStage, type FactoryStepOptions, type FactoryRunResult, type FactoryRunStatus, type FactoryRunSummary, type FactoryRunDetail, type FactoryProgressPage, type FactoryProgressLine, type FactoryPhaseObservation, type FactoryPhaseStatus, type FactoryAgentSummary, } from "./factory.js";
8
17
  /**
9
18
  * Joins the current foreground session.
10
19
  *