@gobing-ai/ts-dual-workflow-engine 0.3.1 → 0.3.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.
Files changed (45) hide show
  1. package/README.md +506 -5
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +7 -11
  5. package/dist/events.d.ts +49 -0
  6. package/dist/events.d.ts.map +1 -0
  7. package/dist/events.js +0 -0
  8. package/dist/extensions.d.ts +60 -0
  9. package/dist/extensions.d.ts.map +1 -0
  10. package/dist/extensions.js +85 -0
  11. package/dist/index.d.ts +5 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -1
  14. package/dist/run-lifecycle.d.ts +58 -0
  15. package/dist/run-lifecycle.d.ts.map +1 -0
  16. package/dist/run-lifecycle.js +149 -0
  17. package/dist/schema-sql.d.ts +1 -0
  18. package/dist/schema-sql.d.ts.map +1 -1
  19. package/dist/schema-sql.js +1 -0
  20. package/dist/schema.d.ts +44 -0
  21. package/dist/schema.d.ts.map +1 -1
  22. package/dist/schema.js +3 -0
  23. package/dist/state-machine.d.ts +7 -2
  24. package/dist/state-machine.d.ts.map +1 -1
  25. package/dist/state-machine.js +63 -72
  26. package/dist/transition-flow.d.ts +1 -2
  27. package/dist/transition-flow.d.ts.map +1 -1
  28. package/dist/transition-flow.js +35 -61
  29. package/dist/types.d.ts +14 -0
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/variables.d.ts +6 -1
  32. package/dist/variables.d.ts.map +1 -1
  33. package/dist/variables.js +7 -0
  34. package/package.json +4 -4
  35. package/src/config.ts +8 -11
  36. package/src/events.ts +19 -0
  37. package/src/extensions.ts +163 -0
  38. package/src/index.ts +24 -1
  39. package/src/run-lifecycle.ts +211 -0
  40. package/src/schema-sql.ts +1 -0
  41. package/src/schema.ts +3 -0
  42. package/src/state-machine.ts +78 -128
  43. package/src/transition-flow.ts +47 -105
  44. package/src/types.ts +16 -0
  45. package/src/variables.ts +13 -1
@@ -1,6 +1,6 @@
1
- import { getProcessEnv } from '@gobing-ai/ts-runtime';
2
1
  import { FSMError } from './errors.js';
3
- import { mergeVars, resolveTemplates } from './variables.js';
2
+ import { allowedEnv, RunLifecycle, runtimeBuiltins } from './run-lifecycle.js';
3
+ import { mergeVars, resolveOnErrorPolicy, resolveTemplates } from './variables.js';
4
4
  /** State-machine workflow driver with an R7 single control function. */
5
5
  export class StateMachineDriver {
6
6
  options;
@@ -9,36 +9,43 @@ export class StateMachineDriver {
9
9
  }
10
10
  /** Run a state-machine workflow to completion or failure. */
11
11
  async run(workflow, options = {}) {
12
- const runId = options.runId ?? crypto.randomUUID();
13
- const startedAt = new Date().toISOString();
14
- const mode = 'state-machine';
15
- await this.options.persistence.createRun(runRecord(runId, workflow.name, mode, startedAt, options.metadata));
12
+ return await RunLifecycle.run(workflow.name, 'state-machine', { persistence: this.options.persistence, events: options.events }, options, (lifecycle) => this.loop(workflow, options, lifecycle));
13
+ }
14
+ async loop(workflow, options, lifecycle) {
15
+ const runId = lifecycle.runId;
16
16
  const states = new Map(workflow.states.map((state) => [state.id, state]));
17
17
  const terminal = new Set(workflow.terminalStates ?? []);
18
18
  const vars = mergeVars(workflow.vars, options.vars);
19
- const env = allowedEnv(workflow.env?.allow ?? [], options.env ?? getProcessEnv());
19
+ const env = allowedEnv(workflow.env?.allow ?? [], options.env);
20
20
  let current = states.get(workflow.initialState);
21
21
  let transitionsTaken = 0;
22
22
  let lastActionResult;
23
23
  const iterationBound = workflow.iterationBound ?? 50;
24
+ const defaultOnError = workflow.defaultOnError;
24
25
  if (current === undefined)
25
26
  throw new FSMError(`Initial state "${workflow.initialState}" is not declared`);
26
27
  while (true) {
27
28
  // 1. Persist current state snapshot before work starts.
28
- await this.options.persistence.saveWorkflowState(runId, current.id, { transitionsTaken });
29
- await this.options.persistence.savePhase(runId, current.id, 'running');
29
+ await lifecycle.enter(current.id, transitionsTaken);
30
30
  // 2. Execute this state's on-enter actions in declaration order.
31
- lastActionResult = await this.runActions(current.onEnter ?? [], workflow.name, current.id, runId, vars, env, options, transitionsTaken);
32
- if (lastActionResult?.ok === false)
33
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, lastActionResult.error);
31
+ const enter = await this.runActions(current.onEnter ?? [], workflow.name, current.id, runId, vars, env, options, transitionsTaken, lifecycle, defaultOnError);
32
+ // Retain the last action result (including failures the policy continued
33
+ // past) so downstream guards can inspect it — matching the transition-flow
34
+ // driver's `continue` semantics. A state with no enter actions must not
35
+ // erase the previous result.
36
+ if (enter.result !== undefined)
37
+ lastActionResult = enter.result;
34
38
  // 3. Stop immediately when an action explicitly declares terminal success.
35
- if (lastActionResult?.terminal === true) {
36
- return await this.done(runId, workflow.name, mode, current.id, transitionsTaken);
39
+ if (enter.outcome === 'terminal') {
40
+ return await lifecycle.done(current.id, transitionsTaken);
41
+ }
42
+ // 4. Halt only when an action failed under a 'fail' policy.
43
+ if (enter.outcome === 'fail') {
44
+ return await lifecycle.fail(current.id, transitionsTaken, lastActionResult?.error);
37
45
  }
38
- // 4. Stop when the current state is terminal or has no outbound transitions.
39
46
  const outbound = workflow.transitions.filter((transition) => transition.from === current?.id);
40
47
  if (terminal.has(current.id) || outbound.length === 0) {
41
- return await this.done(runId, workflow.name, mode, current.id, transitionsTaken);
48
+ return await lifecycle.done(current.id, transitionsTaken);
42
49
  }
43
50
  // 5. Evaluate transition guards in declaration order and pick the first passing transition.
44
51
  const nextTransition = await firstPassingTransition(outbound, this.options.host, {
@@ -48,17 +55,19 @@ export class StateMachineDriver {
48
55
  lastActionResult,
49
56
  });
50
57
  if (nextTransition === undefined) {
51
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, 'no-passing-transition');
58
+ return await lifecycle.fail(current.id, transitionsTaken, 'no-passing-transition');
52
59
  }
53
60
  // 6. Execute this state's on-exit actions before changing state.
54
- const exitResult = await this.runActions(current.onExit ?? [], workflow.name, current.id, runId, vars, env, options, transitionsTaken);
55
- if (exitResult?.ok === false)
56
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, exitResult.error);
61
+ const exit = await this.runActions(current.onExit ?? [], workflow.name, current.id, runId, vars, env, options, transitionsTaken, lifecycle, defaultOnError);
62
+ if (exit.result !== undefined)
63
+ lastActionResult = exit.result;
64
+ if (exit.outcome === 'fail')
65
+ return await lifecycle.fail(current.id, transitionsTaken, exit.result?.error);
57
66
  // 7. Persist transition and move to the target state.
58
67
  transitionsTaken += 1;
59
- await this.options.persistence.saveTransition(runId, current.id, nextTransition.to, nextTransition.trigger ?? null);
68
+ await lifecycle.recordTransition(current.id, nextTransition.to, nextTransition.trigger ?? null);
60
69
  if (transitionsTaken > iterationBound) {
61
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, 'iteration-bound-exceeded');
70
+ return await lifecycle.fail(current.id, transitionsTaken, 'iteration-bound-exceeded');
62
71
  }
63
72
  const nextState = states.get(nextTransition.to);
64
73
  if (nextState === undefined)
@@ -66,51 +75,47 @@ export class StateMachineDriver {
66
75
  current = nextState;
67
76
  }
68
77
  }
69
- async runActions(actions, workflowName, stateId, runId, vars, env, options, transitionsTaken) {
78
+ /**
79
+ * Run a state's actions in order. Returns the last action result (retained even
80
+ * when a failure was continued past, so downstream guards can inspect it) plus an
81
+ * `outcome` discriminator: `terminal` (an action declared terminal success),
82
+ * `fail` (a failure under a 'fail' policy — caller must halt), or `completed`.
83
+ */
84
+ async runActions(actions, workflowName, stateId, runId, vars, env, options, transitionsTaken, lifecycle, defaultOnError) {
70
85
  let last;
71
86
  for (const action of actions) {
72
87
  const resolved = resolveTemplates(action.options ?? {}, {
73
88
  vars,
74
89
  env,
75
- builtins: runtimeBuiltins(workflowName, stateId, runId, transitionsTaken),
90
+ builtins: runtimeBuiltins(workflowName, stateId, runId, transitionsTaken, 'state-machine'),
76
91
  });
77
- last = await this.options.host.runAction(action.kind, resolved, {
78
- runId,
79
- workdir: options.workdir,
80
- stateOrNodeId: stateId,
81
- vars,
82
- env,
83
- metadata: options.metadata,
84
- });
85
- if (!last.ok || last.terminal === true)
86
- return last;
92
+ const actionStartMs = Date.now();
93
+ lifecycle.actionStart(stateId, action.kind);
94
+ try {
95
+ last = await this.options.host.runAction(action.kind, resolved, {
96
+ runId,
97
+ workdir: options.workdir,
98
+ stateOrNodeId: stateId,
99
+ vars,
100
+ env,
101
+ metadata: options.metadata,
102
+ });
103
+ }
104
+ finally {
105
+ lifecycle.actionDone(stateId, action.kind, Date.now() - actionStartMs, last?.ok ?? false);
106
+ }
107
+ if (last.terminal === true)
108
+ return { outcome: 'terminal', result: last };
109
+ if (!last.ok) {
110
+ const policy = resolveOnErrorPolicy(action.onError, defaultOnError, options.onError);
111
+ if (policy === 'fail')
112
+ return { outcome: 'fail', result: last };
113
+ lifecycle.warnActionFailed(stateId, transitionsTaken, last.error);
114
+ }
87
115
  }
88
- return last;
89
- }
90
- async done(runId, workflowName, mode, finalState, transitionsTaken) {
91
- await this.options.persistence.savePhase(runId, finalState, 'done');
92
- await this.options.persistence.finalizeRun(runId, 'done', new Date().toISOString());
93
- return { runId, workflowName, mode, status: 'done', finalState, transitionsTaken };
94
- }
95
- async fail(runId, workflowName, mode, finalState, transitionsTaken, reason = 'failed') {
96
- await this.options.persistence.savePhase(runId, finalState, 'failed');
97
- await this.options.persistence.finalizeRun(runId, 'failed', new Date().toISOString());
98
- return { runId, workflowName, mode, status: 'failed', finalState, transitionsTaken, reason };
116
+ return { outcome: 'completed', result: last };
99
117
  }
100
118
  }
101
- /** Built-in bare template values available to state-machine action options. */
102
- function runtimeBuiltins(workflowName, stateId, runId, transitionsTaken) {
103
- return {
104
- workflow: workflowName,
105
- runId,
106
- task: workflowName,
107
- state: stateId,
108
- node: stateId,
109
- iteration: transitionsTaken,
110
- run: runId,
111
- runtime: 'state-machine',
112
- };
113
- }
114
119
  async function firstPassingTransition(transitions, host, context) {
115
120
  for (const transition of transitions) {
116
121
  if (transition.guard === undefined)
@@ -120,17 +125,3 @@ async function firstPassingTransition(transitions, host, context) {
120
125
  }
121
126
  return undefined;
122
127
  }
123
- function allowedEnv(names, source) {
124
- return Object.fromEntries(names.flatMap((name) => (source[name] === undefined ? [] : [[name, source[name]]])));
125
- }
126
- function runRecord(runId, workflowName, mode, startedAt, metadata) {
127
- return {
128
- id: runId,
129
- workflow_name: workflowName,
130
- mode,
131
- status: 'running',
132
- started_at: startedAt,
133
- completed_at: null,
134
- metadata_json: JSON.stringify(metadata ?? {}),
135
- };
136
- }
@@ -11,7 +11,6 @@ export declare class TransitionFlowDriver {
11
11
  constructor(options: TransitionFlowDriverOptions);
12
12
  /** Run a transition-flow workflow to completion or failure. */
13
13
  run(workflow: TransitionFlowWorkflowDef, options?: WorkflowRunOptions): Promise<WorkflowRunResult>;
14
- private done;
15
- private fail;
14
+ private loop;
16
15
  }
17
16
  //# sourceMappingURL=transition-flow.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transition-flow.d.ts","sourceRoot":"","sources":["../src/transition-flow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAER,yBAAyB,EACzB,0BAA0B,EAC1B,kBAAkB,EAElB,iBAAiB,EACpB,MAAM,SAAS,CAAC;AAGjB,2DAA2D;AAC3D,MAAM,WAAW,2BAA2B;IACxC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC;CACpD;AAED,0EAA0E;AAC1E,qBAAa,oBAAoB;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,2BAA2B;IAEjE,+DAA+D;IACzD,GAAG,CAAC,QAAQ,EAAE,yBAAyB,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;YA8F9F,IAAI;YAYJ,IAAI;CAYrB"}
1
+ {"version":3,"file":"transition-flow.d.ts","sourceRoot":"","sources":["../src/transition-flow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,OAAO,KAAK,EAER,yBAAyB,EACzB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACpB,MAAM,SAAS,CAAC;AAGjB,2DAA2D;AAC3D,MAAM,WAAW,2BAA2B;IACxC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC;CACpD;AAED,0EAA0E;AAC1E,qBAAa,oBAAoB;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,2BAA2B;IAEjE,+DAA+D;IACzD,GAAG,CAAC,QAAQ,EAAE,yBAAyB,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;YAU9F,IAAI;CA8FrB"}
@@ -1,6 +1,6 @@
1
- import { getProcessEnv } from '@gobing-ai/ts-runtime';
2
1
  import { FSMError } from './errors.js';
3
- import { mergeVars, resolveTemplates } from './variables.js';
2
+ import { allowedEnv, RunLifecycle, runtimeBuiltins } from './run-lifecycle.js';
3
+ import { mergeVars, resolveOnErrorPolicy, resolveTemplates } from './variables.js';
4
4
  /** Transition-flow workflow driver with an R7 single control function. */
5
5
  export class TransitionFlowDriver {
6
6
  options;
@@ -9,51 +9,62 @@ export class TransitionFlowDriver {
9
9
  }
10
10
  /** Run a transition-flow workflow to completion or failure. */
11
11
  async run(workflow, options = {}) {
12
- const runId = options.runId ?? crypto.randomUUID();
13
- const startedAt = new Date().toISOString();
14
- const mode = 'transition-flow';
15
- await this.options.persistence.createRun(runRecord(runId, workflow.name, mode, startedAt, options.metadata));
12
+ return await RunLifecycle.run(workflow.name, 'transition-flow', { persistence: this.options.persistence, events: options.events }, options, (lifecycle) => this.loop(workflow, options, lifecycle));
13
+ }
14
+ async loop(workflow, options, lifecycle) {
15
+ const runId = lifecycle.runId;
16
16
  const nodes = new Map(workflow.nodes.map((node) => [node.id, node]));
17
17
  const terminal = new Set(workflow.terminalNodes ?? []);
18
18
  const vars = mergeVars(workflow.vars, options.vars);
19
- const env = allowedEnv(workflow.env?.allow ?? [], options.env ?? getProcessEnv());
19
+ const env = allowedEnv(workflow.env?.allow ?? [], options.env);
20
20
  let current = nodes.get(workflow.initialNode);
21
21
  let transitionsTaken = 0;
22
22
  let lastActionResult;
23
23
  const iterationBound = workflow.iterationBound ?? 50;
24
+ const defaultOnError = workflow.defaultOnError;
24
25
  if (current === undefined) {
25
26
  throw new FSMError(`Initial node "${workflow.initialNode}" is not declared`);
26
27
  }
27
28
  while (true) {
28
29
  // 1. Persist current node snapshot before action execution.
29
- await this.options.persistence.saveWorkflowState(runId, current.id, { transitionsTaken });
30
- await this.options.persistence.savePhase(runId, current.id, 'running');
30
+ await lifecycle.enter(current.id, transitionsTaken);
31
31
  // 2. Execute the node action when one is configured.
32
32
  if (current.action !== undefined) {
33
33
  const resolved = resolveTemplates(current.action.options ?? {}, {
34
34
  vars,
35
35
  env,
36
- builtins: runtimeBuiltins(workflow.name, current.id, runId, transitionsTaken),
37
- });
38
- lastActionResult = await this.options.host.runAction(current.action.kind, resolved, {
39
- runId,
40
- workdir: options.workdir,
41
- stateOrNodeId: current.id,
42
- vars,
43
- env,
44
- metadata: options.metadata,
36
+ builtins: runtimeBuiltins(workflow.name, current.id, runId, transitionsTaken, 'transition-flow'),
45
37
  });
38
+ const actionStartMs = Date.now();
39
+ lifecycle.actionStart(current.id, current.action.kind);
40
+ try {
41
+ lastActionResult = await this.options.host.runAction(current.action.kind, resolved, {
42
+ runId,
43
+ workdir: options.workdir,
44
+ stateOrNodeId: current.id,
45
+ vars,
46
+ env,
47
+ metadata: options.metadata,
48
+ });
49
+ }
50
+ finally {
51
+ lifecycle.actionDone(current.id, current.action.kind, Date.now() - actionStartMs, lastActionResult?.ok ?? false);
52
+ }
46
53
  if (!lastActionResult.ok) {
47
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, lastActionResult.error);
54
+ const policy = resolveOnErrorPolicy(current.action.onError, defaultOnError, options.onError);
55
+ if (policy === 'fail') {
56
+ return await lifecycle.fail(current.id, transitionsTaken, lastActionResult.error);
57
+ }
58
+ lifecycle.warnActionFailed(current.id, transitionsTaken, lastActionResult.error);
48
59
  }
49
60
  if (lastActionResult.terminal === true) {
50
- return await this.done(runId, workflow.name, mode, current.id, transitionsTaken);
61
+ return await lifecycle.done(current.id, transitionsTaken);
51
62
  }
52
63
  }
53
64
  // 3. Stop when the node is terminal or no outgoing edge exists.
54
65
  const outbound = workflow.edges.filter((edge) => edge.from === current?.id);
55
66
  if (terminal.has(current.id) || outbound.length === 0) {
56
- return await this.done(runId, workflow.name, mode, current.id, transitionsTaken);
67
+ return await lifecycle.done(current.id, transitionsTaken);
57
68
  }
58
69
  // 4. Evaluate edge conditions in declaration order and pick the first passing edge.
59
70
  const edge = await firstPassingEdge(outbound, this.options.host, {
@@ -63,14 +74,14 @@ export class TransitionFlowDriver {
63
74
  lastActionResult,
64
75
  });
65
76
  if (edge === undefined) {
66
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, 'no-passing-edge');
77
+ return await lifecycle.fail(current.id, transitionsTaken, 'no-passing-edge');
67
78
  }
68
79
  // 5. Persist the edge transition.
69
80
  transitionsTaken += 1;
70
- await this.options.persistence.saveTransition(runId, current.id, edge.to, edge.condition?.kind ?? null);
81
+ await lifecycle.recordTransition(current.id, edge.to, edge.condition?.kind ?? null);
71
82
  // 6. Enforce the iteration bound after taking the transition.
72
83
  if (transitionsTaken > iterationBound) {
73
- return await this.fail(runId, workflow.name, mode, current.id, transitionsTaken, 'iteration-bound-exceeded');
84
+ return await lifecycle.fail(current.id, transitionsTaken, 'iteration-bound-exceeded');
74
85
  }
75
86
  // 7. Move to the target node and repeat.
76
87
  const nextNode = nodes.get(edge.to);
@@ -79,29 +90,6 @@ export class TransitionFlowDriver {
79
90
  current = nextNode;
80
91
  }
81
92
  }
82
- async done(runId, workflowName, mode, finalState, transitionsTaken) {
83
- await this.options.persistence.savePhase(runId, finalState, 'done');
84
- await this.options.persistence.finalizeRun(runId, 'done', new Date().toISOString());
85
- return { runId, workflowName, mode, status: 'done', finalState, transitionsTaken };
86
- }
87
- async fail(runId, workflowName, mode, finalState, transitionsTaken, reason = 'failed') {
88
- await this.options.persistence.savePhase(runId, finalState, 'failed');
89
- await this.options.persistence.finalizeRun(runId, 'failed', new Date().toISOString());
90
- return { runId, workflowName, mode, status: 'failed', finalState, transitionsTaken, reason };
91
- }
92
- }
93
- /** Built-in bare template values available to transition-flow action options. */
94
- function runtimeBuiltins(workflowName, nodeId, runId, transitionsTaken) {
95
- return {
96
- workflow: workflowName,
97
- runId,
98
- task: workflowName,
99
- state: nodeId,
100
- node: nodeId,
101
- iteration: transitionsTaken,
102
- run: runId,
103
- runtime: 'transition-flow',
104
- };
105
93
  }
106
94
  async function firstPassingEdge(edges, host, context) {
107
95
  for (const edge of edges) {
@@ -112,17 +100,3 @@ async function firstPassingEdge(edges, host, context) {
112
100
  }
113
101
  return undefined;
114
102
  }
115
- function allowedEnv(names, source) {
116
- return Object.fromEntries(names.flatMap((name) => (source[name] === undefined ? [] : [[name, source[name]]])));
117
- }
118
- function runRecord(runId, workflowName, mode, startedAt, metadata) {
119
- return {
120
- id: runId,
121
- workflow_name: workflowName,
122
- mode,
123
- status: 'running',
124
- started_at: startedAt,
125
- completed_at: null,
126
- metadata_json: JSON.stringify(metadata ?? {}),
127
- };
128
- }
package/dist/types.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ /** Action error handling policy: fail-fast or log-and-continue. */
2
+ export type OnErrorPolicy = 'fail' | 'continue';
3
+ import type { EventBus } from '@gobing-ai/ts-infra';
4
+ import type { WorkflowEngineEvents } from './events';
1
5
  /** Workflow execution status persisted for runs and phases. */
2
6
  export type WorkflowStatus = 'running' | 'done' | 'failed';
3
7
  /** Runtime variables and user variables available to workflow definitions. */
@@ -10,6 +14,8 @@ export interface Env {
10
14
  export interface ActionDef {
11
15
  readonly kind: string;
12
16
  readonly options?: Record<string, unknown>;
17
+ /** Per-action error policy override. Falls back to workflow default then run-option then 'fail'. */
18
+ readonly onError?: OnErrorPolicy;
13
19
  }
14
20
  /** Guard predicate definition used by state-machine transitions and transition-flow edges. */
15
21
  export interface GuardDef {
@@ -44,6 +50,8 @@ export interface StateMachineWorkflowDef {
44
50
  readonly initialState: string;
45
51
  readonly terminalStates?: readonly string[];
46
52
  readonly iterationBound?: number;
53
+ /** Default error policy applied to actions that don't specify their own. Defaults to 'fail'. */
54
+ readonly defaultOnError?: OnErrorPolicy;
47
55
  readonly vars?: Vars;
48
56
  readonly env?: Env;
49
57
  readonly states: readonly StateDef[];
@@ -76,6 +84,8 @@ export interface TransitionFlowWorkflowDef {
76
84
  readonly initialNode: string;
77
85
  readonly terminalNodes?: readonly string[];
78
86
  readonly iterationBound?: number;
87
+ /** Default error policy applied to actions that don't specify their own. Defaults to 'fail'. */
88
+ readonly defaultOnError?: OnErrorPolicy;
79
89
  readonly vars?: Vars;
80
90
  readonly env?: Env;
81
91
  readonly nodes: readonly FlowNodeDef[];
@@ -123,6 +133,10 @@ export interface WorkflowRunOptions {
123
133
  readonly vars?: Vars;
124
134
  readonly env?: Record<string, string | undefined>;
125
135
  readonly metadata?: Record<string, unknown>;
136
+ /** Optional event bus for structured run observability. */
137
+ readonly events?: EventBus<WorkflowEngineEvents>;
138
+ /** Run-level error policy override. Lowest precedence; action-level wins. */
139
+ readonly onError?: OnErrorPolicy;
126
140
  }
127
141
  /** Result returned by both driver loops. */
128
142
  export interface WorkflowRunResult {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Vars } from './types';
1
+ import type { OnErrorPolicy, Vars } from './types';
2
2
  /** Runtime context used for workflow variable interpolation. */
3
3
  export interface VariableContext {
4
4
  readonly vars: Vars;
@@ -11,4 +11,9 @@ export declare function mergeVars(workflowVars?: Vars, overrideVars?: Vars): Var
11
11
  export declare function resolveTemplates<T>(value: T, context: VariableContext): T;
12
12
  /** Resolve a single template string. */
13
13
  export declare function resolveTemplateString(value: string, context: VariableContext): string;
14
+ /**
15
+ * Resolve the effective error policy via fixed precedence:
16
+ * `action.onError ?? workflow.defaultOnError ?? runOptions.onError ?? 'fail'`.
17
+ */
18
+ export declare function resolveOnErrorPolicy(actionOnError: OnErrorPolicy | undefined, workflowDefault: OnErrorPolicy | undefined, runOptionOverride: OnErrorPolicy | undefined): OnErrorPolicy;
14
19
  //# sourceMappingURL=variables.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../src/variables.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAIpC,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;CACnE;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,YAAY,GAAE,IAAS,EAAE,YAAY,GAAE,IAAS,GAAG,IAAI,CAEhF;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,GAAG,CAAC,CAgBzE;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAmBrF"}
1
+ {"version":3,"file":"variables.d.ts","sourceRoot":"","sources":["../src/variables.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAInD,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;CACnE;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,YAAY,GAAE,IAAS,EAAE,YAAY,GAAE,IAAS,GAAG,IAAI,CAEhF;AAED,yDAAyD;AACzD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,GAAG,CAAC,CAgBzE;AAED,wCAAwC;AACxC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAmBrF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAChC,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,eAAe,EAAE,aAAa,GAAG,SAAS,EAC1C,iBAAiB,EAAE,aAAa,GAAG,SAAS,GAC7C,aAAa,CAEf"}
package/dist/variables.js CHANGED
@@ -43,3 +43,10 @@ export function resolveTemplateString(value, context) {
43
43
  return String(resolved);
44
44
  });
45
45
  }
46
+ /**
47
+ * Resolve the effective error policy via fixed precedence:
48
+ * `action.onError ?? workflow.defaultOnError ?? runOptions.onError ?? 'fail'`.
49
+ */
50
+ export function resolveOnErrorPolicy(actionOnError, workflowDefault, runOptionOverride) {
51
+ return actionOnError ?? workflowDefault ?? runOptionOverride ?? 'fail';
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-dual-workflow-engine",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
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.3.1",
52
- "@gobing-ai/ts-runtime": "^0.3.1",
53
- "@gobing-ai/ts-utils": "^0.3.1",
51
+ "@gobing-ai/ts-db": "^0.3.3",
52
+ "@gobing-ai/ts-infra": "^0.3.3",
53
+ "@gobing-ai/ts-runtime": "^0.3.3",
54
54
  "zod": "^4.1.0"
55
55
  },
56
56
  "devDependencies": {
package/src/config.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { loadStructuredConfig, parseYamlObject } from '@gobing-ai/ts-runtime';
2
2
  import { WorkflowValidationError } from './errors';
3
+ import { RUNTIME_BUILTIN_KEYS } from './run-lifecycle';
3
4
  import { StateMachineWorkflowDefSchema, TransitionFlowWorkflowDefSchema } from './schema';
4
5
  import type { WorkflowDef } from './types';
5
6
 
7
+ /** Loading options for {@link loadWorkflowDef}. */
6
8
  export interface WorkflowLoadOptions {
7
9
  /** When true, honor a top-level `$schema` ref. Defaults to true for file loads. */
8
10
  validateSchema?: boolean;
@@ -177,17 +179,12 @@ function collectActionOptions(workflow: WorkflowDef): Record<string, unknown>[]
177
179
  return optionSets;
178
180
  }
179
181
 
180
- /** Reserved template namespaces always available at runtime (not user-declared vars). */
181
- const RUNTIME_TEMPLATE_NAMESPACES = new Set([
182
- 'workflow',
183
- 'runId',
184
- 'task',
185
- 'state',
186
- 'node',
187
- 'iteration',
188
- 'run',
189
- 'runtime',
190
- ]);
182
+ /**
183
+ * Reserved template namespaces always available at runtime (not user-declared vars).
184
+ * Single-sourced from {@link RUNTIME_BUILTIN_KEYS} so the validator can never drift
185
+ * from the builtins the drivers actually inject at run time.
186
+ */
187
+ const RUNTIME_TEMPLATE_NAMESPACES = new Set<string>(RUNTIME_BUILTIN_KEYS);
191
188
 
192
189
  /**
193
190
  * Check `${...}` template references inside action options resolve to something:
package/src/events.ts ADDED
@@ -0,0 +1,19 @@
1
+ /** Typed event map for workflow-engine run observability. All events prefixed `workflow.`. */
2
+ export type WorkflowEngineEvents = {
3
+ /** Emitted when a run begins (inside the span). */
4
+ 'workflow.run.started': (data: { workflowName: string; mode: string; runId: string }) => void;
5
+ /** Emitted when a run completes successfully. */
6
+ 'workflow.run.done': (data: { finalState: string; transitionsTaken: number }) => void;
7
+ /** Emitted when a run fails. */
8
+ 'workflow.run.failed': (data: { finalState: string; reason: string }) => void;
9
+ /** Emitted when entering a state or node. */
10
+ 'workflow.node.enter': (data: { node: string; transitionsTaken: number }) => void;
11
+ /** Emitted on a state/node transition. */
12
+ 'workflow.node.transition': (data: { from: string; to: string; trigger: string | null }) => void;
13
+ /** Emitted when an action starts executing. */
14
+ 'workflow.action.start': (data: { node: string; kind: string }) => void;
15
+ /** Emitted when an action finishes executing (success or failure). */
16
+ 'workflow.action.done': (data: { node: string; kind: string; durationMs: number; ok: boolean }) => void;
17
+ /** Emitted when a non-fatal action failure is continued past (onError: 'continue'). */
18
+ 'workflow.action.failed_continue': (data: { node: string; transitionsTaken: number; error?: string }) => void;
19
+ };