[PR #5899] feat(prebuilt): Add structured output tools to ToolNode #4712

Closed
opened 2026-02-20 17:50:37 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langchain-ai/langgraph/pull/5899

State: closed
Merged: Yes


  • Add structured output tools to ToolNode
  • Fix default tool node name to match the actual default ('tools')
  • Update doc-strings to explain what inputs/outputs are for the ToolNode.
  • Mark internal attributes as private (potentially breaking -- although hopefully users aren't accessing these)

Decisions points

  • OK with two properties? Done since users may be relying on tools_by_name and expanding the return type will break user code.

Changes in public/private interface

Marked as public

  • Make tools_by_name an official public property
  • Make structured_output_tools a public property

Marked as private

There should be no reason why users are accessing these attributes

_tool_to_state_args
_tool_to_store_arg
_handle_tool_errors
_messages_key

Usage


    class OutputSchema(BaseModel):
        name: str
        age: int
        location: str

    tool_node = ToolNode([OutputSchema])

    # Test that the structured output tool is registered correctly
    assert "OutputSchema" in tool_node.structured_output_tools

    # Create a tool call that matches the schema
    tool_call = {
        "name": "OutputSchema",
        "args": {"name": "Alice", "age": 30, "location": "NYC"},
        "id": "call_123",
        "type": "tool_call",
    }

    # Test sync execution
    result = tool_node.invoke(
        {"messages": [AIMessage(content="", tool_calls=[tool_call])]}
    )

    # Should return a Command with structured response
    assert isinstance(result, list)
    assert len(result) == 1
    command = result[0]
    assert isinstance(command, Command)

    # Check the update structure
    assert "messages" in command.update
    assert "structured_response" in command.update

    # Check the tool message
    tool_message = command.update["messages"][0]
    assert isinstance(tool_message, ToolMessage)
    assert tool_message.name == "OutputSchema"
    assert tool_message.tool_call_id == "call_123"

    # Check the structured response
    structured_response = command.update["structured_response"]
    assert isinstance(structured_response, OutputSchema)
    assert structured_response.name == "Alice"
    assert structured_response.age == 30
    assert structured_response.location == "NYC"
**Original Pull Request:** https://github.com/langchain-ai/langgraph/pull/5899 **State:** closed **Merged:** Yes --- * Add structured output tools to ToolNode * Fix default tool node name to match the actual default ('tools') * Update doc-strings to explain what inputs/outputs are for the ToolNode. * Mark internal attributes as private (potentially breaking -- although hopefully users aren't accessing these) ## Decisions points * OK with two properties? Done since users may be relying on `tools_by_name` and expanding the return type will break user code. ## Changes in public/private interface ### Marked as public * Make `tools_by_name` an official public property * Make `structured_output_tools` a public property ### Marked as private There should be no reason why users are accessing these attributes ```python _tool_to_state_args _tool_to_store_arg _handle_tool_errors _messages_key ``` ### Usage ```python class OutputSchema(BaseModel): name: str age: int location: str tool_node = ToolNode([OutputSchema]) # Test that the structured output tool is registered correctly assert "OutputSchema" in tool_node.structured_output_tools # Create a tool call that matches the schema tool_call = { "name": "OutputSchema", "args": {"name": "Alice", "age": 30, "location": "NYC"}, "id": "call_123", "type": "tool_call", } # Test sync execution result = tool_node.invoke( {"messages": [AIMessage(content="", tool_calls=[tool_call])]} ) # Should return a Command with structured response assert isinstance(result, list) assert len(result) == 1 command = result[0] assert isinstance(command, Command) # Check the update structure assert "messages" in command.update assert "structured_response" in command.update # Check the tool message tool_message = command.update["messages"][0] assert isinstance(tool_message, ToolMessage) assert tool_message.name == "OutputSchema" assert tool_message.tool_call_id == "call_123" # Check the structured response structured_response = command.update["structured_response"] assert isinstance(structured_response, OutputSchema) assert structured_response.name == "Alice" assert structured_response.age == 30 assert structured_response.location == "NYC" ```
yindo added the pull-request label 2026-02-20 17:50:37 -05:00
yindo closed this issue 2026-02-20 17:50:37 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#4712