@hexabot-ai/agentic 3.1.2-alpha.1 → 3.1.2-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/step-executors/loop-executor.js +26 -39
- package/dist/cjs/step-executors/parallel-executor.js +9 -15
- package/dist/cjs/step-executors/suspension-continuation.js +27 -0
- package/dist/cjs/suspension-rebuilder.js +61 -74
- package/dist/cjs/workflow-runner.js +2 -10
- package/dist/esm/step-executors/loop-executor.js +26 -39
- package/dist/esm/step-executors/parallel-executor.js +9 -15
- package/dist/esm/step-executors/suspension-continuation.js +24 -0
- package/dist/esm/suspension-rebuilder.js +61 -74
- package/dist/esm/workflow-runner.js +2 -10
- package/dist/types/step-executors/loop-executor.d.ts.map +1 -1
- package/dist/types/step-executors/parallel-executor.d.ts.map +1 -1
- package/dist/types/step-executors/suspension-continuation.d.ts +10 -0
- package/dist/types/step-executors/suspension-continuation.d.ts.map +1 -0
- package/dist/types/suspension-rebuilder.d.ts.map +1 -1
- package/dist/types/workflow-runner.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/suspension-rebuilder.test.ts +43 -9
- package/src/__tests__/workflow-runner.test.ts +119 -1
- package/src/step-executors/loop-executor.ts +49 -64
- package/src/step-executors/parallel-executor.ts +13 -20
- package/src/step-executors/suspension-continuation.ts +31 -0
- package/src/suspension-rebuilder.ts +94 -100
- package/src/workflow-runner.ts +4 -11
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
} from '../workflow-types';
|
|
12
12
|
|
|
13
13
|
import { markStepsSkipped } from './skip-helpers';
|
|
14
|
+
import { wrapSuspensionContinuation } from './suspension-continuation';
|
|
14
15
|
import type { StepExecutorEnv } from './types';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -35,29 +36,21 @@ export async function executeParallel(
|
|
|
35
36
|
const childPath = [...path, 'parallel', index];
|
|
36
37
|
const suspension = await env.executeStep(child, state, childPath);
|
|
37
38
|
if (suspension) {
|
|
38
|
-
return {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
return wrapSuspensionContinuation(suspension, async () => {
|
|
40
|
+
if (step.strategy === 'wait_any') {
|
|
41
|
+
if (index + 1 < step.steps.length) {
|
|
42
|
+
markStepsSkipped(
|
|
43
|
+
env,
|
|
44
|
+
step.steps.slice(index + 1),
|
|
45
|
+
state.iterationStack,
|
|
46
|
+
);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
markStepsSkipped(
|
|
49
|
-
env,
|
|
50
|
-
step.steps.slice(index + 1),
|
|
51
|
-
state.iterationStack,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return executeParallel(env, step, state, path, index + 1);
|
|
59
|
-
},
|
|
60
|
-
};
|
|
52
|
+
return executeParallel(env, step, state, path, index + 1);
|
|
53
|
+
});
|
|
61
54
|
}
|
|
62
55
|
|
|
63
56
|
if (step.strategy === 'wait_any') {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Hexabot — Fair Core License (FCL-1.0-ALv2)
|
|
3
|
+
* Copyright (c) 2025 Hexastack.
|
|
4
|
+
* Full terms: see LICENSE.md.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Suspension } from '../workflow-types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Compose a suspension with the continuation that should run once it completes.
|
|
11
|
+
*
|
|
12
|
+
* When resuming a suspension yields another suspension from the same logical
|
|
13
|
+
* step, the follow-up suspension still needs to remember how to continue the
|
|
14
|
+
* surrounding flow after that step eventually finishes.
|
|
15
|
+
*/
|
|
16
|
+
export function wrapSuspensionContinuation(
|
|
17
|
+
suspension: Suspension,
|
|
18
|
+
onComplete: () => Promise<Suspension | void>,
|
|
19
|
+
): Suspension {
|
|
20
|
+
return {
|
|
21
|
+
...suspension,
|
|
22
|
+
continue: async (resumeData: unknown) => {
|
|
23
|
+
const next = await suspension.continue(resumeData);
|
|
24
|
+
if (next) {
|
|
25
|
+
return wrapSuspensionContinuation(next, onComplete);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return onComplete();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from './step-executors/loop-executor';
|
|
13
13
|
import { executeParallel as runParallelExecutor } from './step-executors/parallel-executor';
|
|
14
14
|
import { markStepsSkipped } from './step-executors/skip-helpers';
|
|
15
|
+
import { wrapSuspensionContinuation } from './step-executors/suspension-continuation';
|
|
15
16
|
import type { StepExecutorEnv } from './step-executors/types';
|
|
16
17
|
import {
|
|
17
18
|
StepType,
|
|
@@ -272,17 +273,9 @@ export function buildSuspensionForPath(
|
|
|
272
273
|
|
|
273
274
|
const resumed = await executeStep(step, state, currentPath);
|
|
274
275
|
if (resumed) {
|
|
275
|
-
return
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const next = await resumed.continue(nextResumeData);
|
|
279
|
-
if (next) {
|
|
280
|
-
return next;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
284
|
-
},
|
|
285
|
-
};
|
|
276
|
+
return wrapSuspensionContinuation(resumed, () =>
|
|
277
|
+
deps.executeFlow(steps, state, pathPrefix, current + 1),
|
|
278
|
+
);
|
|
286
279
|
}
|
|
287
280
|
|
|
288
281
|
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
@@ -324,35 +317,35 @@ export function buildSuspensionForPath(
|
|
|
324
317
|
const childIndex =
|
|
325
318
|
typeof childPath[0] === 'number' ? (childPath[0] as number) : 0;
|
|
326
319
|
|
|
327
|
-
return {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if (step.strategy === 'wait_any') {
|
|
336
|
-
if (childIndex + 1 < step.steps.length) {
|
|
337
|
-
markStepsSkipped(
|
|
338
|
-
env,
|
|
339
|
-
step.steps.slice(childIndex + 1),
|
|
340
|
-
state.iterationStack ?? [],
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return undefined;
|
|
320
|
+
return wrapSuspensionContinuation(childSuspension, async () => {
|
|
321
|
+
if (step.strategy === 'wait_any') {
|
|
322
|
+
if (childIndex + 1 < step.steps.length) {
|
|
323
|
+
markStepsSkipped(
|
|
324
|
+
env,
|
|
325
|
+
step.steps.slice(childIndex + 1),
|
|
326
|
+
state.iterationStack ?? [],
|
|
327
|
+
);
|
|
345
328
|
}
|
|
346
329
|
|
|
347
|
-
return
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
330
|
+
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const next = await runParallelExecutor(
|
|
334
|
+
env,
|
|
335
|
+
step,
|
|
336
|
+
state,
|
|
337
|
+
currentPath,
|
|
338
|
+
childIndex + 1,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
if (next) {
|
|
342
|
+
return wrapSuspensionContinuation(next, () =>
|
|
343
|
+
deps.executeFlow(steps, state, pathPrefix, current + 1),
|
|
353
344
|
);
|
|
354
|
-
}
|
|
355
|
-
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
348
|
+
});
|
|
356
349
|
}
|
|
357
350
|
|
|
358
351
|
if (step.type === StepType.Conditional) {
|
|
@@ -382,17 +375,9 @@ export function buildSuspensionForPath(
|
|
|
382
375
|
return null;
|
|
383
376
|
}
|
|
384
377
|
|
|
385
|
-
return
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const next = await branchSuspension.continue(resumeData);
|
|
389
|
-
if (next) {
|
|
390
|
-
return next;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
394
|
-
},
|
|
395
|
-
};
|
|
378
|
+
return wrapSuspensionContinuation(branchSuspension, () =>
|
|
379
|
+
deps.executeFlow(steps, state, pathPrefix, current + 1),
|
|
380
|
+
);
|
|
396
381
|
}
|
|
397
382
|
|
|
398
383
|
if (step.type === StepType.Loop) {
|
|
@@ -441,63 +426,72 @@ export function buildSuspensionForPath(
|
|
|
441
426
|
const accumulator =
|
|
442
427
|
iterationState.accumulator ?? state.accumulator ?? undefined;
|
|
443
428
|
|
|
444
|
-
return {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
429
|
+
return wrapSuspensionContinuation(childSuspension, async () => {
|
|
430
|
+
const scope: EvaluationScope = {
|
|
431
|
+
input: iterationState.input,
|
|
432
|
+
context: env.context.state,
|
|
433
|
+
output: iterationState.output,
|
|
434
|
+
iteration: iterationState.iteration ?? {
|
|
435
|
+
item: undefined,
|
|
436
|
+
index: iterationIndex,
|
|
437
|
+
},
|
|
438
|
+
accumulator,
|
|
439
|
+
};
|
|
440
|
+
const updatedAccumulator = await updateAccumulator(
|
|
441
|
+
step,
|
|
442
|
+
scope,
|
|
443
|
+
accumulator,
|
|
444
|
+
);
|
|
445
|
+
const shouldStop = await shouldStopLoop(step, scope);
|
|
446
|
+
|
|
447
|
+
state.output = iterationState.output;
|
|
448
|
+
|
|
449
|
+
if (step.accumulate && step.name) {
|
|
450
|
+
state.output[step.name] = {
|
|
451
|
+
[step.accumulate.as]: updatedAccumulator,
|
|
461
452
|
};
|
|
462
|
-
|
|
463
|
-
step,
|
|
464
|
-
scope,
|
|
465
|
-
accumulator,
|
|
466
|
-
);
|
|
467
|
-
const shouldStop = await shouldStopLoop(step, scope);
|
|
468
|
-
|
|
469
|
-
state.output = iterationState.output;
|
|
470
|
-
|
|
471
|
-
if (step.accumulate && step.name) {
|
|
472
|
-
state.output[step.name] = {
|
|
473
|
-
[step.accumulate.as]: updatedAccumulator,
|
|
474
|
-
};
|
|
475
|
-
}
|
|
453
|
+
}
|
|
476
454
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
455
|
+
if (step.accumulate) {
|
|
456
|
+
state.accumulator = updatedAccumulator;
|
|
457
|
+
}
|
|
480
458
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
459
|
+
if (shouldStop) {
|
|
460
|
+
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const baseState: ExecutionState = {
|
|
464
|
+
...iterationState,
|
|
465
|
+
iterationStack: ancestorIterationStack,
|
|
466
|
+
accumulator: updatedAccumulator,
|
|
467
|
+
output: state.output,
|
|
468
|
+
};
|
|
469
|
+
const next = await runLoopExecutor(
|
|
470
|
+
env,
|
|
471
|
+
step,
|
|
472
|
+
baseState,
|
|
473
|
+
currentPath,
|
|
474
|
+
iterationIndex + 1,
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
state.output = baseState.output;
|
|
478
|
+
if (step.accumulate) {
|
|
479
|
+
state.accumulator = baseState.accumulator;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (next) {
|
|
483
|
+
return wrapSuspensionContinuation(next, async () => {
|
|
484
|
+
state.output = baseState.output;
|
|
485
|
+
if (step.accumulate) {
|
|
486
|
+
state.accumulator = baseState.accumulator;
|
|
487
|
+
}
|
|
484
488
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
accumulator: updatedAccumulator,
|
|
489
|
-
output: state.output,
|
|
490
|
-
};
|
|
489
|
+
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
490
|
+
});
|
|
491
|
+
}
|
|
491
492
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
step,
|
|
495
|
-
baseState,
|
|
496
|
-
currentPath,
|
|
497
|
-
iterationIndex + 1,
|
|
498
|
-
);
|
|
499
|
-
},
|
|
500
|
-
};
|
|
493
|
+
return deps.executeFlow(steps, state, pathPrefix, current + 1);
|
|
494
|
+
});
|
|
501
495
|
}
|
|
502
496
|
|
|
503
497
|
return null;
|
package/src/workflow-runner.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { RunnerRuntimeControl } from './runner-runtime-control';
|
|
|
17
17
|
import { executeConditional as runConditionalExecutor } from './step-executors/conditional-executor';
|
|
18
18
|
import { executeLoop as runLoopExecutor } from './step-executors/loop-executor';
|
|
19
19
|
import { executeParallel as runParallelExecutor } from './step-executors/parallel-executor';
|
|
20
|
+
import { wrapSuspensionContinuation } from './step-executors/suspension-continuation';
|
|
20
21
|
import { executeTaskStep as runTaskExecutor } from './step-executors/task-executor';
|
|
21
22
|
import type { StepExecutorEnv } from './step-executors/types';
|
|
22
23
|
import {
|
|
@@ -552,17 +553,9 @@ export class WorkflowRunner {
|
|
|
552
553
|
const suspension = await this.executeStep(step, state, stepPath);
|
|
553
554
|
|
|
554
555
|
if (suspension) {
|
|
555
|
-
return
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
const next = await suspension.continue(resumeData);
|
|
559
|
-
if (next) {
|
|
560
|
-
return next;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
return this.executeFlow(steps, state, path, index + 1);
|
|
564
|
-
},
|
|
565
|
-
};
|
|
556
|
+
return wrapSuspensionContinuation(suspension, () =>
|
|
557
|
+
this.executeFlow(steps, state, path, index + 1),
|
|
558
|
+
);
|
|
566
559
|
}
|
|
567
560
|
}
|
|
568
561
|
|