Skip to content

Backfill additionalProperties: false in OpenAI strict tool schemas - #6865

Closed
JamesBLewis wants to merge 1 commit into
spring-projects:mainfrom
JamesBLewis:fix-strict-mode-additional-properties
Closed

Backfill additionalProperties: false in OpenAI strict tool schemas#6865
JamesBLewis wants to merge 1 commit into
spring-projects:mainfrom
JamesBLewis:fix-strict-mode-additional-properties

Conversation

@JamesBLewis

Copy link
Copy Markdown
Contributor

TLDR; When a caller turns on OpenAI's strict tool-calling mode, Spring AI rewrites each tool's JSON schema to meet OpenAI's strict-mode contract but it only handles half of it. It fills in the "required" list and makes optional fields nullable, yet never adds additionalProperties: false, which OpenAI also demands on every object in the schema. Tools whose schemas were generated by Spring AI happen to work because the generator adds it earlier, but tools from MCP servers or with hand-written schemas get rejected by the OpenAI API. This change makes the strict-mode rewrite fill in additionalProperties: false wherever it is missing.

Problem

OpenAiChatModel#applyStrictModeRequirements rewrites a tool's input schema when OpenAiChatOptions#strict(true) is set: it backfills required with every property key and widens previously optional properties to nullable types, recursing into $defs, nested object properties, and array items.

OpenAI's strict function-calling mode additionally requires additionalProperties: false on every object level, and rejects requests otherwise with:

Invalid schema for function '...': 'additionalProperties' is required to be supplied and to be false.

The rewrite never emits it. Schemas produced by JsonSchemaGenerator are unaffected because forbidAdditionalProperties already adds it recursively by default — which is why the gap is invisible on the @Tool/FunctionToolCallback path. Any schema from another source hits the 400 under strict mode:

  • MCP tool schemas (servers rarely emit additionalProperties: false)
  • hand-written ToolDefinition#inputSchema JSON
  • schemas generated with SchemaOption.ALLOW_ADDITIONAL_PROPERTIES_BY_DEFAULT

See #4422

OpenAI's strict function-calling mode requires
"additionalProperties": false on every object level of a tool's
input schema, and rejects the request otherwise.
applyStrictModeRequirements backfills "required" and widens optional
properties to nullable types, but never emitted
"additionalProperties": false. Schemas produced by
JsonSchemaGenerator already carry it, so the gap only bites schemas
from other sources under strict mode: MCP tool schemas, hand-written
inputSchema JSON, or schemas generated with
ALLOW_ADDITIONAL_PROPERTIES_BY_DEFAULT.

Backfill "additionalProperties": false on every object level the
strict-mode rewrite already recurses through (root, $defs
definitions, nested object properties, array items), preserving an
explicitly declared value such as a Map<K,V>-style typed
"additionalProperties", mirroring the guard in
JsonSchemaGenerator#forbidAdditionalProperties. Schemas sent with
strict(false) are untouched.

See spring-projects#4422

Signed-off-by: James Lewis <1495031+JamesBLewis@users.noreply.github.com>
@ilayaperumalg

Copy link
Copy Markdown
Member

@JamesBLewis Thanks for the fix! Rebased and merged via e5e277f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working openai

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants