@hexabot-ai/agentic 3.1.2-alpha.9 → 3.1.2-beta.0

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 (69) hide show
  1. package/README.md +13 -5
  2. package/dist/cjs/action/abstract-action.js +8 -3
  3. package/dist/cjs/errors.js +41 -0
  4. package/dist/cjs/index.js +7 -1
  5. package/dist/cjs/step-executors/parallel-executor.js +238 -24
  6. package/dist/cjs/step-executors/skip-helpers.js +25 -1
  7. package/dist/cjs/step-executors/task-executor.js +77 -10
  8. package/dist/cjs/suspension-rebuilder.js +1 -24
  9. package/dist/cjs/utils/timeout.js +63 -8
  10. package/dist/cjs/utils/workflow-definition-resources.js +73 -0
  11. package/dist/cjs/workflow-runner.js +40 -17
  12. package/dist/esm/action/abstract-action.js +8 -3
  13. package/dist/esm/errors.js +33 -0
  14. package/dist/esm/index.js +2 -0
  15. package/dist/esm/step-executors/parallel-executor.js +239 -25
  16. package/dist/esm/step-executors/skip-helpers.js +23 -0
  17. package/dist/esm/step-executors/task-executor.js +77 -10
  18. package/dist/esm/suspension-rebuilder.js +1 -24
  19. package/dist/esm/utils/timeout.js +63 -8
  20. package/dist/esm/utils/workflow-definition-resources.js +68 -0
  21. package/dist/esm/workflow-runner.js +40 -17
  22. package/dist/types/action/abstract-action.d.ts +1 -1
  23. package/dist/types/action/abstract-action.d.ts.map +1 -1
  24. package/dist/types/action/action.types.d.ts +2 -1
  25. package/dist/types/action/action.types.d.ts.map +1 -1
  26. package/dist/types/context.d.ts +2 -1
  27. package/dist/types/context.d.ts.map +1 -1
  28. package/dist/types/errors.d.ts +10 -0
  29. package/dist/types/errors.d.ts.map +1 -0
  30. package/dist/types/index.d.ts +2 -0
  31. package/dist/types/index.d.ts.map +1 -1
  32. package/dist/types/step-executors/parallel-executor.d.ts +3 -4
  33. package/dist/types/step-executors/parallel-executor.d.ts.map +1 -1
  34. package/dist/types/step-executors/skip-helpers.d.ts +1 -0
  35. package/dist/types/step-executors/skip-helpers.d.ts.map +1 -1
  36. package/dist/types/step-executors/task-executor.d.ts.map +1 -1
  37. package/dist/types/step-executors/types.d.ts +9 -1
  38. package/dist/types/step-executors/types.d.ts.map +1 -1
  39. package/dist/types/suspension-rebuilder.d.ts.map +1 -1
  40. package/dist/types/utils/timeout.d.ts +4 -2
  41. package/dist/types/utils/timeout.d.ts.map +1 -1
  42. package/dist/types/utils/workflow-definition-resources.d.ts +16 -0
  43. package/dist/types/utils/workflow-definition-resources.d.ts.map +1 -0
  44. package/dist/types/workflow-event-emitter.d.ts +12 -13
  45. package/dist/types/workflow-event-emitter.d.ts.map +1 -1
  46. package/dist/types/workflow-runner.d.ts.map +1 -1
  47. package/package.json +1 -1
  48. package/src/__tests__/suspension-rebuilder.test.ts +3 -42
  49. package/src/__tests__/workflow-definition-resources.test.ts +97 -0
  50. package/src/__tests__/workflow-runner.test.ts +58 -5
  51. package/src/action/__tests__/action.test.ts +2 -1
  52. package/src/action/abstract-action.ts +9 -1
  53. package/src/action/action.types.ts +2 -0
  54. package/src/context.ts +2 -0
  55. package/src/errors.ts +43 -0
  56. package/src/index.ts +10 -0
  57. package/src/step-executors/conditional-executor.test.ts +8 -3
  58. package/src/step-executors/loop-executor.test.ts +8 -3
  59. package/src/step-executors/parallel-executor.test.ts +191 -82
  60. package/src/step-executors/parallel-executor.ts +402 -34
  61. package/src/step-executors/skip-helpers.ts +41 -0
  62. package/src/step-executors/task-executor.test.ts +85 -21
  63. package/src/step-executors/task-executor.ts +94 -10
  64. package/src/step-executors/types.ts +14 -1
  65. package/src/suspension-rebuilder.ts +1 -53
  66. package/src/utils/timeout.ts +78 -8
  67. package/src/utils/workflow-definition-resources.ts +111 -0
  68. package/src/workflow-event-emitter.ts +13 -6
  69. package/src/workflow-runner.ts +59 -19
@@ -4,6 +4,7 @@
4
4
  * Full terms: see LICENSE.md.
5
5
  */
6
6
 
7
+ import { getAbortReason, throwIfAborted } from '../errors';
7
8
  import type { RuntimeSuspensionRequest } from '../runner-runtime-control';
8
9
  import type {
9
10
  CompiledTask,
@@ -19,6 +20,7 @@ import type { StepExecutorEnv } from './types';
19
20
  type TaskProgressOutcome =
20
21
  | { type: 'completed'; value: unknown }
21
22
  | { type: 'failed'; error: unknown }
23
+ | { type: 'cancelled'; error: Error }
22
24
  | { type: 'suspended'; request: RuntimeSuspensionRequest };
23
25
 
24
26
  /**
@@ -43,6 +45,12 @@ export async function executeTaskStep(
43
45
  }
44
46
 
45
47
  const stepInfo = env.buildInstanceStepInfo(step, state.iterationStack);
48
+ if (env.signal.aborted) {
49
+ const error = getAbortReason(env.signal);
50
+ recordTaskCancellation(env, stepInfo, error);
51
+ throw error;
52
+ }
53
+
46
54
  const scope: EvaluationScope = {
47
55
  input: state.input,
48
56
  context: env.context.state,
@@ -51,7 +59,13 @@ export async function executeTaskStep(
51
59
  accumulator: state.accumulator,
52
60
  };
53
61
  const inputs = await evaluateMapping(task.inputs, scope);
54
- env.recordStepExecution(stepInfo, {
62
+ if (env.signal.aborted) {
63
+ const error = getAbortReason(env.signal);
64
+ recordTaskCancellation(env, stepInfo, error);
65
+ throw error;
66
+ }
67
+
68
+ const stepExecution = env.recordStepExecution(stepInfo, {
55
69
  action: task.actionName,
56
70
  status: 'running',
57
71
  startedAt: Date.now(),
@@ -61,11 +75,23 @@ export async function executeTaskStep(
61
75
  env.beginStepExecution?.(stepInfo.id);
62
76
  env.setCurrentStep(stepInfo);
63
77
  env.markSnapshot(stepInfo, 'running');
64
- env.emit('hook:step:start', { runId: env.runId, step: stepInfo });
78
+ env.emit('hook:step:start', {
79
+ runId: env.runId,
80
+ step: stepInfo,
81
+ stepExecution,
82
+ });
65
83
 
66
84
  try {
85
+ throwIfAborted(env.signal);
86
+
67
87
  const actionPromise = Promise.resolve().then(() =>
68
- task.action.run(inputs, env.context, task.settings, task.bindings),
88
+ task.action.run(
89
+ inputs,
90
+ env.context,
91
+ task.settings,
92
+ task.bindings,
93
+ env.signal,
94
+ ),
69
95
  );
70
96
  const outcome = await waitForTaskProgress(env, stepInfo.id, actionPromise);
71
97
 
@@ -88,6 +114,12 @@ export async function executeTaskStep(
88
114
  throw outcome.error;
89
115
  }
90
116
 
117
+ if (outcome.type === 'cancelled') {
118
+ env.clearStepSuspensions(stepInfo.id, outcome.error);
119
+ recordTaskCancellation(env, stepInfo, outcome.error);
120
+ throw outcome.error;
121
+ }
122
+
91
123
  return buildSuspensionContinuation(
92
124
  env,
93
125
  stepInfo.id,
@@ -114,8 +146,29 @@ const waitForTaskProgress = async (
114
146
  const suspension = env
115
147
  .waitForStepSuspension(stepId)
116
148
  .then<TaskProgressOutcome>((request) => ({ type: 'suspended', request }));
149
+ let cleanupCancellation = () => undefined;
150
+ const cancellation = new Promise<TaskProgressOutcome>((resolve) => {
151
+ if (env.signal.aborted) {
152
+ resolve({ type: 'cancelled', error: getAbortReason(env.signal) });
153
+
154
+ return;
155
+ }
156
+
157
+ const onAbort = () => {
158
+ resolve({ type: 'cancelled', error: getAbortReason(env.signal) });
159
+ };
117
160
 
118
- return Promise.race([completion, suspension]);
161
+ env.signal.addEventListener('abort', onAbort, { once: true });
162
+ cleanupCancellation = () => {
163
+ env.signal.removeEventListener('abort', onAbort);
164
+ };
165
+ });
166
+
167
+ try {
168
+ return await Promise.race([completion, suspension, cancellation]);
169
+ } finally {
170
+ cleanupCancellation();
171
+ }
119
172
  };
120
173
  const completeTask = async (
121
174
  env: StepExecutorEnv,
@@ -126,14 +179,18 @@ const completeTask = async (
126
179
  result: unknown,
127
180
  ) => {
128
181
  await env.captureTaskOutput(task, state, result);
129
- env.recordStepExecution(stepInfo, {
182
+ const stepExecution = env.recordStepExecution(stepInfo, {
130
183
  status: 'completed',
131
184
  endedAt: Date.now(),
132
185
  output: result,
133
186
  context: { after: env.context.snapshot() },
134
187
  });
135
188
  env.markSnapshot(stepInfo, 'completed');
136
- env.emit('hook:step:success', { runId: env.runId, step: stepInfo });
189
+ env.emit('hook:step:success', {
190
+ runId: env.runId,
191
+ step: stepInfo,
192
+ stepExecution,
193
+ });
137
194
  env.clearStepSuspensions(stepId);
138
195
  };
139
196
  const recordSuspension = (
@@ -142,7 +199,7 @@ const recordSuspension = (
142
199
  reason?: string,
143
200
  data?: unknown,
144
201
  ) => {
145
- env.recordStepExecution(stepInfo, {
202
+ const stepExecution = env.recordStepExecution(stepInfo, {
146
203
  status: 'suspended',
147
204
  endedAt: Date.now(),
148
205
  reason,
@@ -152,6 +209,7 @@ const recordSuspension = (
152
209
  env.emit('hook:step:suspended', {
153
210
  runId: env.runId,
154
211
  step: stepInfo,
212
+ stepExecution,
155
213
  reason,
156
214
  data,
157
215
  });
@@ -231,14 +289,40 @@ const recordTaskFailure = (
231
289
  stepInfo: Suspension['step'],
232
290
  error: unknown,
233
291
  ) => {
234
- env.recordStepExecution(stepInfo, {
292
+ const normalizedError = normalizeError(error);
293
+ const stepExecution = env.recordStepExecution(stepInfo, {
235
294
  status: 'failed',
236
295
  endedAt: Date.now(),
237
- error: normalizeError(error),
296
+ error: normalizedError,
238
297
  context: { after: env.context.snapshot() },
239
298
  });
240
299
  env.markSnapshot(stepInfo, 'failed', normalizeErrorMessage(error));
241
- env.emit('hook:step:error', { runId: env.runId, step: stepInfo, error });
300
+ env.emit('hook:step:error', {
301
+ runId: env.runId,
302
+ step: stepInfo,
303
+ stepExecution,
304
+ error,
305
+ });
306
+ };
307
+ const recordTaskCancellation = (
308
+ env: StepExecutorEnv,
309
+ stepInfo: Suspension['step'],
310
+ error: unknown,
311
+ ) => {
312
+ const normalizedError = normalizeError(error);
313
+ const stepExecution = env.recordStepExecution(stepInfo, {
314
+ status: 'cancelled',
315
+ endedAt: Date.now(),
316
+ error: normalizedError,
317
+ context: { after: env.context.snapshot() },
318
+ });
319
+ env.markSnapshot(stepInfo, 'cancelled', normalizeErrorMessage(error));
320
+ env.emit('hook:step:cancelled', {
321
+ runId: env.runId,
322
+ step: stepInfo,
323
+ stepExecution,
324
+ error,
325
+ });
242
326
  };
243
327
  const normalizeError = (error: unknown): { message: string; stack?: string } =>
244
328
  error instanceof Error
@@ -23,9 +23,21 @@ import type {
23
23
  Suspension,
24
24
  } from '../workflow-types';
25
25
 
26
+ export type StepExecutorEnvForkOverrides = {
27
+ context?: BaseWorkflowContext;
28
+ signal?: AbortSignal;
29
+ setCurrentStep?: (step?: StepInfo) => void;
30
+ captureTaskOutput?: (
31
+ task: CompiledTask,
32
+ state: ExecutionState,
33
+ result: unknown,
34
+ ) => Promise<void>;
35
+ };
36
+
26
37
  export type StepExecutorEnv = {
27
38
  compiled: CompiledWorkflow;
28
39
  context: BaseWorkflowContext;
40
+ signal: AbortSignal;
29
41
  runId?: string;
30
42
  buildInstanceStepInfo: (
31
43
  step: CompiledStep,
@@ -39,7 +51,7 @@ export type StepExecutorEnv = {
39
51
  recordStepExecution: (
40
52
  step: StepInfo,
41
53
  update: Partial<StepExecutionRecord>,
42
- ) => void;
54
+ ) => StepExecutionRecord;
43
55
  emit: <K extends keyof WorkflowEventMap>(
44
56
  event: K,
45
57
  payload: WorkflowEventMap[K],
@@ -67,4 +79,5 @@ export type StepExecutorEnv = {
67
79
  state: ExecutionState,
68
80
  path: Array<number | string>,
69
81
  ) => Promise<Suspension | void>;
82
+ fork: (overrides: StepExecutorEnvForkOverrides) => StepExecutorEnv;
70
83
  };
@@ -10,8 +10,6 @@ import {
10
10
  shouldStopLoop,
11
11
  updateAccumulator,
12
12
  } from './step-executors/loop-executor';
13
- import { executeParallel as runParallelExecutor } from './step-executors/parallel-executor';
14
- import { markStepsSkipped } from './step-executors/skip-helpers';
15
13
  import { wrapSuspensionContinuation } from './step-executors/suspension-continuation';
16
14
  import type { StepExecutorEnv } from './step-executors/types';
17
15
  import {
@@ -295,57 +293,7 @@ export function buildSuspensionForPath(
295
293
  }
296
294
 
297
295
  if (step.type === StepType.Parallel) {
298
- if (rest[0] !== 'parallel') {
299
- return null;
300
- }
301
-
302
- const childPath = rest.slice(1);
303
- const childSuspension = buildSuspensionForPath(
304
- deps,
305
- step.steps,
306
- state,
307
- childPath,
308
- [...currentPath, 'parallel'],
309
- iterationDepth,
310
- suspensionMetadata,
311
- );
312
-
313
- if (!childSuspension) {
314
- return null;
315
- }
316
-
317
- const childIndex =
318
- typeof childPath[0] === 'number' ? (childPath[0] as number) : 0;
319
-
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
- );
328
- }
329
-
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),
344
- );
345
- }
346
-
347
- return deps.executeFlow(steps, state, pathPrefix, current + 1);
348
- });
296
+ return null;
349
297
  }
350
298
 
351
299
  if (step.type === StepType.Conditional) {
@@ -4,43 +4,113 @@
4
4
  * Full terms: see LICENSE.md.
5
5
  */
6
6
 
7
+ import { getAbortReason, throwIfAborted } from '../errors';
8
+
7
9
  /**
8
10
  * Resolves after the specified duration; useful for retry delays.
9
11
  *
10
12
  * @param durationMs - Number of milliseconds to wait before resolving.
13
+ * @param signal - Optional signal used to cancel the wait.
11
14
  * @returns A promise that resolves once the duration elapses.
12
15
  */
13
- export const sleep = (durationMs: number): Promise<void> =>
14
- new Promise((resolve) => setTimeout(resolve, durationMs));
16
+ export const sleep = (
17
+ durationMs: number,
18
+ signal?: AbortSignal,
19
+ ): Promise<void> => {
20
+ if (!signal) {
21
+ return new Promise((resolve) => setTimeout(resolve, durationMs));
22
+ }
23
+
24
+ throwIfAborted(signal);
25
+
26
+ return new Promise((resolve, reject) => {
27
+ const timer = setTimeout(() => {
28
+ signal.removeEventListener('abort', onAbort);
29
+ resolve();
30
+ }, durationMs);
31
+ const onAbort = () => {
32
+ clearTimeout(timer);
33
+ reject(getAbortReason(signal));
34
+ };
35
+
36
+ signal.addEventListener('abort', onAbort, { once: true });
37
+ });
38
+ };
15
39
 
16
40
  /**
17
41
  * Wraps a promise and rejects if it does not settle within the timeout.
18
42
  *
19
43
  * @param promise - Operation that may take longer than the allowed timeout.
20
44
  * @param timeoutMs - Maximum time in milliseconds to wait before rejecting.
45
+ * @param signal - Optional signal used to cancel the operation.
21
46
  * @returns The result of the original promise when it resolves in time.
22
47
  * @throws Error when the timeout is exceeded.
23
48
  */
24
49
  export async function withTimeout<T>(
25
50
  promise: Promise<T>,
26
51
  timeoutMs?: number,
52
+ signal?: AbortSignal,
27
53
  ): Promise<T> {
28
- if (!timeoutMs) {
54
+ if (!timeoutMs && !signal) {
29
55
  return promise;
30
56
  }
31
57
 
32
58
  return new Promise<T>((resolve, reject) => {
33
- const timer = setTimeout(() => {
34
- reject(new Error(`Step execution exceeded timeout of ${timeoutMs}ms`));
35
- }, timeoutMs);
59
+ let settled = false;
60
+ const timer = timeoutMs
61
+ ? setTimeout(() => {
62
+ settled = true;
63
+ signal?.removeEventListener('abort', onAbort);
64
+ reject(
65
+ new Error(`Step execution exceeded timeout of ${timeoutMs}ms`),
66
+ );
67
+ }, timeoutMs)
68
+ : undefined;
69
+ const onAbort = () => {
70
+ if (settled) {
71
+ return;
72
+ }
73
+
74
+ settled = true;
75
+ if (timer) {
76
+ clearTimeout(timer);
77
+ }
78
+ reject(getAbortReason(signal as AbortSignal));
79
+ };
80
+
81
+ if (signal) {
82
+ if (signal.aborted) {
83
+ onAbort();
84
+
85
+ return;
86
+ }
87
+
88
+ signal.addEventListener('abort', onAbort, { once: true });
89
+ }
36
90
 
37
91
  promise.then(
38
92
  (value) => {
39
- clearTimeout(timer);
93
+ if (settled) {
94
+ return;
95
+ }
96
+
97
+ settled = true;
98
+ if (timer) {
99
+ clearTimeout(timer);
100
+ }
101
+ signal?.removeEventListener('abort', onAbort);
40
102
  resolve(value);
41
103
  },
42
104
  (error) => {
43
- clearTimeout(timer);
105
+ if (settled) {
106
+ return;
107
+ }
108
+
109
+ settled = true;
110
+ if (timer) {
111
+ clearTimeout(timer);
112
+ }
113
+ signal?.removeEventListener('abort', onAbort);
44
114
  reject(error);
45
115
  },
46
116
  );
@@ -0,0 +1,111 @@
1
+ /*
2
+ * Hexabot — Fair Core License (FCL-1.0-ALv2)
3
+ * Copyright (c) 2026 Hexastack.
4
+ * Full terms: see LICENSE.md.
5
+ */
6
+
7
+ import type { DefDefinition, WorkflowDefinition } from '../dsl.types';
8
+
9
+ export type WorkflowDefinitionResourceDescriptor = {
10
+ kind: string;
11
+ settingsKey: string;
12
+ };
13
+
14
+ export type WorkflowDefinitionResourceRefs = Record<string, string[]>;
15
+
16
+ export type WorkflowDefinitionResourceIdMaps = Record<
17
+ string,
18
+ Record<string, string>
19
+ >;
20
+
21
+ const getSettingsRef = (
22
+ definition: DefDefinition,
23
+ settingsKey: string,
24
+ ): string | null => {
25
+ const settings = definition.settings;
26
+ if (!settings || typeof settings !== 'object') {
27
+ return null;
28
+ }
29
+
30
+ const value = (settings as Record<string, unknown>)[settingsKey];
31
+
32
+ return typeof value === 'string' && value.trim() ? value : null;
33
+ };
34
+
35
+ /**
36
+ * Collect external resource IDs referenced by workflow definition defs.
37
+ */
38
+ export const collectWorkflowDefinitionResourceRefs = (
39
+ definition: WorkflowDefinition,
40
+ descriptors: WorkflowDefinitionResourceDescriptor[],
41
+ ): WorkflowDefinitionResourceRefs => {
42
+ const result = Object.fromEntries(
43
+ descriptors.map((descriptor) => [descriptor.kind, new Set<string>()]),
44
+ ) as Record<string, Set<string>>;
45
+
46
+ for (const def of Object.values(definition.defs ?? {})) {
47
+ for (const descriptor of descriptors) {
48
+ if (def.kind !== descriptor.kind) {
49
+ continue;
50
+ }
51
+
52
+ const ref = getSettingsRef(def, descriptor.settingsKey);
53
+ if (ref) {
54
+ result[descriptor.kind].add(ref);
55
+ }
56
+ }
57
+ }
58
+
59
+ return Object.fromEntries(
60
+ Object.entries(result).map(([kind, refs]) => [kind, Array.from(refs)]),
61
+ );
62
+ };
63
+
64
+ /**
65
+ * Rewrite external resource IDs referenced by workflow definition defs.
66
+ */
67
+ export const remapWorkflowDefinitionResourceRefs = (
68
+ definition: WorkflowDefinition,
69
+ descriptors: WorkflowDefinitionResourceDescriptor[],
70
+ idMaps: WorkflowDefinitionResourceIdMaps,
71
+ ): WorkflowDefinition => {
72
+ let didChange = false;
73
+ const nextDefs = Object.fromEntries(
74
+ Object.entries(definition.defs ?? {}).map(([defName, def]) => {
75
+ const descriptor = descriptors.find((item) => item.kind === def.kind);
76
+ if (!descriptor) {
77
+ return [defName, def];
78
+ }
79
+
80
+ const currentRef = getSettingsRef(def, descriptor.settingsKey);
81
+ const nextRef = currentRef
82
+ ? idMaps[descriptor.kind]?.[currentRef]
83
+ : undefined;
84
+ if (!currentRef || !nextRef || nextRef === currentRef) {
85
+ return [defName, def];
86
+ }
87
+
88
+ didChange = true;
89
+
90
+ return [
91
+ defName,
92
+ {
93
+ ...def,
94
+ settings: {
95
+ ...(def.settings ?? {}),
96
+ [descriptor.settingsKey]: nextRef,
97
+ },
98
+ },
99
+ ];
100
+ }),
101
+ ) as WorkflowDefinition['defs'];
102
+
103
+ if (!didChange) {
104
+ return definition;
105
+ }
106
+
107
+ return {
108
+ ...definition,
109
+ defs: nextDefs,
110
+ };
111
+ };
@@ -4,6 +4,8 @@
4
4
  * Full terms: see LICENSE.md.
5
5
  */
6
6
 
7
+ import type { StepExecutionRecord } from './context';
8
+
7
9
  export enum StepType {
8
10
  Task = 'task',
9
11
  Parallel = 'parallel',
@@ -17,6 +19,12 @@ export type StepInfo = {
17
19
  type: StepType;
18
20
  };
19
21
 
22
+ export type StepWorkflowEventPayload = {
23
+ runId?: string;
24
+ step: StepInfo;
25
+ stepExecution?: StepExecutionRecord;
26
+ };
27
+
20
28
  export type WorkflowEventMap = {
21
29
  'hook:workflow:start': { runId?: string };
22
30
  'hook:workflow:finish': { runId?: string; output: Record<string, unknown> };
@@ -27,12 +35,11 @@ export type WorkflowEventMap = {
27
35
  reason?: string;
28
36
  data?: unknown;
29
37
  };
30
- 'hook:step:start': { runId?: string; step: StepInfo };
31
- 'hook:step:success': { runId?: string; step: StepInfo };
32
- 'hook:step:error': { runId?: string; step: StepInfo; error: unknown };
33
- 'hook:step:suspended': {
34
- runId?: string;
35
- step: StepInfo;
38
+ 'hook:step:start': StepWorkflowEventPayload;
39
+ 'hook:step:success': StepWorkflowEventPayload;
40
+ 'hook:step:error': StepWorkflowEventPayload & { error: unknown };
41
+ 'hook:step:cancelled': StepWorkflowEventPayload & { error: unknown };
42
+ 'hook:step:suspended': StepWorkflowEventPayload & {
36
43
  reason?: string;
37
44
  data?: unknown;
38
45
  };