poml 0.0.6 → 0.0.8
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.
- checksums.yaml +4 -4
- data/docs/tutorial/advanced/performance.md +695 -0
- data/docs/tutorial/advanced/tool-registration.md +776 -0
- data/docs/tutorial/basic-usage.md +351 -0
- data/docs/tutorial/components/chat-components.md +552 -0
- data/docs/tutorial/components/formatting.md +623 -0
- data/docs/tutorial/components/index.md +366 -0
- data/docs/tutorial/components/media-components.md +259 -0
- data/docs/tutorial/components/schema-components.md +668 -0
- data/docs/tutorial/index.md +185 -0
- data/docs/tutorial/output-formats.md +689 -0
- data/docs/tutorial/quickstart.md +30 -0
- data/docs/tutorial/template-engine.md +540 -0
- data/lib/poml/components/base.rb +146 -4
- data/lib/poml/components/content.rb +10 -3
- data/lib/poml/components/data.rb +539 -19
- data/lib/poml/components/examples.rb +235 -1
- data/lib/poml/components/formatting.rb +184 -18
- data/lib/poml/components/layout.rb +7 -2
- data/lib/poml/components/lists.rb +69 -35
- data/lib/poml/components/meta.rb +134 -5
- data/lib/poml/components/output_schema.rb +19 -1
- data/lib/poml/components/template.rb +72 -61
- data/lib/poml/components/text.rb +30 -1
- data/lib/poml/components/tool.rb +81 -0
- data/lib/poml/components/tool_definition.rb +339 -10
- data/lib/poml/components/tools.rb +14 -0
- data/lib/poml/components/utilities.rb +34 -18
- data/lib/poml/components.rb +19 -0
- data/lib/poml/context.rb +19 -4
- data/lib/poml/parser.rb +88 -63
- data/lib/poml/renderer.rb +191 -9
- data/lib/poml/template_engine.rb +138 -13
- data/lib/poml/version.rb +1 -1
- data/lib/poml.rb +16 -1
- data/readme.md +157 -30
- metadata +87 -4
- data/TUTORIAL.md +0 -987
@@ -0,0 +1,668 @@
|
|
1
|
+
# Schema Components
|
2
|
+
|
3
|
+
POML provides powerful schema components for defining structured AI responses and tool definitions that work across different AI platforms.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
Schema components allow you to define:
|
8
|
+
|
9
|
+
- **Output Schemas** - Structure for AI responses
|
10
|
+
- **Tool Definitions** - AI function calling capabilities
|
11
|
+
- **Metadata Integration** - Automatic inclusion in response metadata
|
12
|
+
|
13
|
+
## Output Schema Component
|
14
|
+
|
15
|
+
The `<output-schema>` component defines the expected structure of AI responses:
|
16
|
+
|
17
|
+
### Basic Usage
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'poml'
|
21
|
+
|
22
|
+
markup = <<~POML
|
23
|
+
<poml>
|
24
|
+
<role>Data Analyst</role>
|
25
|
+
<task>Analyze the provided dataset and generate insights</task>
|
26
|
+
|
27
|
+
<output-schema name="AnalysisResult">
|
28
|
+
{
|
29
|
+
"type": "object",
|
30
|
+
"properties": {
|
31
|
+
"insights": {
|
32
|
+
"type": "array",
|
33
|
+
"items": {"type": "string"},
|
34
|
+
"description": "Key insights from the data"
|
35
|
+
},
|
36
|
+
"confidence": {
|
37
|
+
"type": "number",
|
38
|
+
"minimum": 0,
|
39
|
+
"maximum": 1,
|
40
|
+
"description": "Confidence level of the analysis"
|
41
|
+
},
|
42
|
+
"recommendations": {
|
43
|
+
"type": "array",
|
44
|
+
"items": {"type": "string"},
|
45
|
+
"description": "Actionable recommendations"
|
46
|
+
}
|
47
|
+
},
|
48
|
+
"required": ["insights", "confidence"]
|
49
|
+
}
|
50
|
+
</output-schema>
|
51
|
+
</poml>
|
52
|
+
POML
|
53
|
+
|
54
|
+
result = Poml.process(markup: markup)
|
55
|
+
puts result['metadata']['schemas']
|
56
|
+
```
|
57
|
+
|
58
|
+
### Parser Attribute Support
|
59
|
+
|
60
|
+
POML supports both legacy `lang` and new `parser` attributes:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
# New syntax (recommended)
|
64
|
+
markup = <<~POML
|
65
|
+
<poml>
|
66
|
+
<role>Code Reviewer</role>
|
67
|
+
<task>Review code and provide feedback</task>
|
68
|
+
|
69
|
+
<output-schema name="CodeReview" parser="json">
|
70
|
+
{
|
71
|
+
"type": "object",
|
72
|
+
"properties": {
|
73
|
+
"issues": {
|
74
|
+
"type": "array",
|
75
|
+
"items": {
|
76
|
+
"type": "object",
|
77
|
+
"properties": {
|
78
|
+
"severity": {"type": "string", "enum": ["low", "medium", "high"]},
|
79
|
+
"description": {"type": "string"},
|
80
|
+
"line_number": {"type": "integer"}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
},
|
84
|
+
"overall_score": {
|
85
|
+
"type": "integer",
|
86
|
+
"minimum": 1,
|
87
|
+
"maximum": 10
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
</output-schema>
|
92
|
+
</poml>
|
93
|
+
POML
|
94
|
+
|
95
|
+
# Legacy syntax (still supported)
|
96
|
+
markup_legacy = <<~POML
|
97
|
+
<poml>
|
98
|
+
<output-schema name="CodeReview" lang="json">
|
99
|
+
<!-- Same JSON schema -->
|
100
|
+
</output-schema>
|
101
|
+
</poml>
|
102
|
+
POML
|
103
|
+
```
|
104
|
+
|
105
|
+
### Eval Parser for Dynamic Schemas
|
106
|
+
|
107
|
+
Use `parser="eval"` for dynamic schema generation:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
markup = <<~POML
|
111
|
+
<poml>
|
112
|
+
<role>Survey Analyst</role>
|
113
|
+
<task>Create survey response schema</task>
|
114
|
+
|
115
|
+
<output-schema name="SurveyResponse" parser="eval">
|
116
|
+
{
|
117
|
+
"type": "object",
|
118
|
+
"properties": {
|
119
|
+
{{#questions}}
|
120
|
+
"{{id}}": {
|
121
|
+
"type": "{{type}}",
|
122
|
+
"description": "{{description}}"
|
123
|
+
}{{#unless @last}},{{/unless}}
|
124
|
+
{{/questions}}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
</output-schema>
|
128
|
+
</poml>
|
129
|
+
POML
|
130
|
+
|
131
|
+
context = {
|
132
|
+
'questions' => [
|
133
|
+
{ 'id' => 'satisfaction', 'type' => 'integer', 'description' => 'Satisfaction rating 1-10' },
|
134
|
+
{ 'id' => 'feedback', 'type' => 'string', 'description' => 'Written feedback' },
|
135
|
+
{ 'id' => 'recommend', 'type' => 'boolean', 'description' => 'Would recommend?' }
|
136
|
+
]
|
137
|
+
}
|
138
|
+
|
139
|
+
result = Poml.process(markup: markup, context: context)
|
140
|
+
```
|
141
|
+
|
142
|
+
## Tool Definition Component
|
143
|
+
|
144
|
+
The `<tool-definition>` component defines AI tools and functions:
|
145
|
+
|
146
|
+
### Basic Tool Definition
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
markup = <<~POML
|
150
|
+
<poml>
|
151
|
+
<role>Database Assistant</role>
|
152
|
+
<task>Help with database queries and analysis</task>
|
153
|
+
|
154
|
+
<tool-definition name="execute_query">
|
155
|
+
{
|
156
|
+
"description": "Execute a SQL query on the database",
|
157
|
+
"parameters": {
|
158
|
+
"type": "object",
|
159
|
+
"properties": {
|
160
|
+
"query": {
|
161
|
+
"type": "string",
|
162
|
+
"description": "The SQL query to execute"
|
163
|
+
},
|
164
|
+
"database": {
|
165
|
+
"type": "string",
|
166
|
+
"description": "Database name",
|
167
|
+
"enum": ["users", "products", "orders"]
|
168
|
+
},
|
169
|
+
"limit": {
|
170
|
+
"type": "integer",
|
171
|
+
"description": "Maximum number of rows to return",
|
172
|
+
"default": 100,
|
173
|
+
"maximum": 1000
|
174
|
+
}
|
175
|
+
},
|
176
|
+
"required": ["query", "database"]
|
177
|
+
}
|
178
|
+
}
|
179
|
+
</tool-definition>
|
180
|
+
</poml>
|
181
|
+
POML
|
182
|
+
|
183
|
+
result = Poml.process(markup: markup)
|
184
|
+
puts result['tools'] # Tools are now at top level
|
185
|
+
```
|
186
|
+
|
187
|
+
### Multiple Tool Definitions
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
markup = <<~POML
|
191
|
+
<poml>
|
192
|
+
<role>Data Science Assistant</role>
|
193
|
+
<task>Perform data analysis and visualization</task>
|
194
|
+
|
195
|
+
<tool-definition name="load_dataset">
|
196
|
+
{
|
197
|
+
"description": "Load a dataset from file or URL",
|
198
|
+
"parameters": {
|
199
|
+
"type": "object",
|
200
|
+
"properties": {
|
201
|
+
"source": {"type": "string", "description": "File path or URL"},
|
202
|
+
"format": {"type": "string", "enum": ["csv", "json", "excel"]},
|
203
|
+
"encoding": {"type": "string", "default": "utf-8"}
|
204
|
+
},
|
205
|
+
"required": ["source", "format"]
|
206
|
+
}
|
207
|
+
}
|
208
|
+
</tool-definition>
|
209
|
+
|
210
|
+
<tool-definition name="create_visualization">
|
211
|
+
{
|
212
|
+
"description": "Create a data visualization chart",
|
213
|
+
"parameters": {
|
214
|
+
"type": "object",
|
215
|
+
"properties": {
|
216
|
+
"chart_type": {
|
217
|
+
"type": "string",
|
218
|
+
"enum": ["bar", "line", "scatter", "histogram", "pie"]
|
219
|
+
},
|
220
|
+
"x_column": {"type": "string"},
|
221
|
+
"y_column": {"type": "string"},
|
222
|
+
"title": {"type": "string"},
|
223
|
+
"color_scheme": {"type": "string", "default": "viridis"}
|
224
|
+
},
|
225
|
+
"required": ["chart_type", "x_column"]
|
226
|
+
}
|
227
|
+
}
|
228
|
+
</tool-definition>
|
229
|
+
</poml>
|
230
|
+
POML
|
231
|
+
|
232
|
+
result = Poml.process(markup: markup)
|
233
|
+
```
|
234
|
+
|
235
|
+
### Enhanced Tool Registration
|
236
|
+
|
237
|
+
POML supports enhanced tool registration with parameter conversion:
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
markup = <<~POML
|
241
|
+
<poml>
|
242
|
+
<role>API Integration Assistant</role>
|
243
|
+
<task>Help with API calls and data processing</task>
|
244
|
+
|
245
|
+
<tool-definition name="api-request" parser="json">
|
246
|
+
{
|
247
|
+
"description": "Make HTTP API request",
|
248
|
+
"parameters": {
|
249
|
+
"type": "object",
|
250
|
+
"properties": {
|
251
|
+
"http-method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE"]},
|
252
|
+
"endpoint-url": {"type": "string", "format": "uri"},
|
253
|
+
"request-headers": {"type": "object"},
|
254
|
+
"request-body": {"type": "object"},
|
255
|
+
"timeout-seconds": {"type": "integer", "default": 30},
|
256
|
+
"retry-attempts": {"type": "integer", "default": 3},
|
257
|
+
"follow-redirects": {"type": "boolean", "default": true}
|
258
|
+
},
|
259
|
+
"required": ["http-method", "endpoint-url"]
|
260
|
+
}
|
261
|
+
}
|
262
|
+
</tool-definition>
|
263
|
+
</poml>
|
264
|
+
POML
|
265
|
+
|
266
|
+
result = Poml.process(markup: markup)
|
267
|
+
|
268
|
+
# The enhanced tool registration will convert:
|
269
|
+
# "http-method" -> "httpMethod"
|
270
|
+
# "endpoint-url" -> "endpointUrl"
|
271
|
+
# "request-headers" -> "requestHeaders"
|
272
|
+
# "request-body" -> "requestBody"
|
273
|
+
# "timeout-seconds" -> "timeoutSeconds"
|
274
|
+
# "retry-attempts" -> "retryAttempts"
|
275
|
+
# "follow-redirects" -> "followRedirects"
|
276
|
+
```
|
277
|
+
|
278
|
+
## Legacy Meta Components
|
279
|
+
|
280
|
+
POML maintains backward compatibility with meta-based schema definitions:
|
281
|
+
|
282
|
+
### Meta Output Schema
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
markup = <<~POML
|
286
|
+
<poml>
|
287
|
+
<role>Report Generator</role>
|
288
|
+
<task>Generate performance report</task>
|
289
|
+
|
290
|
+
<meta type="output-schema" name="PerformanceReport">
|
291
|
+
{
|
292
|
+
"type": "object",
|
293
|
+
"properties": {
|
294
|
+
"metrics": {
|
295
|
+
"type": "object",
|
296
|
+
"properties": {
|
297
|
+
"response_time": {"type": "number"},
|
298
|
+
"throughput": {"type": "number"},
|
299
|
+
"error_rate": {"type": "number"}
|
300
|
+
}
|
301
|
+
},
|
302
|
+
"summary": {"type": "string"},
|
303
|
+
"recommendations": {
|
304
|
+
"type": "array",
|
305
|
+
"items": {"type": "string"}
|
306
|
+
}
|
307
|
+
}
|
308
|
+
}
|
309
|
+
</meta>
|
310
|
+
</poml>
|
311
|
+
POML
|
312
|
+
|
313
|
+
result = Poml.process(markup: markup)
|
314
|
+
```
|
315
|
+
|
316
|
+
### Meta Tool Definition
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
markup = <<~POML
|
320
|
+
<poml>
|
321
|
+
<role>File Manager</role>
|
322
|
+
<task>Manage files and directories</task>
|
323
|
+
|
324
|
+
<meta type="tool-definition" name="file_operations">
|
325
|
+
{
|
326
|
+
"description": "Perform file system operations",
|
327
|
+
"parameters": {
|
328
|
+
"type": "object",
|
329
|
+
"properties": {
|
330
|
+
"operation": {
|
331
|
+
"type": "string",
|
332
|
+
"enum": ["read", "write", "delete", "list", "move"]
|
333
|
+
},
|
334
|
+
"path": {"type": "string"},
|
335
|
+
"content": {"type": "string"},
|
336
|
+
"recursive": {"type": "boolean", "default": false}
|
337
|
+
},
|
338
|
+
"required": ["operation", "path"]
|
339
|
+
}
|
340
|
+
}
|
341
|
+
</meta>
|
342
|
+
</poml>
|
343
|
+
POML
|
344
|
+
```
|
345
|
+
|
346
|
+
## Template Variables in Schemas
|
347
|
+
|
348
|
+
Use template variables to create dynamic schemas:
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
markup = <<~POML
|
352
|
+
<poml>
|
353
|
+
<role>{{domain}} Expert</role>
|
354
|
+
<task>Analyze {{entity_type}} data</task>
|
355
|
+
|
356
|
+
<output-schema name="{{schema_name}}">
|
357
|
+
{
|
358
|
+
"type": "object",
|
359
|
+
"properties": {
|
360
|
+
"{{primary_metric}}": {
|
361
|
+
"type": "number",
|
362
|
+
"description": "Primary {{domain}} metric"
|
363
|
+
},
|
364
|
+
"categories": {
|
365
|
+
"type": "array",
|
366
|
+
"items": {
|
367
|
+
"type": "string",
|
368
|
+
"enum": [{{#categories}}"{{.}}"{{#unless @last}},{{/unless}}{{/categories}}]
|
369
|
+
}
|
370
|
+
},
|
371
|
+
"confidence": {
|
372
|
+
"type": "number",
|
373
|
+
"minimum": 0,
|
374
|
+
"maximum": 1
|
375
|
+
}
|
376
|
+
},
|
377
|
+
"required": ["{{primary_metric}}", "confidence"]
|
378
|
+
}
|
379
|
+
</output-schema>
|
380
|
+
</poml>
|
381
|
+
POML
|
382
|
+
|
383
|
+
context = {
|
384
|
+
'domain' => 'Marketing',
|
385
|
+
'entity_type' => 'campaign',
|
386
|
+
'schema_name' => 'CampaignAnalysis',
|
387
|
+
'primary_metric' => 'conversion_rate',
|
388
|
+
'categories' => ['email', 'social', 'paid', 'organic']
|
389
|
+
}
|
390
|
+
|
391
|
+
result = Poml.process(markup: markup, context: context)
|
392
|
+
```
|
393
|
+
|
394
|
+
## Complex Schema Patterns
|
395
|
+
|
396
|
+
### Nested Object Schemas
|
397
|
+
|
398
|
+
```ruby
|
399
|
+
markup = <<~POML
|
400
|
+
<poml>
|
401
|
+
<role>E-commerce Analyst</role>
|
402
|
+
<task>Analyze order data and customer behavior</task>
|
403
|
+
|
404
|
+
<output-schema name="OrderAnalysis">
|
405
|
+
{
|
406
|
+
"type": "object",
|
407
|
+
"properties": {
|
408
|
+
"order_summary": {
|
409
|
+
"type": "object",
|
410
|
+
"properties": {
|
411
|
+
"total_orders": {"type": "integer"},
|
412
|
+
"total_revenue": {"type": "number"},
|
413
|
+
"average_order_value": {"type": "number"},
|
414
|
+
"top_products": {
|
415
|
+
"type": "array",
|
416
|
+
"items": {
|
417
|
+
"type": "object",
|
418
|
+
"properties": {
|
419
|
+
"product_id": {"type": "string"},
|
420
|
+
"name": {"type": "string"},
|
421
|
+
"sales_count": {"type": "integer"},
|
422
|
+
"revenue": {"type": "number"}
|
423
|
+
}
|
424
|
+
}
|
425
|
+
}
|
426
|
+
}
|
427
|
+
},
|
428
|
+
"customer_insights": {
|
429
|
+
"type": "object",
|
430
|
+
"properties": {
|
431
|
+
"new_customers": {"type": "integer"},
|
432
|
+
"returning_customers": {"type": "integer"},
|
433
|
+
"customer_segments": {
|
434
|
+
"type": "array",
|
435
|
+
"items": {
|
436
|
+
"type": "object",
|
437
|
+
"properties": {
|
438
|
+
"segment_name": {"type": "string"},
|
439
|
+
"customer_count": {"type": "integer"},
|
440
|
+
"avg_order_value": {"type": "number"}
|
441
|
+
}
|
442
|
+
}
|
443
|
+
}
|
444
|
+
}
|
445
|
+
},
|
446
|
+
"recommendations": {
|
447
|
+
"type": "array",
|
448
|
+
"items": {
|
449
|
+
"type": "object",
|
450
|
+
"properties": {
|
451
|
+
"category": {"type": "string"},
|
452
|
+
"priority": {"type": "string", "enum": ["low", "medium", "high"]},
|
453
|
+
"action": {"type": "string"},
|
454
|
+
"expected_impact": {"type": "string"}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
},
|
459
|
+
"required": ["order_summary", "customer_insights", "recommendations"]
|
460
|
+
}
|
461
|
+
</output-schema>
|
462
|
+
</poml>
|
463
|
+
POML
|
464
|
+
```
|
465
|
+
|
466
|
+
### Conditional Schemas
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
markup = <<~POML
|
470
|
+
<poml>
|
471
|
+
<role>{{analysis_type}} Specialist</role>
|
472
|
+
<task>Perform {{analysis_type}} analysis</task>
|
473
|
+
|
474
|
+
<if condition="{{analysis_type}} == 'financial'">
|
475
|
+
<output-schema name="FinancialAnalysis">
|
476
|
+
{
|
477
|
+
"type": "object",
|
478
|
+
"properties": {
|
479
|
+
"revenue_metrics": {"type": "object"},
|
480
|
+
"cost_analysis": {"type": "object"},
|
481
|
+
"profitability": {"type": "number"},
|
482
|
+
"cash_flow": {"type": "array"}
|
483
|
+
}
|
484
|
+
}
|
485
|
+
</output-schema>
|
486
|
+
</if>
|
487
|
+
|
488
|
+
<if condition="{{analysis_type}} == 'technical'">
|
489
|
+
<output-schema name="TechnicalAnalysis">
|
490
|
+
{
|
491
|
+
"type": "object",
|
492
|
+
"properties": {
|
493
|
+
"performance_metrics": {"type": "object"},
|
494
|
+
"security_assessment": {"type": "object"},
|
495
|
+
"scalability_score": {"type": "number"},
|
496
|
+
"recommendations": {"type": "array"}
|
497
|
+
}
|
498
|
+
}
|
499
|
+
</output-schema>
|
500
|
+
</if>
|
501
|
+
</poml>
|
502
|
+
POML
|
503
|
+
```
|
504
|
+
|
505
|
+
## Integration with Output Formats
|
506
|
+
|
507
|
+
### OpenAI Response Format
|
508
|
+
|
509
|
+
```ruby
|
510
|
+
markup = <<~POML
|
511
|
+
<poml>
|
512
|
+
<role>Research Assistant</role>
|
513
|
+
<task>Summarize research findings</task>
|
514
|
+
|
515
|
+
<output-schema name="ResearchSummary">
|
516
|
+
{
|
517
|
+
"type": "object",
|
518
|
+
"properties": {
|
519
|
+
"key_findings": {"type": "array", "items": {"type": "string"}},
|
520
|
+
"methodology": {"type": "string"},
|
521
|
+
"confidence_level": {"type": "number"}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
</output-schema>
|
525
|
+
</poml>
|
526
|
+
POML
|
527
|
+
|
528
|
+
result = Poml.process(markup: markup, format: 'openaiResponse')
|
529
|
+
|
530
|
+
puts result['content'] # The prompt
|
531
|
+
puts result['metadata']['schemas'] # Schema definitions
|
532
|
+
```
|
533
|
+
|
534
|
+
### Pydantic Format
|
535
|
+
|
536
|
+
```ruby
|
537
|
+
result = Poml.process(markup: markup, format: 'pydantic')
|
538
|
+
|
539
|
+
puts result['schemas'] # Strict JSON schemas for Python
|
540
|
+
puts result['metadata']['python_compatibility'] # Python-specific info
|
541
|
+
```
|
542
|
+
|
543
|
+
## Validation and Error Handling
|
544
|
+
|
545
|
+
### Schema Validation
|
546
|
+
|
547
|
+
```ruby
|
548
|
+
def validate_schema_format(markup)
|
549
|
+
result = Poml.process(markup: markup)
|
550
|
+
schemas = result['metadata']['schemas']
|
551
|
+
|
552
|
+
schemas.each do |schema|
|
553
|
+
# Validate JSON schema format
|
554
|
+
begin
|
555
|
+
JSON.parse(schema['content']) if schema['content'].is_a?(String)
|
556
|
+
puts "✅ Schema '#{schema['name']}' is valid"
|
557
|
+
rescue JSON::ParserError => e
|
558
|
+
puts "❌ Schema '#{schema['name']}' has invalid JSON: #{e.message}"
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
```
|
563
|
+
|
564
|
+
### Tool Definition Validation
|
565
|
+
|
566
|
+
```ruby
|
567
|
+
def validate_tool_definitions(markup)
|
568
|
+
result = Poml.process(markup: markup)
|
569
|
+
tools = result['tools'] # Tools are now at top level
|
570
|
+
|
571
|
+
tools.each do |tool|
|
572
|
+
required_fields = ['description', 'parameters']
|
573
|
+
missing_fields = required_fields - tool.keys
|
574
|
+
|
575
|
+
if missing_fields.empty?
|
576
|
+
puts "✅ Tool '#{tool['name']}' is complete"
|
577
|
+
else
|
578
|
+
puts "❌ Tool '#{tool['name']}' missing: #{missing_fields.join(', ')}"
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
```
|
583
|
+
|
584
|
+
## Best Practices
|
585
|
+
|
586
|
+
### 1. Use Descriptive Schema Names
|
587
|
+
|
588
|
+
```ruby
|
589
|
+
# Good
|
590
|
+
<output-schema name="UserProfileAnalysis">
|
591
|
+
|
592
|
+
# Better
|
593
|
+
<output-schema name="UserBehaviorAnalysisResult">
|
594
|
+
```
|
595
|
+
|
596
|
+
### 2. Include Comprehensive Descriptions
|
597
|
+
|
598
|
+
```ruby
|
599
|
+
{
|
600
|
+
"type": "object",
|
601
|
+
"properties": {
|
602
|
+
"sentiment_score": {
|
603
|
+
"type": "number",
|
604
|
+
"minimum": -1,
|
605
|
+
"maximum": 1,
|
606
|
+
"description": "Sentiment analysis score where -1 is very negative, 0 is neutral, and 1 is very positive"
|
607
|
+
}
|
608
|
+
}
|
609
|
+
}
|
610
|
+
```
|
611
|
+
|
612
|
+
### 3. Use Validation Constraints
|
613
|
+
|
614
|
+
```ruby
|
615
|
+
{
|
616
|
+
"type": "object",
|
617
|
+
"properties": {
|
618
|
+
"email": {
|
619
|
+
"type": "string",
|
620
|
+
"format": "email",
|
621
|
+
"description": "Valid email address"
|
622
|
+
},
|
623
|
+
"age": {
|
624
|
+
"type": "integer",
|
625
|
+
"minimum": 0,
|
626
|
+
"maximum": 150,
|
627
|
+
"description": "Age in years"
|
628
|
+
},
|
629
|
+
"priority": {
|
630
|
+
"type": "string",
|
631
|
+
"enum": ["low", "medium", "high", "critical"],
|
632
|
+
"description": "Priority level"
|
633
|
+
}
|
634
|
+
}
|
635
|
+
}
|
636
|
+
```
|
637
|
+
|
638
|
+
### 4. Organize Complex Schemas
|
639
|
+
|
640
|
+
```ruby
|
641
|
+
# Break complex schemas into logical sections
|
642
|
+
{
|
643
|
+
"type": "object",
|
644
|
+
"properties": {
|
645
|
+
"user_data": {
|
646
|
+
"type": "object",
|
647
|
+
"description": "User profile information",
|
648
|
+
"properties": { /* user fields */ }
|
649
|
+
},
|
650
|
+
"analytics": {
|
651
|
+
"type": "object",
|
652
|
+
"description": "Analytics and metrics",
|
653
|
+
"properties": { /* analytics fields */ }
|
654
|
+
},
|
655
|
+
"metadata": {
|
656
|
+
"type": "object",
|
657
|
+
"description": "Processing metadata",
|
658
|
+
"properties": { /* metadata fields */ }
|
659
|
+
}
|
660
|
+
}
|
661
|
+
}
|
662
|
+
```
|
663
|
+
|
664
|
+
## Next Steps
|
665
|
+
|
666
|
+
- Learn about [Tool Registration](../advanced/tool-registration.md) for enhanced tool features
|
667
|
+
- Explore [Output Formats](../output-formats.md) for schema integration
|
668
|
+
- Check [Integration Examples](../integration/rails.md) for real-world usage
|