Repository: langchain
Issue: Streaming output does not work when using bind_tools
Labels: investigate

### Checked other resources

- [X] This is a bug, not a usage question. For questions, please use GitHub Discussions.
- [X] I added a clear and detailed title that summarizes the issue.
- [X] I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
- [X] I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue.

### Example Code

```python
import asyncio
import inspect
from typing import Annotated, TypedDict

from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from langchain_ollama import ChatOllama
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import AnyMessage, add_messages
from langgraph.prebuilt import ToolNode

OLLAMA_MODEL = "llama3.2:latest"
OLLAMA_URL = "http://127.0.0.1:11434"


class GraphState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]


@tool
def get_weather() -> str:
    """Inform the user that the weather is 15°C and it would rain and throw a joke in there also, but keep it brief 20 words max."""
    return "Inform the user that the weather is 15°C and it would rain and throw a joke in there also, but keep it brief 20 words max."


prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            """
            You are a helpful AI assistant specializing in weather. Provide accurate and clear weather information,
            forecasts, and safety tips based on user input. Offer localized details when provided with a location and
            explain weather phenomena concisely. If information is unclear or unavailable, ask for clarification. Be 
            user-friendly and reliable. DO NOT respond with more than 20 words.
            """,
        ),
        ("placeholder", "{messages}"),
    ]
)


def build_graph(agent, tools):
    async def call_model(state, config):
        response = await agent.ainvoke(state, config)
        return {"messages": response}

    def should_continue(state):
        last_message = state["messages"][-1]
        return "tools" if last_message.tool_calls else END

    builder = StateGraph(GraphState)
    builder.add_node("agent", call_model)
    builder.add_node("tools", ToolNode(tools))
    builder.add_edge(START, "agent")
    builder.add_conditional_edges("agent", should_continue, ["tools", END])
    builder.add_edge("tools", "agent")
    builder.add_edge("agent", END)

    return builder.compile()


async def run_graph(input_message, agent, tools):
    app = build_graph(agent, tools)
    async for msg, metadata in app.astream(
        {"messages": [HumanMessage(content=input_message, name="user")]},
        stream_mode="messages",
    ):
        if msg.content and not isinstance(msg, HumanMessage):
            yield msg.content


async def test_chatollama_with_tools():
    llm = ChatOllama(
        base_url=OLLAMA_URL,
        model=OLLAMA_MODEL,
        temperature=0.1,
        num_ctx=8000,
        num_predict=-2,
    )
    tools = [get_weather]
    agent = prompt | llm.bind_tools(tools)

    print("\n\n" + "=" * 20 + f" {inspect.currentframe().f_code.co_name} " + "=" * 20)
    async for msg in run_graph("What's the weather like in Tokyo?", agent, tools):
        print(msg, end="|", flush=True)


async def test_chatollama_no_tools():
    llm = ChatOllama(
        base_url=OLLAMA_URL,
        model=OLLAMA_MODEL,
        temperature=0.1,
        num_ctx=8000,
        num_predict=-2,
    )
    tools = []
    agent = prompt | llm.bind_tools(tools)

    print("\n\n" + "=" * 20 + f" {inspect.currentframe().f_code.co_name} " + "=" * 20)
    async for msg in run_graph("What's the weather like in Tokyo?", agent, tools):
        print(msg, end="|", flush=True)


async def test_chatopenai_with_tools():
    # We use the ChatOpenAI interface with ollama backend to make sure that the issue is not with ChatOllama interface only
    llm = ChatOpenAI(
        base_url=OLLAMA_URL + "/v1",
        model=OLLAMA_MODEL,
        temperature=0.1,
        api_key="ollama",
    )
    tools = [get_weather]
    agent = prompt | llm.bind_tools(tools)

    print("\n\n" + "=" * 20 + f" {inspect.currentframe().f_code.co_name} " + "=" * 20)
    async for msg in run_graph("What's the weather like in Tokyo?", agent, tools):
        print(msg, end="|", flush=True)


async def test_chatopenai_no_tools():
    llm = ChatOpenAI(
        base_url=OLLAMA_URL + "/v1",
        model=OLLAMA_MODEL,
        temperature=0.1,
        api_key="ollama",
    )
    tools = []
    agent = prompt | llm.bind_tools(tools)

    print("\n\n" + "=" * 20 + f" {inspect.currentframe().f_code.co_name} " + "=" * 20)
    async for msg in run_graph("What's the weather like in Tokyo?", agent, tools):
        print(msg, end="|", flush=True)


if __name__ == "__main__":

    async def main():
        await test_chatollama_no_tools()
        await test_chatollama_with_tools()
        await test_chatopenai_no_tools()
        await test_chatopenai_with_tools()

    asyncio.run(main())
```


### Error Message and Stack Trace (if applicable)

_No response_

### Description

I'm trying to use an agentic graph via langgraph and stream the output to the end user. 
The problem is that the output is not streamed when I use bind_tools function.
I'm already familiar with this [issue](https://github.com/langchain-ai/langchain/issues/26971) but it still doesn't work in my case.


For example the code above outputs:
```
==================== test_chatollama_no_tools ====================
Currently|:| Part|ly| cloudy| with| a| high| of| |22|°C| (|72|°F|)| and| low| of| |18|°C| (|64|°F|).|

==================== test_chatollama_with_tools ====================
Inform the user that the weather is 15°C and it would rain and throw a joke in there also, but keep it brief 20 words max.|"Rainy day in Tokyo! Better grab an umbrella... or a sake to drown your sorrows, as they say!"|

==================== test_chatopenai_no_tools ====================
Currently|:| Part|ly| cloudy| with| a| high| of| |22|°C| (|72|°F|)| and| a| low| of| |18|°C| (|64|°F|).|

==================== test_chatopenai_with_tools ====================
Inform the user that the weather is 15°C and it would rain and throw a joke in there also, but keep it brief 20 words max.|"Rainy days in Tokyo can be 'drizzly' affairs! Current temp: 15°C. Check forecasts for updates."|
```


### System Info

## Package Requirements
langgraph==0.2.37
langchain==0.3.14
langchain_community==0.3.14
langchain-ollama==0.2.2
langchain-openai==0.2.14

## Ollama Version
ollama version is 0.5.4

## System
Ubuntu 24.04.1 LTS
Python 3.12.3