@outputai/core 0.10.1-dev.b7b2fbe.0 → 0.10.1-next.1070949.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 (77) hide show
  1. package/package.json +8 -7
  2. package/src/bus.js +58 -20
  3. package/src/bus.spec.js +135 -77
  4. package/src/consts.js +5 -2
  5. package/src/errors.d.ts +12 -2
  6. package/src/errors.js +17 -3
  7. package/src/errors.spec.js +19 -0
  8. package/src/helpers/activity_options.js +21 -0
  9. package/src/helpers/activity_options.spec.js +55 -0
  10. package/src/helpers/error_serializer.js +236 -0
  11. package/src/helpers/error_serializer.spec.js +413 -0
  12. package/src/helpers/errors.js +23 -14
  13. package/src/helpers/errors.spec.js +31 -75
  14. package/src/helpers/fetch.js +1 -38
  15. package/src/helpers/fetch.spec.js +1 -39
  16. package/src/helpers/function.js +13 -0
  17. package/src/helpers/function.spec.js +23 -1
  18. package/src/helpers/object.js +5 -1
  19. package/src/helpers/object.spec.js +5 -0
  20. package/src/helpers/redact.js +51 -0
  21. package/src/helpers/redact.spec.js +66 -0
  22. package/src/helpers/string.js +10 -0
  23. package/src/helpers/string.spec.js +36 -1
  24. package/src/hooks/index.d.ts +76 -78
  25. package/src/hooks/index.js +57 -49
  26. package/src/hooks/index.spec.js +104 -105
  27. package/src/hooks/pending_hooks.js +24 -0
  28. package/src/hooks/pending_hooks.spec.js +62 -0
  29. package/src/interface/evaluator.d.ts +10 -9
  30. package/src/interface/evaluator.js +1 -6
  31. package/src/interface/evaluator.spec.js +10 -10
  32. package/src/interface/index.js +2 -1
  33. package/src/interface/step.d.ts +16 -15
  34. package/src/interface/step.js +1 -6
  35. package/src/interface/step.spec.js +10 -10
  36. package/src/interface/validations/index.js +33 -53
  37. package/src/interface/validations/index.spec.js +25 -17
  38. package/src/interface/webhook.js +1 -2
  39. package/src/interface/webhook.spec.js +25 -19
  40. package/src/interface/workflow.d.ts +25 -18
  41. package/src/interface/workflow.js +24 -52
  42. package/src/interface/workflow.spec.js +109 -108
  43. package/src/interface/workflow_activity_options.js +2 -5
  44. package/src/interface/workflow_utils.d.ts +15 -0
  45. package/src/interface/workflow_utils.js +19 -0
  46. package/src/interface/workflow_utils.spec.js +82 -1
  47. package/src/sdk/runtime/events.d.ts +4 -6
  48. package/src/sdk/runtime/events.js +2 -15
  49. package/src/sdk/runtime/events.spec.js +14 -92
  50. package/src/tracing/trace_engine.js +9 -11
  51. package/src/tracing/trace_engine.spec.js +67 -28
  52. package/src/worker/catalog_workflow/catalog_job.js +3 -3
  53. package/src/worker/catalog_workflow/catalog_job.spec.js +1 -1
  54. package/src/worker/configs.js +0 -3
  55. package/src/worker/global_functions.js +2 -2
  56. package/src/worker/global_functions.spec.js +3 -3
  57. package/src/worker/index.js +20 -11
  58. package/src/worker/index.spec.js +29 -16
  59. package/src/worker/interceptors/activity.js +34 -21
  60. package/src/worker/interceptors/activity.spec.js +77 -172
  61. package/src/worker/interceptors/workflow.js +53 -11
  62. package/src/worker/interceptors/workflow.spec.js +176 -49
  63. package/src/worker/loader/workflows.js +16 -3
  64. package/src/worker/loader/workflows.spec.js +37 -5
  65. package/src/worker/log_hooks.js +22 -19
  66. package/src/worker/log_hooks.spec.js +14 -6
  67. package/src/worker/sinks.js +8 -8
  68. package/src/worker/sinks.spec.js +9 -9
  69. package/src/worker/telemetry.js +2 -1
  70. package/src/worker/temporal_logger.js +33 -0
  71. package/src/worker/temporal_logger.spec.js +90 -0
  72. package/src/helpers/aggregations.js +0 -44
  73. package/src/helpers/aggregations.spec.js +0 -92
  74. package/src/tracing/tools/utils.js +0 -42
  75. package/src/tracing/tools/utils.spec.js +0 -83
  76. package/src/worker/proxy.js +0 -20
  77. package/src/worker/proxy.spec.js +0 -51
@@ -80,114 +80,108 @@ export interface WorkflowDetails {
80
80
  }
81
81
 
82
82
  /**
83
- * Attribute totals collected while an activity executes.
84
- */
85
- export interface Aggregations {
86
- /** Cost totals collected from HTTP request cost and LLM usage attributes. */
87
- cost: {
88
- total: number;
89
- };
90
- /** Token totals collected from LLM usage attributes. */
91
- tokens: {
92
- [tokenType: string]: number | undefined;
93
- total: number;
94
- };
95
- /** HTTP request count totals. */
96
- httpRequests: {
97
- total: number;
98
- };
99
- }
100
-
101
- /**
102
- * Common lifecycle hook payload fields for events associated with a workflow.
83
+ * Common hook payload fields
103
84
  */
104
85
  export interface HookPayloadBase {
105
86
  /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
106
87
  eventId: string;
107
88
  /** Timestamp of the event */
108
89
  eventDate: number;
109
- /** Information about the current workflow execution */
110
- workflowDetails: WorkflowDetails;
111
90
  }
112
91
 
113
92
  /**
114
- * Common hook payload fields for events associated with an activity.
93
+ * A serialized error-like object emitted from a workflow.
94
+ *
95
+ * Additional enumerable properties from the original error may also be present.
115
96
  */
116
- export interface ActivityPayloadBase extends HookPayloadBase {
117
- /** Temporal's activityInfo(). */
118
- activityInfo: Info;
119
- /** Output component kind for the activity, e.g. step or evaluator. */
120
- outputActivityKind: string;
97
+ export interface SerializedError {
98
+ /** Error name. */
99
+ name: string;
100
+ /** Error message. */
101
+ message: string;
102
+ /** Serialized underlying cause, when present. */
103
+ cause?: SerializedError;
104
+ /** Additional properties captured from the original error. */
105
+ [property: string]: unknown;
121
106
  }
122
107
 
123
108
  /**
124
- * Payload passed to the onError() handler when a workflow, activity or runtime error occurs.
109
+ * Common hook payload fields for events associated with an workflow.
125
110
  */
126
- export interface ErrorHookPayload {
127
- /** UUID v4 stamped per emit. Stable per-emit idempotency key. */
128
- eventId: string;
129
- /** Timestamp of the event */
130
- eventDate: number;
131
- /** Origin of the error: workflow execution, activity execution, or runtime. */
132
- source: 'workflow' | 'activity' | 'runtime';
111
+ export interface WorkflowPayloadBase extends HookPayloadBase {
133
112
  /** Information about the current workflow execution */
134
- workflowDetails?: WorkflowDetails;
135
- /** Temporal's activityInfo(). If source is activity */
136
- activityInfo?: Info;
137
- /** Output component kind for the activity, e.g. step, evaluator, or internal_step. */
138
- outputActivityKind?: string;
139
- /** Attribute totals collected during the activity execution. */
140
- aggregations?: Aggregations | null;
141
- /** The error thrown. */
142
- error: Error;
113
+ workflowDetails: WorkflowDetails;
143
114
  }
144
115
 
145
116
  /**
146
117
  * Payload passed to the onWorkflowStart() handler when a workflow run begins.
147
118
  */
148
- export type WorkflowStartHookPayload = HookPayloadBase;
119
+ export type WorkflowStartHookPayload = WorkflowPayloadBase;
149
120
 
150
121
  /**
151
122
  * Payload passed to the onWorkflowEnd() handler when a workflow run completes successfully.
152
123
  */
153
- export type WorkflowEndHookPayload = HookPayloadBase;
124
+ export type WorkflowEndHookPayload = WorkflowPayloadBase;
154
125
 
155
126
  /**
156
127
  * Payload passed to the onWorkflowError() handler when a workflow run fails.
157
128
  */
158
- export interface WorkflowErrorHookPayload extends HookPayloadBase {
159
- /** The error thrown. */
160
- error: Error;
129
+ export interface WorkflowErrorHookPayload extends WorkflowPayloadBase {
130
+ /** Serialized workflow error. */
131
+ error: SerializedError;
161
132
  }
162
133
 
163
134
  /**
164
- * Common activity lifecycle hook payload fields.
135
+ * Common hook payload fields for events associated with an activity.
165
136
  */
166
- export type ActivityHookPayload = ActivityPayloadBase;
137
+ export interface ActivityPayloadBase extends HookPayloadBase {
138
+ /** Information about the current workflow execution */
139
+ workflowDetails: WorkflowDetails;
140
+ /** Temporal's activityInfo(). */
141
+ activityInfo: Info;
142
+ /** Output component kind for the activity, e.g. step, evaluator, or internal_step. */
143
+ outputActivityKind: string;
144
+ }
167
145
 
168
146
  /**
169
147
  * Payload passed to the onActivityStart() handler when an activity starts.
170
148
  */
171
- export type ActivityStartHookPayload = ActivityHookPayload;
149
+ export type ActivityStartHookPayload = ActivityPayloadBase;
172
150
 
173
151
  /**
174
152
  * Payload passed to the onActivityEnd() handler when an activity completes successfully.
175
153
  */
176
- export interface ActivityEndHookPayload extends ActivityHookPayload {
177
- /** Attribute totals collected during the activity execution. */
178
- aggregations: Aggregations | null;
179
- }
154
+ export type ActivityEndHookPayload = ActivityPayloadBase;
180
155
 
181
156
  /**
182
157
  * Payload passed to the onActivityError() handler when an activity fails.
183
158
  */
184
- export interface ActivityErrorHookPayload extends ActivityHookPayload {
185
- /** Attribute totals collected during the activity execution. */
186
- aggregations: Aggregations | null;
159
+ export interface ActivityErrorHookPayload extends ActivityPayloadBase {
187
160
  /** The error thrown. */
188
161
  error: Error;
189
162
  }
190
163
 
164
+ /**
165
+ * Payload passed to the onError() handler when a workflow, activity or runtime error occurs.
166
+ */
167
+ export type ErrorHookPayload =
168
+ ( WorkflowPayloadBase & {
169
+ /** Workflow error origin. */
170
+ source: 'workflow';
171
+ /** Serialized workflow error. */
172
+ error: SerializedError;
173
+ } ) |
174
+ ( ActivityErrorHookPayload & {
175
+ /** Activity error origin. */
176
+ source: 'activity';
177
+ } ) |
178
+ ( HookPayloadBase & {
179
+ /** Worker runtime error origin. */
180
+ source: 'runtime';
181
+ /** The original error instance. */
182
+ error: Error;
183
+ } );
184
+
191
185
  /**
192
186
  * Register a handler to be invoked on workflow, activity or runtime errors.
193
187
  *
@@ -233,8 +227,6 @@ export declare function onWorkflowError( handler: ( payload: WorkflowErrorHookPa
233
227
  /**
234
228
  * Register a handler to be invoked when an activity starts.
235
229
  *
236
- * Excludes internal activities.
237
- *
238
230
  * @param handler - Function called with the activity start payload.
239
231
  */
240
232
  export declare function onActivityStart( handler: ( payload: ActivityStartHookPayload ) => void ): void;
@@ -242,8 +234,6 @@ export declare function onActivityStart( handler: ( payload: ActivityStartHookPa
242
234
  /**
243
235
  * Register a handler to be invoked when an activity completes successfully.
244
236
  *
245
- * Excludes internal activities.
246
- *
247
237
  * @param handler - Function called with the activity end payload.
248
238
  */
249
239
  export declare function onActivityEnd( handler: ( payload: ActivityEndHookPayload ) => void ): void;
@@ -251,24 +241,32 @@ export declare function onActivityEnd( handler: ( payload: ActivityEndHookPayloa
251
241
  /**
252
242
  * Register a handler to be invoked when an activity fails.
253
243
  *
254
- * Excludes internal activities.
255
- *
256
244
  * @param handler - Function called with the activity error payload.
257
245
  */
258
246
  export declare function onActivityError( handler: ( payload: ActivityErrorHookPayload ) => void ): void;
259
247
 
260
- /**
261
- * Framework-managed envelope added to payloads passed to on() handlers.
262
- */
263
- export interface OnHookEnvelope extends HookPayloadBase {
264
- /** Temporal's activityInfo(). */
265
- activityInfo: Info;
266
- /** Output component kind for the activity, e.g. step, evaluator, or internal_step. */
248
+ /** Framework metadata, optional activity context, and the emitted payload. */
249
+ export type ExternalHookPayload<TPayload = unknown> = HookPayloadBase & {
250
+ /** Information about the current workflow execution, when emitted from an activity. */
251
+ workflowDetails?: WorkflowDetails;
252
+ /** Temporal's activityInfo(), when emitted from an activity. */
253
+ activityInfo?: Info;
254
+ /** Output component kind, when emitted from an activity. */
267
255
  outputActivityKind?: string;
268
- }
256
+ /** The emitted payload */
257
+ payload: TPayload | undefined;
258
+ };
269
259
 
270
- export type OnHookPayload<TAttributes extends Record<string, unknown> = Record<string, unknown>> =
271
- OnHookEnvelope & TAttributes;
260
+ /**
261
+ * Emit a custom event from the current activity.
262
+ *
263
+ * @param eventName - The name of the event to emit.
264
+ * @param payload - Optional value forwarded to on() handlers.
265
+ */
266
+ export declare function emit(
267
+ eventName: string,
268
+ payload?: unknown
269
+ ): boolean;
272
270
 
273
271
  /**
274
272
  * Register a handler to be invoked when a given event happens
@@ -276,7 +274,7 @@ export type OnHookPayload<TAttributes extends Record<string, unknown> = Record<s
276
274
  * @param eventName - The name of the event to subscribe
277
275
  * @param handler - Function called with the event payload
278
276
  */
279
- export declare function on<TAttributes extends Record<string, unknown> = Record<string, unknown>>(
277
+ export declare function on<TPayload = unknown>(
280
278
  eventName: string,
281
- handler: ( payload: OnHookPayload<TAttributes> ) => void
279
+ handler: ( event: ExternalHookPayload<TPayload> ) => void
282
280
  ): void;
@@ -1,68 +1,76 @@
1
- import { messageBus } from '#bus';
2
- import { BusEventType, ComponentType, WORKFLOW_CATALOG } from '#consts';
1
+ import { mainEventBus, stepEventBus } from '#bus';
2
+ import { BusEventType } from '#consts';
3
+ import { serializeError } from '#helpers/error_serializer';
3
4
  import { createChildLogger } from '#logger';
5
+ import { pendingHooks } from './pending_hooks.js';
4
6
 
5
7
  const log = createChildLogger( 'Hooks' );
6
8
 
7
9
  /**
8
- * Invokes an external hook handler function with a try catch around it
10
+ * Invokes a function within a try catch and log the error.
9
11
  *
10
12
  * @param {Function} fn
11
13
  * @param {any} args - Args to invoke the function with
12
14
  * @param {string} hookName - hookName to identify this hook function in the logs
13
15
  */
14
- const safeInvoke = async ( fn, args, hookName ) => {
15
- try {
16
- await fn( args );
17
- } catch ( error ) {
18
- log.error( `${hookName} hook error`, { message: error.message, stack: error.stack } );
19
- }
16
+ const callHookCb = ( fn, args, hookName ) => {
17
+ const promise = Promise.resolve()
18
+ .then( () => fn( args ) )
19
+ .catch( e => log.error( `${hookName} hook error`, { error: serializeError( e ) } ) )
20
+ .finally( () => pendingHooks.delete( promise ) );
21
+ pendingHooks.add( promise );
22
+ return promise;
20
23
  };
21
24
 
22
- /** Triggers on any errors: workflow, activity and runtime */
23
- export const onError = handler => {
24
- messageBus.on( BusEventType.ACTIVITY_ERROR, async payload =>
25
- safeInvoke( handler, { source: 'activity', ...payload }, 'onError' ) );
26
- messageBus.on( BusEventType.WORKFLOW_ERROR, async payload =>
27
- safeInvoke( handler, { source: 'workflow', ...payload }, 'onError' ) );
28
- messageBus.on( BusEventType.RUNTIME_ERROR, async payload =>
29
- safeInvoke( handler, { source: 'runtime', ...payload }, 'onError' ) );
25
+ // General Life-cycle
26
+ // --------------------------------------
27
+ const onError = cb => {
28
+ mainEventBus.on( BusEventType.ACTIVITY_ERROR, async payload =>
29
+ callHookCb( cb, { source: 'activity', ...payload }, 'onError' ) );
30
+ mainEventBus.on( BusEventType.WORKFLOW_ERROR, async payload =>
31
+ callHookCb( cb, { source: 'workflow', ...payload }, 'onError' ) );
32
+ mainEventBus.on( BusEventType.RUNTIME_ERROR, async payload =>
33
+ callHookCb( cb, { source: 'runtime', ...payload }, 'onError' ) );
30
34
  };
31
35
 
32
- /** Listen to worker before start events */
33
- export const onBeforeWorkerStart = handler => messageBus.on( BusEventType.WORKER_BEFORE_START, () =>
34
- safeInvoke( handler, undefined, 'onBeforeWorkerStart' ) );
36
+ const onBeforeWorkerStart = cb => mainEventBus.on( BusEventType.WORKER_BEFORE_START, () => callHookCb( cb, undefined, 'onBeforeWorkerStart' ) );
35
37
 
36
- /** Catalog workflow events should not be emitted */
37
- const shouldEmitWorkflowEvent = workflowDetails => WORKFLOW_CATALOG !== workflowDetails.workflowType;
38
+ // Workflow Life-cycle
39
+ // --------------------------------------
40
+ const onWorkflowStart = cb => mainEventBus.on( BusEventType.WORKFLOW_START, payload => callHookCb( cb, payload, 'onWorkflowStart' ) );
41
+ const onWorkflowEnd = cb => mainEventBus.on( BusEventType.WORKFLOW_END, payload => callHookCb( cb, payload, 'onWorkflowEnd' ) );
42
+ const onWorkflowError = cb => mainEventBus.on( BusEventType.WORKFLOW_ERROR, payload => callHookCb( cb, payload, 'onWorkflowError' ) );
38
43
 
39
- /** Listen to workflow start events, excludes catalog workflow */
40
- export const onWorkflowStart = handler => messageBus.on( BusEventType.WORKFLOW_START, ( { workflowDetails, ...eventFields } ) =>
41
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowStart' ) : null );
44
+ // Activity Life-cycle
45
+ // --------------------------------------
46
+ const onActivityStart = cb => mainEventBus.on( BusEventType.ACTIVITY_START, fields => callHookCb( cb, fields, 'onActivityStart' ) );
47
+ const onActivityEnd = cb => mainEventBus.on( BusEventType.ACTIVITY_END, fields => callHookCb( cb, fields, 'onActivityEnd' ) );
48
+ const onActivityError = cb => mainEventBus.on( BusEventType.ACTIVITY_ERROR, fields => callHookCb( cb, fields, 'onActivityError' ) );
42
49
 
43
- /** Listen to workflow end events, excludes catalog workflow */
44
- export const onWorkflowEnd = handler => messageBus.on( BusEventType.WORKFLOW_END, ( { workflowDetails, ...eventFields } ) =>
45
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowEnd' ) : null );
46
-
47
- /** Listen to workflow error events, excludes catalog workflow */
48
- export const onWorkflowError = handler => messageBus.on( BusEventType.WORKFLOW_ERROR, ( { workflowDetails, ...eventFields } ) =>
49
- shouldEmitWorkflowEvent( workflowDetails ) ? safeInvoke( handler, { workflowDetails, ...eventFields }, 'onWorkflowError' ) : null );
50
-
51
- /** Internal activities do not trigger hooks */
52
- const shouldEmitActivityEvent = outputActivityKind => outputActivityKind !== ComponentType.INTERNAL_STEP;
53
-
54
- /** Listen to workflow start events, excludes catalog workflow */
55
- export const onActivityStart = handler => messageBus.on( BusEventType.ACTIVITY_START, ( { outputActivityKind, ...eventFields } ) =>
56
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityStart' ) : null );
57
-
58
- /** Listen to workflow end events, excludes catalog workflow */
59
- export const onActivityEnd = handler => messageBus.on( BusEventType.ACTIVITY_END, ( { outputActivityKind, ...eventFields } ) =>
60
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityEnd' ) : null );
50
+ // Generic Events
51
+ // --------------------------------------
52
+ /** Listen to both sdk and custom events */
53
+ const on = ( eventName, cb ) => {
54
+ stepEventBus.on( `sdk:${eventName}`, payload => callHookCb( cb, payload, eventName ) );
55
+ stepEventBus.on( `usr:${eventName}`, payload => callHookCb( cb, payload, eventName ) );
56
+ };
61
57
 
62
- /** Listen to workflow error events, excludes catalog workflow */
63
- export const onActivityError = handler => messageBus.on( BusEventType.ACTIVITY_ERROR, ( { outputActivityKind, ...eventFields } ) =>
64
- shouldEmitActivityEvent( outputActivityKind ) ? safeInvoke( handler, { outputActivityKind, ...eventFields }, 'onActivityError' ) : null );
58
+ /**
59
+ * Emits a custom event
60
+ * @param {string} eventName
61
+ * @param {any} payload
62
+ */
63
+ const emit = ( eventName, payload ) => stepEventBus.emit( `usr:${eventName}`, payload );
65
64
 
66
- /** Generic listener for events emitted elsewhere (outside core) */
67
- export const on = ( eventName, handler ) => messageBus.on( `external:${eventName}`, payload =>
68
- safeInvoke( handler, payload, eventName ) );
65
+ export {
66
+ emit,
67
+ on,
68
+ onActivityEnd,
69
+ onActivityError,
70
+ onActivityStart,
71
+ onBeforeWorkerStart,
72
+ onError,
73
+ onWorkflowEnd,
74
+ onWorkflowError,
75
+ onWorkflowStart
76
+ };