When streaming messages from Claude (Anthropic models) in LangGraph, the model sometimes includes explanatory text before making tool calls (e.g., “I’ll get the weather information for both New York and San Francisco for you.”).
The problem is that these text chunks arrive before the tool_use content blocks, making it impossible to determine whether the streaming text is:
Preliminary reasoning/thoughts that precede a tool call, or
The actual final response to the user
This creates a challenge for UI rendering, as we cannot know whether to display the text immediately or wait to see if a tool call follows.
Expected Behavior:
Either:
Provide a way to identify which text chunks are associated with tool calls versus final responses during streaming, or
Offer a configuration option to disable these preliminary text chunks entirely when tools are being used, so only the tool calls and final responses are streamed
Current Workaround:
Currently, we must wait until the complete message is received to determine the message type, which defeats the purpose of streaming for real-time UI updates.
from langgraph.graph import StateGraph, add_messages
from langchain.tools import tool
from langchain_anthropic import ChatAnthropic
from typing import TypedDict, Annotated
Define your state schema
class State(TypedDict):
messages: Annotated[list, add_messages]
Create a simple tool
@tool
def get_weather(city: str) → str:
“”“Get weather information for a city.”“”
weather_data = {“New York”: “Rainy, 65°F”, “San Francisco”: “Sunny, 70°F”, “London”: “Cloudy, 55°F”}
return weather_data.get(city, f"Weather data not available for {city}")
Create a tool node that handles tool calls
from langgraph.prebuilt import ToolNode
tools = [get_weather]
tool_node = ToolNode(tools)
LLM node that can call tools
def llm_node(state: State):
llm = ChatAnthropic(
model=“claude-sonnet-4-5-20250929”,
api_key=“sk-ant-api03–C1kHLOao0p37mNdNDEBRtNct0e3oQcbXsiavx8ddphOUVK6KScl8t_AMsT37_ioisofwgsfFxA20ag_d4unTw-AX3l3gAA”,
)
# llm = ChatOpenAI(
# model=“gpt-4o”,
# api_key=“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”,
# )
llm_with_tools = llm.bind_tools(tools)
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
Build the graph
graph = StateGraph(State)
graph.add_node(“llm”, llm_node)
graph.add_node(“tools”, tool_node)
Route: if the LLM calls a tool, go to tools node, otherwise end
def should_use_tools(state: State):
last_message = state[“messages”][-1]
# Check if the last message has tool calls
if hasattr(last_message, “tool_calls”) and last_message.tool_calls:
return “tools”
return “end”
graph.set_entry_point(“llm”)
graph.add_conditional_edges(“llm”, should_use_tools, {“tools”: “tools”, “end”: “end”})
graph.add_edge(“tools”, “llm”) # After tools run, return to LLM
compiled_graph = graph.compile()
if name == “main”:
# Stream and print all messages
from langchain.messages import HumanMessage
initial_state = {"messages": [HumanMessage(content="What's the weather in New York and San Francisco?")]}`
Output:
{'content': [], 'additional_kwargs': {}, 'response_metadata': {'model_name': 'claude-sonnet-4-5-20250929', 'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': "I'll get", 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' the weather information for both New York and', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' San Francisco for you.', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'id': 'toolu_01Sz73zV5mpd4zrdThssKvnY', 'input': {}, 'name': 'get_weather', 'type': 'tool_use', 'index': 1}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': 'get_weather', 'args': {}, 'id': 'toolu_01Sz73zV5mpd4zrdThssKvnY', 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': 'get_weather', 'args': '', 'id': 'toolu_01Sz73zV5mpd4zrdThssKvnY', 'index': 1, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': '', 'type': 'input_json_delta', 'index': 1}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': '', 'args': {}, 'id': None, 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '', 'id': None, 'index': 1, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': '{"city"', 'type': 'input_json_delta', 'index': 1}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': '', 'args': {}, 'id': None, 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '{"city"', 'id': None, 'index': 1, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': ': "New Yor', 'type': 'input_json_delta', 'index': 1}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': ': "New Yor', 'id': None, 'error': None, 'type': 'invalid_tool_call'}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': ': "New Yor', 'id': None, 'index': 1, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': 'k"}', 'type': 'input_json_delta', 'index': 1}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'k"}', 'id': None, 'error': None, 'type': 'invalid_tool_call'}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'k"}', 'id': None, 'index': 1, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'id': 'toolu_01Y8UrYNCRhYkiq9yubs1Ms7', 'input': {}, 'name': 'get_weather', 'type': 'tool_use', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': 'get_weather', 'args': {}, 'id': 'toolu_01Y8UrYNCRhYkiq9yubs1Ms7', 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': 'get_weather', 'args': '', 'id': 'toolu_01Y8UrYNCRhYkiq9yubs1Ms7', 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': '', 'type': 'input_json_delta', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': '', 'args': {}, 'id': None, 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '', 'id': None, 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': '{"', 'type': 'input_json_delta', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [{'name': '', 'args': {}, 'id': None, 'type': 'tool_call'}], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '{"', 'id': None, 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': 'city": ', 'type': 'input_json_delta', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'city": ', 'id': None, 'error': None, 'type': 'invalid_tool_call'}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'city": ', 'id': None, 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': '"San F', 'type': 'input_json_delta', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': '"San F', 'id': None, 'error': None, 'type': 'invalid_tool_call'}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': '"San F', 'id': None, 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [{'partial_json': 'rancisco"}', 'type': 'input_json_delta', 'index': 2}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [{'name': None, 'args': 'rancisco"}', 'id': None, 'error': None, 'type': 'invalid_tool_call'}], 'usage_metadata': None, 'tool_call_chunks': [{'name': None, 'args': 'rancisco"}', 'id': None, 'index': 2, 'type': 'tool_call_chunk'}], 'chunk_position': None}
{'content': [], 'additional_kwargs': {}, 'response_metadata': {'stop_reason': 'tool_use', 'stop_sequence': None, 'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-b80f-7a52-9447-9d18bb12c548', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': {'input_tokens': 568, 'output_tokens': 108, 'total_tokens': 676, 'input_token_details': {'cache_creation': 0, 'cache_read': 0}}, 'tool_call_chunks': [], 'chunk_position': 'last'}
{'content': 'Rainy, 65°F', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': 'get_weather', 'id': '92288d1a-8262-42d3-90eb-38d68206c0f7', 'tool_call_id': 'toolu_01Sz73zV5mpd4zrdThssKvnY', 'artifact': None, 'status': 'success'}
{'content': 'Sunny, 70°F', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': 'get_weather', 'id': 'c53f55a1-fc34-4b81-b8f3-59212983719f', 'tool_call_id': 'toolu_01Y8UrYNCRhYkiq9yubs1Ms7', 'artifact': None, 'status': 'success'}
{'content': [], 'additional_kwargs': {}, 'response_metadata': {'model_name': 'claude-sonnet-4-5-20250929', 'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': "Here's the current", 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' weather:', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': '\n\n-', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' **New York**: Rainy,', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' 65°F\n- **San', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': ' Francisco**: Sunny, 70°', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [{'text': 'F', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': [], 'chunk_position': None}
{'content': [], 'additional_kwargs': {}, 'response_metadata': {'stop_reason': 'end_turn', 'stop_sequence': None, 'model_provider': 'anthropic'}, 'type': 'AIMessageChunk', 'name': None, 'id': 'lc_run--019bf1d8-bea8-76d3-bcb4-1985351168a8', 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': {'input_tokens': 754, 'output_tokens': 36, 'total_tokens': 790, 'input_token_details': {'cache_creation': 0, 'cache_read': 0}}, 'tool_call_chunks': [], 'chunk_position': 'last'}