fix(langchain): normalize raw schemas in middleware response_format override (#35019)

Normalizes raw Pydantic schemas to AutoStrategy when middleware
overrides response_format.

When middleware calls
`request.override(response_format=SomePydanticClass)` with a raw schema,
the code now wraps it in `AutoStrategy` before processing. This prevents
an `IndexError` crash that occurred because raw schemas were falling
through to the "no structured output" branch.

Fixes #35008

Co-authored-by: Guofang Tang <tinggofun@gmail.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-02-06 07:32:26 -05:00
1 parent 8767a462ca
commit 81b4752419
1 file changed
+13 -8
+13 -8
View File
@@ -1137,25 +1137,30 @@ def create_agent(
)
raise ValueError(msg)
# Normalize raw schemas to AutoStrategy
# (handles middleware override with raw Pydantic classes)
response_format: ResponseFormat[Any] | Any | None = request.response_format
if response_format is not None and not isinstance(
response_format, (AutoStrategy, ToolStrategy, ProviderStrategy)
):
response_format = AutoStrategy(schema=response_format)
# Determine effective response format (auto-detect if needed)
effective_response_format: ResponseFormat[Any] | None
if isinstance(request.response_format, AutoStrategy):
if isinstance(response_format, AutoStrategy):
# User provided raw schema via AutoStrategy - auto-detect best strategy based on model
if _supports_provider_strategy(request.model, tools=request.tools):
# Model supports provider strategy - use it
effective_response_format = ProviderStrategy(schema=request.response_format.schema)
elif (
request.response_format is initial_response_format
and tool_strategy_for_setup is not None
):
effective_response_format = ProviderStrategy(schema=response_format.schema)
elif response_format is initial_response_format and tool_strategy_for_setup is not None:
# Model doesn't support provider strategy - use ToolStrategy
# Reuse the strategy from setup if possible to preserve tool names
effective_response_format = tool_strategy_for_setup
else:
effective_response_format = ToolStrategy(schema=request.response_format.schema)
effective_response_format = ToolStrategy(schema=response_format.schema)
else:
# User explicitly specified a strategy - preserve it
effective_response_format = request.response_format
effective_response_format = response_format
# Build final tools list including structured output tools
# request.tools now only contains BaseTool instances (converted from callables)