@yolk-sdk/vercel-workflows 0.1.0-canary.72 → 0.1.0-canary.74

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 CHANGED
@@ -132,10 +132,40 @@ export async function runAgentWorkflow(input: { request: unknown; context: unkno
132
132
  }
133
133
  ```
134
134
 
135
- `runModelStep`, `runToolBatchStep`, `closeStream`, and `writeError` are host-owned
136
- `'use step'` functions. Keep provider calls, tools, persistence, telemetry, and Effect runtimes in
135
+ `runModelStep`, `closeStream`, and `writeError` are host-owned `'use step'` functions.
136
+ `runToolBatchStep` may instead be Workflow orchestration calling concrete per-call steps. Keep provider calls, tools, persistence, telemetry, and Effect runtimes in
137
137
  those steps, not in the `'use workflow'` orchestration body.
138
138
 
139
+ ## Independent children
140
+
141
+ `orchestrateWorkflowToolBatch` runs a full-batch `preflight` before any `execute` callback,
142
+ limits local concurrency, and returns results in original call order. Both callbacks are host
143
+ seams: perform IO in steps, not in the orchestration helper. The host commits exactly one tool
144
+ result per call. Return a pause value from preflight when any HITL request is pending.
145
+ If an execution rejects, the helper stops dispatching new calls, settles already-active siblings,
146
+ and returns their ordered progress plus `failures`. Hosts must propagate those failures while
147
+ retaining completed results and usage; do not treat a partial batch as successful.
148
+
149
+ Start child workflows with Workflow 5 `start(childWorkflow, args)` **from orchestration**, not
150
+ inside the parent tool step. A child wrapper runs its own model/tool steps and returns a typed
151
+ application outcome; platform `completed` alone does not prove application success. Foreground
152
+ hosts await that child outcome; background hosts return an accepted handle and continue.
153
+
154
+ `awaitWorkflowChild({ read, sleep })` polls short durable read steps with a host-provided Workflow
155
+ `sleep` between reads. Both callbacks receive the same zero-based attempt index, so hosts can
156
+ apply capped backoff and end an observation after a bounded number of reads. At that ceiling,
157
+ `read` should return `{ done: true, value: stillRunningObservation }`; this ends polling, not the
158
+ child lifecycle. Preserve an owned handle for eventual result lookup. Existing zero-argument
159
+ callbacks remain supported and the helper has no implicit budget. Hosts must explicitly bound
160
+ long waits to avoid unbounded durable event accumulation. Do not hold a step open awaiting a long
161
+ `run.returnValue` poll.
162
+
163
+ Hosts own immutable logical reservations, admission/CAS, ownership checks, storage, bounded
164
+ fanout, safe errors, credentials, and cancellation policy. Parent completion/failure must not
165
+ implicitly cancel independent children. Explicit Stop should persist a durable tombstone before
166
+ sweeping admitted child ids, reject late admission, and expose partial sweep failures for retry.
167
+ Give each independent stream and parallel call its own deterministic event-id namespace.
168
+
139
169
  ## Awaiting input
140
170
 
141
171
  When a tool batch needs HITL input, return `awaitingInput` from `runToolBatchStep`. The package
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
2
  import { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
3
+ import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
4
+ export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
2
  import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
3
+ import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
4
+ export { awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
@@ -0,0 +1,42 @@
1
+ //#region src/workflow-children.d.ts
2
+ /** Workflow orchestration only. Callbacks must be durable steps (sleep must be Workflow sleep).
3
+ * A read is short-lived; never put a long returnValue poll inside a step.
4
+ * Both callbacks receive a deterministic zero-based attempt for host budgets/backoff.
5
+ * Defaults remain unbounded: hosts end observation at their ceiling by returning done + value.
6
+ */
7
+ declare function awaitWorkflowChild<A>(input: {
8
+ readonly read: (attempt: number) => Promise<{
9
+ readonly done: false;
10
+ } | {
11
+ readonly done: true;
12
+ readonly value: A;
13
+ }>;
14
+ readonly sleep: (attempt: number) => Promise<void>;
15
+ }): Promise<A>;
16
+ /** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
17
+ * active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
18
+ */
19
+ declare function orchestrateWorkflowToolBatch<Call, Result, Pause>(input: {
20
+ readonly calls: ReadonlyArray<Call>;
21
+ readonly concurrency: number;
22
+ readonly preflight: () => Promise<{
23
+ readonly ready: true;
24
+ } | {
25
+ readonly ready: false;
26
+ readonly value: Pause;
27
+ }>;
28
+ readonly execute: (call: Call, index: number) => Promise<Result>;
29
+ }): Promise<{
30
+ readonly ready: true;
31
+ readonly results: ReadonlyArray<Result>;
32
+ readonly failures?: ReadonlyArray<{
33
+ readonly index: number;
34
+ readonly error: unknown;
35
+ }>;
36
+ } | {
37
+ readonly ready: false;
38
+ readonly value: Pause;
39
+ }>;
40
+ //#endregion
41
+ export { awaitWorkflowChild, orchestrateWorkflowToolBatch };
42
+ //# sourceMappingURL=workflow-children.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-children.d.mts","names":[],"sources":["../src/workflow-children.ts"],"mappings":";;AAKA;;;;iBAAsB,kBAAA,GAAA,CAAsB,KAAA;EAAA,SACjC,IAAA,GACP,OAAA,aACG,OAAA;IAAA,SAAmB,IAAA;EAAA;IAAA,SAA2B,IAAA;IAAA,SAAqB,KAAA,EAAO,CAAA;EAAA;EAAA,SACtE,KAAA,GAAQ,OAAA,aAAoB,OAAA;AAAA,IACnC,OAAA,CAAQ,CAAA;;;;iBAYU,4BAAA,qBAAA,CAAkD,KAAA;EAAA,SAC7D,KAAA,EAAO,aAAA,CAAc,IAAA;EAAA,SACrB,WAAA;EAAA,SACA,SAAA,QAAiB,OAAA;IAAA,SACb,KAAA;EAAA;IAAA,SAA2B,KAAA;IAAA,SAAuB,KAAA,EAAO,KAAA;EAAA;EAAA,SAE7D,OAAA,GAAU,IAAA,EAAM,IAAA,EAAM,KAAA,aAAkB,OAAA,CAAQ,MAAA;AAAA,IACvD,OAAA;EAAA,SAEW,KAAA;EAAA,SACA,OAAA,EAAS,aAAA,CAAc,MAAA;EAAA,SACvB,QAAA,GAAW,aAAA;IAAA,SAAyB,KAAA;IAAA,SAAwB,KAAA;EAAA;AAAA;EAAA,SAE5D,KAAA;EAAA,SAAuB,KAAA,EAAO,KAAA;AAAA"}
@@ -0,0 +1,53 @@
1
+ //#region src/workflow-children.ts
2
+ /** Workflow orchestration only. Callbacks must be durable steps (sleep must be Workflow sleep).
3
+ * A read is short-lived; never put a long returnValue poll inside a step.
4
+ * Both callbacks receive a deterministic zero-based attempt for host budgets/backoff.
5
+ * Defaults remain unbounded: hosts end observation at their ceiling by returning done + value.
6
+ */
7
+ async function awaitWorkflowChild(input) {
8
+ const { read, sleep } = input;
9
+ for (let attempt = 0;; attempt++) {
10
+ const state = await read(attempt);
11
+ if (state.done) return state.value;
12
+ await sleep(attempt);
13
+ }
14
+ }
15
+ /** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
16
+ * active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
17
+ */
18
+ async function orchestrateWorkflowToolBatch(input) {
19
+ const { calls, concurrency, preflight, execute } = input;
20
+ const prepared = await preflight();
21
+ if (!prepared.ready) return prepared;
22
+ const width = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 1;
23
+ const entries = calls.map((call, index) => ({
24
+ call,
25
+ index
26
+ }));
27
+ let next = 0;
28
+ const results = /* @__PURE__ */ new Map();
29
+ const failures = [];
30
+ await Promise.all(Array.from({ length: Math.min(width, calls.length) }, async () => {
31
+ while (failures.length === 0) {
32
+ const entry = entries[next++];
33
+ if (entry === void 0) return;
34
+ try {
35
+ results.set(entry.index, await execute(entry.call, entry.index));
36
+ } catch (error) {
37
+ failures.push({
38
+ index: entry.index,
39
+ error
40
+ });
41
+ }
42
+ }
43
+ }));
44
+ return {
45
+ ready: true,
46
+ results: [...results.entries()].sort(([a], [b]) => a - b).map(([, result]) => result),
47
+ ...failures.length === 0 ? {} : { failures: failures.sort((a, b) => a.index - b.index) }
48
+ };
49
+ }
50
+ //#endregion
51
+ export { awaitWorkflowChild, orchestrateWorkflowToolBatch };
52
+
53
+ //# sourceMappingURL=workflow-children.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-children.mjs","names":[],"sources":["../src/workflow-children.ts"],"sourcesContent":["/** Workflow orchestration only. Callbacks must be durable steps (sleep must be Workflow sleep).\n * A read is short-lived; never put a long returnValue poll inside a step.\n * Both callbacks receive a deterministic zero-based attempt for host budgets/backoff.\n * Defaults remain unbounded: hosts end observation at their ceiling by returning done + value.\n */\nexport async function awaitWorkflowChild<A>(input: {\n readonly read: (\n attempt: number\n ) => Promise<{ readonly done: false } | { readonly done: true; readonly value: A }>\n readonly sleep: (attempt: number) => Promise<void>\n}): Promise<A> {\n const { read, sleep } = input\n for (let attempt = 0; ; attempt++) {\n const state = await read(attempt)\n if (state.done) return state.value\n await sleep(attempt)\n }\n}\n\n/** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already\n * active siblings, and return their ordered progress alongside failures. Hosts must handle failures.\n */\nexport async function orchestrateWorkflowToolBatch<Call, Result, Pause>(input: {\n readonly calls: ReadonlyArray<Call>\n readonly concurrency: number\n readonly preflight: () => Promise<\n { readonly ready: true } | { readonly ready: false; readonly value: Pause }\n >\n readonly execute: (call: Call, index: number) => Promise<Result>\n}): Promise<\n | {\n readonly ready: true\n readonly results: ReadonlyArray<Result>\n readonly failures?: ReadonlyArray<{ readonly index: number; readonly error: unknown }>\n }\n | { readonly ready: false; readonly value: Pause }\n> {\n const { calls, concurrency, preflight, execute } = input\n const prepared = await preflight()\n if (!prepared.ready) return prepared\n const width = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 1\n const entries = calls.map((call, index) => ({ call, index }))\n let next = 0\n const results = new Map<number, Result>()\n const failures: Array<{ readonly index: number; readonly error: unknown }> = []\n await Promise.all(\n Array.from({ length: Math.min(width, calls.length) }, async () => {\n while (failures.length === 0) {\n const entry = entries[next++]\n if (entry === undefined) return\n try {\n results.set(entry.index, await execute(entry.call, entry.index))\n } catch (error) {\n failures.push({ index: entry.index, error })\n }\n }\n })\n )\n return {\n ready: true,\n results: [...results.entries()].sort(([a], [b]) => a - b).map(([, result]) => result),\n ...(failures.length === 0 ? {} : { failures: failures.sort((a, b) => a.index - b.index) })\n }\n}\n"],"mappings":";;;;;;AAKA,eAAsB,mBAAsB,OAK7B;CACb,MAAM,EAAE,MAAM,UAAU;CACxB,KAAK,IAAI,UAAU,IAAK,WAAW;EACjC,MAAM,QAAQ,MAAM,KAAK,OAAO;EAChC,IAAI,MAAM,MAAM,OAAO,MAAM;EAC7B,MAAM,MAAM,OAAO;CACrB;AACF;;;;AAKA,eAAsB,6BAAkD,OActE;CACA,MAAM,EAAE,OAAO,aAAa,WAAW,YAAY;CACnD,MAAM,WAAW,MAAM,UAAU;CACjC,IAAI,CAAC,SAAS,OAAO,OAAO;CAC5B,MAAM,QAAQ,OAAO,SAAS,WAAW,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,CAAC,IAAI;CACpF,MAAM,UAAU,MAAM,KAAK,MAAM,WAAW;EAAE;EAAM;CAAM,EAAE;CAC5D,IAAI,OAAO;CACX,MAAM,0BAAU,IAAI,IAAoB;CACxC,MAAM,WAAuE,CAAC;CAC9E,MAAM,QAAQ,IACZ,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,MAAM,MAAM,EAAE,GAAG,YAAY;EAChE,OAAO,SAAS,WAAW,GAAG;GAC5B,MAAM,QAAQ,QAAQ;GACtB,IAAI,UAAU,KAAA,GAAW;GACzB,IAAI;IACF,QAAQ,IAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,CAAC;GACjE,SAAS,OAAO;IACd,SAAS,KAAK;KAAE,OAAO,MAAM;KAAO;IAAM,CAAC;GAC7C;EACF;CACF,CAAC,CACH;CACA,OAAO;EACL,OAAO;EACP,SAAS,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE,KAAK,GAAG,YAAY,MAAM;EACpF,GAAI,SAAS,WAAW,IAAI,CAAC,IAAI,EAAE,UAAU,SAAS,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;CAC1F;AACF"}
@@ -1,3 +1,4 @@
1
1
  import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
2
  import { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
3
+ import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
4
+ export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/dist/workflow.mjs CHANGED
@@ -1,3 +1,4 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
2
  import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
3
+ import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
4
+ export { awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/vercel-workflows",
3
- "version": "0.1.0-canary.72",
3
+ "version": "0.1.0-canary.74",
4
4
  "description": "Vercel Workflow orchestration primitives for Yolk agent loops.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -31,3 +31,4 @@ export type {
31
31
  WorkflowStepResult,
32
32
  WriteDurableAgentEventInput
33
33
  } from './workflow.ts'
34
+ export { awaitWorkflowChild, orchestrateWorkflowToolBatch } from './workflow-children.ts'
@@ -0,0 +1,64 @@
1
+ /** Workflow orchestration only. Callbacks must be durable steps (sleep must be Workflow sleep).
2
+ * A read is short-lived; never put a long returnValue poll inside a step.
3
+ * Both callbacks receive a deterministic zero-based attempt for host budgets/backoff.
4
+ * Defaults remain unbounded: hosts end observation at their ceiling by returning done + value.
5
+ */
6
+ export async function awaitWorkflowChild<A>(input: {
7
+ readonly read: (
8
+ attempt: number
9
+ ) => Promise<{ readonly done: false } | { readonly done: true; readonly value: A }>
10
+ readonly sleep: (attempt: number) => Promise<void>
11
+ }): Promise<A> {
12
+ const { read, sleep } = input
13
+ for (let attempt = 0; ; attempt++) {
14
+ const state = await read(attempt)
15
+ if (state.done) return state.value
16
+ await sleep(attempt)
17
+ }
18
+ }
19
+
20
+ /** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
21
+ * active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
22
+ */
23
+ export async function orchestrateWorkflowToolBatch<Call, Result, Pause>(input: {
24
+ readonly calls: ReadonlyArray<Call>
25
+ readonly concurrency: number
26
+ readonly preflight: () => Promise<
27
+ { readonly ready: true } | { readonly ready: false; readonly value: Pause }
28
+ >
29
+ readonly execute: (call: Call, index: number) => Promise<Result>
30
+ }): Promise<
31
+ | {
32
+ readonly ready: true
33
+ readonly results: ReadonlyArray<Result>
34
+ readonly failures?: ReadonlyArray<{ readonly index: number; readonly error: unknown }>
35
+ }
36
+ | { readonly ready: false; readonly value: Pause }
37
+ > {
38
+ const { calls, concurrency, preflight, execute } = input
39
+ const prepared = await preflight()
40
+ if (!prepared.ready) return prepared
41
+ const width = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 1
42
+ const entries = calls.map((call, index) => ({ call, index }))
43
+ let next = 0
44
+ const results = new Map<number, Result>()
45
+ const failures: Array<{ readonly index: number; readonly error: unknown }> = []
46
+ await Promise.all(
47
+ Array.from({ length: Math.min(width, calls.length) }, async () => {
48
+ while (failures.length === 0) {
49
+ const entry = entries[next++]
50
+ if (entry === undefined) return
51
+ try {
52
+ results.set(entry.index, await execute(entry.call, entry.index))
53
+ } catch (error) {
54
+ failures.push({ index: entry.index, error })
55
+ }
56
+ }
57
+ })
58
+ )
59
+ return {
60
+ ready: true,
61
+ results: [...results.entries()].sort(([a], [b]) => a - b).map(([, result]) => result),
62
+ ...(failures.length === 0 ? {} : { failures: failures.sort((a, b) => a.index - b.index) })
63
+ }
64
+ }
package/src/workflow.ts CHANGED
@@ -35,3 +35,4 @@ export type {
35
35
  SequencedDurableAgentEvent,
36
36
  WriteDurableAgentEventInput
37
37
  } from './workflow-events.ts'
38
+ export { awaitWorkflowChild, orchestrateWorkflowToolBatch } from './workflow-children.ts'