@gobing-ai/ts-dual-workflow-engine 0.4.32 → 0.4.35
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/action-step.d.ts +21 -12
- package/dist/action-step.d.ts.map +1 -1
- package/dist/action-step.js +21 -14
- package/dist/state-machine.js +5 -5
- package/package.json +4 -4
- package/src/action-step.ts +37 -16
- package/src/state-machine.ts +3 -3
package/dist/action-step.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { WorkflowEngineHost } from './host';
|
|
2
2
|
import type { RunLifecycle } from './run-lifecycle';
|
|
3
3
|
import { type WorkflowMode } from './run-lifecycle';
|
|
4
|
-
import type { ActionDef, ActionResult, OnErrorPolicy, WorkflowPersistenceAdapter, WorkflowRunOptions } from './types';
|
|
4
|
+
import type { ActionDef, ActionResult, OnErrorPolicy, Vars, WorkflowPersistenceAdapter, WorkflowRunOptions } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Outcome discriminator for a single action step. `terminal` means the action
|
|
7
7
|
* declared terminal success (the run is done); `fail` means a failure under a
|
|
@@ -9,10 +9,17 @@ import type { ActionDef, ActionResult, OnErrorPolicy, WorkflowPersistenceAdapter
|
|
|
9
9
|
* a failure that the 'continue' policy logged past) and the loop may proceed.
|
|
10
10
|
*/
|
|
11
11
|
export type ActionStepOutcome = 'completed' | 'terminal' | 'fail';
|
|
12
|
-
/** Result of running one or more action steps: last result
|
|
12
|
+
/** Result of running one or more action steps: last result, a control-flow discriminator, and the accumulated `setVars` of every step in the sequence. */
|
|
13
13
|
export interface ActionStepResult {
|
|
14
14
|
readonly outcome: ActionStepOutcome;
|
|
15
15
|
readonly result: ActionResult | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Sequence-level accumulation of `setVars` from every action that ran
|
|
18
|
+
* (including the terminal/failing one). Single-step callers get just that
|
|
19
|
+
* step's setVars. Drivers merge this map into their run-local vars after
|
|
20
|
+
* the sequence settles.
|
|
21
|
+
*/
|
|
22
|
+
readonly setVars?: Vars;
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Everything an action step needs that does not change between the two drivers:
|
|
@@ -38,9 +45,9 @@ export interface ActionStepDeps {
|
|
|
38
45
|
* Run one action through its full lifecycle: resolve templates, persist the
|
|
39
46
|
* start row, time the host invocation inside try/finally, persist + emit the
|
|
40
47
|
* finalize, then classify terminal/fail/continue. `vars` is read-only here;
|
|
41
|
-
* callers thread any `setVars` from the returned result
|
|
42
|
-
*
|
|
43
|
-
* differently across
|
|
48
|
+
* callers thread any `setVars` from the returned result forward — the sequence
|
|
49
|
+
* runner does so within a sequence, and drivers merge the accumulated map
|
|
50
|
+
* across states/nodes (each dialect carries vars differently across its loop).
|
|
44
51
|
*
|
|
45
52
|
* This is the single seam both drivers share for action execution (ADR-006 §7
|
|
46
53
|
* keeps the *control loops* dialect-specific; only this per-action mechanism is
|
|
@@ -49,13 +56,15 @@ export interface ActionStepDeps {
|
|
|
49
56
|
export declare function runActionStep(action: ActionDef, vars: Record<string, string>, deps: ActionStepDeps): Promise<ActionStepResult>;
|
|
50
57
|
/**
|
|
51
58
|
* Run a sequence of actions in declaration order, stopping at the first
|
|
52
|
-
* `terminal` or `fail` outcome.
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
+
* `terminal` or `fail` outcome. `setVars` from each action is threaded forward
|
|
60
|
+
* BEFORE the next action runs, so action N+1 resolves its templates (and sees
|
|
61
|
+
* `context.vars`) with every prior same-sequence `setVars` applied — the YAML
|
|
62
|
+
* reads imperatively. The returned `setVars` accumulates the maps of every
|
|
63
|
+
* action that ran (including a continued-past failure and the terminal/failing
|
|
64
|
+
* action itself); it is the caller (the state-machine driver) that merges it
|
|
65
|
+
* into run-local vars after the sequence settles. Returns the last action
|
|
66
|
+
* result (retained even when a failure was continued past, so downstream
|
|
67
|
+
* guards can inspect it) plus the controlling outcome.
|
|
59
68
|
*/
|
|
60
69
|
export declare function runActionSequence(actions: readonly ActionDef[], vars: Record<string, string>, deps: ActionStepDeps): Promise<ActionStepResult>;
|
|
61
70
|
//# sourceMappingURL=action-step.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-step.d.ts","sourceRoot":"","sources":["../src/action-step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"action-step.d.ts","sourceRoot":"","sources":["../src/action-step.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,KAAK,EACR,SAAS,EACT,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,0BAA0B,EAC1B,kBAAkB,EACrB,MAAM,SAAS,CAAC;AAGjB;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAElE,0JAA0J;AAC1J,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC;IACjD,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,aAAa,GAAG,SAAS,CAAC;CACtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAC/B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,IAAI,EAAE,cAAc,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAkD3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACnC,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,IAAI,EAAE,cAAc,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAc3B"}
|
package/dist/action-step.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defaultActionRedactor } from './persistence.js';
|
|
2
2
|
import { runtimeBuiltins } from './run-lifecycle.js';
|
|
3
|
-
import { resolveOnErrorPolicy, resolveTemplates } from './variables.js';
|
|
3
|
+
import { mergeSetVars, resolveOnErrorPolicy, resolveTemplates } from './variables.js';
|
|
4
4
|
/**
|
|
5
5
|
* Run one action through its full lifecycle: resolve templates, persist the
|
|
6
6
|
* start row, time the host invocation inside try/finally, persist + emit the
|
|
7
7
|
* finalize, then classify terminal/fail/continue. `vars` is read-only here;
|
|
8
|
-
* callers thread any `setVars` from the returned result
|
|
9
|
-
*
|
|
10
|
-
* differently across
|
|
8
|
+
* callers thread any `setVars` from the returned result forward — the sequence
|
|
9
|
+
* runner does so within a sequence, and drivers merge the accumulated map
|
|
10
|
+
* across states/nodes (each dialect carries vars differently across its loop).
|
|
11
11
|
*
|
|
12
12
|
* This is the single seam both drivers share for action execution (ADR-006 §7
|
|
13
13
|
* keeps the *control loops* dialect-specific; only this per-action mechanism is
|
|
@@ -60,24 +60,31 @@ export async function runActionStep(action, vars, deps) {
|
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Run a sequence of actions in declaration order, stopping at the first
|
|
63
|
-
* `terminal` or `fail` outcome.
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
63
|
+
* `terminal` or `fail` outcome. `setVars` from each action is threaded forward
|
|
64
|
+
* BEFORE the next action runs, so action N+1 resolves its templates (and sees
|
|
65
|
+
* `context.vars`) with every prior same-sequence `setVars` applied — the YAML
|
|
66
|
+
* reads imperatively. The returned `setVars` accumulates the maps of every
|
|
67
|
+
* action that ran (including a continued-past failure and the terminal/failing
|
|
68
|
+
* action itself); it is the caller (the state-machine driver) that merges it
|
|
69
|
+
* into run-local vars after the sequence settles. Returns the last action
|
|
70
|
+
* result (retained even when a failure was continued past, so downstream
|
|
71
|
+
* guards can inspect it) plus the controlling outcome.
|
|
70
72
|
*/
|
|
71
73
|
export async function runActionSequence(actions, vars, deps) {
|
|
72
74
|
let last;
|
|
75
|
+
let acc;
|
|
73
76
|
for (const action of actions) {
|
|
74
77
|
const step = await runActionStep(action, vars, deps);
|
|
75
78
|
if (step.result !== undefined)
|
|
76
79
|
last = step.result;
|
|
80
|
+
if (step.result?.setVars) {
|
|
81
|
+
acc = mergeSetVars(acc ?? {}, step.result.setVars);
|
|
82
|
+
vars = mergeSetVars(vars, step.result.setVars);
|
|
83
|
+
}
|
|
77
84
|
if (step.outcome === 'terminal')
|
|
78
|
-
return { outcome: 'terminal', result: last };
|
|
85
|
+
return { outcome: 'terminal', result: last, setVars: acc };
|
|
79
86
|
if (step.outcome === 'fail')
|
|
80
|
-
return { outcome: 'fail', result: last };
|
|
87
|
+
return { outcome: 'fail', result: last, setVars: acc };
|
|
81
88
|
}
|
|
82
|
-
return { outcome: 'completed', result: last };
|
|
89
|
+
return { outcome: 'completed', result: last, setVars: acc };
|
|
83
90
|
}
|
package/dist/state-machine.js
CHANGED
|
@@ -69,8 +69,8 @@ export class StateMachineDriver {
|
|
|
69
69
|
// erase the previous result.
|
|
70
70
|
if (enter.result !== undefined)
|
|
71
71
|
lastActionResult = enter.result;
|
|
72
|
-
if (enter.
|
|
73
|
-
vars = mergeSetVars(vars, enter.
|
|
72
|
+
if (enter.setVars)
|
|
73
|
+
vars = mergeSetVars(vars, enter.setVars);
|
|
74
74
|
if (enter.outcome === 'terminal') {
|
|
75
75
|
return failure.has(current.id)
|
|
76
76
|
? await lifecycle.fail(current.id, transitionsTaken, `terminal:${current.id}`)
|
|
@@ -122,8 +122,8 @@ export class StateMachineDriver {
|
|
|
122
122
|
});
|
|
123
123
|
if (exit.result !== undefined)
|
|
124
124
|
lastActionResult = exit.result;
|
|
125
|
-
if (exit.
|
|
126
|
-
vars = mergeSetVars(vars, exit.
|
|
125
|
+
if (exit.setVars)
|
|
126
|
+
vars = mergeSetVars(vars, exit.setVars);
|
|
127
127
|
if (exit.outcome === 'fail')
|
|
128
128
|
return await lifecycle.fail(current.id, transitionsTaken, exit.result?.error);
|
|
129
129
|
// 7. Atomically commit the transition + new state snapshot + phase in a
|
|
@@ -146,7 +146,7 @@ export class StateMachineDriver {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
/** Dry-run sentinel: no action ran, so there is nothing to retain and nothing to halt on. */
|
|
149
|
-
const EMPTY_OUTCOME = { outcome: 'completed', result: undefined };
|
|
149
|
+
const EMPTY_OUTCOME = { outcome: 'completed', result: undefined, setVars: undefined };
|
|
150
150
|
async function firstPassingTransition(transitions, host, context, lifecycle) {
|
|
151
151
|
for (const transition of transitions) {
|
|
152
152
|
if (transition.guard === undefined)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-dual-workflow-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.35",
|
|
4
4
|
"description": "@gobing-ai/ts-dual-workflow-engine — State-machine and transition-flow workflow runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-dual-workflow-engine-v<version> && git push --tags' && exit 1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@gobing-ai/ts-db": "^0.4.
|
|
52
|
-
"@gobing-ai/ts-infra": "^0.4.
|
|
53
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
51
|
+
"@gobing-ai/ts-db": "^0.4.35",
|
|
52
|
+
"@gobing-ai/ts-infra": "^0.4.35",
|
|
53
|
+
"@gobing-ai/ts-runtime": "^0.4.35",
|
|
54
54
|
"zod": "^4.1.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
package/src/action-step.ts
CHANGED
|
@@ -2,8 +2,15 @@ import type { WorkflowEngineHost } from './host';
|
|
|
2
2
|
import { defaultActionRedactor } from './persistence';
|
|
3
3
|
import type { RunLifecycle } from './run-lifecycle';
|
|
4
4
|
import { runtimeBuiltins, type WorkflowMode } from './run-lifecycle';
|
|
5
|
-
import type {
|
|
6
|
-
|
|
5
|
+
import type {
|
|
6
|
+
ActionDef,
|
|
7
|
+
ActionResult,
|
|
8
|
+
OnErrorPolicy,
|
|
9
|
+
Vars,
|
|
10
|
+
WorkflowPersistenceAdapter,
|
|
11
|
+
WorkflowRunOptions,
|
|
12
|
+
} from './types';
|
|
13
|
+
import { mergeSetVars, resolveOnErrorPolicy, resolveTemplates } from './variables';
|
|
7
14
|
|
|
8
15
|
/**
|
|
9
16
|
* Outcome discriminator for a single action step. `terminal` means the action
|
|
@@ -13,10 +20,17 @@ import { resolveOnErrorPolicy, resolveTemplates } from './variables';
|
|
|
13
20
|
*/
|
|
14
21
|
export type ActionStepOutcome = 'completed' | 'terminal' | 'fail';
|
|
15
22
|
|
|
16
|
-
/** Result of running one or more action steps: last result
|
|
23
|
+
/** Result of running one or more action steps: last result, a control-flow discriminator, and the accumulated `setVars` of every step in the sequence. */
|
|
17
24
|
export interface ActionStepResult {
|
|
18
25
|
readonly outcome: ActionStepOutcome;
|
|
19
26
|
readonly result: ActionResult | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Sequence-level accumulation of `setVars` from every action that ran
|
|
29
|
+
* (including the terminal/failing one). Single-step callers get just that
|
|
30
|
+
* step's setVars. Drivers merge this map into their run-local vars after
|
|
31
|
+
* the sequence settles.
|
|
32
|
+
*/
|
|
33
|
+
readonly setVars?: Vars;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
36
|
/**
|
|
@@ -44,9 +58,9 @@ export interface ActionStepDeps {
|
|
|
44
58
|
* Run one action through its full lifecycle: resolve templates, persist the
|
|
45
59
|
* start row, time the host invocation inside try/finally, persist + emit the
|
|
46
60
|
* finalize, then classify terminal/fail/continue. `vars` is read-only here;
|
|
47
|
-
* callers thread any `setVars` from the returned result
|
|
48
|
-
*
|
|
49
|
-
* differently across
|
|
61
|
+
* callers thread any `setVars` from the returned result forward — the sequence
|
|
62
|
+
* runner does so within a sequence, and drivers merge the accumulated map
|
|
63
|
+
* across states/nodes (each dialect carries vars differently across its loop).
|
|
50
64
|
*
|
|
51
65
|
* This is the single seam both drivers share for action execution (ADR-006 §7
|
|
52
66
|
* keeps the *control loops* dialect-specific; only this per-action mechanism is
|
|
@@ -110,13 +124,15 @@ export async function runActionStep(
|
|
|
110
124
|
|
|
111
125
|
/**
|
|
112
126
|
* Run a sequence of actions in declaration order, stopping at the first
|
|
113
|
-
* `terminal` or `fail` outcome.
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
127
|
+
* `terminal` or `fail` outcome. `setVars` from each action is threaded forward
|
|
128
|
+
* BEFORE the next action runs, so action N+1 resolves its templates (and sees
|
|
129
|
+
* `context.vars`) with every prior same-sequence `setVars` applied — the YAML
|
|
130
|
+
* reads imperatively. The returned `setVars` accumulates the maps of every
|
|
131
|
+
* action that ran (including a continued-past failure and the terminal/failing
|
|
132
|
+
* action itself); it is the caller (the state-machine driver) that merges it
|
|
133
|
+
* into run-local vars after the sequence settles. Returns the last action
|
|
134
|
+
* result (retained even when a failure was continued past, so downstream
|
|
135
|
+
* guards can inspect it) plus the controlling outcome.
|
|
120
136
|
*/
|
|
121
137
|
export async function runActionSequence(
|
|
122
138
|
actions: readonly ActionDef[],
|
|
@@ -124,11 +140,16 @@ export async function runActionSequence(
|
|
|
124
140
|
deps: ActionStepDeps,
|
|
125
141
|
): Promise<ActionStepResult> {
|
|
126
142
|
let last: ActionResult | undefined;
|
|
143
|
+
let acc: Vars | undefined;
|
|
127
144
|
for (const action of actions) {
|
|
128
145
|
const step = await runActionStep(action, vars, deps);
|
|
129
146
|
if (step.result !== undefined) last = step.result;
|
|
130
|
-
if (step.
|
|
131
|
-
|
|
147
|
+
if (step.result?.setVars) {
|
|
148
|
+
acc = mergeSetVars(acc ?? {}, step.result.setVars);
|
|
149
|
+
vars = mergeSetVars(vars, step.result.setVars);
|
|
150
|
+
}
|
|
151
|
+
if (step.outcome === 'terminal') return { outcome: 'terminal', result: last, setVars: acc };
|
|
152
|
+
if (step.outcome === 'fail') return { outcome: 'fail', result: last, setVars: acc };
|
|
132
153
|
}
|
|
133
|
-
return { outcome: 'completed', result: last };
|
|
154
|
+
return { outcome: 'completed', result: last, setVars: acc };
|
|
134
155
|
}
|
package/src/state-machine.ts
CHANGED
|
@@ -109,7 +109,7 @@ export class StateMachineDriver {
|
|
|
109
109
|
// driver's `continue` semantics. A state with no enter actions must not
|
|
110
110
|
// erase the previous result.
|
|
111
111
|
if (enter.result !== undefined) lastActionResult = enter.result;
|
|
112
|
-
if (enter.
|
|
112
|
+
if (enter.setVars) vars = mergeSetVars(vars, enter.setVars);
|
|
113
113
|
if (enter.outcome === 'terminal') {
|
|
114
114
|
return failure.has(current.id)
|
|
115
115
|
? await lifecycle.fail(current.id, transitionsTaken, `terminal:${current.id}`)
|
|
@@ -170,7 +170,7 @@ export class StateMachineDriver {
|
|
|
170
170
|
defaultOnError,
|
|
171
171
|
});
|
|
172
172
|
if (exit.result !== undefined) lastActionResult = exit.result;
|
|
173
|
-
if (exit.
|
|
173
|
+
if (exit.setVars) vars = mergeSetVars(vars, exit.setVars);
|
|
174
174
|
if (exit.outcome === 'fail') return await lifecycle.fail(current.id, transitionsTaken, exit.result?.error);
|
|
175
175
|
|
|
176
176
|
// 7. Atomically commit the transition + new state snapshot + phase in a
|
|
@@ -200,7 +200,7 @@ export class StateMachineDriver {
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/** Dry-run sentinel: no action ran, so there is nothing to retain and nothing to halt on. */
|
|
203
|
-
const EMPTY_OUTCOME = { outcome: 'completed', result: undefined } as const;
|
|
203
|
+
const EMPTY_OUTCOME = { outcome: 'completed', result: undefined, setVars: undefined } as const;
|
|
204
204
|
|
|
205
205
|
async function firstPassingTransition(
|
|
206
206
|
transitions: StateMachineWorkflowDef['transitions'],
|