adispatch_custom_event not emitted in time when run via langgraph up (works on LangGraph cloud) #327

Closed
opened 2026-02-20 17:36:43 -05:00 by yindo · 1 comment
Owner

Originally created by @mme on GitHub (Nov 28, 2024).

Originally assigned to: @eyurtsev on GitHub.

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph/LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangGraph/LangChain rather than my code.
  • I am sure this is better as an issue rather than a GitHub discussion, since this is a LangGraph bug and not a design question.

Example Code

# This snippet is from the CopilotKit <> LangGraph integration
# We are using copilotkit_emit_state to send state updates to CopilotKit while
# a node is running.
# copilotkit_emit_state is just a thin wrapper around adispatch_custom_event:
# https://github.com/CopilotKit/CopilotKit/blob/3b362e5858f193c56e0e3baf184451eb1d6170fe/sdk-python/copilotkit/langchain.py#L120

async def search_node(state: AgentState, config: RunnableConfig):
    """
    The search node is responsible for searching the internet for resources.
    """
    ai_message = cast(AIMessage, state["messages"][-1])

    state["resources"] = state.get("resources", [])
    state["logs"] = state.get("logs", [])
    queries = ai_message.tool_calls[0]["args"]["queries"]

    for query in queries:
        state["logs"].append({
            "message": f"Search for {query}",
            "done": False
        })

    await copilotkit_emit_state(config, state)

    search_results = []

    for i, query in enumerate(queries):
        response = tavily_client.search(query)
        search_results.append(response)
        state["logs"][i]["done"] = True
        await copilotkit_emit_state(config, state)

    config = copilotkit_customize_config(
        config,
        emit_intermediate_state=[{
            "state_key": "resources",
            "tool": "ExtractResources",
            "tool_argument": "resources",
        }],
    )

    model = get_model(state)
    ainvoke_kwargs = {}
    if model.__class__.__name__ in ["ChatOpenAI"]:
        ainvoke_kwargs["parallel_tool_calls"] = False

    # figure out which resources to use
    response = await model.bind_tools(
        [ExtractResources],
        tool_choice="ExtractResources",
        **ainvoke_kwargs
    ).ainvoke([
        SystemMessage(
            content="""
            You need to extract the 3-5 most relevant resources from the following search results.
            """
        ),
        *state["messages"],
        ToolMessage(
        tool_call_id=ai_message.tool_calls[0]["id"],
        content=f"Performed search: {search_results}"
    )
    ], config)

    state["logs"] = []
    await copilotkit_emit_state(config, state)

Error Message and Stack Trace (if applicable)

No response

Description

On cloud, the custom event is immediately sent. With the local setup via langgraph up, the events are sent with a delay and arrive in the wrong order (so the user can see the current status of the searches being performed)

System Info

CLI

$ langgraph --version
LangGraph CLI, version 0.1.60

System Information

OS: Darwin
OS Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000
Python Version: 3.11.9 (main, Apr 2 2024, 08:25:04) [Clang 15.0.0 (clang-1500.3.9.4)]

Package Information

langchain_core: 0.3.19
langchain: 0.3.7
langsmith: 0.1.143
langchain_openai: 0.2.9
langchain_text_splitters: 0.3.2
langgraph: 0.2.52
langserve: 0.0.41

Other Dependencies

aiohttp: 3.10.5
async-timeout: 4.0.2
fastapi: 0.115.0
httpx: 0.27.2
httpx-sse: 0.4.0
jsonpatch: 1.33
langgraph-checkpoint: 2.0.5
langgraph-sdk: 0.1.36
numpy: 1.26.4
openai: 1.54.5
orjson: 3.10.7
packaging: 24.1
pydantic: 2.9.2
PyYAML: 6.0.2
requests: 2.32.3
requests-toolbelt: 1.0.0
SQLAlchemy: 2.0.35
sse-starlette: 2.1.3
tenacity: 8.5.0
tiktoken: 0.7.0
typing-extensions: 4.12.2

Originally created by @mme on GitHub (Nov 28, 2024). Originally assigned to: @eyurtsev on GitHub. ### Checked other resources - [X] I added a very descriptive title to this issue. - [X] I searched the [LangGraph](https://langchain-ai.github.io/langgraph/)/LangChain documentation with the integrated search. - [X] I used the GitHub search to find a similar question and didn't find it. - [X] I am sure that this is a bug in LangGraph/LangChain rather than my code. - [X] I am sure this is better as an issue [rather than a GitHub discussion](https://github.com/langchain-ai/langgraph/discussions/new/choose), since this is a LangGraph bug and not a design question. ### Example Code ```python # This snippet is from the CopilotKit <> LangGraph integration # We are using copilotkit_emit_state to send state updates to CopilotKit while # a node is running. # copilotkit_emit_state is just a thin wrapper around adispatch_custom_event: # https://github.com/CopilotKit/CopilotKit/blob/3b362e5858f193c56e0e3baf184451eb1d6170fe/sdk-python/copilotkit/langchain.py#L120 async def search_node(state: AgentState, config: RunnableConfig): """ The search node is responsible for searching the internet for resources. """ ai_message = cast(AIMessage, state["messages"][-1]) state["resources"] = state.get("resources", []) state["logs"] = state.get("logs", []) queries = ai_message.tool_calls[0]["args"]["queries"] for query in queries: state["logs"].append({ "message": f"Search for {query}", "done": False }) await copilotkit_emit_state(config, state) search_results = [] for i, query in enumerate(queries): response = tavily_client.search(query) search_results.append(response) state["logs"][i]["done"] = True await copilotkit_emit_state(config, state) config = copilotkit_customize_config( config, emit_intermediate_state=[{ "state_key": "resources", "tool": "ExtractResources", "tool_argument": "resources", }], ) model = get_model(state) ainvoke_kwargs = {} if model.__class__.__name__ in ["ChatOpenAI"]: ainvoke_kwargs["parallel_tool_calls"] = False # figure out which resources to use response = await model.bind_tools( [ExtractResources], tool_choice="ExtractResources", **ainvoke_kwargs ).ainvoke([ SystemMessage( content=""" You need to extract the 3-5 most relevant resources from the following search results. """ ), *state["messages"], ToolMessage( tool_call_id=ai_message.tool_calls[0]["id"], content=f"Performed search: {search_results}" ) ], config) state["logs"] = [] await copilotkit_emit_state(config, state) ``` ### Error Message and Stack Trace (if applicable) _No response_ ### Description On cloud, the custom event is immediately sent. With the local setup via `langgraph up`, the events are sent with a delay and arrive in the wrong order (so the user can see the current status of the searches being performed) ### System Info CLI ------------------ > $ langgraph --version > LangGraph CLI, version 0.1.60 System Information ------------------ > OS: Darwin > OS Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000 > Python Version: 3.11.9 (main, Apr 2 2024, 08:25:04) [Clang 15.0.0 (clang-1500.3.9.4)] Package Information ------------------- > langchain_core: 0.3.19 > langchain: 0.3.7 > langsmith: 0.1.143 > langchain_openai: 0.2.9 > langchain_text_splitters: 0.3.2 > langgraph: 0.2.52 > langserve: 0.0.41 Other Dependencies ------------------ > aiohttp: 3.10.5 > async-timeout: 4.0.2 > fastapi: 0.115.0 > httpx: 0.27.2 > httpx-sse: 0.4.0 > jsonpatch: 1.33 > langgraph-checkpoint: 2.0.5 > langgraph-sdk: 0.1.36 > numpy: 1.26.4 > openai: 1.54.5 > orjson: 3.10.7 > packaging: 24.1 > pydantic: 2.9.2 > PyYAML: 6.0.2 > requests: 2.32.3 > requests-toolbelt: 1.0.0 > SQLAlchemy: 2.0.35 > sse-starlette: 2.1.3 > tenacity: 8.5.0 > tiktoken: 0.7.0 > typing-extensions: 4.12.2
yindo closed this issue 2026-02-20 17:36:43 -05:00
Author
Owner

@mme commented on GitHub (Dec 2, 2024):

Closing. The issue was that response = tavily_client.search(query) is a blocking call. Switching to an async call fixed the issue.

@mme commented on GitHub (Dec 2, 2024): Closing. The issue was that `response = tavily_client.search(query)` is a blocking call. Switching to an async call fixed the issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#327