From b4f9cbc435d051a5143f624842af6458fbcf1c51 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 14 Aug 2026 21:00:16 +0800 Subject: [PATCH] preserve loose tool schema compatibility --- backend/open_webui/routers/openai.py | 8 ++++++-- test/test_openai_responses_payload.py | 29 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 test/test_openai_responses_payload.py diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index c0af667ba3..0d1ac11bd0 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -1403,8 +1403,12 @@ def convert_to_responses_payload(payload: dict) -> dict: # Responses tools default to strict mode when the field is # omitted. Preserve the loose-schema semantics of Chat, # MCP, and OpenAPI function tools unless strictness was - # explicitly requested by the caller. - converted_tool['strict'] = func.get('strict', False) + # explicitly requested by the caller. Keep the old wire + # format for tools without a parameters schema. + if 'strict' in func: + converted_tool['strict'] = func['strict'] + elif 'parameters' in func: + converted_tool['strict'] = False converted_tools.append(converted_tool) else: # Already in correct format or unknown format, pass through diff --git a/test/test_openai_responses_payload.py b/test/test_openai_responses_payload.py new file mode 100644 index 0000000000..fdc42223d9 --- /dev/null +++ b/test/test_openai_responses_payload.py @@ -0,0 +1,29 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parents[1] / 'backend')) + +from open_webui.routers.openai import convert_to_responses_payload + + +def _convert_tool(function: dict) -> dict: + payload = convert_to_responses_payload( + { + 'messages': [], + 'tools': [{'type': 'function', 'function': function}], + } + ) + return payload['tools'][0] + + +def test_convert_to_responses_payload_preserves_explicit_strict_values(): + assert _convert_tool({'name': 'strict', 'parameters': {}, 'strict': True})['strict'] is True + assert _convert_tool({'name': 'loose', 'parameters': {}, 'strict': False})['strict'] is False + + +def test_convert_to_responses_payload_defaults_schema_tools_to_loose(): + assert _convert_tool({'name': 'default', 'parameters': {}})['strict'] is False + + +def test_convert_to_responses_payload_omits_strict_for_tools_without_parameters(): + assert 'strict' not in _convert_tool({'name': 'no-schema'})