From f5b007c196136ea9566626c6242f5ce4332f7c2e Mon Sep 17 00:00:00 2001 From: "open-swe[bot]" Date: Mon, 11 Aug 2025 20:08:34 +0000 Subject: [PATCH] Apply patch [skip ci] --- .../langgraph/prebuilt/chat_agent_executor.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py b/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py index d1e5bb83f..e0373651c 100644 --- a/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py +++ b/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py @@ -774,6 +774,100 @@ def create_react_agent( response = await model_with_structured_output.ainvoke(messages, config) return {"structured_response": response} + def respond( + state: StateSchema, runtime: Runtime[ContextT], config: RunnableConfig + ) -> StateSchema: + """Handle structured response creation when response schema tool is called.""" + messages = _get_state_value(state, "messages") + last_message = messages[-1] + + if not isinstance(last_message, AIMessage) or not last_message.tool_calls: + raise ValueError("Expected last message to be AIMessage with tool calls") + + # Find the response schema tool call + response_tool_call = None + for tool_call in last_message.tool_calls: + if tool_call["name"] == response_tool_name: + response_tool_call = tool_call + break + + if response_tool_call is None: + raise ValueError(f"Expected tool call with name '{response_tool_name}'") + + # Extract the actual schema from tuple if needed + actual_schema = response_format + if isinstance(response_format, tuple): + _, actual_schema = response_format + + # Coerce tool call arguments into response schema + try: + if hasattr(actual_schema, '__call__'): + # For BaseModel classes + structured_response = actual_schema(**response_tool_call["args"]) + else: + # For dict schemas, just return the args + structured_response = response_tool_call["args"] + except Exception as e: + raise ValueError(f"Failed to coerce tool call args into response schema: {e}") + + # Create artificial tool message + tool_message = ToolMessage( + content="Here is your structured response", + tool_call_id=response_tool_call["id"] + ) + + return { + "messages": [tool_message], + "structured_response": structured_response + } + + async def arespond( + state: StateSchema, runtime: Runtime[ContextT], config: RunnableConfig + ) -> StateSchema: + """Async handle structured response creation when response schema tool is called.""" + messages = _get_state_value(state, "messages") + last_message = messages[-1] + + if not isinstance(last_message, AIMessage) or not last_message.tool_calls: + raise ValueError("Expected last message to be AIMessage with tool calls") + + # Find the response schema tool call + response_tool_call = None + for tool_call in last_message.tool_calls: + if tool_call["name"] == response_tool_name: + response_tool_call = tool_call + break + + if response_tool_call is None: + raise ValueError(f"Expected tool call with name '{response_tool_name}'") + + # Extract the actual schema from tuple if needed + actual_schema = response_format + if isinstance(response_format, tuple): + _, actual_schema = response_format + + # Coerce tool call arguments into response schema + try: + if hasattr(actual_schema, '__call__'): + # For BaseModel classes + structured_response = actual_schema(**response_tool_call["args"]) + else: + # For dict schemas, just return the args + structured_response = response_tool_call["args"] + except Exception as e: + raise ValueError(f"Failed to coerce tool call args into response schema: {e}") + + # Create artificial tool message + tool_message = ToolMessage( + content="Here is your structured response", + tool_call_id=response_tool_call["id"] + ) + + return { + "messages": [tool_message], + "structured_response": structured_response + } + if not tool_calling_enabled: # Define a new graph workflow = StateGraph(state_schema=state_schema, context_schema=context_schema) @@ -994,3 +1088,4 @@ __all__ = [ +