feat: add output field constraints (enum, pattern, range, length, optional, nullable) - #372
Open
hertznsk wants to merge 9 commits into
Open
feat: add output field constraints (enum, pattern, range, length, optional, nullable)#372hertznsk wants to merge 9 commits into
hertznsk wants to merge 9 commits into
Conversation
…el optional fields
…d sanitize pydantic-ai tool schema
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Workflow authors can now declare real constraints in their agents'
output:blocks — allowed value lists (enum), regex patterns (pattern), numeric ranges (minimum/maximum), string length limits (minLength/maxLength), optional fields (required: false), and nullable fields (nullable: true). Every provider (Claude, Copilot, Hermes, Claude Agent SDK, ACA) enforces them the same way, and on Claude the model gets an automatic in-session chance to fix a constraint violation before the workflow fails.What changed
OutputFieldschema model gains eight optional fields (enum,pattern,minimum,maximum,minLength,maxLength,required,nullable) with Pydantic validators rejecting type-inappropriate combinations (e.g.patternontype: number,Noneentries inenum— usenullable: trueinstead)._schema.py) emit the new keywords in both flavours (JSON schema and prompt schema);requiredarrays list only required fields;nullablerenders astype: [<T>, "null"]; nodefaultkeys ever appear in generated schemas.AfterValidator(strict Python semantics identical to the final validator — noLiteral[...]/ Rust-regex surprises) while advertising them to the model viajson_schema_extra. Constraint violations raise inside the pydantic-ai output-retry loop, giving the model a free in-session self-correction. Optional fields useexclude_unset=Trueso an omitted key is never materialized asNone.validate_output) checks all eight constraints after the type check, recursion-aware (object properties and array items). Legacy error messages remain byte-identical when no new fields are used.required: falseis rejected at load time via aWorkflowConfigmodel validator (optional output fields are only allowed inside object properties).output_formatpayload, pydantic constraints on the Claude dynamic model, and identicalValidationErrorfromvalidate_output. The ACA wire boundary is covered too (constraint fields survive the round trip).docs/workflow-syntax.mdgains a "Field constraints" subsection; new exampleexamples/output-constraints.yamlexercising every field; CHANGELOG entry under Unreleased.Deliberately out of scope
additionalProperties: false/ extra-key rejection (deferred to a follow-up).multipleOf,format,const, etc.).Test plan
uv run pytest -m "not performance" -q— full suite greenmake lint/make typecheck— cleanmake validate-examples— greenFunctionModelreturning a violating payload then a valid one)