@output.ai/core 0.0.15 → 0.1.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 (45) hide show
  1. package/bin/worker.sh +1 -1
  2. package/package.json +17 -10
  3. package/src/configs.js +1 -6
  4. package/src/configs.spec.js +2 -50
  5. package/src/consts.js +6 -8
  6. package/src/index.d.ts +169 -7
  7. package/src/index.js +18 -1
  8. package/src/interface/evaluator.js +146 -0
  9. package/src/interface/step.js +4 -9
  10. package/src/interface/{schema_utils.js → validations/runtime.js} +0 -14
  11. package/src/interface/validations/runtime.spec.js +29 -0
  12. package/src/interface/validations/schema_utils.js +8 -0
  13. package/src/interface/validations/static.js +13 -1
  14. package/src/interface/validations/static.spec.js +29 -1
  15. package/src/interface/webhook.js +16 -4
  16. package/src/interface/workflow.js +32 -54
  17. package/src/internal_activities/index.js +16 -12
  18. package/src/tracing/index.d.ts +47 -0
  19. package/src/tracing/index.js +154 -0
  20. package/src/tracing/index.private.spec.js +84 -0
  21. package/src/tracing/index.public.spec.js +86 -0
  22. package/src/tracing/tracer_tree.js +83 -0
  23. package/src/tracing/tracer_tree.spec.js +115 -0
  24. package/src/tracing/utils.js +21 -0
  25. package/src/tracing/utils.spec.js +14 -0
  26. package/src/worker/catalog_workflow/catalog.js +19 -10
  27. package/src/worker/index.js +1 -5
  28. package/src/worker/interceptors/activity.js +28 -10
  29. package/src/worker/interceptors/workflow.js +19 -1
  30. package/src/worker/loader.js +6 -6
  31. package/src/worker/loader.spec.js +6 -9
  32. package/src/worker/sinks.js +56 -10
  33. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +35 -4
  34. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +12 -4
  35. package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +5 -4
  36. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +13 -4
  37. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +16 -2
  38. package/src/worker/webpack_loaders/workflow_rewriter/tools.js +46 -13
  39. package/src/worker/webpack_loaders/workflow_rewriter/tools.spec.js +20 -2
  40. package/src/worker/tracer/index.js +0 -75
  41. package/src/worker/tracer/index.test.js +0 -103
  42. package/src/worker/tracer/tracer_tree.js +0 -84
  43. package/src/worker/tracer/tracer_tree.test.js +0 -115
  44. /package/src/{worker/async_storage.js → async_storage.js} +0 -0
  45. /package/src/interface/{schema_utils.spec.js → validations/schema_utils.spec.js} +0 -0
package/bin/worker.sh CHANGED
@@ -18,7 +18,7 @@ fi
18
18
  # Get the real script directory (should be node_modules/<pkg>/bin)
19
19
  script_dir="$(cd "$(dirname "$real_script")" && pwd)"
20
20
 
21
- # SDK dir is the parent (node_modules/flow-core)
21
+ # SDK dir is the parent (node_modules/output-core)
22
22
  sdk_dir="$(dirname "$script_dir")"
23
23
 
24
24
  cd ${sdk_dir}
package/package.json CHANGED
@@ -1,24 +1,28 @@
1
1
  {
2
2
  "name": "@output.ai/core",
3
- "version": "0.0.15",
3
+ "version": "0.1.0",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
- "main": "src/index.js",
7
- "types": "src/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./src/index.d.ts",
9
+ "import": "./src/index.js"
10
+ },
11
+ "./tracing": {
12
+ "types": "./src/tracing/index.d.ts",
13
+ "import": "./src/tracing/index.js"
14
+ }
15
+ },
8
16
  "files": [
9
17
  "./src",
10
18
  "./bin"
11
19
  ],
12
- "scripts": {
13
- "worker": "node ./src/worker/index.js"
14
- },
15
20
  "bin": {
16
- "flow-worker": "./bin/worker.sh",
21
+ "output-worker": "./bin/worker.sh",
17
22
  "outputai": "./bin/worker.sh"
18
23
  },
19
- "repository": {
20
- "type": "git",
21
- "url": "git+https://github.com/growthxai/flow-sdk"
24
+ "scripts": {
25
+ "worker": "node ./src/worker/index.js"
22
26
  },
23
27
  "dependencies": {
24
28
  "@babel/generator": "7.28.3",
@@ -29,10 +33,13 @@
29
33
  "@temporalio/workflow": "1.13.0",
30
34
  "zod": "4.1.9"
31
35
  },
36
+ "license": "UNLICENSED",
32
37
  "imports": {
33
38
  "#consts": "./src/consts.js",
34
39
  "#configs": "./src/configs.js",
35
40
  "#errors": "./src/errors.js",
41
+ "#tracing": "./src/tracing/index.js",
42
+ "#async_storage": "./src/async_storage.js",
36
43
  "#internal_activities": "./src/internal_activities/index.js"
37
44
  }
38
45
  }
package/src/configs.js CHANGED
@@ -7,8 +7,7 @@ const envVarSchema = z.object( {
7
7
  TEMPORAL_NAMESPACE: z.string().optional().default( 'default' ),
8
8
  TEMPORAL_API_KEY: z.string().optional(),
9
9
  CATALOG_ID: z.string().regex( /^[a-z0-9_.@-]+$/i ),
10
- API_AUTH_KEY: z.string().optional(),
11
- TRACING_ENABLED: z.stringbool().optional()
10
+ API_AUTH_KEY: z.string().optional()
12
11
  } );
13
12
 
14
13
  const { data: safeEnvVar, error } = envVarSchema.safeParse( process.env );
@@ -30,7 +29,3 @@ export const worker = {
30
29
  export const api = {
31
30
  authKey: safeEnvVar.API_AUTH_KEY
32
31
  };
33
-
34
- export const tracing = {
35
- enabled: safeEnvVar.TRACING_ENABLED
36
- };
@@ -181,38 +181,6 @@ describe( 'configs', () => {
181
181
  const { api } = await import( './configs.js' );
182
182
  expect( api.authKey ).toBeUndefined();
183
183
  } );
184
-
185
- it( 'should handle TRACING_ENABLED when true', async () => {
186
- process.env = {
187
- TEMPORAL_ADDRESS: 'http://localhost:7233',
188
- CATALOG_ID: 'test-catalog',
189
- TRACING_ENABLED: 'true'
190
- };
191
-
192
- const { tracing } = await import( './configs.js' );
193
- expect( tracing.enabled ).toBe( true );
194
- } );
195
-
196
- it( 'should handle TRACING_ENABLED when false', async () => {
197
- process.env = {
198
- TEMPORAL_ADDRESS: 'http://localhost:7233',
199
- CATALOG_ID: 'test-catalog',
200
- TRACING_ENABLED: 'false'
201
- };
202
-
203
- const { tracing } = await import( './configs.js' );
204
- expect( tracing.enabled ).toBe( false );
205
- } );
206
-
207
- it( 'should handle missing TRACING_ENABLED', async () => {
208
- process.env = {
209
- TEMPORAL_ADDRESS: 'http://localhost:7233',
210
- CATALOG_ID: 'test-catalog'
211
- };
212
-
213
- const { tracing } = await import( './configs.js' );
214
- expect( tracing.enabled ).toBeUndefined();
215
- } );
216
184
  } );
217
185
  } );
218
186
 
@@ -253,20 +221,6 @@ describe( 'configs', () => {
253
221
  } );
254
222
  } );
255
223
 
256
- it( 'should export tracing config', async () => {
257
- process.env = {
258
- TEMPORAL_ADDRESS: 'http://localhost:7233',
259
- CATALOG_ID: 'test-catalog',
260
- TRACING_ENABLED: 'true'
261
- };
262
-
263
- const { tracing } = await import( './configs.js' );
264
-
265
- expect( tracing ).toEqual( {
266
- enabled: true
267
- } );
268
- } );
269
-
270
224
  it( 'should have correct static worker config values', async () => {
271
225
  process.env = {
272
226
  TEMPORAL_ADDRESS: 'http://localhost:7233',
@@ -361,11 +315,10 @@ describe( 'configs', () => {
361
315
  TEMPORAL_NAMESPACE: 'production',
362
316
  TEMPORAL_API_KEY: 'prod-api-key-123',
363
317
  CATALOG_ID: 'prod.catalog@v1',
364
- API_AUTH_KEY: 'secure-auth-key',
365
- TRACING_ENABLED: 'true'
318
+ API_AUTH_KEY: 'secure-auth-key'
366
319
  };
367
320
 
368
- const { worker, api, tracing } = await import( './configs.js' );
321
+ const { worker, api } = await import( './configs.js' );
369
322
 
370
323
  expect( worker.address ).toBe( 'https://temporal.cloud.example.com' );
371
324
  expect( worker.namespace ).toBe( 'production' );
@@ -373,7 +326,6 @@ describe( 'configs', () => {
373
326
  expect( worker.catalogId ).toBe( 'prod.catalog@v1' );
374
327
  expect( worker.taskQueue ).toBe( 'prod.catalog@v1' );
375
328
  expect( api.authKey ).toBe( 'secure-auth-key' );
376
- expect( tracing.enabled ).toBe( true );
377
329
  } );
378
330
  } );
379
331
  } );
package/src/consts.js CHANGED
@@ -1,11 +1,9 @@
1
- export const SEND_WEBHOOK_ACTIVITY_NAME = '__internal#sendWebhookPost';
2
- export const READ_TRACE_FILE = '__internal#readTraceFile';
1
+ export const ACTIVITY_SEND_WEBHOOK = '__internal#sendWebhook';
2
+ export const ACTIVITY_READ_TRACE_FILE = '__internal#readTraceFile';
3
3
  export const METADATA_ACCESS_SYMBOL = Symbol( '__metadata' );
4
4
  export const WORKFLOWS_INDEX_FILENAME = '__workflows_entrypoint.js';
5
- export const THIS_LIB_NAME = 'core';
6
- export const TraceEvent = {
7
- WORKFLOW_START: 'workflow_start',
8
- WORKFLOW_END: 'workflow_end',
9
- STEP_START: 'step_start',
10
- STEP_END: 'step_end'
5
+ export const ComponentType = {
6
+ EVALUATOR: 'evaluator',
7
+ INTERNAL_STEP: 'internal_step',
8
+ STEP: 'step'
11
9
  };
package/src/index.d.ts CHANGED
@@ -19,6 +19,13 @@ export { z } from 'zod';
19
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
20
  type AnyZodSchema = z.ZodType<any, any, any>;
21
21
 
22
+ /*
23
+ ╭─────────╮
24
+ │ S T E P │╮
25
+ ╰─────────╯│
26
+ ╰─────────╯
27
+ */
28
+
22
29
  /*
23
30
  * There are 4 overloads of the "step" function:
24
31
  * - with fn receiving input and returning output;
@@ -28,7 +35,7 @@ type AnyZodSchema = z.ZodType<any, any, any>;
28
35
  */
29
36
 
30
37
  /**
31
- * Creates logical unit of work with Zod schemas for both input and output.
38
+ * Creates logical unit of work defined schema for both input and output.
32
39
  *
33
40
  * @param {object} options - Step options
34
41
  * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
@@ -50,7 +57,7 @@ export async function step<
50
57
  } ): ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>;
51
58
 
52
59
  /**
53
- * Creates logical unit of work with Zod schema for input only.
60
+ * Creates logical unit of work with defined schema for input only.
54
61
  *
55
62
  * @param {object} options - Step options
56
63
  * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
@@ -69,7 +76,7 @@ export async function step<
69
76
  } ): ( input: z.infer<InputSchema> ) => Promise<void>;
70
77
 
71
78
  /**
72
- * Creates logical unit of work with Zod schema for output only.
79
+ * Creates logical unit of work with defined schema for output only.
73
80
  *
74
81
  * @param {object} options - Step options
75
82
  * @param {string} options.name - Human-readable step name (only letters, numbers and "_")
@@ -102,6 +109,12 @@ export async function step( options: {
102
109
  fn: () => Promise<void>;
103
110
  } ): () => Promise<void>;
104
111
 
112
+ /*
113
+ ╭─────────────────╮
114
+ │ W O R K F L O W │╮
115
+ ╰─────────────────╯│
116
+ ╰─────────────────╯
117
+ */
105
118
  /*
106
119
  * There are 4 overloads of the "workflow" function:
107
120
  * - with fn receiving input and returning output;
@@ -111,7 +124,7 @@ export async function step( options: {
111
124
  */
112
125
 
113
126
  /**
114
- * Creates a workflow orchestrator with Zod schemas for both input and output.
127
+ * Creates a workflow orchestrator defined schema for both input and output.
115
128
  *
116
129
  * @param {object} options - Workflow options
117
130
  * @param {string} options.name - Unique workflow name
@@ -133,7 +146,7 @@ export function workflow<
133
146
  } ): ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>;
134
147
 
135
148
  /**
136
- * Creates a workflow orchestrator with Zod schema for input only.
149
+ * Creates a workflow orchestrator with defined schema for input only.
137
150
  *
138
151
  * @param {object} options - Workflow options
139
152
  * @param {string} options.name - Unique workflow name
@@ -152,7 +165,7 @@ export function workflow<
152
165
  } ): ( input: z.infer<InputSchema> ) => Promise<void>;
153
166
 
154
167
  /**
155
- * Creates a workflow orchestrator with Zod schema for output only.
168
+ * Creates a workflow orchestrator with defined schema for output only.
156
169
  *
157
170
  * @param {object} options - Workflow options
158
171
  * @param {string} options.name - Unique workflow name
@@ -171,7 +184,7 @@ export function workflow<
171
184
  } ): () => Promise<z.infer<OutputSchema>>;
172
185
 
173
186
  /**
174
- * Creates a workflow orchestrator without schemas.
187
+ * Creates a workflow orchestrator without defined schemas.
175
188
  *
176
189
  * @param {object} options - Workflow options
177
190
  * @param {string} options.name - Unique workflow name
@@ -185,6 +198,155 @@ export function workflow( options : {
185
198
  fn: () => Promise<void>
186
199
  } ): () => Promise<void>;
187
200
 
201
+ /*
202
+ ╭───────────────────╮
203
+ │ E V A L U A T O R │╮
204
+ ╰───────────────────╯│
205
+ ╰───────────────────╯
206
+ */
207
+
208
+ /**
209
+ * Generic EvaluationResult class, represents the result of an evaluation
210
+ */
211
+ class EvaluationResult {
212
+ /**
213
+ * @constructor
214
+ * @param {object} args
215
+ * @param {any} args.value - The value of the evaluation
216
+ * @param {number} args.confidence - The confidence on the evaluation
217
+ * @param {string} [args.reasoning] - The reasoning behind the result
218
+ */
219
+ constructor( args: { value: any; confidence: number; reasoning?: string } ); // eslint-disable-line @typescript-eslint/no-explicit-any
220
+
221
+ /**
222
+ * @returns {any} The evaluation result value
223
+ */
224
+
225
+ get value(): any; // eslint-disable-line @typescript-eslint/no-explicit-any
226
+
227
+ /**
228
+ * @returns {number} The evaluation result confidence
229
+ */
230
+ get confidence(): number;
231
+
232
+ /**
233
+ * @returns {string} The evaluation result reasoning
234
+ */
235
+ get reasoning(): string;
236
+ }
237
+
238
+ /**
239
+ * An evaluation result where the value is a string
240
+ * @extends EvaluationResult
241
+ */
242
+ export class EvaluationStringResult extends EvaluationResult {
243
+ /**
244
+ * @constructor
245
+ * @param {object} args
246
+ * @param {string} args.value - The value of the evaluation
247
+ * @param {number} args.confidence - The confidence on the evaluation
248
+ * @param {string} [args.reasoning] - The reasoning behind the result
249
+ */
250
+ constructor( args: { value: string; confidence: number; reasoning?: string } );
251
+
252
+ /**
253
+ * @returns {string} The evaluation result value
254
+ */
255
+ get value(): string;
256
+ }
257
+
258
+ /**
259
+ * An evaluation result where the value is a number
260
+ * @extends EvaluationResult
261
+ */
262
+ export class EvaluationNumberResult extends EvaluationResult {
263
+ /**
264
+ * @constructor
265
+ * @param {object} args
266
+ * @param {number} args.value - The value of the evaluation
267
+ * @param {number} args.confidence - The confidence on the evaluation
268
+ * @param {string} [args.reasoning] - The reasoning behind the result
269
+ */
270
+ constructor( args: { value: number; confidence: number; reasoning?: string } );
271
+
272
+ /**
273
+ * @returns {number} The evaluation result value
274
+ */
275
+ get value(): number;
276
+ }
277
+
278
+ /**
279
+ * An evaluation result where the value is a boolean
280
+ * @extends EvaluationResult
281
+ */
282
+ export class EvaluationBooleanResult extends EvaluationResult {
283
+ /**
284
+ * @constructor
285
+ * @param {object} args
286
+ * @param {boolean} args.value - The value of the evaluation
287
+ * @param {number} args.confidence - The confidence on the evaluation
288
+ * @param {string} [args.reasoning] - The reasoning behind the result
289
+ */
290
+ constructor( args: { value: boolean; confidence: number; reasoning?: string } );
291
+
292
+ /**
293
+ * @returns {boolean} The evaluation result value
294
+ */
295
+ get value(): boolean;
296
+ }
297
+
298
+ /*
299
+ * There are 2 overloads of the "evaluator" function:
300
+ * - with fn receiving input;
301
+ * - with fn receiving void;
302
+ */
303
+
304
+ /**
305
+ * Creates workflow evaluation of work defined schema for input.
306
+ *
307
+ * @param {object} options - Evaluator options
308
+ * @param {string} options.name - Human-readable evaluator name (only letters, numbers and "_")
309
+ * @param {string} [options.description] - Description of the evaluator
310
+ * @param {z.ZodType} options.inputSchema - Zod schema for the fn input
311
+ * @param {function} options.fn - The function logic: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
312
+ * @returns {function} Function with signature: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
313
+ */
314
+ export async function evaluator<
315
+ InputSchema extends AnyZodSchema,
316
+ Result extends EvaluationResult
317
+ >( options: {
318
+ name: string;
319
+ description?: string;
320
+ inputSchema: InputSchema;
321
+ fn: ( input: z.infer<InputSchema> ) => Promise<Result>;
322
+ } ): ( input: z.infer<InputSchema> ) => Promise<Result>;
323
+
324
+ /**
325
+ * Creates workflow evaluation without a defined input schema.
326
+ *
327
+ * @param {object} options - Evaluator options
328
+ * @param {string} options.name - Human-readable evaluator name (only letters, numbers and "_")
329
+ * @param {string} [options.description] - Description of the evaluator
330
+ * @param {z.ZodType} options.inputSchema - Zod schema for the fn input
331
+ * @param {function} options.fn - The function logic: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
332
+ * @returns {function} Function with signature: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
333
+ */
334
+ export async function evaluator<
335
+ InputSchema extends AnyZodSchema,
336
+ Result extends EvaluationResult
337
+ >( options: {
338
+ name: string;
339
+ description?: string;
340
+ fn: ( input: z.infer<InputSchema> ) => Promise<Result>;
341
+ } ): ( input: z.infer<InputSchema> ) => Promise<Result>;
342
+
343
+ /*
344
+ ╭───────────╮
345
+ │ O T H E R │╮
346
+ ╰───────────╯│
347
+ ╰───────────╯
348
+ */
349
+
188
350
  /**
189
351
  * Create a webhook call that pauses the workflow until resumed via signal.
190
352
  *
package/src/index.js CHANGED
@@ -1,7 +1,24 @@
1
+ import { evaluator, EvaluationStringResult, EvaluationNumberResult, EvaluationBooleanResult } from './interface/evaluator.js';
1
2
  import { step } from './interface/step.js';
2
3
  import { workflow } from './interface/workflow.js';
3
4
  import { createWebhook } from './interface/webhook.js';
4
5
  import { FatalError, ValidationError } from './errors.js';
5
6
  import { z } from 'zod';
6
7
 
7
- export { step, workflow, createWebhook, FatalError, ValidationError, z };
8
+ export {
9
+ // base building blocks
10
+ evaluator,
11
+ step,
12
+ workflow,
13
+ // Evaluation results
14
+ EvaluationNumberResult,
15
+ EvaluationStringResult,
16
+ EvaluationBooleanResult,
17
+ // webhook tool
18
+ createWebhook,
19
+ // errors
20
+ FatalError,
21
+ ValidationError,
22
+ // zod
23
+ z
24
+ };
@@ -0,0 +1,146 @@
1
+ import { setMetadata } from './metadata.js';
2
+ import { validateEvaluator } from './validations/static.js';
3
+ import { validateWithSchema } from './validations/runtime.js';
4
+ import { ValidationError } from '#errors';
5
+ import { ComponentType } from '#consts';
6
+ import * as z from 'zod';
7
+
8
+ /**
9
+ * Error for when EvaluationResult are invalid
10
+ */
11
+ class EvaluationResultValidationError extends ValidationError {};
12
+
13
+ /**
14
+ * Generic EvaluationResult class, represents the result
15
+ * of an evaluation
16
+ */
17
+ export class EvaluationResult {
18
+
19
+ /**
20
+ * Returns the evaluation result value
21
+ * @type {any}
22
+ */
23
+ value = null;
24
+
25
+ /**
26
+ * Returns the confidence value, between 0 and 1.
27
+ * @type {number}
28
+ */
29
+ confidence = undefined;
30
+
31
+ /**
32
+ * Returns the reasoning value.
33
+ * @type {string}
34
+ */
35
+ reasoning = undefined;
36
+
37
+ static #schema = z.object( {
38
+ value: z.any(),
39
+ confidence: z.number(),
40
+ reasoning: z.string().optional()
41
+ } );
42
+
43
+ /**
44
+ * @constructor
45
+ * @param {object} args
46
+ * @param {any} args.value - The value of the evaluation
47
+ * @param {number} args.confidence - The confidence on the evaluation
48
+ * @param {string} [args.reasoning] - The reasoning behind the result
49
+ */
50
+ constructor( args ) {
51
+ if ( !EvaluationResult.#schema.safeParse( args ) ) {
52
+ throw new EvaluationResultValidationError( z.prettifyError( result.error ) );
53
+ }
54
+ this.value = args.value;
55
+ this.confidence = args.confidence;
56
+ this.reasoning = args.reasoning;
57
+ }
58
+ };
59
+
60
+ /**
61
+ * An evaluation result that uses a string value
62
+ * @extends EvaluationResult
63
+ * @property {string} value - The evaluation result value
64
+ */
65
+ export class EvaluationStringResult extends EvaluationResult {
66
+ static #valueSchema = z.string();
67
+
68
+ /**
69
+ * @constructor
70
+ * @param {object} args
71
+ * @param {string} args.value - The value of the evaluation
72
+ * @param {number} args.confidence - The confidence on the evaluation
73
+ * @param {string} [args.reasoning] - The reasoning behind the result
74
+ */
75
+ constructor( args ) {
76
+ if ( !EvaluationStringResult.#valueSchema.safeParse( args.value ) ) {
77
+ throw new EvaluationResultValidationError( z.prettifyError( result.error ) );
78
+ }
79
+ super( args );
80
+ }
81
+ };
82
+
83
+ /**
84
+ * An evaluation result that uses a boolean value
85
+ * @extends EvaluationResult
86
+ * @property {boolean} value - The evaluation result value
87
+ */
88
+ export class EvaluationBooleanResult extends EvaluationResult {
89
+ static #valueSchema = z.boolean();
90
+
91
+ /**
92
+ * @constructor
93
+ * @param {object} args
94
+ * @param {boolean} args.value - The value of the evaluation
95
+ * @param {number} args.confidence - The confidence on the evaluation
96
+ * @param {string} [args.reasoning] - The reasoning behind the result
97
+ */
98
+ constructor( args ) {
99
+ if ( !EvaluationBooleanResult.#valueSchema.safeParse( args.value ) ) {
100
+ throw new EvaluationResultValidationError( z.prettifyError( result.error ) );
101
+ }
102
+ super( args );
103
+ }
104
+ };
105
+
106
+ /**
107
+ * An evaluation result that uses a number value
108
+ * @extends EvaluationResult
109
+ * @property {number} value - The evaluation result value
110
+ */
111
+ export class EvaluationNumberResult extends EvaluationResult {
112
+ static #valueSchema = z.number();
113
+
114
+ /**
115
+ * @constructor
116
+ * @param {object} args
117
+ * @param {number} args.value - The value of the evaluation
118
+ * @param {number} args.confidence - The confidence on the evaluation
119
+ * @param {string} [args.reasoning] - The reasoning behind the result
120
+ */
121
+ constructor( args ) {
122
+ if ( !EvaluationNumberResult.#valueSchema.safeParse( args.value ) ) {
123
+ throw new EvaluationResultValidationError( z.prettifyError( result.error ) );
124
+ }
125
+ super( args );
126
+ }
127
+ };
128
+
129
+ export function evaluator( { name, description, inputSchema, fn } ) {
130
+ validateEvaluator( { name, description, inputSchema, fn } );
131
+
132
+ const wrapper = async input => {
133
+ validateWithSchema( inputSchema, input, `Evaluator ${name} input` );
134
+
135
+ const output = await fn( input );
136
+
137
+ if ( !output instanceof EvaluationResult ) {
138
+ throw new ValidationError( 'Evaluators must return an EvaluationResult' );
139
+ }
140
+
141
+ return output;
142
+ };
143
+
144
+ setMetadata( wrapper, { name, description, inputSchema, type: ComponentType.EVALUATOR } );
145
+ return wrapper;
146
+ };
@@ -1,15 +1,10 @@
1
1
  import { setMetadata } from './metadata.js';
2
2
  import { validateStep } from './validations/static.js';
3
- import { validateWithSchema } from './schema_utils.js';
3
+ import { validateWithSchema } from './validations/runtime.js';
4
+ import { ComponentType } from '#consts';
4
5
 
5
6
  export function step( { name, description, inputSchema, outputSchema, fn } ) {
6
- validateStep( {
7
- name,
8
- description,
9
- inputSchema,
10
- outputSchema,
11
- fn
12
- } );
7
+ validateStep( { name, description, inputSchema, outputSchema, fn } );
13
8
 
14
9
  const wrapper = async input => {
15
10
  validateWithSchema( inputSchema, input, `Step ${name} input` );
@@ -21,6 +16,6 @@ export function step( { name, description, inputSchema, outputSchema, fn } ) {
21
16
  return output;
22
17
  };
23
18
 
24
- setMetadata( wrapper, { name, description, inputSchema, outputSchema } );
19
+ setMetadata( wrapper, { name, description, inputSchema, outputSchema, type: ComponentType.STEP } );
25
20
  return wrapper;
26
21
  };
@@ -1,18 +1,5 @@
1
1
  import { ValidationError } from '#errors';
2
2
 
3
- /**
4
- * Detects if a schema is a Zod schema object
5
- * @param {unknown} schema - The schema to check
6
- * @returns {boolean} True if the schema is a Zod schema
7
- */
8
- export function isZodSchema( schema ) {
9
- return schema &&
10
- typeof schema === 'object' &&
11
- '_def' in schema &&
12
- typeof schema.parse === 'function' &&
13
- typeof schema.parseAsync === 'function';
14
- }
15
-
16
3
  /**
17
4
  * Validates data against a Zod schema using safeParse
18
5
  * @param {unknown} schema - The Zod schema to validate against
@@ -31,4 +18,3 @@ export function validateWithSchema( schema, data, context ) {
31
18
  throw new ValidationError( `${context} validation failed: ${result.error.message}` );
32
19
  }
33
20
  }
34
-
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { validateWithSchema } from './runtime.js';
4
+ import { ValidationError } from '#errors';
5
+
6
+ describe( 'runtime validations', () => {
7
+ describe( 'validateWithSchema', () => {
8
+ it( 'no-ops when schema is falsy', () => {
9
+ expect( () => validateWithSchema( undefined, { a: 1 }, 'X' ) ).not.toThrow();
10
+ expect( () => validateWithSchema( null, { a: 1 }, 'X' ) ).not.toThrow();
11
+ } );
12
+
13
+ it( 'passes on valid data', () => {
14
+ const schema = z.object( { a: z.string(), b: z.number().optional() } );
15
+ expect( () => validateWithSchema( schema, { a: 'ok' }, 'Test' ) ).not.toThrow();
16
+ } );
17
+
18
+ it( 'throws ValidationError on invalid data and prefixes context', () => {
19
+ const schema = z.object( { a: z.string() } );
20
+ const call = () => validateWithSchema( schema, { a: 1 }, 'MyCtx' );
21
+ expect( call ).toThrow( ValidationError );
22
+ try {
23
+ call();
24
+ } catch ( e ) {
25
+ expect( String( e.message ) ).toContain( 'MyCtx validation failed:' );
26
+ }
27
+ } );
28
+ } );
29
+ } );
@@ -0,0 +1,8 @@
1
+ import { ZodType } from 'zod';
2
+
3
+ /**
4
+ * Detects if a schema is a ZodType instance
5
+ * @param {unknown} schema - The schema to check
6
+ * @returns {boolean} True if the schema is a Zod schema
7
+ */
8
+ export const isZodSchema = schema => schema instanceof ZodType;