fix(openai): preserve loose tool schemas in Responses conversion - #28543
fix(openai): preserve loose tool schemas in Responses conversion#28543seanxuu wants to merge 2 commits into
Conversation
|
@seanxuu Probably worth linking to openai docs where it says this? |
|
@gaby Thanks for the suggestion — I added the OpenAI Responses API reference to the PR description, which documents the |
amerob
left a comment
There was a problem hiding this comment.
The underlying diagnosis is right: the Responses API defaults function tools to strict, Chat Completions doesn't, so a tool that round-tripped fine through /chat/completions starts rejecting its own schema once converted. Tools coming from MCP and OpenAPI are exactly the ones with schemas that won't satisfy strict mode (missing additionalProperties: false, optional fields absent from required), so this is a real breakage to fix.
One thing I'd think about before merging: the change moves strict from sometimes absent to always present.
converted_tool['strict'] = func.get('strict', False)convert_to_responses_payload runs against whatever the user has pointed Open-WebUI at, and self-hosted Responses implementations are a lot patchier than OpenAI's. A shim that doesn't know strict and validates its request body strictly used to receive a payload with no such key and was fine; now it gets strict: false on every tool and may 400. That's a regression that would only show up for people on non-OpenAI backends — which is a large slice of this project's users.
Preserving the fix while staying compatible is a one-liner:
if 'strict' in func:
converted_tool['strict'] = func['strict']
elif 'parameters' in func:
converted_tool['strict'] = Falseso you only assert loose-schema semantics when there's actually a schema to be loose about, and tools without parameters keep the old wire format. Not insisting on that shape specifically — mainly flagging that "always emit the field" is the part with blast radius beyond the bug being fixed.
Also worth a test. convert_to_responses_payload is pure dict-in/dict-out, so pinning the three cases (explicit strict: true preserved, explicit false preserved, omitted becomes false) is cheap and would catch a future refactor quietly restoring the strict default.
Fixes #27750
What changed
strict: falsewhen converting a Chat Completions function tool that does not specify strictness.strict: trueandstrict: falsevalues.This keeps optional MCP/OpenAPI tool parameters optional when the payload is sent to the Responses API. The OpenAI Responses API reference documents
strictfor function tools and its default behavior.Validation
backend/open_webui/routers/openai.pyruff format --check backend/open_webui/routers/openai.pygit diff --checkChangelog
Fixed
Contributor License Agreement