@output.ai/core 0.0.13 → 0.0.15

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.
@@ -1,6 +1,26 @@
1
+ import { z } from 'zod';
1
2
  import { METADATA_ACCESS_SYMBOL } from '#consts';
2
3
  import { Catalog, CatalogActivity, CatalogWorkflow } from './catalog.js';
3
4
 
5
+ /**
6
+ * Converts a Zod schema to JSON Schema format.
7
+ *
8
+ * @param {any} schema - A zod schema
9
+ * @returns {object|null} JSON Schema object, or null if schema is invalid
10
+ */
11
+ const convertToJsonSchema = schema => {
12
+ if ( !schema ) {
13
+ return null;
14
+ }
15
+
16
+ try {
17
+ return z.toJSONSchema( schema );
18
+ } catch ( error ) {
19
+ console.warn( 'Invalid schema provided (expected Zod schema):', schema, error );
20
+ return null;
21
+ }
22
+ };
23
+
4
24
  /**
5
25
  * Converts the list of workflows and the activities into the catalog information.
6
26
  *
@@ -14,8 +34,17 @@ export const createCatalog = ( { workflows, activities } ) =>
14
34
  workflows.reduce( ( catalog, workflow ) =>
15
35
  catalog.addWorkflow( new CatalogWorkflow( {
16
36
  ...workflow,
37
+ inputSchema: convertToJsonSchema( workflow.inputSchema ),
38
+ outputSchema: convertToJsonSchema( workflow.outputSchema ),
17
39
  activities: Object.entries( activities )
18
40
  .filter( ( [ k ] ) => k.startsWith( `${workflow.path}#` ) )
19
- .map( ( [ _, v ] ) => new CatalogActivity( v[METADATA_ACCESS_SYMBOL] ) )
41
+ .map( ( [ _, v ] ) => {
42
+ const metadata = v[METADATA_ACCESS_SYMBOL];
43
+ return new CatalogActivity( {
44
+ ...metadata,
45
+ inputSchema: convertToJsonSchema( metadata.inputSchema ),
46
+ outputSchema: convertToJsonSchema( metadata.outputSchema )
47
+ } );
48
+ } )
20
49
  } ) )
21
50
  , new Catalog() );
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
+ import { z } from 'zod';
2
3
 
3
4
  // Provide the same symbol to the module under test and to the test
4
5
  const METADATA_ACCESS_SYMBOL = Symbol( '__metadata' );
@@ -19,16 +20,16 @@ describe( 'createCatalog', () => {
19
20
  path: '/flows/flow1',
20
21
  pathname: '/flows/flow1/workflow.js',
21
22
  description: 'desc-flow1',
22
- inputSchema: { in: 'f1' },
23
- outputSchema: { out: 'f1' }
23
+ inputSchema: z.object( { in: z.literal( 'f1' ) } ),
24
+ outputSchema: z.object( { out: z.literal( 'f1' ) } )
24
25
  },
25
26
  {
26
27
  name: 'flow2',
27
28
  path: '/flows/flow2',
28
29
  pathname: '/flows/flow2/workflow.js',
29
30
  description: 'desc-flow2',
30
- inputSchema: { in: 'f2' },
31
- outputSchema: { out: 'f2' }
31
+ inputSchema: z.object( { in: z.literal( 'f2' ) } ),
32
+ outputSchema: z.object( { out: z.literal( 'f2' ) } )
32
33
  }
33
34
  ];
34
35
 
@@ -37,8 +38,8 @@ describe( 'createCatalog', () => {
37
38
  name: 'A1',
38
39
  path: '/flows/flow1#A1',
39
40
  description: 'desc-a1',
40
- inputSchema: { in: 'a1' },
41
- outputSchema: { out: 'a1' }
41
+ inputSchema: z.object( { in: z.literal( 'a1' ) } ),
42
+ outputSchema: z.object( { out: z.literal( 'a1' ) } )
42
43
  } );
43
44
 
44
45
  const activity2 = () => {};
@@ -46,8 +47,8 @@ describe( 'createCatalog', () => {
46
47
  name: 'A2',
47
48
  path: '/flows/flow1#A2',
48
49
  description: 'desc-a2',
49
- inputSchema: { in: 'a2' },
50
- outputSchema: { out: 'a2' }
50
+ inputSchema: z.object( { in: z.literal( 'a2' ) } ),
51
+ outputSchema: z.object( { out: z.literal( 'a2' ) } )
51
52
  } );
52
53
 
53
54
  const activity3 = () => {};
@@ -55,8 +56,8 @@ describe( 'createCatalog', () => {
55
56
  name: 'B1',
56
57
  path: '/flows/flow2#B1',
57
58
  description: 'desc-b1',
58
- inputSchema: { in: 'b1' },
59
- outputSchema: { out: 'b1' }
59
+ inputSchema: z.object( { in: z.literal( 'b1' ) } ),
60
+ outputSchema: z.object( { out: z.literal( 'b1' ) } )
60
61
  } );
61
62
 
62
63
  const activity4 = () => {};
@@ -64,8 +65,8 @@ describe( 'createCatalog', () => {
64
65
  name: 'X',
65
66
  path: '/other#X',
66
67
  description: 'desc-x',
67
- inputSchema: { in: 'x' },
68
- outputSchema: { out: 'x' }
68
+ inputSchema: z.object( { in: z.literal( 'x' ) } ),
69
+ outputSchema: z.object( { out: z.literal( 'x' ) } )
69
70
  } );
70
71
 
71
72
  const activities = {
@@ -96,20 +97,56 @@ describe( 'createCatalog', () => {
96
97
  name: 'flow1',
97
98
  path: '/flows/flow1',
98
99
  description: 'desc-flow1',
99
- inputSchema: { in: 'f1' },
100
- outputSchema: { out: 'f1' },
100
+ inputSchema: {
101
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
102
+ type: 'object',
103
+ properties: { in: { type: 'string', const: 'f1' } },
104
+ required: [ 'in' ],
105
+ additionalProperties: false
106
+ },
107
+ outputSchema: {
108
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
109
+ type: 'object',
110
+ properties: { out: { type: 'string', const: 'f1' } },
111
+ required: [ 'out' ],
112
+ additionalProperties: false
113
+ },
101
114
  activities: [
102
115
  {
103
116
  name: 'A1',
104
117
  description: 'desc-a1',
105
- inputSchema: { in: 'a1' },
106
- outputSchema: { out: 'a1' }
118
+ inputSchema: {
119
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
120
+ type: 'object',
121
+ properties: { in: { type: 'string', const: 'a1' } },
122
+ required: [ 'in' ],
123
+ additionalProperties: false
124
+ },
125
+ outputSchema: {
126
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
127
+ type: 'object',
128
+ properties: { out: { type: 'string', const: 'a1' } },
129
+ required: [ 'out' ],
130
+ additionalProperties: false
131
+ }
107
132
  },
108
133
  {
109
134
  name: 'A2',
110
135
  description: 'desc-a2',
111
- inputSchema: { in: 'a2' },
112
- outputSchema: { out: 'a2' }
136
+ inputSchema: {
137
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
138
+ type: 'object',
139
+ properties: { in: { type: 'string', const: 'a2' } },
140
+ required: [ 'in' ],
141
+ additionalProperties: false
142
+ },
143
+ outputSchema: {
144
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
145
+ type: 'object',
146
+ properties: { out: { type: 'string', const: 'a2' } },
147
+ required: [ 'out' ],
148
+ additionalProperties: false
149
+ }
113
150
  }
114
151
  ]
115
152
  },
@@ -117,14 +154,38 @@ describe( 'createCatalog', () => {
117
154
  name: 'flow2',
118
155
  path: '/flows/flow2',
119
156
  description: 'desc-flow2',
120
- inputSchema: { in: 'f2' },
121
- outputSchema: { out: 'f2' },
157
+ inputSchema: {
158
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
159
+ type: 'object',
160
+ properties: { in: { type: 'string', const: 'f2' } },
161
+ required: [ 'in' ],
162
+ additionalProperties: false
163
+ },
164
+ outputSchema: {
165
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
166
+ type: 'object',
167
+ properties: { out: { type: 'string', const: 'f2' } },
168
+ required: [ 'out' ],
169
+ additionalProperties: false
170
+ },
122
171
  activities: [
123
172
  {
124
173
  name: 'B1',
125
174
  description: 'desc-b1',
126
- inputSchema: { in: 'b1' },
127
- outputSchema: { out: 'b1' }
175
+ inputSchema: {
176
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
177
+ type: 'object',
178
+ properties: { in: { type: 'string', const: 'b1' } },
179
+ required: [ 'in' ],
180
+ additionalProperties: false
181
+ },
182
+ outputSchema: {
183
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
184
+ type: 'object',
185
+ properties: { out: { type: 'string', const: 'b1' } },
186
+ required: [ 'out' ],
187
+ additionalProperties: false
188
+ }
128
189
  }
129
190
  ]
130
191
  }
@@ -1,3 +0,0 @@
1
- import Ajv from 'ajv';
2
-
3
- export const ajv = new Ajv();
@@ -1,69 +0,0 @@
1
- import { FatalError } from '#errors';
2
- import { ajv } from './ajv_provider.js';
3
-
4
- /**
5
- * Error type for when the input/output of a step/workflow doesn't match its input/output schema, respectively
6
- */
7
- export class MismatchSchemaError extends FatalError {}
8
- /**
9
- * Error type for when the input of a step/workflow doesn't match its input schema
10
- * @extends MismatchSchemaError
11
- */
12
- export class InvalidInputError extends MismatchSchemaError {}
13
- /**
14
- * Error type for when the output of a step/workflow doesn't match its output schema
15
- * @extends MismatchSchemaError
16
- */
17
- export class InvalidOutputError extends MismatchSchemaError {}
18
-
19
- const validate = ( ErrorClass, type, name, schema, payload ) => {
20
- const validate = ajv.compile( schema );
21
- const valid = validate( payload );
22
-
23
- if ( !valid ) {
24
- throw new ErrorClass( `Invalid input at ${type} "${name}": ${ajv.errorsText( validate.errors )}` );
25
- }
26
- };
27
-
28
- const validateInput = validate.bind( null, InvalidInputError );
29
- const validateOutput = validate.bind( null, InvalidOutputError );
30
-
31
- /**
32
- * Validates step input
33
- *
34
- * @param {name} name - step's name
35
- * @param {object} schema - step's input schema
36
- * @param {any} - the input to validate
37
- * @throws InvalidInputError
38
- */
39
- export const validateStepInput = validateInput.bind( null, 'step' );
40
-
41
- /**
42
- * Validates step output
43
- *
44
- * @param {name} name - step's name
45
- * @param {object} schema - step's output schema
46
- * @param {any} - the output to validate
47
- * @throws InvalidOutputError
48
- */
49
- export const validateStepOutput = validateOutput.bind( null, 'step' );
50
-
51
- /**
52
- * Validates workflow input
53
- *
54
- * @param {name} name - workflow's name
55
- * @param {object} schema - workflow's input schema
56
- * @param {any} - the input to validate
57
- * @throws InvalidInputError
58
- */
59
- export const validateWorkflowInput = validateInput.bind( null, 'workflow' );
60
-
61
- /**
62
- * Validates workflow output
63
- *
64
- * @param {name} name - workflow's name
65
- * @param {object} schema - workflow's output schema
66
- * @param {any} - the output to validate
67
- * @throws InvalidOutputError
68
- */
69
- export const validateWorkflowOutput = validateOutput.bind( null, 'workflow' );
@@ -1,50 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { validateStepInput, validateWorkflowInput, InvalidInputError } from './runtime.js';
3
-
4
- describe( 'Runtime validations spec', () => {
5
- describe( 'validateStepInput', () => {
6
- it( 'passes with matching payload', () => {
7
- const schema = {
8
- type: 'object',
9
- properties: { id: { type: 'string' }, count: { type: 'integer', minimum: 0 } },
10
- required: [ 'id' ],
11
- additionalProperties: false
12
- };
13
- expect( () => validateStepInput( 'myStep', schema, { id: 'x', count: 2 } ) ).not.toThrow();
14
- } );
15
-
16
- it( 'rejects invalid payload', () => {
17
- const schema = {
18
- type: 'object',
19
- properties: { id: { type: 'string' }, count: { type: 'integer', minimum: 0 } },
20
- required: [ 'id' ],
21
- additionalProperties: false
22
- };
23
- const error = new InvalidInputError( 'Invalid input at step "myStep": data must have required property \'id\'' );
24
- expect( () => validateStepInput( 'myStep', schema, { count: -1 } ) ).toThrow( error );
25
- } );
26
- } );
27
-
28
- describe( 'validateWorkflowInput', () => {
29
- it( 'passes with matching payload', () => {
30
- const schema = {
31
- type: 'object',
32
- properties: { name: { type: 'string' }, enabled: { type: 'boolean' } },
33
- required: [ 'name' ],
34
- additionalProperties: false
35
- };
36
- expect( () => validateWorkflowInput( 'myWorkflow', schema, { name: 'wf', enabled: true } ) ).not.toThrow();
37
- } );
38
-
39
- it( 'rejects invalid payload', () => {
40
- const schema = {
41
- type: 'object',
42
- properties: { name: { type: 'string' }, enabled: { type: 'boolean' } },
43
- required: [ 'name' ],
44
- additionalProperties: false
45
- };
46
- const error = new InvalidInputError( 'Invalid input at workflow "myWorkflow": data must have required property \'name\'' );
47
- expect( () => validateWorkflowInput( 'myWorkflow', schema, { enabled: 'yes' } ) ).toThrow( error );
48
- } );
49
- } );
50
- } );