Fix malformed json_schema response_format envelope (#229)#252
Conversation
AbstractOpenAiCompatibleTextGenerationModel::prepareResponseFormatParam()
emitted the bare output schema directly under `json_schema`. The OpenAI
Structured Outputs spec requires `json_schema` to be an object carrying the
schema under a `schema` key plus a required `name`, so compliant endpoints
rejected structured-output requests with:
400 missing_required_parameter: response_format.json_schema.name
Wrap the schema as `{ name: 'response', schema: <schema> }`. `strict` is left
unset on purpose: enabling it would impose extra schema constraints (every
object needs `additionalProperties: false`, all properties in `required`) that
arbitrary caller schemas rarely satisfy, which would trade one 400 for another.
Per the spec only `name` is required.
Verified live against the OpenAI Chat Completions API: the previous payload
returns 400 with the exact error above, the fixed payload returns 200.
Updates the two existing assertions and adds a regression test asserting the
envelope shape (name present, schema wrapped, strict absent, raw schema no
longer emitted directly under json_schema).
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## trunk #252 +/- ##
=========================================
Coverage 88.12% 88.13%
Complexity 1213 1213
=========================================
Files 60 60
Lines 3934 3937 +3
=========================================
+ Hits 3467 3470 +3
Misses 467 467
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Closing as a duplicate of #251, which predates this PR and already covers the same fix (and additionally passes through pre-wrapped |
Fixes #229.
Problem
AbstractOpenAiCompatibleTextGenerationModel::prepareResponseFormatParam()emitted the bare output schema directly underjson_schema:The OpenAI Structured Outputs spec requires
json_schemato be an object carrying the schema under aschemakey plus a requiredname. As a result, any provider extending this base class fails on structured-output requests (asJsonResponse($schema)) against a compliant endpoint with:Plain text generation is unaffected (the broken path is gated behind the
application/jsonoutput MIME type). Permissive self-hosted servers may silently accept the malformed payload, which is why this only surfaces on strict endpoints (OpenAI, OpenRouter→Azure, etc.).Fix
Wrap the schema in the spec-compliant envelope:
strictis intentionally left unset. Enabling it imposes extra schema constraints (every object needsadditionalProperties: false, all properties listed inrequired) that arbitrary caller schemas rarely satisfy — that would trade one 400 for another. Per the spec, onlynameis required.Verification
testPrepareResponseFormatParamSchemaEnvelopeHasName) asserting the envelope shape —namepresent, schema wrapped underschema,strictabsent, and the raw schema no longer emitted directly underjson_schema.400 missing_required_parameter: response_format.json_schema.name; the payload produced by the patched method returns200with valid JSON content.composer lintclean (phpcs PSR-12 + phpstan max);composer test:unitgreen.