fix: recursive array/object JSON Schema in tool params across all runtimes#332
Merged
Merged
Conversation
…times
The wire-format conversion functions (_schema_to_wire, schemaToWire,
PropertiesToJsonSchema, parameters_to_json_schema) were producing flat
schemas like {"type": "array"} with no "items" for array properties and
no nested "properties" for object properties. This caused LLMs to
invent their own field names inside array items and objects.
The schema emitter types (ArrayProperty.items, ObjectProperty.properties)
were already correct — the bug was purely in the hand-written wire
conversion code that didn't recurse into nested types.
Fix: Replace flat schema conversion with recursive property-to-JSON-Schema
logic in all 5 runtimes:
- Python OpenAI/Azure/Foundry: _schema_to_wire delegates to _property_to_json_schema
- Python Anthropic: same pattern
- TypeScript OpenAI: schemaToWire delegates to propertyToJsonSchema
- TypeScript Anthropic: same pattern
- C#: new recursive PropertyToJsonSchema method in SchemaHelpers
- Rust OpenAI: new property_to_json_schema fn for tools + structured output
- Rust Anthropic: same for tools
Structured output (_property_to_json_schema / propertyToJsonSchema) was
already correct in Python and TypeScript. C# and Rust were also fixed
for structured output paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sethjuarez
force-pushed
the
sethjuarez/fix-array-item-schema-support
branch
from
April 10, 2026 21:15
3035812 to
9d9ce99
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sethjuarez
added a commit
that referenced
this pull request
Apr 10, 2026
Bump Python (2.0.0a8), TypeScript (2.0.0-alpha.8), C# (2.0.0-alpha.8), and VS Code extension packages for release including: - fix: recursive array/object JSON Schema in tool params (#332) - feat: Rust runtime parity + optional authenticationMode (#333) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sethjuarez
added a commit
that referenced
this pull request
Apr 11, 2026
* chore: bump all runtimes to alpha.8 Bump Python (2.0.0a8), TypeScript (2.0.0-alpha.8), C# (2.0.0-alpha.8), and VS Code extension packages for release including: - fix: recursive array/object JSON Schema in tool params (#332) - feat: Rust runtime parity + optional authenticationMode (#333) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: nonce type coercion bug in parser strict mode across all runtimes When randomBytes/token_hex generates an all-digit hex nonce (e.g. '1234567890123456'), parseAttrs type coercion converts it to a number. The subsequent strict comparison (number !== string) always fails, causing a spurious 'Nonce mismatch' error. Fix: compare nonces as strings in buildMessage/build_message across Python, TypeScript, and Rust parsers. Probability of all-digit 16-char hex: (10/16)^16 ≈ 0.01% — matches the observed flaky CI failure rate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add conceptual documentation for thread inputs (conversation history) Adds a new core-concepts page explaining how thread inputs work in Prompty: - What threads are and why they use nonce-based expansion - How to declare kind: thread inputs and place them in templates - Data format with multi-language examples (Python, TypeScript, C#, Rust) - Internal pipeline mechanics (render → parse → expand) - Best practices: token budgets, sliding windows, stateless design - Integration with agent mode Also adds cross-references from the file-format doc, core-concepts index, and the chat-assistant tutorial. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Problem
Tool parameter schemas with nested arrays and objects produced flat JSON Schema like
{"type": "array"}withoutitems, and{"type": "object"}without nestedproperties. This caused LLMs to invent their own field names inside array items, leading to undefined values in the caller's code.Example — this
.promptytool definition:Before (sent to LLM):
{ "encounters": { "type": "array" } }After (sent to LLM):
{ "encounters": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "difficulty": { "type": "integer" } }, "required": ["title", "difficulty"], "additionalProperties": false } } }Root Cause
The schema emitter types (
ArrayProperty.items,ObjectProperty.properties) were already correct —ArrayPropertyhasitems: PropertyandObjectPropertyhasproperties: list[Property]. The bug was in the hand-written wire-format conversion functions that mapped these to flat JSON Schema without recursing.Fix
Replace flat schema conversion with recursive property→JSON Schema logic in all runtimes:
providers/openai/executor.py_schema_to_wiredelegates to_property_to_json_schemaproviders/anthropic/executor.pypackages/openai/src/wire.tsschemaToWiredelegates topropertyToJsonSchemapackages/anthropic/src/wire.tsPrompty.Core/SchemaHelpers.csPropertyToJsonSchema()methodprompty-openai/src/wire.rsproperty_to_json_schema()for tools + outputsprompty-anthropic/src/wire.rsNote: Structured output was already correct in Python and TypeScript (they had a separate recursive path). C# and Rust structured output was also flat and is now fixed.
Tests
@prompty/coreresolution issue blocks test runner)cargo check) for bothprompty-openaiandprompty-anthropic