fix: fail fast on tools + structured output conflict for OpenRouter (Issue #7132) #7196
+133
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements a short‑term, fail‑fast guardrail for issue #7132 and adds a dedicated reproduction sample plus regression tests.
When
AssistantAgentis used with an OpenRouter (OpenAI‑compatible) model andoutput_content_typeis a Pydantic model, theOpenAIChatCompletionClientcurrently routes requests throughbeta.chat.completions.parse(response_format=...). In this structured‑output mode, the OpenAI API does not support tool calling, so requests that include bothresponse_formatandtoolsresult in tool calls being silently ignored.This PR makes that incompatibility explicit and prevents the “silent tool drop” behavior.
Changes
1. Fail‑fast guardrail in
_process_create_argsFile:
python/packages/autogen-ext/src/autogen_ext/models/openai/_openai_client.pyMethod:
_process_create_argsRight after
converted_tools = convert_tools(tools), we now check for the incompatible combination of structured output and tools:Behavior:
response_format_valueis set (Pydantic‑based structured output is enabled), andconverted_toolsis non‑empty (at least one function tool is present)._process_create_argsraisesValueErrorwith a descriptive message._process_create_argsis changed:2. Regression tests for the guardrail
File:
python/packages/autogen-ext/tests/models/test_openai_model_client.pyAdded a minimal Pydantic model used only for these tests:
Added a minimal tool function:
Test 1: Pydantic
json_output+ tools →ValueErrortest_structured_output_with_tools_raises_value_errorBaseOpenAIChatCompletionClientwith aMagicMockunderlying client andmodel_info.structured_output=True.messages=[UserMessage(...)]tools=[FunctionTool.from_function(_dummy_tool_for_guardrail)]json_output=Weatherclient._process_create_args(...).ValueErroris raised."Cannot use structured output (output_content_type) together with function tools".Test 2: Pydantic
json_output+ no tools → passestest_structured_output_without_tools_passesWeathermodel.tools=[].client._process_create_args(...).create_paramshasresponse_format is Weather.len(create_params.tools) == 0.Both tests use a mocked underlying client and only exercise
_process_create_args; they do not perform any real network calls.3. Reproduction sample
File:
python/samples/agentchat_openrouter/assistant_openrouter_output_content_type.pySample that reproduces issue #7132 using
AssistantAgentwith an OpenRouter model:get_weather).output_content_typeto a Pydantic model.ValueErrordescribed above.Structural / Long‑Term Note
This PR intentionally does not attempt to make “tools + structured output in one request” work, because it is not compatible with the current OpenAI API contract.
beta.chat.completions.parse(response_format=...)is designed for returning structured JSON that matches the schema in a single step.tool_call, external code runs, and then the model is called again with tool results.Trying to combine both in a single request is structurally incompatible with the current API behavior.
A more robust long‑term solution would be to change the agent workflow to use a two‑step protocol:
response_format) to execute tools and collect their outputs.response_formatset and tools disabled, to turn tool outputs into a typed response.This PR is a short‑term, fail‑fast guardrail that makes the incompatibility explicit; it does not change the higher‑level agent workflow.
Testing
Local runs:
uv run pytest packages/autogen-ext/tests/models/test_openai_model_client.pyValueErroras expected under the guardrail.The new unit tests:
test_structured_output_with_tools_raises_value_errortest_structured_output_without_tools_passesboth pass.