societyai 0.0.1
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/CHANGELOG.md +111 -0
- package/LICENSE +21 -0
- package/README.md +879 -0
- package/dist/builder.d.ts +181 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +667 -0
- package/dist/builder.js.map +1 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +107 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +319 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +85 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +219 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +395 -0
- package/dist/events.js.map +1 -0
- package/dist/graph.d.ts +104 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +366 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory.d.ts +146 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +353 -0
- package/dist/memory.js.map +1 -0
- package/dist/metrics.d.ts +143 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +271 -0
- package/dist/metrics.js.map +1 -0
- package/dist/middleware.d.ts +147 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +484 -0
- package/dist/middleware.js.map +1 -0
- package/dist/models.d.ts +32 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +211 -0
- package/dist/models.js.map +1 -0
- package/dist/patterns.d.ts +6 -0
- package/dist/patterns.d.ts.map +1 -0
- package/dist/patterns.js +68 -0
- package/dist/patterns.js.map +1 -0
- package/dist/pipeline.d.ts +84 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +569 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/retry.d.ts +5 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +70 -0
- package/dist/retry.js.map +1 -0
- package/dist/society.d.ts +94 -0
- package/dist/society.d.ts.map +1 -0
- package/dist/society.js +721 -0
- package/dist/society.js.map +1 -0
- package/dist/strategies.d.ts +55 -0
- package/dist/strategies.d.ts.map +1 -0
- package/dist/strategies.js +678 -0
- package/dist/strategies.js.map +1 -0
- package/dist/tools.d.ts +88 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +366 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +64 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +334 -0
- package/dist/validation.js.map +1 -0
- package/dist/worker-pool.d.ts +17 -0
- package/dist/worker-pool.d.ts.map +1 -0
- package/dist/worker-pool.js +80 -0
- package/dist/worker-pool.js.map +1 -0
- package/docs/README.md +468 -0
- package/docs/advanced.md +616 -0
- package/docs/aggregation-strategies.md +926 -0
- package/docs/api-reference.md +771 -0
- package/docs/architecture.md +648 -0
- package/docs/context-system.md +642 -0
- package/docs/event-system.md +1047 -0
- package/docs/examples.md +576 -0
- package/docs/getting-started.md +564 -0
- package/docs/graph-execution.md +389 -0
- package/docs/memory-system.md +497 -0
- package/docs/metrics-observability.md +560 -0
- package/docs/middleware-system.md +1038 -0
- package/docs/migration.md +296 -0
- package/docs/pipeline-patterns.md +761 -0
- package/docs/structured-output.md +612 -0
- package/docs/tool-calling.md +491 -0
- package/docs/workflows.md +740 -0
- package/examples/README.md +234 -0
- package/examples/advanced-patterns.ts +115 -0
- package/examples/complete-integration.ts +327 -0
- package/examples/graph-workflow.ts +161 -0
- package/examples/memory-system.ts +155 -0
- package/examples/metrics-tracking.ts +243 -0
- package/examples/structured-output.ts +231 -0
- package/examples/tool-calling.ts +163 -0
- package/package.json +94 -0
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# Structured Output Validation
|
|
2
|
+
|
|
3
|
+
The Structured Output Validation system ensures AI-generated outputs conform to expected JSON schemas with automatic validation, retry logic, and error feedback.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Structured Output Validation provides:
|
|
8
|
+
|
|
9
|
+
- **JSON Schema Validation**: Industry-standard schema validation
|
|
10
|
+
- **Automatic Retry**: Re-prompt agent with error feedback
|
|
11
|
+
- **Error Extraction**: Detailed validation error messages
|
|
12
|
+
- **Complex Schemas**: Support for nested objects, arrays, patterns, enums
|
|
13
|
+
- **Markdown Extraction**: Extract JSON from markdown code blocks
|
|
14
|
+
- **Type Constraints**: Validate types, ranges, lengths, patterns
|
|
15
|
+
- **Helper Functions**: Quick schema creation and validation
|
|
16
|
+
|
|
17
|
+
## Core Components
|
|
18
|
+
|
|
19
|
+
### StructuredOutputValidator
|
|
20
|
+
|
|
21
|
+
Main validation class:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { StructuredOutputValidator } from 'societyai';
|
|
25
|
+
|
|
26
|
+
const schema = {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
name: { type: 'string' },
|
|
30
|
+
age: { type: 'number', minimum: 0, maximum: 150 },
|
|
31
|
+
email: { type: 'string', format: 'email' },
|
|
32
|
+
},
|
|
33
|
+
required: ['name', 'age'],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const validator = new StructuredOutputValidator(schema);
|
|
37
|
+
|
|
38
|
+
// Validate JSON string
|
|
39
|
+
const result = validator.validate('{"name": "Alice", "age": 30}');
|
|
40
|
+
|
|
41
|
+
if (result.valid) {
|
|
42
|
+
console.log('Valid data:', result.data);
|
|
43
|
+
} else {
|
|
44
|
+
console.error('Validation errors:', result.errors);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### ValidationResult
|
|
49
|
+
|
|
50
|
+
Result of validation:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
interface ValidationResult {
|
|
54
|
+
valid: boolean; // Is valid?
|
|
55
|
+
data?: unknown; // Parsed data if valid
|
|
56
|
+
errors?: ValidationError[]; // Errors if invalid
|
|
57
|
+
errorMessage?: string; // Formatted error message
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface ValidationError {
|
|
61
|
+
path: string; // JSON path to error
|
|
62
|
+
message: string; // Error description
|
|
63
|
+
expected?: string; // Expected value/type
|
|
64
|
+
actual?: unknown; // Actual value
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## JSON Schema Support
|
|
69
|
+
|
|
70
|
+
### Basic Types
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const schema = {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
// String
|
|
77
|
+
name: { type: 'string' },
|
|
78
|
+
|
|
79
|
+
// Number
|
|
80
|
+
age: { type: 'number' },
|
|
81
|
+
|
|
82
|
+
// Integer
|
|
83
|
+
count: { type: 'integer' },
|
|
84
|
+
|
|
85
|
+
// Boolean
|
|
86
|
+
active: { type: 'boolean' },
|
|
87
|
+
|
|
88
|
+
// Null
|
|
89
|
+
deleted: { type: 'null' },
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Required Fields
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const schema = {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
username: { type: 'string' },
|
|
101
|
+
email: { type: 'string' },
|
|
102
|
+
},
|
|
103
|
+
required: ['username', 'email'], // Both required
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// This will fail
|
|
107
|
+
validator.validate('{"username": "alice"}');
|
|
108
|
+
// Error: Missing required property 'email'
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### String Constraints
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const schema = {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
username: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
minLength: 3,
|
|
120
|
+
maxLength: 20,
|
|
121
|
+
pattern: '^[a-zA-Z0-9_]+$', // Alphanumeric + underscore
|
|
122
|
+
},
|
|
123
|
+
email: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
format: 'email',
|
|
126
|
+
},
|
|
127
|
+
status: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
enum: ['active', 'inactive', 'pending'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Number Constraints
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const schema = {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
age: {
|
|
142
|
+
type: 'number',
|
|
143
|
+
minimum: 0,
|
|
144
|
+
maximum: 150,
|
|
145
|
+
},
|
|
146
|
+
rating: {
|
|
147
|
+
type: 'number',
|
|
148
|
+
minimum: 1,
|
|
149
|
+
maximum: 5,
|
|
150
|
+
multipleOf: 0.5, // 1, 1.5, 2, 2.5, ...
|
|
151
|
+
},
|
|
152
|
+
price: {
|
|
153
|
+
type: 'number',
|
|
154
|
+
exclusiveMinimum: 0, // Greater than 0, not equal
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Arrays
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const schema = {
|
|
164
|
+
type: 'object',
|
|
165
|
+
properties: {
|
|
166
|
+
tags: {
|
|
167
|
+
type: 'array',
|
|
168
|
+
items: { type: 'string' },
|
|
169
|
+
minItems: 1,
|
|
170
|
+
maxItems: 10,
|
|
171
|
+
uniqueItems: true,
|
|
172
|
+
},
|
|
173
|
+
coordinates: {
|
|
174
|
+
type: 'array',
|
|
175
|
+
items: { type: 'number' },
|
|
176
|
+
minItems: 2,
|
|
177
|
+
maxItems: 2, // Exactly 2 items
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Valid
|
|
183
|
+
validator.validate('{"tags": ["ai", "ml"], "coordinates": [10.5, 20.3]}');
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Nested Objects
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const schema = {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
user: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
properties: {
|
|
195
|
+
name: { type: 'string' },
|
|
196
|
+
address: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: {
|
|
199
|
+
street: { type: 'string' },
|
|
200
|
+
city: { type: 'string' },
|
|
201
|
+
zip: { type: 'string', pattern: '^\\d{5}$' },
|
|
202
|
+
},
|
|
203
|
+
required: ['city'],
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
required: ['name'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Enums
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const schema = {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
status: {
|
|
219
|
+
type: 'string',
|
|
220
|
+
enum: ['draft', 'published', 'archived'],
|
|
221
|
+
},
|
|
222
|
+
priority: {
|
|
223
|
+
type: 'number',
|
|
224
|
+
enum: [1, 2, 3],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Automatic Retry with Error Feedback
|
|
231
|
+
|
|
232
|
+
The `validateAndRetry` method automatically re-prompts the agent when validation fails:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import { StructuredOutputValidator, StandardModelBase } from 'societyai';
|
|
236
|
+
|
|
237
|
+
const schema = {
|
|
238
|
+
type: 'object',
|
|
239
|
+
properties: {
|
|
240
|
+
name: { type: 'string' },
|
|
241
|
+
age: { type: 'number' },
|
|
242
|
+
},
|
|
243
|
+
required: ['name', 'age'],
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const validator = new StructuredOutputValidator(schema);
|
|
247
|
+
|
|
248
|
+
class JSONGeneratorModel extends StandardModelBase {
|
|
249
|
+
constructor() {
|
|
250
|
+
super({ name: 'json-gen' }, async (prompt: unknown) => {
|
|
251
|
+
// AI generates JSON (might be invalid initially)
|
|
252
|
+
return '{"name": "Alice", "age": "30"}'; // age is string, should be number
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const model = new JSONGeneratorModel();
|
|
258
|
+
|
|
259
|
+
// Validates and retries up to 3 times
|
|
260
|
+
const result = await validator.validateAndRetry(
|
|
261
|
+
async (previousError?: string) => {
|
|
262
|
+
const prompt = previousError
|
|
263
|
+
? `Previous attempt had errors: ${previousError}\n\nPlease fix and try again.`
|
|
264
|
+
: 'Generate user JSON';
|
|
265
|
+
|
|
266
|
+
return await model.process(prompt);
|
|
267
|
+
},
|
|
268
|
+
3 // Max attempts
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (result.valid) {
|
|
272
|
+
console.log('Valid data:', result.data);
|
|
273
|
+
} else {
|
|
274
|
+
console.error('Failed after 3 attempts:', result.errorMessage);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Markdown Code Block Extraction
|
|
279
|
+
|
|
280
|
+
Automatically extract JSON from markdown:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
const validator = new StructuredOutputValidator(schema);
|
|
284
|
+
|
|
285
|
+
const markdown = `
|
|
286
|
+
Here's the user data:
|
|
287
|
+
|
|
288
|
+
\`\`\`json
|
|
289
|
+
{
|
|
290
|
+
"name": "Alice",
|
|
291
|
+
"age": 30
|
|
292
|
+
}
|
|
293
|
+
\`\`\`
|
|
294
|
+
`;
|
|
295
|
+
|
|
296
|
+
const result = validator.validate(markdown);
|
|
297
|
+
// Automatically extracts JSON from code block
|
|
298
|
+
console.log(result.data); // { name: "Alice", age: 30 }
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Helper Functions
|
|
302
|
+
|
|
303
|
+
### createSchema
|
|
304
|
+
|
|
305
|
+
Quick schema creation:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
import { createSchema } from 'societyai';
|
|
309
|
+
|
|
310
|
+
const schema = createSchema({
|
|
311
|
+
type: 'object',
|
|
312
|
+
properties: {
|
|
313
|
+
title: { type: 'string' },
|
|
314
|
+
count: { type: 'number' },
|
|
315
|
+
},
|
|
316
|
+
required: ['title'],
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### validateJSON
|
|
321
|
+
|
|
322
|
+
Direct validation without creating a validator:
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { validateJSON } from 'societyai';
|
|
326
|
+
|
|
327
|
+
const result = validateJSON('{"name": "Alice"}', {
|
|
328
|
+
type: 'object',
|
|
329
|
+
properties: {
|
|
330
|
+
name: { type: 'string' },
|
|
331
|
+
},
|
|
332
|
+
required: ['name'],
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Complete Example
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import {
|
|
340
|
+
StructuredOutputValidator,
|
|
341
|
+
StructuredOutputBuilder,
|
|
342
|
+
StandardModelBase,
|
|
343
|
+
} from 'societyai';
|
|
344
|
+
|
|
345
|
+
// Define user schema
|
|
346
|
+
const userSchema = {
|
|
347
|
+
type: 'object',
|
|
348
|
+
properties: {
|
|
349
|
+
username: {
|
|
350
|
+
type: 'string',
|
|
351
|
+
minLength: 3,
|
|
352
|
+
maxLength: 20,
|
|
353
|
+
pattern: '^[a-zA-Z0-9_]+$',
|
|
354
|
+
},
|
|
355
|
+
email: {
|
|
356
|
+
type: 'string',
|
|
357
|
+
format: 'email',
|
|
358
|
+
},
|
|
359
|
+
age: {
|
|
360
|
+
type: 'number',
|
|
361
|
+
minimum: 13,
|
|
362
|
+
maximum: 120,
|
|
363
|
+
},
|
|
364
|
+
interests: {
|
|
365
|
+
type: 'array',
|
|
366
|
+
items: { type: 'string' },
|
|
367
|
+
minItems: 1,
|
|
368
|
+
maxItems: 10,
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
required: ['username', 'email'],
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
// Create validator with builder
|
|
375
|
+
const validator = StructuredOutputBuilder.create()
|
|
376
|
+
.withSchema(userSchema)
|
|
377
|
+
.withMaxRetries(3)
|
|
378
|
+
.withStrictMode(true)
|
|
379
|
+
.build();
|
|
380
|
+
|
|
381
|
+
// AI model
|
|
382
|
+
class UserGenerator extends StandardModelBase {
|
|
383
|
+
private attempts = 0;
|
|
384
|
+
|
|
385
|
+
constructor() {
|
|
386
|
+
super({ name: 'user-gen' }, async (prompt: unknown) => {
|
|
387
|
+
this.attempts++;
|
|
388
|
+
|
|
389
|
+
if (this.attempts === 1) {
|
|
390
|
+
// First attempt: invalid (age is string)
|
|
391
|
+
return '{"username": "alice_123", "email": "alice@example.com", "age": "25"}';
|
|
392
|
+
} else {
|
|
393
|
+
// Second attempt: valid (after feedback)
|
|
394
|
+
return '{"username": "alice_123", "email": "alice@example.com", "age": 25, "interests": ["AI", "coding"]}';
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const model = new UserGenerator();
|
|
401
|
+
|
|
402
|
+
// Validate with automatic retry
|
|
403
|
+
const result = await validator.validateAndRetry(async (previousError?: string) => {
|
|
404
|
+
const prompt = previousError
|
|
405
|
+
? `Previous JSON was invalid:\n${previousError}\n\nPlease fix it.`
|
|
406
|
+
: 'Generate a user JSON object';
|
|
407
|
+
|
|
408
|
+
return await model.process(prompt);
|
|
409
|
+
}, 3);
|
|
410
|
+
|
|
411
|
+
if (result.valid) {
|
|
412
|
+
console.log('Valid user:', result.data);
|
|
413
|
+
// { username: "alice_123", email: "alice@example.com", age: 25, interests: ["AI", "coding"] }
|
|
414
|
+
} else {
|
|
415
|
+
console.error('Validation failed:', result.errorMessage);
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Error Messages
|
|
420
|
+
|
|
421
|
+
Detailed error messages help debug validation failures:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const result = validator.validate('{"name": "A", "age": -5}');
|
|
425
|
+
|
|
426
|
+
if (!result.valid) {
|
|
427
|
+
result.errors?.forEach((error) => {
|
|
428
|
+
console.log(`Path: ${error.path}`);
|
|
429
|
+
console.log(`Message: ${error.message}`);
|
|
430
|
+
console.log(`Expected: ${error.expected}`);
|
|
431
|
+
console.log(`Actual: ${error.actual}`);
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Output:
|
|
436
|
+
// Path: /name
|
|
437
|
+
// Message: String is too short (minimum length: 3)
|
|
438
|
+
// Expected: minLength: 3
|
|
439
|
+
// Actual: "A"
|
|
440
|
+
//
|
|
441
|
+
// Path: /age
|
|
442
|
+
// Message: Number is below minimum
|
|
443
|
+
// Expected: minimum: 0
|
|
444
|
+
// Actual: -5
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Integration with Agents
|
|
448
|
+
|
|
449
|
+
Create agents that always return valid JSON:
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
class ValidatedAgent extends StandardModelBase {
|
|
453
|
+
constructor(
|
|
454
|
+
private validator: StructuredOutputValidator,
|
|
455
|
+
name: string
|
|
456
|
+
) {
|
|
457
|
+
super({ name }, async (prompt: unknown) => {
|
|
458
|
+
// AI generates JSON
|
|
459
|
+
return this.generateJSON(prompt);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async process(prompt: unknown): Promise<string> {
|
|
464
|
+
// Validate and retry
|
|
465
|
+
const result = await this.validator.validateAndRetry(async (previousError?: string) => {
|
|
466
|
+
const enhancedPrompt = previousError
|
|
467
|
+
? `${prompt}\n\nPrevious attempt had errors: ${previousError}`
|
|
468
|
+
: prompt;
|
|
469
|
+
|
|
470
|
+
return await super.process(enhancedPrompt);
|
|
471
|
+
}, 3);
|
|
472
|
+
|
|
473
|
+
if (!result.valid) {
|
|
474
|
+
throw new Error(`Failed to generate valid JSON: ${result.errorMessage}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return JSON.stringify(result.data);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
private generateJSON(prompt: unknown): string {
|
|
481
|
+
// Implementation
|
|
482
|
+
return '{}';
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## Best Practices
|
|
488
|
+
|
|
489
|
+
1. **Clear Schemas**: Define precise schemas with all constraints
|
|
490
|
+
2. **Required Fields**: Always specify which fields are required
|
|
491
|
+
3. **Provide Examples**: Include example outputs in prompts
|
|
492
|
+
4. **Limit Retries**: Set reasonable max retries (2-3)
|
|
493
|
+
5. **Detailed Errors**: Use error feedback to help AI self-correct
|
|
494
|
+
6. **Test Schemas**: Validate your schemas with known good/bad data
|
|
495
|
+
7. **Version Schemas**: Track schema changes for compatibility
|
|
496
|
+
8. **Document Formats**: Provide format examples for complex types
|
|
497
|
+
|
|
498
|
+
## Common Patterns
|
|
499
|
+
|
|
500
|
+
### API Response Validation
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
const apiResponseSchema = {
|
|
504
|
+
type: 'object',
|
|
505
|
+
properties: {
|
|
506
|
+
status: {
|
|
507
|
+
type: 'string',
|
|
508
|
+
enum: ['success', 'error'],
|
|
509
|
+
},
|
|
510
|
+
data: {
|
|
511
|
+
type: 'object',
|
|
512
|
+
},
|
|
513
|
+
message: {
|
|
514
|
+
type: 'string',
|
|
515
|
+
},
|
|
516
|
+
timestamp: {
|
|
517
|
+
type: 'string',
|
|
518
|
+
format: 'date-time',
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
required: ['status'],
|
|
522
|
+
};
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### Form Validation
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
const formSchema = {
|
|
529
|
+
type: 'object',
|
|
530
|
+
properties: {
|
|
531
|
+
firstName: {
|
|
532
|
+
type: 'string',
|
|
533
|
+
minLength: 1,
|
|
534
|
+
},
|
|
535
|
+
lastName: {
|
|
536
|
+
type: 'string',
|
|
537
|
+
minLength: 1,
|
|
538
|
+
},
|
|
539
|
+
email: {
|
|
540
|
+
type: 'string',
|
|
541
|
+
format: 'email',
|
|
542
|
+
},
|
|
543
|
+
phone: {
|
|
544
|
+
type: 'string',
|
|
545
|
+
pattern: '^\\+?[0-9]{10,15}$',
|
|
546
|
+
},
|
|
547
|
+
acceptTerms: {
|
|
548
|
+
type: 'boolean',
|
|
549
|
+
const: true,
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
required: ['firstName', 'lastName', 'email', 'acceptTerms'],
|
|
553
|
+
};
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Analysis Results
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
const analysisSchema = {
|
|
560
|
+
type: 'object',
|
|
561
|
+
properties: {
|
|
562
|
+
summary: {
|
|
563
|
+
type: 'string',
|
|
564
|
+
minLength: 50,
|
|
565
|
+
},
|
|
566
|
+
sentiment: {
|
|
567
|
+
type: 'string',
|
|
568
|
+
enum: ['positive', 'negative', 'neutral'],
|
|
569
|
+
},
|
|
570
|
+
confidence: {
|
|
571
|
+
type: 'number',
|
|
572
|
+
minimum: 0,
|
|
573
|
+
maximum: 1,
|
|
574
|
+
},
|
|
575
|
+
keywords: {
|
|
576
|
+
type: 'array',
|
|
577
|
+
items: { type: 'string' },
|
|
578
|
+
minItems: 1,
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
required: ['summary', 'sentiment', 'confidence'],
|
|
582
|
+
};
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
## Integration with Graph
|
|
586
|
+
|
|
587
|
+
Use validated outputs in workflows:
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
const validator = new StructuredOutputValidator(schema);
|
|
591
|
+
|
|
592
|
+
const agent = AgentBuilder.create()
|
|
593
|
+
.withId('json-agent')
|
|
594
|
+
.withRole(role)
|
|
595
|
+
.withModel(new ValidatedModel(validator))
|
|
596
|
+
.build();
|
|
597
|
+
|
|
598
|
+
const graph = GraphBuilder.create()
|
|
599
|
+
.addNode('start', NodeType.START)
|
|
600
|
+
.addNode('generate', NodeType.AGENT, { agentId: 'json-agent' })
|
|
601
|
+
.addNode('end', NodeType.END)
|
|
602
|
+
.addEdge('start', 'generate')
|
|
603
|
+
.addEdge('generate', 'end')
|
|
604
|
+
.build();
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## Next Steps
|
|
608
|
+
|
|
609
|
+
- See [Memory System](./memory-system.md) for context management
|
|
610
|
+
- See [Tool Calling](./tool-calling.md) for external interactions
|
|
611
|
+
- See [Metrics](./metrics-observability.md) for tracking performance
|
|
612
|
+
- See [Examples](./examples.md) for complete implementations
|