@outputai/core 0.7.0 → 0.7.1-next.0e958f3.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.
- package/bin/worker.sh +6 -0
- package/package.json +1 -1
- package/src/consts.js +0 -4
- package/src/errors.js +6 -2
- package/src/hooks/index.d.ts +10 -0
- package/src/interface/evaluator.js +7 -20
- package/src/interface/evaluator.spec.js +117 -1
- package/src/interface/step.js +8 -9
- package/src/interface/step.spec.js +124 -0
- package/src/interface/validations/index.js +108 -0
- package/src/interface/validations/index.spec.js +182 -0
- package/src/interface/validations/schemas.js +113 -0
- package/src/interface/validations/schemas.spec.js +209 -0
- package/src/interface/webhook.js +1 -1
- package/src/interface/webhook.spec.js +1 -1
- package/src/interface/workflow.d.ts +10 -9
- package/src/interface/workflow.js +76 -164
- package/src/interface/workflow.spec.js +637 -521
- package/src/interface/workflow_activity_options.js +16 -0
- package/src/interface/workflow_utils.js +1 -1
- package/src/interface/zod_integration.spec.js +2 -2
- package/src/internal_utils/aggregations.js +0 -10
- package/src/internal_utils/aggregations.spec.js +1 -48
- package/src/internal_utils/errors.js +14 -8
- package/src/internal_utils/errors.spec.js +73 -27
- package/src/utils/index.d.ts +19 -0
- package/src/utils/utils.js +46 -0
- package/src/utils/utils.spec.js +82 -1
- package/src/worker/bundle.js +26 -0
- package/src/worker/bundle.spec.js +52 -0
- package/src/worker/catalog_workflow/catalog_job.js +148 -0
- package/src/worker/catalog_workflow/catalog_job.spec.js +232 -0
- package/src/worker/check.js +24 -0
- package/src/worker/connection_monitor.js +112 -0
- package/src/worker/connection_monitor.spec.js +199 -0
- package/src/worker/index.js +140 -34
- package/src/worker/index.spec.js +280 -108
- package/src/worker/interceptors/activity.js +7 -24
- package/src/worker/interceptors/activity.spec.js +97 -66
- package/src/worker/interceptors/index.js +4 -7
- package/src/worker/interceptors/modules.js +15 -0
- package/src/worker/interceptors/workflow.js +4 -7
- package/src/worker/interceptors/workflow.spec.js +49 -42
- package/src/worker/interruption.js +33 -0
- package/src/worker/interruption.spec.js +86 -0
- package/src/worker/loader_tools.js +1 -1
- package/src/worker/loader_tools.spec.js +36 -0
- package/src/worker/{setup_telemetry.js → telemetry.js} +9 -4
- package/src/worker/{setup_telemetry.spec.js → telemetry.spec.js} +3 -3
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +5 -109
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +31 -103
- package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +5 -6
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +11 -83
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +8 -11
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +9 -9
- package/src/interface/validations/runtime.js +0 -20
- package/src/interface/validations/runtime.spec.js +0 -29
- package/src/interface/validations/schema_utils.js +0 -8
- package/src/interface/validations/schema_utils.spec.js +0 -67
- package/src/interface/validations/static.js +0 -137
- package/src/interface/validations/static.spec.js +0 -397
- package/src/interface/workflow.replay_compatibility.spec.js +0 -254
- package/src/worker/shutdown.js +0 -26
- package/src/worker/shutdown.spec.js +0 -82
- package/src/worker/start_catalog.js +0 -96
- package/src/worker/start_catalog.spec.js +0 -179
package/bin/worker.sh
CHANGED
|
@@ -23,4 +23,10 @@ sdk_dir="$(dirname "$script_dir")"
|
|
|
23
23
|
|
|
24
24
|
cd ${sdk_dir}
|
|
25
25
|
|
|
26
|
+
# Route `output-worker --check` to the bundle-check entry, which validates the
|
|
27
|
+
# workflow bundle without a Temporal connection or worker config.
|
|
28
|
+
if [[ " $* " == *" --check "* ]]; then
|
|
29
|
+
exec node "${sdk_dir}/src/worker/check.js" "${invocation_dir}"
|
|
30
|
+
fi
|
|
31
|
+
|
|
26
32
|
exec node "${sdk_dir}/src/worker/index.js" "${invocation_dir}" "${@:2}"
|
package/package.json
CHANGED
package/src/consts.js
CHANGED
package/src/errors.js
CHANGED
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* Any generic fatal errors
|
|
8
8
|
*/
|
|
9
|
-
export class FatalError extends Error {
|
|
9
|
+
export class FatalError extends Error {
|
|
10
|
+
name = 'FatalError';
|
|
11
|
+
}
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Any validation error
|
|
13
15
|
*/
|
|
14
|
-
export class ValidationError extends Error {
|
|
16
|
+
export class ValidationError extends Error {
|
|
17
|
+
name = 'ValidationError';
|
|
18
|
+
}
|
package/src/hooks/index.d.ts
CHANGED
|
@@ -85,6 +85,8 @@ export interface WorkflowDetails {
|
|
|
85
85
|
export interface ErrorHookPayload {
|
|
86
86
|
/** UUID v4 stamped per emit. Stable per-emit idempotency key. */
|
|
87
87
|
eventId: string;
|
|
88
|
+
/** Timestamp of the event */
|
|
89
|
+
eventDate: number;
|
|
88
90
|
/** Origin of the error: workflow execution, activity execution, or runtime. */
|
|
89
91
|
source: 'workflow' | 'activity' | 'runtime';
|
|
90
92
|
/** Information about the current workflow execution */
|
|
@@ -103,6 +105,8 @@ export interface ErrorHookPayload {
|
|
|
103
105
|
export interface WorkflowStartHookPayload {
|
|
104
106
|
/** UUID v4 stamped per emit. Stable per-emit idempotency key. */
|
|
105
107
|
eventId: string;
|
|
108
|
+
/** Timestamp of the event */
|
|
109
|
+
eventDate: number;
|
|
106
110
|
/** Information about the current workflow execution */
|
|
107
111
|
workflowDetails: WorkflowDetails;
|
|
108
112
|
}
|
|
@@ -113,6 +117,8 @@ export interface WorkflowStartHookPayload {
|
|
|
113
117
|
export interface WorkflowEndHookPayload {
|
|
114
118
|
/** UUID v4 stamped per emit. Stable per-emit idempotency key. */
|
|
115
119
|
eventId: string;
|
|
120
|
+
/** Timestamp of the event */
|
|
121
|
+
eventDate: number;
|
|
116
122
|
/** Information about the current workflow execution */
|
|
117
123
|
workflowDetails: WorkflowDetails;
|
|
118
124
|
}
|
|
@@ -123,6 +129,8 @@ export interface WorkflowEndHookPayload {
|
|
|
123
129
|
export interface WorkflowErrorHookPayload {
|
|
124
130
|
/** UUID v4 stamped per emit. Stable per-emit idempotency key. */
|
|
125
131
|
eventId: string;
|
|
132
|
+
/** Timestamp of the event */
|
|
133
|
+
eventDate: number;
|
|
126
134
|
/** Information about the current workflow execution */
|
|
127
135
|
workflowDetails: WorkflowDetails;
|
|
128
136
|
/** The error thrown. */
|
|
@@ -177,6 +185,8 @@ export declare function onWorkflowError( handler: ( payload: WorkflowErrorHookPa
|
|
|
177
185
|
export interface OnHookEnvelope {
|
|
178
186
|
/** UUID v4 stamped per emit. Stable per-emit idempotency key. */
|
|
179
187
|
eventId: string;
|
|
188
|
+
/** Timestamp of the event */
|
|
189
|
+
eventDate: number;
|
|
180
190
|
/** Information about the current workflow execution */
|
|
181
191
|
workflowDetails: WorkflowDetails;
|
|
182
192
|
/** Temporal's activityInfo(). */
|
|
@@ -1,31 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { validateWithSchema } from './validations/runtime.js';
|
|
1
|
+
import { EvaluatorValidator } from './validations/index.js';
|
|
3
2
|
import { setMetadata } from '#utils';
|
|
4
|
-
import { ValidationError } from '#errors';
|
|
5
3
|
import { ComponentType } from '#consts';
|
|
6
|
-
|
|
4
|
+
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param {object} opts
|
|
10
|
-
* @param {string} opts.name
|
|
11
|
-
* @param {string} opts.description
|
|
12
|
-
* @param {z.ZodType} opts.inputSchema
|
|
13
|
-
* @param {Function} opts.fn
|
|
14
|
-
* @param {object} opts.options
|
|
15
|
-
* @returns {Function}
|
|
6
|
+
* Create a new evaluator (activity flavor) and return a wrapper function around its fn handler
|
|
16
7
|
*/
|
|
17
8
|
export function evaluator( { name, description, inputSchema, fn, options } ) {
|
|
18
|
-
|
|
9
|
+
EvaluatorValidator.validateDefinition( { name, description, inputSchema, fn, options } );
|
|
10
|
+
const validator = new EvaluatorValidator( { name, inputSchema } );
|
|
19
11
|
|
|
20
12
|
const wrapper = async input => {
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
validator.validateInput( input );
|
|
23
14
|
const output = await fn( input );
|
|
24
|
-
|
|
25
|
-
if ( !( output instanceof EvaluationResult ) ) {
|
|
26
|
-
throw new ValidationError( 'Evaluators must return an EvaluationResult' );
|
|
27
|
-
}
|
|
28
|
-
|
|
15
|
+
validator.validateOutput( output );
|
|
29
16
|
return output;
|
|
30
17
|
};
|
|
31
18
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import {
|
|
3
3
|
EvaluationResult,
|
|
4
4
|
EvaluationStringResult,
|
|
@@ -7,6 +7,122 @@ import {
|
|
|
7
7
|
EvaluationFeedback
|
|
8
8
|
} from './evaluation_result.js';
|
|
9
9
|
import { ValidationError } from '#errors';
|
|
10
|
+
import { ComponentType } from '#consts';
|
|
11
|
+
|
|
12
|
+
const validateDefinitionMock = vi.hoisted( () => vi.fn() );
|
|
13
|
+
const validateInputMock = vi.hoisted( () => vi.fn() );
|
|
14
|
+
const validateOutputMock = vi.hoisted( () => vi.fn() );
|
|
15
|
+
const validatorConstructorMock = vi.hoisted( () => vi.fn() );
|
|
16
|
+
|
|
17
|
+
vi.mock( './validations/index.js', () => {
|
|
18
|
+
class EvaluatorValidator {
|
|
19
|
+
static validateDefinition( ...args ) {
|
|
20
|
+
return validateDefinitionMock( ...args );
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
constructor( ...args ) {
|
|
24
|
+
validatorConstructorMock( ...args );
|
|
25
|
+
this.validateInput = validateInputMock;
|
|
26
|
+
this.validateOutput = validateOutputMock;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return { EvaluatorValidator };
|
|
31
|
+
} );
|
|
32
|
+
|
|
33
|
+
describe( 'evaluator()', () => {
|
|
34
|
+
beforeEach( () => {
|
|
35
|
+
vi.clearAllMocks();
|
|
36
|
+
} );
|
|
37
|
+
|
|
38
|
+
it( 'validates the definition, creates a runtime validator, and attaches metadata', async () => {
|
|
39
|
+
const { evaluator } = await import( './evaluator.js' );
|
|
40
|
+
const inputSchema = { safeParse: vi.fn() };
|
|
41
|
+
const fn = vi.fn().mockResolvedValue( new EvaluationResult( { value: 'ok', confidence: 1 } ) );
|
|
42
|
+
const options = { activityOptions: { startToCloseTimeout: '1m' } };
|
|
43
|
+
|
|
44
|
+
const wrapper = evaluator( {
|
|
45
|
+
name: 'test_evaluator',
|
|
46
|
+
description: 'Test evaluator',
|
|
47
|
+
inputSchema,
|
|
48
|
+
fn,
|
|
49
|
+
options
|
|
50
|
+
} );
|
|
51
|
+
|
|
52
|
+
expect( validateDefinitionMock ).toHaveBeenCalledWith( {
|
|
53
|
+
name: 'test_evaluator',
|
|
54
|
+
description: 'Test evaluator',
|
|
55
|
+
inputSchema,
|
|
56
|
+
fn,
|
|
57
|
+
options
|
|
58
|
+
} );
|
|
59
|
+
expect( validatorConstructorMock ).toHaveBeenCalledWith( {
|
|
60
|
+
name: 'test_evaluator',
|
|
61
|
+
inputSchema
|
|
62
|
+
} );
|
|
63
|
+
|
|
64
|
+
const [ metadataSymbol ] = Object.getOwnPropertySymbols( wrapper );
|
|
65
|
+
expect( wrapper[metadataSymbol] ).toEqual( {
|
|
66
|
+
name: 'test_evaluator',
|
|
67
|
+
description: 'Test evaluator',
|
|
68
|
+
inputSchema,
|
|
69
|
+
type: ComponentType.EVALUATOR,
|
|
70
|
+
options
|
|
71
|
+
} );
|
|
72
|
+
} );
|
|
73
|
+
|
|
74
|
+
it( 'validates input and output around the evaluator function', async () => {
|
|
75
|
+
const { evaluator } = await import( './evaluator.js' );
|
|
76
|
+
const output = new EvaluationResult( { value: 'ok', confidence: 1 } );
|
|
77
|
+
const fn = vi.fn().mockResolvedValue( output );
|
|
78
|
+
const wrapper = evaluator( {
|
|
79
|
+
name: 'runtime_evaluator',
|
|
80
|
+
inputSchema: undefined,
|
|
81
|
+
fn
|
|
82
|
+
} );
|
|
83
|
+
|
|
84
|
+
await expect( wrapper( { value: 'input' } ) ).resolves.toBe( output );
|
|
85
|
+
|
|
86
|
+
expect( validateInputMock ).toHaveBeenCalledWith( { value: 'input' } );
|
|
87
|
+
expect( fn ).toHaveBeenCalledWith( { value: 'input' } );
|
|
88
|
+
expect( validateOutputMock ).toHaveBeenCalledWith( output );
|
|
89
|
+
} );
|
|
90
|
+
|
|
91
|
+
it( 'does not call the evaluator function when input validation throws', async () => {
|
|
92
|
+
const { evaluator } = await import( './evaluator.js' );
|
|
93
|
+
const error = new ValidationError( 'invalid input' );
|
|
94
|
+
validateInputMock.mockImplementationOnce( () => {
|
|
95
|
+
throw error;
|
|
96
|
+
} );
|
|
97
|
+
const fn = vi.fn();
|
|
98
|
+
const wrapper = evaluator( {
|
|
99
|
+
name: 'invalid_input_evaluator',
|
|
100
|
+
fn
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
await expect( wrapper( { value: 'bad' } ) ).rejects.toBe( error );
|
|
104
|
+
expect( fn ).not.toHaveBeenCalled();
|
|
105
|
+
expect( validateOutputMock ).not.toHaveBeenCalled();
|
|
106
|
+
} );
|
|
107
|
+
|
|
108
|
+
it( 'propagates output validation errors after the evaluator function runs', async () => {
|
|
109
|
+
const { evaluator } = await import( './evaluator.js' );
|
|
110
|
+
const error = new ValidationError( 'invalid output' );
|
|
111
|
+
validateOutputMock.mockImplementationOnce( () => {
|
|
112
|
+
throw error;
|
|
113
|
+
} );
|
|
114
|
+
const output = { value: 'not-an-evaluation-result' };
|
|
115
|
+
const fn = vi.fn().mockResolvedValue( output );
|
|
116
|
+
const wrapper = evaluator( {
|
|
117
|
+
name: 'invalid_output_evaluator',
|
|
118
|
+
fn
|
|
119
|
+
} );
|
|
120
|
+
|
|
121
|
+
await expect( wrapper( { value: 'input' } ) ).rejects.toBe( error );
|
|
122
|
+
expect( fn ).toHaveBeenCalledOnce();
|
|
123
|
+
expect( validateOutputMock ).toHaveBeenCalledWith( output );
|
|
124
|
+
} );
|
|
125
|
+
} );
|
|
10
126
|
|
|
11
127
|
describe( 'interface/evaluator - EvaluationResult classes', () => {
|
|
12
128
|
describe( 'class inheritance', () => {
|
package/src/interface/step.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { StepValidator } from './validations/index.js';
|
|
2
2
|
import { setMetadata } from '#utils';
|
|
3
|
-
import { validateStep } from './validations/static.js';
|
|
4
|
-
import { validateWithSchema } from './validations/runtime.js';
|
|
5
3
|
import { ComponentType } from '#consts';
|
|
6
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Create a new step (activity flavor) and return a wrapper function around its fn handler
|
|
7
|
+
*/
|
|
7
8
|
export function step( { name, description, inputSchema, outputSchema, fn, options } ) {
|
|
8
|
-
|
|
9
|
+
StepValidator.validateDefinition( { name, description, inputSchema, outputSchema, fn, options } );
|
|
10
|
+
const validator = new StepValidator( { name, inputSchema, outputSchema } );
|
|
9
11
|
|
|
10
12
|
const wrapper = async input => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
validator.validateInput( input );
|
|
13
14
|
const output = await fn( input );
|
|
14
|
-
|
|
15
|
-
validateWithSchema( outputSchema, output, `Step ${name} output` );
|
|
16
|
-
|
|
15
|
+
validator.validateOutput( output );
|
|
17
16
|
return output;
|
|
18
17
|
};
|
|
19
18
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { ValidationError } from '#errors';
|
|
3
|
+
import { ComponentType } from '#consts';
|
|
4
|
+
|
|
5
|
+
const validateDefinitionMock = vi.hoisted( () => vi.fn() );
|
|
6
|
+
const validateInputMock = vi.hoisted( () => vi.fn() );
|
|
7
|
+
const validateOutputMock = vi.hoisted( () => vi.fn() );
|
|
8
|
+
const validatorConstructorMock = vi.hoisted( () => vi.fn() );
|
|
9
|
+
|
|
10
|
+
vi.mock( './validations/index.js', () => {
|
|
11
|
+
class StepValidator {
|
|
12
|
+
static validateDefinition( ...args ) {
|
|
13
|
+
return validateDefinitionMock( ...args );
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor( ...args ) {
|
|
17
|
+
validatorConstructorMock( ...args );
|
|
18
|
+
this.validateInput = validateInputMock;
|
|
19
|
+
this.validateOutput = validateOutputMock;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { StepValidator };
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
describe( 'step()', () => {
|
|
27
|
+
beforeEach( () => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
it( 'validates the definition, creates a runtime validator, and attaches metadata', async () => {
|
|
32
|
+
const { step } = await import( './step.js' );
|
|
33
|
+
const inputSchema = { safeParse: vi.fn() };
|
|
34
|
+
const outputSchema = { safeParse: vi.fn() };
|
|
35
|
+
const fn = vi.fn().mockResolvedValue( { ok: true } );
|
|
36
|
+
const options = { activityOptions: { startToCloseTimeout: '1m' } };
|
|
37
|
+
|
|
38
|
+
const wrapper = step( {
|
|
39
|
+
name: 'test_step',
|
|
40
|
+
description: 'Test step',
|
|
41
|
+
inputSchema,
|
|
42
|
+
outputSchema,
|
|
43
|
+
fn,
|
|
44
|
+
options
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
expect( validateDefinitionMock ).toHaveBeenCalledWith( {
|
|
48
|
+
name: 'test_step',
|
|
49
|
+
description: 'Test step',
|
|
50
|
+
inputSchema,
|
|
51
|
+
outputSchema,
|
|
52
|
+
fn,
|
|
53
|
+
options
|
|
54
|
+
} );
|
|
55
|
+
expect( validatorConstructorMock ).toHaveBeenCalledWith( {
|
|
56
|
+
name: 'test_step',
|
|
57
|
+
inputSchema,
|
|
58
|
+
outputSchema
|
|
59
|
+
} );
|
|
60
|
+
|
|
61
|
+
const [ metadataSymbol ] = Object.getOwnPropertySymbols( wrapper );
|
|
62
|
+
expect( wrapper[metadataSymbol] ).toEqual( {
|
|
63
|
+
name: 'test_step',
|
|
64
|
+
description: 'Test step',
|
|
65
|
+
inputSchema,
|
|
66
|
+
outputSchema,
|
|
67
|
+
type: ComponentType.STEP,
|
|
68
|
+
options
|
|
69
|
+
} );
|
|
70
|
+
} );
|
|
71
|
+
|
|
72
|
+
it( 'validates input and output around the step function', async () => {
|
|
73
|
+
const { step } = await import( './step.js' );
|
|
74
|
+
const output = { ok: true };
|
|
75
|
+
const fn = vi.fn().mockResolvedValue( output );
|
|
76
|
+
const wrapper = step( {
|
|
77
|
+
name: 'runtime_step',
|
|
78
|
+
inputSchema: undefined,
|
|
79
|
+
outputSchema: undefined,
|
|
80
|
+
fn
|
|
81
|
+
} );
|
|
82
|
+
|
|
83
|
+
await expect( wrapper( { value: 'input' } ) ).resolves.toBe( output );
|
|
84
|
+
|
|
85
|
+
expect( validateInputMock ).toHaveBeenCalledWith( { value: 'input' } );
|
|
86
|
+
expect( fn ).toHaveBeenCalledWith( { value: 'input' } );
|
|
87
|
+
expect( validateOutputMock ).toHaveBeenCalledWith( output );
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
it( 'does not call the step function when input validation throws', async () => {
|
|
91
|
+
const { step } = await import( './step.js' );
|
|
92
|
+
const error = new ValidationError( 'invalid input' );
|
|
93
|
+
validateInputMock.mockImplementationOnce( () => {
|
|
94
|
+
throw error;
|
|
95
|
+
} );
|
|
96
|
+
const fn = vi.fn();
|
|
97
|
+
const wrapper = step( {
|
|
98
|
+
name: 'invalid_input_step',
|
|
99
|
+
fn
|
|
100
|
+
} );
|
|
101
|
+
|
|
102
|
+
await expect( wrapper( { value: 'bad' } ) ).rejects.toBe( error );
|
|
103
|
+
expect( fn ).not.toHaveBeenCalled();
|
|
104
|
+
expect( validateOutputMock ).not.toHaveBeenCalled();
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
it( 'propagates output validation errors after the step function runs', async () => {
|
|
108
|
+
const { step } = await import( './step.js' );
|
|
109
|
+
const error = new ValidationError( 'invalid output' );
|
|
110
|
+
validateOutputMock.mockImplementationOnce( () => {
|
|
111
|
+
throw error;
|
|
112
|
+
} );
|
|
113
|
+
const output = { ok: false };
|
|
114
|
+
const fn = vi.fn().mockResolvedValue( output );
|
|
115
|
+
const wrapper = step( {
|
|
116
|
+
name: 'invalid_output_step',
|
|
117
|
+
fn
|
|
118
|
+
} );
|
|
119
|
+
|
|
120
|
+
await expect( wrapper( { value: 'input' } ) ).rejects.toBe( error );
|
|
121
|
+
expect( fn ).toHaveBeenCalledOnce();
|
|
122
|
+
expect( validateOutputMock ).toHaveBeenCalledWith( output );
|
|
123
|
+
} );
|
|
124
|
+
} );
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ValidationError } from '#errors';
|
|
2
|
+
import { prettifyError } from 'zod';
|
|
3
|
+
import {
|
|
4
|
+
evaluatorOutputSchema,
|
|
5
|
+
evaluatorSchema,
|
|
6
|
+
httpRequestSchema,
|
|
7
|
+
executeInParallelSchema,
|
|
8
|
+
stepSchema,
|
|
9
|
+
workflowInvocationOptionsSchema,
|
|
10
|
+
workflowSchema
|
|
11
|
+
} from './schemas.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates data using a Zod schema
|
|
15
|
+
* @param {unknown} data
|
|
16
|
+
* @param {ZodType} schema
|
|
17
|
+
* @param {string} prefix - Validation error prefix
|
|
18
|
+
* @throws {ValidationError} If validation fails
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
21
|
+
const validate = ( data, schema, prefix = '' ) => {
|
|
22
|
+
if ( !schema ) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result = schema.safeParse( data );
|
|
27
|
+
if ( !result.success ) {
|
|
28
|
+
throw new ValidationError( `${prefix} validation failed: ${prettifyError( result.error ) }` );
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class WorkflowValidator {
|
|
33
|
+
static validateDefinition( definition ) {
|
|
34
|
+
validate( definition, workflowSchema, 'Workflow' );
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor( { name, inputSchema, outputSchema } ) {
|
|
38
|
+
this.name = name;
|
|
39
|
+
this.inputSchema = inputSchema;
|
|
40
|
+
this.outputSchema = outputSchema;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
validateInput( input ) {
|
|
44
|
+
validate( input, this.inputSchema, `Workflow "${this.name}" input` );
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
validateOutput( output ) {
|
|
48
|
+
validate( output, this.outputSchema, `Workflow "${this.name}" output` );
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
validateInvocationOptions( options ) {
|
|
52
|
+
validate( options, workflowInvocationOptionsSchema, `Workflow "${this.name}" invocation options` );
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class StepValidator {
|
|
57
|
+
static validateDefinition( definition ) {
|
|
58
|
+
validate( definition, stepSchema, 'Step' );
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
constructor( { name, inputSchema, outputSchema } ) {
|
|
62
|
+
this.name = name;
|
|
63
|
+
this.inputSchema = inputSchema;
|
|
64
|
+
this.outputSchema = outputSchema;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
validateInput( input ) {
|
|
68
|
+
validate( input, this.inputSchema, `Step "${this.name}" input` );
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
validateOutput( output ) {
|
|
72
|
+
validate( output, this.outputSchema, `Step "${this.name}" output` );
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class EvaluatorValidator {
|
|
77
|
+
static validateDefinition( definition ) {
|
|
78
|
+
validate( definition, evaluatorSchema, 'Evaluator' );
|
|
79
|
+
}
|
|
80
|
+
constructor( { name, inputSchema } ) {
|
|
81
|
+
this.name = name;
|
|
82
|
+
this.inputSchema = inputSchema;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
validateInput( input ) {
|
|
86
|
+
validate( input, this.inputSchema, `Evaluator "${this.name}" input` );
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
validateOutput( output ) {
|
|
90
|
+
validate( output, evaluatorOutputSchema, `Evaluator "${this.name}" output` );
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Validate request payload
|
|
96
|
+
* @param {object} args - The request arguments
|
|
97
|
+
*/
|
|
98
|
+
export function validateRequestPayload( args ) {
|
|
99
|
+
validate( args, httpRequestSchema, 'Request payload' );
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Validate executeInParallel
|
|
104
|
+
* @param {object} args - The request arguments
|
|
105
|
+
*/
|
|
106
|
+
export function validateExecuteInParallel( args ) {
|
|
107
|
+
validate( args, executeInParallelSchema, 'ExecuteInParallel' );
|
|
108
|
+
};
|