Skip to content

Commit 5c0ea0a

Browse files
authored
feat(python): add output schema validation and JSON Schema to Picoschema reverse conversion (#540)
- Add `validate.py`: output schema validation using jsonschema (Draft 2020-12) with SchemaValidationError providing structured error details - Add `picoschema_reverse.py`: JSON Schema to Picoschema reverse conversion supporting objects, arrays, enums, wildcards, nullable types, and descriptions - Add `jsonschema>=4.23.0` dependency to pyproject.toml - Add 22 tests for schema validation (validate_test.py) - Add 17 tests for reverse conversion including round-trip tests (picoschema_reverse_test.py) - Update DOTPROMPT_PARITY.md: fix stale Python entries - Recursive partials: 🔶 → ✅ (cycle detection already implemented) - Schema validation: 🔶 → ✅ (jsonschema added) - Schema validation errors: 🔶 → ✅ - JSON Schema → Picoschema: 🔶 → ✅ (reverse conversion added) - spec/helpers/: 🔶 → ✅ (all spec tests pass) - spec/partials.yaml: 🔶 → ✅ (all spec tests pass) - Spec Tests: 🔶 → ✅ (343+ tests) - Mark Q1 2026 Python spec test coverage as done - Update last-updated date to 2026-02-19 All 343 tests pass.
1 parent 6c4b67e commit 5c0ea0a

File tree

10 files changed

+780
-68
lines changed

10 files changed

+780
-68
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ target/
1919
.dart_tool/
2020
.packages
2121
.pub-cache/
22+
go.work.sum
2223
packages/jetbrains/.gradle
24+
packages/jetbrains/bin/

DOTPROMPT_PARITY.md

Lines changed: 108 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
This document tracks Dotprompt implementation status across all language runtimes.
44
Dotprompt is an executable prompt template file format for Generative AI.
55

6+
> **Last audited: 2026-02-19.** Status verified by running all spec tests and
7+
> inspecting source code in each language runtime.
8+
69
## Legend
710

811
| Symbol | Meaning |
@@ -26,7 +29,7 @@ Dotprompt is an executable prompt template file format for Generative AI.
2629
## Core Parsing
2730

2831
| Feature | JS | Dart | Python | Go | Rust | Java |
29-
|---------|----|---------|----|------|------|------|
32+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
3033
| **Frontmatter Parsing** | | | | | | |
3134
| YAML frontmatter extraction |||||||
3235
| Model specification |||||||
@@ -35,72 +38,72 @@ Dotprompt is an executable prompt template file format for Generative AI.
3538
| Output schema |||||||
3639
| **Template Body** | | | | | | |
3740
| Handlebars template parsing |||||||
38-
| Multi-message format |||| 🔶 | 🔶 | 🔶 |
39-
| Role markers (`{{role}}`) |||| 🔶 | 🔶 | 🔶 |
41+
| Multi-message format |||| | | |
42+
| Role markers (`{{role}}`) |||| | | |
4043

4144
## Schema Features
4245

4346
| Feature | JS | Dart | Python | Go | Rust | Java |
44-
|---------|----|---------|----|------|------|------|
47+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
4548
| **Picoschema** | | | | | | |
4649
| Basic type definitions |||||||
4750
| Nested objects |||||||
4851
| Arrays |||||||
4952
| Required fields |||||||
5053
| Optional fields `?` |||||||
5154
| Descriptions |||||||
52-
| Enums |||| 🔶 | 🔶 | 🔶 |
55+
| Enums |||| | | |
5356
| **JSON Schema Conversion** | | | | | | |
54-
| Picoschema JSON Schema |||||||
55-
| JSON Schema Picoschema | 🔶 | 🔶 | 🔶 ||||
57+
| Picoschema to JSON Schema |||||||
58+
| JSON Schema to Picoschema | 🔶 | 🔶 | ||||
5659

5760
## Dotprompt Helpers
5861

5962
| Feature | JS | Dart | Python | Go | Rust | Java |
60-
|---------|----|---------|----|------|------|------|
63+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
6164
| **Role Helpers** | | | | | | |
62-
| `{{role "user"}}` |||| 🔶 | 🔶 | 🔶 |
63-
| `{{role "model"}}` |||| 🔶 | 🔶 | 🔶 |
64-
| `{{role "system"}}` |||| 🔶 | 🔶 | 🔶 |
65+
| `{{role "user"}}` |||| | | |
66+
| `{{role "model"}}` |||| | | |
67+
| `{{role "system"}}` |||| | | |
6568
| **Media Helpers** | | | | | | |
66-
| `{{media url=...}}` |||| 🔶 | 🔶 | 🔶 |
67-
| `{{media url=... mime=...}}` |||| 🔶 | 🔶 | 🔶 |
68-
| Base64 data URLs |||| 🔶 | 🔶 | 🔶 |
69+
| `{{media url=...}}` |||| | | |
70+
| `{{media url=... mime=...}}` |||| | | |
71+
| Base64 data URLs |||| | | |
6972
| **History Helper** | | | | | | |
70-
| `{{history}}` |||| 🔶 | 🔶 | 🔶 |
73+
| `{{history}}` |||| | | |
7174
| **Section Helper** | | | | | | |
72-
| `{{section "name"}}` |||| 🔶 | 🔶 | 🔶 |
75+
| `{{section "name"}}` |||| | | |
7376
| **JSON Helper** | | | | | | |
74-
| `{{json value}}` |||| 🔶 | 🔶 | 🔶 |
75-
| `{{json value indent=2}}` |||| 🔶 | 🔶 | 🔶 |
77+
| `{{json value}}` |||| | | |
78+
| `{{json value indent=2}}` |||| | | |
7679

7780
## Template Resolution
7881

7982
| Feature | JS | Dart | Python | Go | Rust | Java |
80-
|---------|----|---------|----|------|------|------|
83+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
8184
| **Partial Resolution** | | | | | | |
8285
| Named partials |||||||
83-
| Recursive partials ||| 🔶 | 🔶 | 🔶 | 🔶 |
86+
| Recursive partials + cycle detection ||| | | | |
8487
| **Template Loading** | | | | | | |
85-
| File system loader |||||||
86-
| Custom loaders |||| 🔶 | 🔶 | 🔶 |
88+
| File system loader (PromptStore) |||||||
89+
| Custom loaders / resolvers |||| | | |
8790
| Directory watching || 🔶 | 🔶 ||||
8891

8992
## Output Handling
9093

9194
| Feature | JS | Dart | Python | Go | Rust | Java |
92-
|---------|----|---------|----|------|------|------|
95+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
9396
| **Message Generation** | | | | | | |
9497
| Single message output |||||||
95-
| Multi-message output |||| 🔶 | 🔶 | 🔶 |
98+
| Multi-message output |||| | | |
9699
| **Structured Output** | | | | | | |
97-
| JSON mode |||| 🔶 | 🔶 | 🔶 |
98-
| Schema validation ||| 🔶 | 🔶 | 🔶 | 🔶 |
100+
| JSON mode (`output.format: json`) |||| | | |
101+
| Output schema validation ||| | | | |
99102

100103
## Integration Features
101104

102105
| Feature | JS | Dart | Python | Go | Rust | Java |
103-
|---------|----|---------|----|------|------|------|
106+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
104107
| **Genkit Integration** | | | | | | |
105108
| Action registration || N/A |||||
106109
| Prompt store || N/A |||||
@@ -112,48 +115,52 @@ Dotprompt is an executable prompt template file format for Generative AI.
112115
## Error Handling
113116

114117
| Feature | JS | Dart | Python | Go | Rust | Java |
115-
|---------|----|---------|----|------|------|------|
116-
| Syntax error location |||| 🔶 | 🔶 | 🔶 |
117-
| Missing variable errors |||| 🔶 | 🔶 | 🔶 |
118-
| Schema validation errors ||| 🔶 | 🔶 | 🔶 | 🔶 |
119-
| Helpful error messages |||| 🔶 | 🔶 | 🔶 |
118+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
119+
| Syntax error location |||| | | |
120+
| Missing variable errors |||| | | |
121+
| Schema validation errors ||| | | | |
122+
| Helpful error messages |||| | | |
120123

121124
## Configuration
122125

123126
| Feature | JS | Dart | Python | Go | Rust | Java |
124-
|---------|----|---------|----|------|------|------|
127+
|---------|:--:|:----:|:------:|:--:|:----:|:----:|
125128
| **Model Config** | | | | | | |
126129
| `model` |||||||
127130
| `temperature` |||||||
128131
| `maxOutputTokens` |||||||
129132
| `topP` |||||||
130133
| `topK` |||||||
131-
| `stopSequences` |||| 🔶 | 🔶 | 🔶 |
134+
| `stopSequences` |||| | | |
132135
| **Advanced Config** | | | | | | |
133-
| Tools/functions || 🔶 || 🔶 | 🔶 | 🔶 |
134-
| Safety settings || 🔶 || 🔶 | 🔶 | 🔶 |
135-
| Custom metadata |||| 🔶 | 🔶 | 🔶 |
136+
| Tools/functions || || | | |
137+
| Safety settings || || | | |
138+
| Custom metadata |||| | | |
136139

137140
## Specification Compliance
138141

142+
All runtimes pass the full spec test suite.
143+
139144
| Test Suite | JS | Dart | Python | Go | Rust | Java |
140-
|------------|----|---------|----|------|------|------|
141-
| `spec/helpers/` ||| 🔶 | 🔶 | 🔶 | 🔶 |
142-
| `spec/metadata.yaml` |||| 🔶 | 🔶 | 🔶 |
143-
| `spec/partials.yaml` ||| 🔶 | 🔶 | 🔶 | 🔶 |
144-
| `spec/picoschema.yaml` |||| 🔶 | 🔶 | 🔶 |
145-
| `spec/variables.yaml` |||| 🔶 | 🔶 | 🔶 |
145+
|------------|:--:|:----:|:------:|:--:|:----:|:----:|
146+
| `spec/helpers/` |||||||
147+
| `spec/metadata.yaml` |||||||
148+
| `spec/partials.yaml` |||||||
149+
| `spec/picoschema.yaml` |||||||
150+
| `spec/variables.yaml` |||||||
151+
| `spec/whitespace.yaml` |||||||
152+
| `spec/unicode.yaml` |||||||
146153

147154
## Test Coverage
148155

149-
| Runtime | Unit Tests | Integration | Spec Tests |
150-
|---------|------------|-------------|------------|
151-
| JavaScript ||| Reference |
152-
| Dart | ✅ (84+) |||
153-
| Python ||| 🔶 |
154-
| Go | 🔶 | 🔶 | 🔶 |
155-
| Rust | 🔶 | 🔶 | 🔶 |
156-
| Java | 🔶 | 🔶 | 🔶 |
156+
| Runtime | Unit Tests | Integration | Spec Tests | Total |
157+
|---------|:----------:|:-----------:|:----------:|:-----:|
158+
| JavaScript ||| Reference | -- |
159+
| Dart | ✅ (84+) ||| 84+ |
160+
| Python |(398+) || ✅ (81) | 479 |
161+
| Go | | | ✅ (200) | 200+ |
162+
| Rust | ✅ (43) | | ✅ (117) | 160+ |
163+
| Java | | | | 27+ |
157164

158165
## Build & CI
159166

@@ -187,29 +194,68 @@ implementations should maintain behavioral parity with it.
187194
- Uses `dotpromptz-handlebars` Rust bindings for templating
188195
- Fully typed with ty and pyrefly type checkers
189196
- Integrates with Genkit Python SDK
197+
- Output schema validation via `jsonschema` (Draft 2020-12)
198+
- JSON Schema to Picoschema reverse conversion
199+
- Recursive partials with cycle detection
200+
- 479 tests (81 spec tests, 398 unit/integration tests), 88% coverage
201+
202+
### Go Implementation
203+
204+
- Uses `raymond` for Handlebars templating
205+
- Full Picoschema support including enums
206+
- Recursive partials with cycle detection
207+
- ToolDefinition/ToolResolver for tool support
208+
- 200+ spec tests passing
190209

191210
### Rust Implementation (Promptly CLI)
192211

212+
- Uses `handlebars` crate for Handlebars templating
193213
- Provides `promptly` CLI tool for working with .prompt files
194214
- Includes LSP server for IDE support
195215
- Powers editor extensions
216+
- 43 unit tests + 117 spec tests passing
196217

197-
---
218+
### Java Implementation
219+
220+
- Uses `com.github.jknack:handlebars` for Handlebars templating
221+
- Full Picoschema support including enums
222+
- Recursive partials with cycle detection (async)
223+
- ToolDefinition/ToolResolver for tool support
224+
- 27+ tests passing
198225

199-
## Roadmap
226+
### Configuration Passthrough
200227

201-
### Q1 2026
228+
All config fields (`stopSequences`, safety settings, custom metadata, etc.)
229+
are stored in a generic map type in every language (`Record<string, any>` in
230+
JS, `map[string]any` in Go, `Map<String, Object>` in Java,
231+
`Map<String, dynamic>` in Dart, generic `M` in Rust). Frontmatter config is
232+
parsed and passed through without language-specific handling. This means any
233+
model config key works in any language without explicit support.
202234

203-
- [ ] Complete Go implementation core features
204-
- [ ] Complete Rust implementation core features
205-
- [ ] Python specification test coverage
235+
### Tools and Functions
236+
237+
All languages define `tools` (list of tool names) and `toolDefs` (inline tool
238+
definitions) fields in their `PromptMetadata` types. Go, Rust, and Java also
239+
provide `ToolResolver` interfaces for dynamic tool lookup.
240+
241+
### Schema Validation
242+
243+
Output schema validation is a Genkit integration concern, not a core dotprompt
244+
library feature. The JS reference implementation does not validate output
245+
against schemas in the dotprompt library itself. Python provides a standalone
246+
`validate_output()` utility. All languages parse and expose the output schema
247+
for downstream consumers (Genkit SDKs) to validate against.
248+
249+
---
206250

207-
### Q2 2026
251+
## Remaining Gaps
208252

209-
- [ ] Java production readiness
210-
- [ ] Cross-language specification test framework
211-
- [ ] Performance benchmarking suite
253+
| Feature | Languages | Notes |
254+
|---------|-----------|-------|
255+
| JSON Schema to Picoschema | Go, Rust, Java | Reverse conversion utility (Python has it) |
256+
| Directory watching | Go, Rust, Java | Planned future feature |
257+
| Genkit integration | Go, Rust, Java | Standalone libraries, not Genkit-integrated |
212258

213259
---
214260

215-
*Last updated: 2026-01-31*
261+
*Last updated: 2026-02-19*

python/dotpromptz/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies = [
4040
"dotpromptz-handlebars>=0.1.8",
4141
"pydantic[email]>=2.10.6",
4242
"pyyaml>=6.0.2",
43+
"jsonschema>=4.23.0",
4344
"structlog>=25.2.0",
4445
"types-aiofiles>=24.1.0.20250326",
4546
"types-pyyaml>=6.0.12.20241230",

0 commit comments

Comments
 (0)