diff --git a/libs/langgraph/langgraph/utils/config.py b/libs/langgraph/langgraph/utils/config.py index 064a2b408..47de1f021 100644 --- a/libs/langgraph/langgraph/utils/config.py +++ b/libs/langgraph/langgraph/utils/config.py @@ -1,3 +1,5 @@ +import asyncio +import sys from collections import ChainMap from typing import Any, Optional, Sequence @@ -293,6 +295,14 @@ def ensure_config(*configs: Optional[RunnableConfig]) -> RunnableConfig: def get_configurable() -> dict[str, Any]: + if sys.version_info < (3, 11): + try: + if asyncio.current_task(): + raise RuntimeError( + "Python 3.11 or later required to use this in an async context" + ) + except RuntimeError: + pass if var_config := var_child_runnable_config.get(): return var_config[CONF] else: diff --git a/libs/langgraph/tests/__snapshots__/test_pregel_async.ambr b/libs/langgraph/tests/__snapshots__/test_pregel_async.ambr index 3d4021111..adef94c62 100644 --- a/libs/langgraph/tests/__snapshots__/test_pregel_async.ambr +++ b/libs/langgraph/tests/__snapshots__/test_pregel_async.ambr @@ -1334,18 +1334,14 @@ __start__([
__start__
]):::first router_node(router_node) normal_llm_node(normal_llm_node) - weather_graph_model_node(model_node) - weather_graph_weather_node(weather_node__end__
]):::last __start__ --> router_node; normal_llm_node --> __end__; - weather_graph_weather_node --> __end__; + weather_graph --> __end__; router_node -.-> normal_llm_node; - router_node -.-> weather_graph_model_node; + router_node -.-> weather_graph; router_node -.-> __end__; - subgraph weather_graph - weather_graph_model_node --> weather_graph_weather_node; - end classDef default fill:#f2f0ff,line-height:1.2 classDef first fill-opacity:0 classDef last fill:#bfb6fc diff --git a/libs/langgraph/tests/test_pregel_async.py b/libs/langgraph/tests/test_pregel_async.py index 1e4823d7e..022076fd9 100644 --- a/libs/langgraph/tests/test_pregel_async.py +++ b/libs/langgraph/tests/test_pregel_async.py @@ -257,6 +257,10 @@ async def test_node_cancellation_on_other_node_exception_two() -> None: await graph.ainvoke(1) +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="Python 3.11+ is required for async contextvars support", +) @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) async def test_dynamic_interrupt(checkpointer_name: str) -> None: class State(TypedDict): @@ -399,6 +403,10 @@ async def test_dynamic_interrupt(checkpointer_name: str) -> None: ) +@pytest.mark.skipif( + sys.version_info < (3, 11), + reason="Python 3.11+ is required for async contextvars support", +) @pytest.mark.parametrize("checkpointer_name", ALL_CHECKPOINTERS_ASYNC) async def test_node_not_cancelled_on_other_node_interrupted( checkpointer_name: str,