fix(ai): add nullable() to configFiles schema to support OpenAI stric…#4268
fix(ai): add nullable() to configFiles schema to support OpenAI stric…#4268qveys wants to merge 1 commit intoDokploy:canaryfrom
Conversation
…t mode
OpenAI strict mode requires all keys in `properties` to also appear in `required`. The `configFiles` field was marked as `.optional()` in the Zod schema, which generates a JSON Schema where `configFiles` is in `properties` but not in `required`, causing the error:
"Invalid schema for response_format 'response': In context=('properties', 'suggestions', 'items'), 'required' is required to be supplied and to be an array including every key in properties. Missing 'configFiles'."
Adding `.nullable()` before `.optional()` generates an `anyOf: [{...}, {type: 'null'}]` pattern while keeping `configFiles` in `required`, which is compatible with OpenAI strict mode.
Fixes Dokploy#4267
There was a problem hiding this comment.
Pull request overview
This PR aims to fix the AI Assistant’s OpenAI strict-mode response_format schema validation error by adjusting how the configFiles field is represented in the Zod schema used for structured variant suggestions.
Changes:
- Updates the Zod schema for
configFilesundersuggestVariantsto includenullable()in addition tooptional().
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| configFiles: z | ||
| .array( | ||
| z.object({ | ||
| content: z.string(), | ||
| filePath: z.string(), | ||
| }), | ||
| ) | ||
| .optional(), | ||
| .nullable().optional(), |
There was a problem hiding this comment.
configFiles is still wrapped in .optional() here, so the generated JSON Schema will likely continue omitting it from the object's required array—this seems to leave the OpenAI strict-mode error unresolved. To satisfy strict mode, configFiles should be a required property and represent “no files” via an empty array (preferred, to avoid null leaking downstream) or via nullable without optional (and then ensure downstream types/validators accept null).
| }), | ||
| ) | ||
| .optional(), | ||
| .nullable().optional(), |
There was a problem hiding this comment.
This change is targeting OpenAI strict-mode JSON Schema generation; it would be safer to add a regression test that asserts the produced schema includes configFiles in the required array (and that its type matches the intended “optional” representation, e.g. empty array or nullable). The repo already has Vitest coverage for other server-exported utilities, so a small unit test would help prevent future SDK/schema changes from reintroducing this failure.
| .nullable().optional(), | |
| .nullable(), |
…t mode
OpenAI strict mode requires all keys in
propertiesto also appear inrequired. TheconfigFilesfield was marked as.optional()in the Zod schema, which generates a JSON Schema whereconfigFilesis inpropertiesbut not inrequired, causing the error:"Invalid schema for response_format 'response': In context=('properties', 'suggestions', 'items'), 'required' is required to be supplied and to be an array including every key in properties. Missing 'configFiles'."
Adding
.nullable()before.optional()generates ananyOf: [{...}, {type: 'null'}]pattern while keepingconfigFilesinrequired, which is compatible with OpenAI strict mode.Fixes #4267
What is this PR about?
Please describe in a short paragraph what this PR is about.
Checklist
Before submitting this PR, please make sure that:
canarybranch.Issues related (if applicable)
closes #123
Screenshots (if applicable)
Greptile Summary
This PR fixes an OpenAI strict-mode schema incompatibility by adding
.nullable()before.optional()on theconfigFilesZod field. When using the Vercel AI SDK's OpenAI provider,zod-to-json-schematransforms.nullable().optional()fields into required-but-nullable properties (adding them torequiredwith ananyOf: [{…}, {type: "null"}]type), satisfying the constraint that every key inpropertiesmust appear inrequired.Confidence Score: 5/5
Safe to merge — the change is a one-line fix with no runtime risk and all consumers already guard against falsy values.
The fix is correct and well-targeted. All callers use truthy checks or optional chaining, so a null value returned by the model is handled safely. The only remaining note is a minor TypeScript type inconsistency in the DockerOutput interface that has no production impact.
No files require special attention.
Comments Outside Diff (1)
packages/server/src/services/ai.ts, line 27 (link)DockerOutputinterface not updated fornullThe
configFilesfield inDockerOutputis typed asArray<...> | undefined(via?:), but the Zod schema now also allowsnull. At runtime the AI model could returnnullfor this field, which would be mis-typed. All current consumers use truthy/optional-chaining guards so there is no runtime breakage, but a strict TypeScript assignment (const f: typeof item.configFiles = item.configFiles) could silently accept anullvalue. Keeping the interface in sync avoids confusion.Reviews (1): Last reviewed commit: "fix(ai): add nullable() to configFiles s..." | Re-trigger Greptile