From 81b4752419df992b65357fe544372743ab3de77a Mon Sep 17 00:00:00 2001 From: "Guofang.Tang" Date: Fri, 6 Feb 2026 20:32:26 +0800 Subject: [PATCH] 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 Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com> --- libs/langchain_v1/langchain/agents/factory.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libs/langchain_v1/langchain/agents/factory.py b/libs/langchain_v1/langchain/agents/factory.py index 762e1c55b4..886436a691 100644 --- a/libs/langchain_v1/langchain/agents/factory.py +++ b/libs/langchain_v1/langchain/agents/factory.py @@ -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)