@github/copilot-sdk 1.0.15-preview.0 → 1.0.15-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.
@@ -29,6 +29,7 @@ var import_telemetry = require("./telemetry.js");
29
29
  var import_schema = require("./schema.js");
30
30
  var import_types = require("./types.js");
31
31
  var import_factory = require("./factory.js");
32
+ var import_workflow = require("./workflow.js");
32
33
  function isFactoryResumeErrorCode(value) {
33
34
  return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "factory_already_running" || value === "factory_limits_invalid" || value === "factory_session_disposed" || value === "factory_storage_unavailable" || value === "factory_storage_corrupt";
34
35
  }
@@ -38,6 +39,15 @@ function copyDefinedFactoryAgentOption(source, target, key) {
38
39
  target[key] = value;
39
40
  }
40
41
  }
42
+ function isWorkflowResumeErrorCode(value) {
43
+ return value === "not_found" || value === "non_resumable" || value === "workflow_run_not_resumable" || value === "already_active" || value === "workflow_already_running" || value === "workflow_limits_invalid" || value === "workflow_session_disposed" || value === "workflow_storage_unavailable" || value === "workflow_storage_corrupt";
44
+ }
45
+ function copyDefinedWorkflowAgentOption(source, target, key) {
46
+ const value = source[key];
47
+ if (value !== void 0) {
48
+ target[key] = value;
49
+ }
50
+ }
41
51
  const factoryExecutionStore = new import_node_async_hooks.AsyncLocalStorage();
42
52
  function throwIfFactoryExecutionIsActive() {
43
53
  if (factoryExecutionStore.getStore()?.active) {
@@ -46,6 +56,18 @@ function throwIfFactoryExecutionIsActive() {
46
56
  );
47
57
  }
48
58
  }
59
+ const workflowExecutionStore = new import_node_async_hooks.AsyncLocalStorage();
60
+ function throwIfWorkflowExecutionIsActive() {
61
+ if (workflowExecutionStore.getStore()?.active) {
62
+ throw new Error(
63
+ "workflow.run, workflow.resume, and workflow.pause are not allowed while a workflow body is running on this call path."
64
+ );
65
+ }
66
+ }
67
+ function runInWorkflowHelperScope(helperScope, callback) {
68
+ const current = workflowExecutionStore.getStore();
69
+ return workflowExecutionStore.run({ active: current?.active ?? false, helperScope }, callback);
70
+ }
49
71
  function runInFactoryHelperScope(helperScope, callback) {
50
72
  const current = factoryExecutionStore.getStore();
51
73
  return factoryExecutionStore.run({ active: current?.active ?? false, helperScope }, callback);
@@ -127,6 +149,54 @@ async function runFactoryPipeline(items, ...stages) {
127
149
  })
128
150
  );
129
151
  }
152
+ async function runWorkflowParallel(thunks) {
153
+ if (!Array.isArray(thunks)) {
154
+ throw new Error(
155
+ "parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
156
+ );
157
+ }
158
+ assertFactoryFanoutSize("parallel", thunks.length);
159
+ if (thunks.some((thunk) => typeof thunk !== "function")) {
160
+ throw new Error(
161
+ "parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
162
+ );
163
+ }
164
+ return Promise.all(
165
+ thunks.map(
166
+ (thunk) => Promise.resolve().then(() => runInWorkflowHelperScope("parallel", thunk)).catch((error) => {
167
+ if (isFactoryFatalError(error)) {
168
+ throw error;
169
+ }
170
+ return null;
171
+ })
172
+ )
173
+ );
174
+ }
175
+ async function runWorkflowPipeline(items, ...stages) {
176
+ if (!Array.isArray(items)) {
177
+ throw new Error("pipeline(items, ...stages): items must be an array");
178
+ }
179
+ assertFactoryFanoutSize("pipeline", items.length);
180
+ return Promise.all(
181
+ items.map(async (item, index) => {
182
+ let previous = item;
183
+ for (const stage of stages) {
184
+ try {
185
+ previous = await runInWorkflowHelperScope(
186
+ "pipeline",
187
+ () => stage(previous, item, index)
188
+ );
189
+ } catch (error) {
190
+ if (isFactoryFatalError(error)) {
191
+ throw error;
192
+ }
193
+ return null;
194
+ }
195
+ }
196
+ return previous;
197
+ })
198
+ );
199
+ }
130
200
  class FactoryProgressBuffer {
131
201
  constructor(send) {
132
202
  this.send = send;
@@ -206,6 +276,85 @@ class FactoryProgressBuffer {
206
276
  }
207
277
  }
208
278
  }
279
+ class WorkflowProgressBuffer {
280
+ constructor(send) {
281
+ this.send = send;
282
+ }
283
+ send;
284
+ nextSeq = 0;
285
+ pending = [];
286
+ flushTimer;
287
+ flushTail = Promise.resolve();
288
+ flushError;
289
+ flushFailed = false;
290
+ closed = false;
291
+ enqueue(kind, text) {
292
+ if (this.closed) {
293
+ throw new Error("Cannot log after the workflow run has settled");
294
+ }
295
+ this.pending.push({ seq: this.nextSeq++, kind, text });
296
+ this.scheduleFlush();
297
+ }
298
+ async flush() {
299
+ this.clearFlushTimer();
300
+ const lines = this.pending.splice(0);
301
+ if (lines.length > 0) {
302
+ this.flushTail = this.flushTail.then(async () => {
303
+ try {
304
+ await this.send(lines);
305
+ } catch (error) {
306
+ if (!this.flushFailed) {
307
+ this.flushFailed = true;
308
+ this.flushError = error;
309
+ }
310
+ }
311
+ });
312
+ }
313
+ await this.flushTail;
314
+ if (this.flushFailed) {
315
+ throw this.flushError;
316
+ }
317
+ }
318
+ async close() {
319
+ this.closed = true;
320
+ this.clearFlushTimer();
321
+ const lines = this.pending.splice(0);
322
+ await this.flushTail;
323
+ if (this.flushFailed) {
324
+ console.warn(
325
+ "Ignoring a background workflow progress flush failure after the workflow body settled",
326
+ this.flushError
327
+ );
328
+ }
329
+ if (lines.length > 0) {
330
+ try {
331
+ await this.send(lines);
332
+ } catch (error) {
333
+ console.warn(
334
+ "Failed to flush final workflow progress after the workflow body settled",
335
+ error
336
+ );
337
+ }
338
+ }
339
+ }
340
+ scheduleFlush() {
341
+ if (this.flushTimer !== void 0) {
342
+ return;
343
+ }
344
+ this.flushTimer = setTimeout(() => {
345
+ this.flushTimer = void 0;
346
+ void this.flush().catch(() => {
347
+ });
348
+ }, FACTORY_LOG_FLUSH_DELAY_MS);
349
+ this.flushTimer.unref?.();
350
+ }
351
+ clearFlushTimer() {
352
+ if (this.flushTimer !== void 0) {
353
+ clearTimeout(this.flushTimer);
354
+ this.flushTimer = void 0;
355
+ }
356
+ }
357
+ }
209
358
  async function awaitFactoryOperation(operation, signal) {
210
359
  let rejectAbort;
211
360
  const abortPromise = new Promise((_resolve, reject) => {
@@ -220,11 +369,19 @@ async function awaitFactoryOperation(operation, signal) {
220
369
  signal.removeEventListener("abort", onAbort);
221
370
  }
222
371
  }
372
+ async function awaitWorkflowOperation(operation, signal) {
373
+ return awaitFactoryOperation(operation, signal);
374
+ }
223
375
  function throwIfFactoryAborted(signal) {
224
376
  if (signal.aborted) {
225
377
  throw signal.reason ?? new DOMException("Factory run was aborted", "AbortError");
226
378
  }
227
379
  }
380
+ function throwIfWorkflowAborted(signal) {
381
+ if (signal.aborted) {
382
+ throw signal.reason ?? new DOMException("Workflow run was aborted", "AbortError");
383
+ }
384
+ }
228
385
  function isFactoryAbortError(error) {
229
386
  return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
230
387
  }
@@ -263,6 +420,8 @@ class CopilotSession {
263
420
  commandHandlers = /* @__PURE__ */ new Map();
264
421
  factories = /* @__PURE__ */ new Map();
265
422
  factoryAbortControllers = /* @__PURE__ */ new Map();
423
+ workflows = /* @__PURE__ */ new Map();
424
+ workflowAbortControllers = /* @__PURE__ */ new Map();
266
425
  permissionHandler;
267
426
  mcpAuthHandler;
268
427
  userInputHandler;
@@ -346,6 +505,56 @@ class CopilotSession {
346
505
  },
347
506
  cancel: async (runId) => this.rpc.factory.cancel({ runId })
348
507
  };
508
+ workflow = {
509
+ run: (async (nameOrHandle, options) => {
510
+ throwIfWorkflowExecutionIsActive();
511
+ const name = typeof nameOrHandle === "string" ? nameOrHandle : (0, import_workflow.getWorkflowDefinition)(nameOrHandle).meta.name;
512
+ const envelope = await this.rpc.workflow.run({
513
+ name,
514
+ args: options?.args === void 0 ? {} : options.args,
515
+ options: {
516
+ limits: options?.limits,
517
+ notifyOnComplete: options?.notifyOnComplete,
518
+ logPhaseNames: options?.logPhaseNames
519
+ }
520
+ });
521
+ return this.settleWorkflowRun(envelope);
522
+ }),
523
+ resume: (async (runId, options) => {
524
+ throwIfWorkflowExecutionIsActive();
525
+ let response;
526
+ try {
527
+ response = await this.rpc.workflow.resume({
528
+ runId,
529
+ limits: options?.limits,
530
+ notifyOnComplete: options?.notifyOnComplete,
531
+ logPhaseNames: options?.logPhaseNames
532
+ });
533
+ } catch (error) {
534
+ if (error instanceof import_node.ResponseError && typeof error.data === "object" && error.data !== null) {
535
+ const code = error.data.code;
536
+ if (isWorkflowResumeErrorCode(code)) {
537
+ throw new import_workflow.WorkflowResumeError(code, error.message);
538
+ }
539
+ }
540
+ throw error;
541
+ }
542
+ return this.settleWorkflowRun(response.run);
543
+ }),
544
+ getRun: async (runId) => this.rpc.workflow.getRun({ runId }),
545
+ waitForRun: (runId, options) => this.waitForWorkflowRun(runId, options?.signal),
546
+ listRuns: (async (options) => {
547
+ const page = await this.rpc.workflow.listRuns(options ?? {});
548
+ return options === void 0 ? page.runs : page;
549
+ }),
550
+ getRunDetail: (runId) => this.rpc.workflow.getRunDetail({ runId }),
551
+ getRunProgress: (runId, options = {}) => this.rpc.workflow.getRunProgress({ runId, ...options }),
552
+ pause: async (runId) => {
553
+ throwIfWorkflowExecutionIsActive();
554
+ return this.rpc.workflow.pause({ runId });
555
+ },
556
+ cancel: async (runId) => this.rpc.workflow.cancel({ runId })
557
+ };
349
558
  /**
350
559
  * Resolve a start/resume envelope into the terminal envelope callers expect.
351
560
  *
@@ -433,6 +642,86 @@ class CopilotSession {
433
642
  void read();
434
643
  });
435
644
  }
645
+ settleWorkflowRun(envelope) {
646
+ if ((0, import_workflow.isWorkflowRunTerminal)(envelope.status)) {
647
+ return Promise.resolve(envelope);
648
+ }
649
+ return this.waitForWorkflowRun(envelope.runId);
650
+ }
651
+ /**
652
+ * Resolve when a workflow run reaches a terminal status.
653
+ *
654
+ * The subscription is installed *before* the first read so a transition
655
+ * landing between the two cannot be missed, and re-reads are serialized so
656
+ * overlapping invalidation events cannot interleave — the run's revision
657
+ * advances once per operation, so a burst of events is common and must
658
+ * collapse into a single in-flight read. A bounded periodic re-read keeps a
659
+ * dropped invalidation from leaving the wait pending forever.
660
+ */
661
+ waitForWorkflowRun(runId, signal) {
662
+ const abortError = () => signal?.reason ?? new DOMException("Workflow run wait was aborted", "AbortError");
663
+ if (signal?.aborted === true) {
664
+ return Promise.reject(abortError());
665
+ }
666
+ return new Promise((resolve, reject) => {
667
+ let settled = false;
668
+ let reading = false;
669
+ let rereadRequested = false;
670
+ let pollHandle;
671
+ let unsubscribe;
672
+ let onAbort;
673
+ const finish = (complete) => {
674
+ if (settled) {
675
+ return;
676
+ }
677
+ settled = true;
678
+ if (pollHandle !== void 0) {
679
+ clearInterval(pollHandle);
680
+ }
681
+ unsubscribe?.();
682
+ if (onAbort !== void 0) {
683
+ signal?.removeEventListener("abort", onAbort);
684
+ }
685
+ complete();
686
+ };
687
+ const read = async () => {
688
+ if (settled) {
689
+ return;
690
+ }
691
+ if (reading) {
692
+ rereadRequested = true;
693
+ return;
694
+ }
695
+ reading = true;
696
+ try {
697
+ do {
698
+ rereadRequested = false;
699
+ const envelope = await this.rpc.workflow.getRun({ runId });
700
+ if ((0, import_workflow.isWorkflowRunTerminal)(envelope.status)) {
701
+ finish(() => resolve(envelope));
702
+ return;
703
+ }
704
+ } while (rereadRequested && !settled);
705
+ } catch (error) {
706
+ finish(() => reject(error));
707
+ } finally {
708
+ reading = false;
709
+ }
710
+ };
711
+ if (signal !== void 0) {
712
+ onAbort = () => finish(() => reject(abortError()));
713
+ signal.addEventListener("abort", onAbort, { once: true });
714
+ }
715
+ unsubscribe = this.on("factory.run_updated", (event) => {
716
+ if (event.data.runId === runId) {
717
+ void read();
718
+ }
719
+ });
720
+ pollHandle = setInterval(() => void read(), 5e3);
721
+ pollHandle.unref?.();
722
+ void read();
723
+ });
724
+ }
436
725
  /**
437
726
  * Typed session-scoped RPC methods.
438
727
  */
@@ -695,6 +984,13 @@ class CopilotSession {
695
984
  }
696
985
  }
697
986
  this.factoryAbortControllers.clear();
987
+ this.workflows.clear();
988
+ for (const controllersForRun of this.workflowAbortControllers.values()) {
989
+ for (const controller of controllersForRun.values()) {
990
+ controller.abort();
991
+ }
992
+ }
993
+ this.workflowAbortControllers.clear();
698
994
  this.transformCallbacks?.clear();
699
995
  }
700
996
  /** @internal */
@@ -1328,6 +1624,192 @@ class CopilotSession {
1328
1624
  }
1329
1625
  };
1330
1626
  }
1627
+ /**
1628
+ * Registers workflow closures and reverse-RPC handlers for this session.
1629
+ *
1630
+ * @param workflows - Workflow handles declared by the joining extension.
1631
+ * @internal Called by the SDK when an extension joins a session.
1632
+ */
1633
+ registerWorkflows(workflows) {
1634
+ this.workflows.clear();
1635
+ if (!workflows || workflows.length === 0) {
1636
+ delete this.clientSessionApis.workflow;
1637
+ return;
1638
+ }
1639
+ for (const handle of workflows) {
1640
+ const definition = (0, import_workflow.getWorkflowDefinition)(handle);
1641
+ if (this.workflows.has(definition.meta.name)) {
1642
+ throw new Error(
1643
+ `Duplicate workflow name "${definition.meta.name}". Workflow names must be unique within a joinSession call.`
1644
+ );
1645
+ }
1646
+ this.workflows.set(definition.meta.name, definition);
1647
+ }
1648
+ const self = this;
1649
+ this.clientSessionApis.workflow = {
1650
+ async execute(params) {
1651
+ const definition = self.workflows.get(params.name);
1652
+ if (!definition) {
1653
+ const message = `No workflow registered with name "${params.name}"`;
1654
+ throw new import_node.ResponseError(import_node.ErrorCodes.InvalidParams, message, {
1655
+ code: "workflow_not_found",
1656
+ name: params.name
1657
+ });
1658
+ }
1659
+ const controller = new AbortController();
1660
+ let controllersForRun = self.workflowAbortControllers.get(params.runId);
1661
+ if (controllersForRun === void 0) {
1662
+ controllersForRun = /* @__PURE__ */ new Map();
1663
+ self.workflowAbortControllers.set(params.runId, controllersForRun);
1664
+ }
1665
+ controllersForRun.set(params.executionToken, controller);
1666
+ const progress = new WorkflowProgressBuffer(async (lines) => {
1667
+ await self.rpc.workflow.log({
1668
+ runId: params.runId,
1669
+ executionToken: params.executionToken,
1670
+ lines
1671
+ });
1672
+ });
1673
+ try {
1674
+ const context = {
1675
+ runId: params.runId,
1676
+ args: params.args,
1677
+ session: self,
1678
+ signal: controller.signal,
1679
+ phase: (title) => {
1680
+ throwIfWorkflowAborted(controller.signal);
1681
+ progress.enqueue("phase", title);
1682
+ },
1683
+ log: (message) => {
1684
+ throwIfWorkflowAborted(controller.signal);
1685
+ progress.enqueue("log", message);
1686
+ },
1687
+ agent: async (prompt, options = {}) => {
1688
+ await progress.flush();
1689
+ const opts = {};
1690
+ for (const key of import_workflow.WORKFLOW_AGENT_OPTION_KEYS) {
1691
+ copyDefinedWorkflowAgentOption(options, opts, key);
1692
+ }
1693
+ const response = await awaitWorkflowOperation(
1694
+ () => self.rpc.workflow.agent({
1695
+ workflowRunId: params.runId,
1696
+ executionToken: params.executionToken,
1697
+ prompt,
1698
+ opts
1699
+ }),
1700
+ controller.signal
1701
+ );
1702
+ return response.result ?? null;
1703
+ },
1704
+ step: async (key, producer, options = {}) => {
1705
+ await progress.flush();
1706
+ if (options.volatile) {
1707
+ throwIfWorkflowAborted(controller.signal);
1708
+ return producer();
1709
+ }
1710
+ const cached = await awaitWorkflowOperation(
1711
+ () => self.rpc.workflow.journal.get({
1712
+ runId: params.runId,
1713
+ executionToken: params.executionToken,
1714
+ key
1715
+ }),
1716
+ controller.signal
1717
+ );
1718
+ if (cached.hit) {
1719
+ if (cached.resultJson === void 0) {
1720
+ throw new Error(
1721
+ `step("${key}") journal returned a hit without a result`
1722
+ );
1723
+ }
1724
+ assertWorkflowStepResult(cached.resultJson, key);
1725
+ return cached.resultJson;
1726
+ }
1727
+ const result2 = await producer();
1728
+ assertWorkflowStepResult(result2, key);
1729
+ await awaitWorkflowOperation(
1730
+ () => self.rpc.workflow.journal.put({
1731
+ runId: params.runId,
1732
+ executionToken: params.executionToken,
1733
+ key,
1734
+ resultJson: result2
1735
+ }),
1736
+ controller.signal
1737
+ );
1738
+ return result2;
1739
+ },
1740
+ pause: async (key) => {
1741
+ if (typeof key !== "string" || key.length === 0) {
1742
+ throw new Error("Workflow pause checkpoint key must not be empty");
1743
+ }
1744
+ const helperScope = workflowExecutionStore.getStore()?.helperScope;
1745
+ if (helperScope !== void 0) {
1746
+ throw new Error(
1747
+ `Workflow pause checkpoints are not allowed inside ${helperScope}() branches`
1748
+ );
1749
+ }
1750
+ await progress.flush();
1751
+ const response = await awaitWorkflowOperation(
1752
+ () => self.internalRpc.workflow.pauseAtCheckpoint({
1753
+ runId: params.runId,
1754
+ executionToken: params.executionToken,
1755
+ key
1756
+ }),
1757
+ controller.signal
1758
+ );
1759
+ switch (response.action) {
1760
+ case "continue":
1761
+ return;
1762
+ case "pause":
1763
+ await awaitWorkflowOperation(
1764
+ () => new Promise(() => {
1765
+ }),
1766
+ controller.signal
1767
+ );
1768
+ }
1769
+ },
1770
+ parallel: runWorkflowParallel,
1771
+ pipeline: runWorkflowPipeline,
1772
+ workflow: async () => {
1773
+ throw new Error("nested workflows are not supported");
1774
+ }
1775
+ };
1776
+ const execution = { active: true };
1777
+ const result = await workflowExecutionStore.run(execution, async () => {
1778
+ try {
1779
+ return await definition.run(context);
1780
+ } finally {
1781
+ execution.active = false;
1782
+ }
1783
+ });
1784
+ if (result === void 0) {
1785
+ return {};
1786
+ }
1787
+ assertWorkflowResult(result);
1788
+ return { result };
1789
+ } finally {
1790
+ try {
1791
+ await progress.close();
1792
+ } finally {
1793
+ const controllersForRun2 = self.workflowAbortControllers.get(params.runId);
1794
+ if (controllersForRun2?.get(params.executionToken) === controller) {
1795
+ controllersForRun2.delete(params.executionToken);
1796
+ if (controllersForRun2.size === 0) {
1797
+ self.workflowAbortControllers.delete(params.runId);
1798
+ }
1799
+ }
1800
+ }
1801
+ }
1802
+ },
1803
+ async abort(params) {
1804
+ const controllersForRun = self.workflowAbortControllers.get(params.runId);
1805
+ const controller = controllersForRun?.get(params.executionToken);
1806
+ if (controller !== void 0) {
1807
+ controller.abort(new DOMException("Workflow run was aborted", "AbortError"));
1808
+ }
1809
+ return {};
1810
+ }
1811
+ };
1812
+ }
1331
1813
  /**
1332
1814
  * Registers per-provider {@link BearerTokenProvider} callbacks for BYOK providers
1333
1815
  * configured with managed-identity / on-demand bearer-token auth.
@@ -2022,6 +2504,20 @@ function assertFactoryStepResult(value, key) {
2022
2504
  allowTopLevelUndefined: false
2023
2505
  });
2024
2506
  }
2507
+ function assertWorkflowResult(value) {
2508
+ assertStrictJson(value, {
2509
+ code: "workflow_result_not_json",
2510
+ label: "Workflow result",
2511
+ allowTopLevelUndefined: true
2512
+ });
2513
+ }
2514
+ function assertWorkflowStepResult(value, key) {
2515
+ assertStrictJson(value, {
2516
+ code: "workflow_step_not_json",
2517
+ label: `Workflow step "${key}" result`,
2518
+ allowTopLevelUndefined: false
2519
+ });
2520
+ }
2025
2521
  // Annotate the CommonJS export names for ESM import in node:
2026
2522
  0 && (module.exports = {
2027
2523
  CopilotSession
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var workflow_exports = {};
20
+ __export(workflow_exports, {
21
+ WORKFLOW_AGENT_OPTION_KEYS: () => WORKFLOW_AGENT_OPTION_KEYS,
22
+ WorkflowResumeError: () => WorkflowResumeError,
23
+ defineWorkflow: () => defineWorkflow,
24
+ getWorkflowDefinition: () => getWorkflowDefinition,
25
+ isWorkflowRunTerminal: () => isWorkflowRunTerminal
26
+ });
27
+ module.exports = __toCommonJS(workflow_exports);
28
+ const WORKFLOW_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
29
+ "completed",
30
+ "halted",
31
+ "paused",
32
+ "cancelled",
33
+ "error"
34
+ ]);
35
+ function isWorkflowRunTerminal(status) {
36
+ return WORKFLOW_TERMINAL_STATUSES.has(status);
37
+ }
38
+ const WORKFLOW_AGENT_OPTION_KEYS = [
39
+ "label",
40
+ "schema",
41
+ "model",
42
+ "reasoningEffort",
43
+ "contextTier",
44
+ "agent"
45
+ ];
46
+ class WorkflowResumeError extends Error {
47
+ constructor(code, message) {
48
+ super(message);
49
+ this.code = code;
50
+ this.name = "WorkflowResumeError";
51
+ }
52
+ code;
53
+ }
54
+ const workflowHandles = /* @__PURE__ */ new WeakMap();
55
+ const MAX_WORKFLOW_TIMEOUT_SECONDS = 2147483647e-3;
56
+ const NANO_AIU_PER_AIU = 1e9;
57
+ function deepFreeze(value) {
58
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
59
+ Object.freeze(value);
60
+ for (const nested of Object.values(value)) {
61
+ deepFreeze(nested);
62
+ }
63
+ }
64
+ return value;
65
+ }
66
+ function validateLimits(meta) {
67
+ const limits = meta.limits;
68
+ if (!limits) {
69
+ return;
70
+ }
71
+ for (const field of ["maxConcurrentSubagents", "maxTotalSubagents"]) {
72
+ const value = limits[field];
73
+ if (value !== void 0 && (!Number.isInteger(value) || value <= 0)) {
74
+ throw new Error(`Workflow limit "${field}" must be a positive integer`);
75
+ }
76
+ }
77
+ if (limits.timeoutSeconds !== void 0 && (!Number.isFinite(limits.timeoutSeconds) || limits.timeoutSeconds <= 0)) {
78
+ throw new Error(
79
+ 'Workflow limit "timeoutSeconds" must be a positive, finite number of seconds'
80
+ );
81
+ }
82
+ if (limits.timeoutSeconds !== void 0 && limits.timeoutSeconds > MAX_WORKFLOW_TIMEOUT_SECONDS) {
83
+ throw new Error(
84
+ `Workflow limit "timeoutSeconds" must not exceed ${MAX_WORKFLOW_TIMEOUT_SECONDS} seconds`
85
+ );
86
+ }
87
+ if (limits.maxAiCredits !== void 0) {
88
+ const maxNanoAiu = Math.round(limits.maxAiCredits * NANO_AIU_PER_AIU);
89
+ if (!Number.isFinite(limits.maxAiCredits) || limits.maxAiCredits <= 0 || !Number.isSafeInteger(maxNanoAiu) || maxNanoAiu < 1) {
90
+ throw new Error(
91
+ 'Workflow limit "maxAiCredits" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling'
92
+ );
93
+ }
94
+ }
95
+ }
96
+ function validatePhases(meta) {
97
+ const titles = /* @__PURE__ */ new Set();
98
+ for (const phase of meta.phases) {
99
+ if (phase.title.trim().length === 0) {
100
+ throw new Error("Workflow phase titles must not be empty");
101
+ }
102
+ if (titles.has(phase.title)) {
103
+ throw new Error(`Workflow phase title "${phase.title}" is declared more than once`);
104
+ }
105
+ titles.add(phase.title);
106
+ }
107
+ }
108
+ function defineWorkflow(definition) {
109
+ const meta = deepFreeze(structuredClone(definition.meta));
110
+ validateLimits(meta);
111
+ validatePhases(meta);
112
+ const stored = {
113
+ meta,
114
+ run: definition.run
115
+ };
116
+ const handle = Object.freeze({ meta });
117
+ workflowHandles.set(handle, stored);
118
+ return handle;
119
+ }
120
+ function getWorkflowDefinition(handle) {
121
+ const definition = workflowHandles.get(handle);
122
+ if (!definition) {
123
+ throw new Error("Invalid workflow handle");
124
+ }
125
+ return definition;
126
+ }
127
+ // Annotate the CommonJS export names for ESM import in node:
128
+ 0 && (module.exports = {
129
+ WORKFLOW_AGENT_OPTION_KEYS,
130
+ WorkflowResumeError,
131
+ defineWorkflow,
132
+ getWorkflowDefinition,
133
+ isWorkflowRunTerminal
134
+ });