@yolk-sdk/vercel-workflows 0.1.0-canary.72 → 0.1.0-canary.73
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 +26 -2
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/workflow-children.d.mts +40 -0
- package/dist/workflow-children.d.mts.map +1 -0
- package/dist/workflow-children.mjs +51 -0
- package/dist/workflow-children.mjs.map +1 -0
- package/dist/workflow.d.mts +2 -1
- package/dist/workflow.mjs +2 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/workflow-children.ts +62 -0
- package/src/workflow.ts +1 -0
package/README.md
CHANGED
|
@@ -132,10 +132,34 @@ export async function runAgentWorkflow(input: { request: unknown; context: unkno
|
|
|
132
132
|
}
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
`runModelStep`, `
|
|
136
|
-
`
|
|
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. Do not hold a step open awaiting a long `run.returnValue` poll.
|
|
156
|
+
|
|
157
|
+
Hosts own immutable logical reservations, admission/CAS, ownership checks, storage, bounded
|
|
158
|
+
fanout, safe errors, credentials, and cancellation policy. Parent completion/failure must not
|
|
159
|
+
implicitly cancel independent children. Explicit Stop should persist a durable tombstone before
|
|
160
|
+
sweeping admitted child ids, reject late admission, and expose partial sweep failures for retry.
|
|
161
|
+
Give each independent stream and parallel call its own deterministic event-id namespace.
|
|
162
|
+
|
|
139
163
|
## Awaiting input
|
|
140
164
|
|
|
141
165
|
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
|
-
|
|
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
|
-
|
|
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,40 @@
|
|
|
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
|
+
*/
|
|
5
|
+
declare function awaitWorkflowChild<A>(input: {
|
|
6
|
+
readonly read: () => Promise<{
|
|
7
|
+
readonly done: false;
|
|
8
|
+
} | {
|
|
9
|
+
readonly done: true;
|
|
10
|
+
readonly value: A;
|
|
11
|
+
}>;
|
|
12
|
+
readonly sleep: () => Promise<void>;
|
|
13
|
+
}): Promise<A>;
|
|
14
|
+
/** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
|
|
15
|
+
* active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
|
|
16
|
+
*/
|
|
17
|
+
declare function orchestrateWorkflowToolBatch<Call, Result, Pause>(input: {
|
|
18
|
+
readonly calls: ReadonlyArray<Call>;
|
|
19
|
+
readonly concurrency: number;
|
|
20
|
+
readonly preflight: () => Promise<{
|
|
21
|
+
readonly ready: true;
|
|
22
|
+
} | {
|
|
23
|
+
readonly ready: false;
|
|
24
|
+
readonly value: Pause;
|
|
25
|
+
}>;
|
|
26
|
+
readonly execute: (call: Call, index: number) => Promise<Result>;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
readonly ready: true;
|
|
29
|
+
readonly results: ReadonlyArray<Result>;
|
|
30
|
+
readonly failures?: ReadonlyArray<{
|
|
31
|
+
readonly index: number;
|
|
32
|
+
readonly error: unknown;
|
|
33
|
+
}>;
|
|
34
|
+
} | {
|
|
35
|
+
readonly ready: false;
|
|
36
|
+
readonly value: Pause;
|
|
37
|
+
}>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { awaitWorkflowChild, orchestrateWorkflowToolBatch };
|
|
40
|
+
//# sourceMappingURL=workflow-children.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-children.d.mts","names":[],"sources":["../src/workflow-children.ts"],"mappings":";;AAGA;;iBAAsB,kBAAA,GAAA,CAAsB,KAAA;EAAA,SACjC,IAAA,QAAY,OAAA;IAAA,SACR,IAAA;EAAA;IAAA,SAA2B,IAAA;IAAA,SAAqB,KAAA,EAAO,CAAA;EAAA;EAAA,SAE3D,KAAA,QAAa,OAAA;AAAA,IACpB,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,51 @@
|
|
|
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
|
+
*/
|
|
5
|
+
async function awaitWorkflowChild(input) {
|
|
6
|
+
const { read, sleep } = input;
|
|
7
|
+
for (;;) {
|
|
8
|
+
const state = await read();
|
|
9
|
+
if (state.done) return state.value;
|
|
10
|
+
await sleep();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
|
|
14
|
+
* active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
|
|
15
|
+
*/
|
|
16
|
+
async function orchestrateWorkflowToolBatch(input) {
|
|
17
|
+
const { calls, concurrency, preflight, execute } = input;
|
|
18
|
+
const prepared = await preflight();
|
|
19
|
+
if (!prepared.ready) return prepared;
|
|
20
|
+
const width = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 1;
|
|
21
|
+
const entries = calls.map((call, index) => ({
|
|
22
|
+
call,
|
|
23
|
+
index
|
|
24
|
+
}));
|
|
25
|
+
let next = 0;
|
|
26
|
+
const results = /* @__PURE__ */ new Map();
|
|
27
|
+
const failures = [];
|
|
28
|
+
await Promise.all(Array.from({ length: Math.min(width, calls.length) }, async () => {
|
|
29
|
+
while (failures.length === 0) {
|
|
30
|
+
const entry = entries[next++];
|
|
31
|
+
if (entry === void 0) return;
|
|
32
|
+
try {
|
|
33
|
+
results.set(entry.index, await execute(entry.call, entry.index));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
failures.push({
|
|
36
|
+
index: entry.index,
|
|
37
|
+
error
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
return {
|
|
43
|
+
ready: true,
|
|
44
|
+
results: [...results.entries()].sort(([a], [b]) => a - b).map(([, result]) => result),
|
|
45
|
+
...failures.length === 0 ? {} : { failures: failures.sort((a, b) => a.index - b.index) }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { awaitWorkflowChild, orchestrateWorkflowToolBatch };
|
|
50
|
+
|
|
51
|
+
//# 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 */\nexport async function awaitWorkflowChild<A>(input: {\n readonly read: () => Promise<\n { readonly done: false } | { readonly done: true; readonly value: A }\n >\n readonly sleep: () => Promise<void>\n}): Promise<A> {\n const { read, sleep } = input\n for (;;) {\n const state = await read()\n if (state.done) return state.value\n await sleep()\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":";;;;AAGA,eAAsB,mBAAsB,OAK7B;CACb,MAAM,EAAE,MAAM,UAAU;CACxB,SAAS;EACP,MAAM,QAAQ,MAAM,KAAK;EACzB,IAAI,MAAM,MAAM,OAAO,MAAM;EAC7B,MAAM,MAAM;CACd;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"}
|
package/dist/workflow.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
|
-
|
|
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
|
-
|
|
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
package/src/index.ts
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
*/
|
|
4
|
+
export async function awaitWorkflowChild<A>(input: {
|
|
5
|
+
readonly read: () => Promise<
|
|
6
|
+
{ readonly done: false } | { readonly done: true; readonly value: A }
|
|
7
|
+
>
|
|
8
|
+
readonly sleep: () => Promise<void>
|
|
9
|
+
}): Promise<A> {
|
|
10
|
+
const { read, sleep } = input
|
|
11
|
+
for (;;) {
|
|
12
|
+
const state = await read()
|
|
13
|
+
if (state.done) return state.value
|
|
14
|
+
await sleep()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Preflight fences the entire batch. On rejection, stop dispatching new work, settle already
|
|
19
|
+
* active siblings, and return their ordered progress alongside failures. Hosts must handle failures.
|
|
20
|
+
*/
|
|
21
|
+
export async function orchestrateWorkflowToolBatch<Call, Result, Pause>(input: {
|
|
22
|
+
readonly calls: ReadonlyArray<Call>
|
|
23
|
+
readonly concurrency: number
|
|
24
|
+
readonly preflight: () => Promise<
|
|
25
|
+
{ readonly ready: true } | { readonly ready: false; readonly value: Pause }
|
|
26
|
+
>
|
|
27
|
+
readonly execute: (call: Call, index: number) => Promise<Result>
|
|
28
|
+
}): Promise<
|
|
29
|
+
| {
|
|
30
|
+
readonly ready: true
|
|
31
|
+
readonly results: ReadonlyArray<Result>
|
|
32
|
+
readonly failures?: ReadonlyArray<{ readonly index: number; readonly error: unknown }>
|
|
33
|
+
}
|
|
34
|
+
| { readonly ready: false; readonly value: Pause }
|
|
35
|
+
> {
|
|
36
|
+
const { calls, concurrency, preflight, execute } = input
|
|
37
|
+
const prepared = await preflight()
|
|
38
|
+
if (!prepared.ready) return prepared
|
|
39
|
+
const width = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : 1
|
|
40
|
+
const entries = calls.map((call, index) => ({ call, index }))
|
|
41
|
+
let next = 0
|
|
42
|
+
const results = new Map<number, Result>()
|
|
43
|
+
const failures: Array<{ readonly index: number; readonly error: unknown }> = []
|
|
44
|
+
await Promise.all(
|
|
45
|
+
Array.from({ length: Math.min(width, calls.length) }, async () => {
|
|
46
|
+
while (failures.length === 0) {
|
|
47
|
+
const entry = entries[next++]
|
|
48
|
+
if (entry === undefined) return
|
|
49
|
+
try {
|
|
50
|
+
results.set(entry.index, await execute(entry.call, entry.index))
|
|
51
|
+
} catch (error) {
|
|
52
|
+
failures.push({ index: entry.index, error })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
return {
|
|
58
|
+
ready: true,
|
|
59
|
+
results: [...results.entries()].sort(([a], [b]) => a - b).map(([, result]) => result),
|
|
60
|
+
...(failures.length === 0 ? {} : { failures: failures.sort((a, b) => a.index - b.index) })
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/workflow.ts
CHANGED