|
24 | 24 | PublicAgentState,
|
25 | 25 | )
|
26 | 26 | from langchain.agents.structured_output import (
|
| 27 | + AutoStrategy, |
27 | 28 | MultipleStructuredOutputsError,
|
28 | 29 | OutputToolBinding,
|
29 | 30 | ProviderStrategy,
|
@@ -194,22 +195,33 @@ def create_agent( # noqa: PLR0915
|
194 | 195 | tools = []
|
195 | 196 |
|
196 | 197 | # Convert response format and setup structured output tools
|
197 |
| - # Raw schemas are converted to ToolStrategy upfront to calculate tools during agent creation. |
198 |
| - # If auto-detection is needed, the strategy may be replaced with ProviderStrategy later. |
199 |
| - initial_response_format: ToolStrategy | ProviderStrategy | None |
200 |
| - is_auto_detect: bool |
| 198 | + # Raw schemas are wrapped in AutoStrategy to preserve auto-detection intent. |
| 199 | + # AutoStrategy is converted to ToolStrategy upfront to calculate tools during agent creation, |
| 200 | + # but may be replaced with ProviderStrategy later based on model capabilities. |
| 201 | + initial_response_format: ToolStrategy | ProviderStrategy | AutoStrategy | None |
201 | 202 | if response_format is None:
|
202 |
| - initial_response_format, is_auto_detect = None, False |
| 203 | + initial_response_format = None |
203 | 204 | elif isinstance(response_format, (ToolStrategy, ProviderStrategy)):
|
204 | 205 | # Preserve explicitly requested strategies
|
205 |
| - initial_response_format, is_auto_detect = response_format, False |
| 206 | + initial_response_format = response_format |
| 207 | + elif isinstance(response_format, AutoStrategy): |
| 208 | + # AutoStrategy provided - preserve it for later auto-detection |
| 209 | + initial_response_format = response_format |
206 | 210 | else:
|
207 |
| - # Raw schema - convert to ToolStrategy for now (may be replaced with ProviderStrategy) |
208 |
| - initial_response_format, is_auto_detect = ToolStrategy(schema=response_format), True |
| 211 | + # Raw schema - wrap in AutoStrategy to enable auto-detection |
| 212 | + initial_response_format = AutoStrategy(schema=response_format) |
| 213 | + |
| 214 | + # For AutoStrategy, convert to ToolStrategy to setup tools upfront |
| 215 | + # (may be replaced with ProviderStrategy later based on model) |
| 216 | + tool_strategy_for_setup: ToolStrategy | None = None |
| 217 | + if isinstance(initial_response_format, AutoStrategy): |
| 218 | + tool_strategy_for_setup = ToolStrategy(schema=initial_response_format.schema) |
| 219 | + elif isinstance(initial_response_format, ToolStrategy): |
| 220 | + tool_strategy_for_setup = initial_response_format |
209 | 221 |
|
210 | 222 | structured_output_tools: dict[str, OutputToolBinding] = {}
|
211 |
| - if isinstance(initial_response_format, ToolStrategy): |
212 |
| - for response_schema in initial_response_format.schema_specs: |
| 223 | + if tool_strategy_for_setup: |
| 224 | + for response_schema in tool_strategy_for_setup.schema_specs: |
213 | 225 | structured_tool_info = OutputToolBinding.from_schema_spec(response_schema)
|
214 | 226 | structured_output_tools[structured_tool_info.tool.name] = structured_tool_info
|
215 | 227 | middleware_tools = [t for m in middleware for t in getattr(m, "tools", [])]
|
@@ -412,17 +424,18 @@ def _get_bound_model(request: ModelRequest) -> tuple[Runnable, ResponseFormat |
|
412 | 424 | raise ValueError(msg)
|
413 | 425 |
|
414 | 426 | # Determine effective response format (auto-detect if needed)
|
415 |
| - effective_response_format: ResponseFormat | None = request.response_format |
416 |
| - if ( |
417 |
| - # User provided raw schema - auto-detect best strategy based on model |
418 |
| - is_auto_detect |
419 |
| - and isinstance(request.response_format, ToolStrategy) |
420 |
| - and |
421 |
| - # Model supports provider strategy - use it instead |
422 |
| - _supports_provider_strategy(request.model) |
423 |
| - ): |
424 |
| - effective_response_format = ProviderStrategy(schema=response_format) # type: ignore[arg-type] |
425 |
| - # else: keep ToolStrategy from initial conversion |
| 427 | + effective_response_format: ResponseFormat | None |
| 428 | + if isinstance(request.response_format, AutoStrategy): |
| 429 | + # User provided raw schema via AutoStrategy - auto-detect best strategy based on model |
| 430 | + if _supports_provider_strategy(request.model): |
| 431 | + # Model supports provider strategy - use it |
| 432 | + effective_response_format = ProviderStrategy(schema=request.response_format.schema) |
| 433 | + else: |
| 434 | + # Model doesn't support provider strategy - use ToolStrategy |
| 435 | + effective_response_format = ToolStrategy(schema=request.response_format.schema) |
| 436 | + else: |
| 437 | + # User explicitly specified a strategy - preserve it |
| 438 | + effective_response_format = request.response_format |
426 | 439 |
|
427 | 440 | # Bind model based on effective response format
|
428 | 441 | if isinstance(effective_response_format, ProviderStrategy):
|
|
0 commit comments