[ Skip to content ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graphbetajoin)
**Join us at the inaugural PyAI Conf in San Francisco on March 10th![Learn More](https://pyai.events/?utm_source=pydantic-ai) **
[ ![logo](https://ai.pydantic.dev/img/logo-white.svg) ](https://ai.pydantic.dev/ "Pydantic AI")
Pydantic AI
pydantic_graph.beta.join
Type to start searching
[ pydantic/pydantic-ai
  * v1.63.0
  * 15.1k
  * 1.7k

](https://github.com/pydantic/pydantic-ai "Go to repository")
[ ![logo](https://ai.pydantic.dev/img/logo-white.svg) ](https://ai.pydantic.dev/ "Pydantic AI") Pydantic AI
[ pydantic/pydantic-ai
  * v1.63.0
  * 15.1k
  * 1.7k

](https://github.com/pydantic/pydantic-ai "Go to repository")
  * [ Pydantic AI  ](https://ai.pydantic.dev/)
  * [ Installation  ](https://ai.pydantic.dev/install/)
  * [ Getting Help  ](https://ai.pydantic.dev/help/)
  * [ Troubleshooting  ](https://ai.pydantic.dev/troubleshooting/)
  * [ Pydantic AI Gateway  ](https://ai.pydantic.dev/gateway/)
  * Documentation
    * Core Concepts
      * [ Agents  ](https://ai.pydantic.dev/agent/)
      * [ Dependencies  ](https://ai.pydantic.dev/dependencies/)
      * [ Function Tools  ](https://ai.pydantic.dev/tools/)
      * [ Output  ](https://ai.pydantic.dev/output/)
      * [ Messages and chat history  ](https://ai.pydantic.dev/message-history/)
      * [ Direct Model Requests  ](https://ai.pydantic.dev/direct/)
    * Models & Providers
      * [ Overview  ](https://ai.pydantic.dev/models/overview/)
      * [ OpenAI  ](https://ai.pydantic.dev/models/openai/)
      * [ Anthropic  ](https://ai.pydantic.dev/models/anthropic/)
      * [ Google  ](https://ai.pydantic.dev/models/google/)
      * [ xAI  ](https://ai.pydantic.dev/models/xai/)
      * [ Bedrock  ](https://ai.pydantic.dev/models/bedrock/)
      * [ Cerebras  ](https://ai.pydantic.dev/models/cerebras/)
      * [ Cohere  ](https://ai.pydantic.dev/models/cohere/)
      * [ Groq  ](https://ai.pydantic.dev/models/groq/)
      * [ Hugging Face  ](https://ai.pydantic.dev/models/huggingface/)
      * [ Mistral  ](https://ai.pydantic.dev/models/mistral/)
      * [ OpenRouter  ](https://ai.pydantic.dev/models/openrouter/)
      * [ Outlines  ](https://ai.pydantic.dev/models/outlines/)
    * Tools & Toolsets
      * [ Function Tools  ](https://ai.pydantic.dev/tools/)
      * [ Advanced Tool Features  ](https://ai.pydantic.dev/tools-advanced/)
      * [ Toolsets  ](https://ai.pydantic.dev/toolsets/)
      * [ Deferred Tools  ](https://ai.pydantic.dev/deferred-tools/)
      * [ Built-in Tools  ](https://ai.pydantic.dev/builtin-tools/)
      * [ Common Tools  ](https://ai.pydantic.dev/common-tools/)
      * [ Third-Party Tools  ](https://ai.pydantic.dev/third-party-tools/)
    * Advanced Features
      * [ Image, Audio, Video & Document Input  ](https://ai.pydantic.dev/input/)
      * [ Thinking  ](https://ai.pydantic.dev/thinking/)
      * [ HTTP Request Retries  ](https://ai.pydantic.dev/retries/)
    * MCP
      * [ Overview  ](https://ai.pydantic.dev/mcp/overview/)
      * [ Client  ](https://ai.pydantic.dev/mcp/client/)
      * [ FastMCP Client  ](https://ai.pydantic.dev/mcp/fastmcp-client/)
      * [ Server  ](https://ai.pydantic.dev/mcp/server/)
    * [ Multi-Agent Patterns  ](https://ai.pydantic.dev/multi-agent-applications/)
    * [ Web Chat UI  ](https://ai.pydantic.dev/web/)
    * [ Embeddings  ](https://ai.pydantic.dev/embeddings/)
    * [ Testing  ](https://ai.pydantic.dev/testing/)
  * Pydantic Evals
    * [ Overview  ](https://ai.pydantic.dev/evals/)
    * Getting Started
      * [ Quick Start  ](https://ai.pydantic.dev/evals/quick-start/)
      * [ Core Concepts  ](https://ai.pydantic.dev/evals/core-concepts/)
    * Evaluators
      * [ Overview  ](https://ai.pydantic.dev/evals/evaluators/overview/)
      * [ Built-in Evaluators  ](https://ai.pydantic.dev/evals/evaluators/built-in/)
      * [ LLM Judge  ](https://ai.pydantic.dev/evals/evaluators/llm-judge/)
      * [ Custom Evaluators  ](https://ai.pydantic.dev/evals/evaluators/custom/)
      * [ Report Evaluators  ](https://ai.pydantic.dev/evals/evaluators/report-evaluators/)
      * [ Span-Based  ](https://ai.pydantic.dev/evals/evaluators/span-based/)
    * How-To Guides
      * [ Logfire Integration  ](https://ai.pydantic.dev/evals/how-to/logfire-integration/)
      * [ Dataset Management  ](https://ai.pydantic.dev/evals/how-to/dataset-management/)
      * [ Dataset Serialization  ](https://ai.pydantic.dev/evals/how-to/dataset-serialization/)
      * [ Concurrency & Performance  ](https://ai.pydantic.dev/evals/how-to/concurrency/)
      * [ Multi-Run Evaluation  ](https://ai.pydantic.dev/evals/how-to/multi-run/)
      * [ Retry Strategies  ](https://ai.pydantic.dev/evals/how-to/retry-strategies/)
      * [ Metrics & Attributes  ](https://ai.pydantic.dev/evals/how-to/metrics-attributes/)
    * Examples
      * [ Simple Validation  ](https://ai.pydantic.dev/evals/examples/simple-validation/)
  * Pydantic Graph
    * [ Overview  ](https://ai.pydantic.dev/graph/)
    * [ Beta API  ](https://ai.pydantic.dev/graph/beta/)
      * [ Steps  ](https://ai.pydantic.dev/graph/beta/steps/)
      * [ Joins & Reducers  ](https://ai.pydantic.dev/graph/beta/joins/)
      * [ Decisions  ](https://ai.pydantic.dev/graph/beta/decisions/)
      * [ Parallel Execution  ](https://ai.pydantic.dev/graph/beta/parallel/)
  * Integrations
    * [ Debugging & Monitoring with Pydantic Logfire  ](https://ai.pydantic.dev/logfire/)
    * Durable Execution
      * [ Overview  ](https://ai.pydantic.dev/durable_execution/overview/)
      * [ Temporal  ](https://ai.pydantic.dev/durable_execution/temporal/)
      * [ DBOS  ](https://ai.pydantic.dev/durable_execution/dbos/)
      * [ Prefect  ](https://ai.pydantic.dev/durable_execution/prefect/)
    * UI Event Streams
      * [ Overview  ](https://ai.pydantic.dev/ui/overview/)
      * [ AG-UI  ](https://ai.pydantic.dev/ui/ag-ui/)
      * [ Vercel AI  ](https://ai.pydantic.dev/ui/vercel-ai/)
    * [ Agent2Agent (A2A)  ](https://ai.pydantic.dev/a2a/)
  * Related Packages
    * [ clai  ](https://ai.pydantic.dev/cli/)
  * Examples
    * [ Setup  ](https://ai.pydantic.dev/examples/setup/)
    * Getting Started
      * [ Pydantic Model  ](https://ai.pydantic.dev/examples/pydantic-model/)
      * [ Weather agent  ](https://ai.pydantic.dev/examples/weather-agent/)
    * Conversational Agents
      * [ Chat App with FastAPI  ](https://ai.pydantic.dev/examples/chat-app/)
      * [ Bank support  ](https://ai.pydantic.dev/examples/bank-support/)
    * Data & Analytics
      * [ SQL Generation  ](https://ai.pydantic.dev/examples/sql-gen/)
      * [ Data Analyst  ](https://ai.pydantic.dev/examples/data-analyst/)
      * [ RAG  ](https://ai.pydantic.dev/examples/rag/)
    * Streaming
      * [ Stream markdown  ](https://ai.pydantic.dev/examples/stream-markdown/)
      * [ Stream whales  ](https://ai.pydantic.dev/examples/stream-whales/)
    * Complex Workflows
      * [ Flight booking  ](https://ai.pydantic.dev/examples/flight-booking/)
      * [ Question Graph  ](https://ai.pydantic.dev/examples/question-graph/)
    * Business Applications
      * [ Slack Lead Qualifier with Modal  ](https://ai.pydantic.dev/examples/slack-lead-qualifier/)
    * UI Examples
      * [ Agent User Interaction (AG-UI)  ](https://ai.pydantic.dev/examples/ag-ui/)
  * API Reference
    * pydantic_ai
      * [ pydantic_ai.ag_ui  ](https://ai.pydantic.dev/api/ag_ui/)
      * [ pydantic_ai.agent  ](https://ai.pydantic.dev/api/agent/)
      * [ pydantic_ai.builtin_tools  ](https://ai.pydantic.dev/api/builtin_tools/)
      * [ pydantic_ai.common_tools  ](https://ai.pydantic.dev/api/common_tools/)
      * [ pydantic_ai — Concurrency  ](https://ai.pydantic.dev/api/concurrency/)
      * [ pydantic_ai.direct  ](https://ai.pydantic.dev/api/direct/)
      * [ pydantic_ai.durable_exec  ](https://ai.pydantic.dev/api/durable_exec/)
      * [ pydantic_ai.embeddings  ](https://ai.pydantic.dev/api/embeddings/)
      * [ pydantic_ai.exceptions  ](https://ai.pydantic.dev/api/exceptions/)
      * [ pydantic_ai.ext  ](https://ai.pydantic.dev/api/ext/)
      * [ pydantic_ai.format_prompt  ](https://ai.pydantic.dev/api/format_prompt/)
      * [ pydantic_ai.mcp  ](https://ai.pydantic.dev/api/mcp/)
      * [ pydantic_ai.messages  ](https://ai.pydantic.dev/api/messages/)
      * [ pydantic_ai.models.anthropic  ](https://ai.pydantic.dev/api/models/anthropic/)
      * [ pydantic_ai.models  ](https://ai.pydantic.dev/api/models/base/)
      * [ pydantic_ai.models.bedrock  ](https://ai.pydantic.dev/api/models/bedrock/)
      * [ pydantic_ai.models.cerebras  ](https://ai.pydantic.dev/api/models/cerebras/)
      * [ pydantic_ai.models.cohere  ](https://ai.pydantic.dev/api/models/cohere/)
      * [ pydantic_ai.models.fallback  ](https://ai.pydantic.dev/api/models/fallback/)
      * [ pydantic_ai.models.function  ](https://ai.pydantic.dev/api/models/function/)
      * [ pydantic_ai.models.google  ](https://ai.pydantic.dev/api/models/google/)
      * [ pydantic_ai.models.xai  ](https://ai.pydantic.dev/api/models/xai/)
      * [ pydantic_ai.models.groq  ](https://ai.pydantic.dev/api/models/groq/)
      * [ pydantic_ai.models.huggingface  ](https://ai.pydantic.dev/api/models/huggingface/)
      * [ pydantic_ai.models.instrumented  ](https://ai.pydantic.dev/api/models/instrumented/)
      * [ pydantic_ai.models.mcp_sampling  ](https://ai.pydantic.dev/api/models/mcp-sampling/)
      * [ pydantic_ai.models.mistral  ](https://ai.pydantic.dev/api/models/mistral/)
      * [ pydantic_ai.models.openai  ](https://ai.pydantic.dev/api/models/openai/)
      * [ pydantic_ai.models.openrouter  ](https://ai.pydantic.dev/api/models/openrouter/)
      * [ pydantic_ai.models.outlines  ](https://ai.pydantic.dev/api/models/outlines/)
      * [ pydantic_ai.models.test  ](https://ai.pydantic.dev/api/models/test/)
      * [ pydantic_ai.models.wrapper  ](https://ai.pydantic.dev/api/models/wrapper/)
      * [ pydantic_ai.output  ](https://ai.pydantic.dev/api/output/)
      * [ pydantic_ai.profiles  ](https://ai.pydantic.dev/api/profiles/)
      * [ pydantic_ai.providers  ](https://ai.pydantic.dev/api/providers/)
      * [ pydantic_ai.result  ](https://ai.pydantic.dev/api/result/)
      * [ pydantic_ai.retries  ](https://ai.pydantic.dev/api/retries/)
      * [ pydantic_ai.run  ](https://ai.pydantic.dev/api/run/)
      * [ pydantic_ai.settings  ](https://ai.pydantic.dev/api/settings/)
      * [ pydantic_ai.tools  ](https://ai.pydantic.dev/api/tools/)
      * [ pydantic_ai.toolsets  ](https://ai.pydantic.dev/api/toolsets/)
      * [ pydantic_ai.ui.ag_ui  ](https://ai.pydantic.dev/api/ui/ag_ui/)
      * [ pydantic_ai.ui  ](https://ai.pydantic.dev/api/ui/base/)
      * [ pydantic_ai.ui.vercel_ai  ](https://ai.pydantic.dev/api/ui/vercel_ai/)
      * [ pydantic_ai.usage  ](https://ai.pydantic.dev/api/usage/)
    * pydantic_evals
      * [ pydantic_evals.dataset  ](https://ai.pydantic.dev/api/pydantic_evals/dataset/)
      * [ pydantic_evals.evaluators  ](https://ai.pydantic.dev/api/pydantic_evals/evaluators/)
      * [ pydantic_evals.reporting  ](https://ai.pydantic.dev/api/pydantic_evals/reporting/)
      * [ pydantic_evals.otel  ](https://ai.pydantic.dev/api/pydantic_evals/otel/)
      * [ pydantic_evals.generation  ](https://ai.pydantic.dev/api/pydantic_evals/generation/)
    * pydantic_graph
      * [ pydantic_graph  ](https://ai.pydantic.dev/api/pydantic_graph/graph/)
      * [ pydantic_graph.nodes  ](https://ai.pydantic.dev/api/pydantic_graph/nodes/)
      * [ pydantic_graph.persistence  ](https://ai.pydantic.dev/api/pydantic_graph/persistence/)
      * [ pydantic_graph.mermaid  ](https://ai.pydantic.dev/api/pydantic_graph/mermaid/)
      * [ pydantic_graph.exceptions  ](https://ai.pydantic.dev/api/pydantic_graph/exceptions/)
      * Beta API
        * [ pydantic_graph.beta  ](https://ai.pydantic.dev/api/pydantic_graph/beta/)
        * [ pydantic_graph.beta.graph  ](https://ai.pydantic.dev/api/pydantic_graph/beta_graph/)
        * [ pydantic_graph.beta.graph_builder  ](https://ai.pydantic.dev/api/pydantic_graph/beta_graph_builder/)
        * [ pydantic_graph.beta.step  ](https://ai.pydantic.dev/api/pydantic_graph/beta_step/)
        * pydantic_graph.beta.join  [ pydantic_graph.beta.join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/)
          * [ join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join)
          * [ JoinState  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinState)
          * [ ReducerContext  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext)
            * [ state  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.state)
            * [ deps  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.deps)
            * [ cancel_sibling_tasks  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.cancel_sibling_tasks)
          * [ ReducerFunction  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerFunction)
          * [ reduce_null  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_null)
          * [ reduce_list_append  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_list_append)
          * [ reduce_list_extend  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_list_extend)
          * [ reduce_dict_update  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_dict_update)
          * [ SupportsSum  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.SupportsSum)
          * [ reduce_sum  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_sum)
          * [ ReduceFirstValue  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReduceFirstValue)
            * [ __call__  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReduceFirstValue.__call__)
          * [ Join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join)
            * [ as_node  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join.as_node)
          * [ JoinNode  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode)
            * [ join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.join)
            * [ inputs  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.inputs)
            * [ run  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.run)
        * [ pydantic_graph.beta.decision  ](https://ai.pydantic.dev/api/pydantic_graph/beta_decision/)
        * [ pydantic_graph.beta.node  ](https://ai.pydantic.dev/api/pydantic_graph/beta_node/)
    * fasta2a
      * [ fasta2a  ](https://ai.pydantic.dev/api/fasta2a/)
  * Project
    * [ Contributing  ](https://ai.pydantic.dev/contributing/)
    * [ Upgrade Guide  ](https://ai.pydantic.dev/changelog/)
    * [ Version policy  ](https://ai.pydantic.dev/version-policy/)


  * [ join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join)
  * [ JoinState  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinState)
  * [ ReducerContext  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext)
    * [ state  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.state)
    * [ deps  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.deps)
    * [ cancel_sibling_tasks  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext.cancel_sibling_tasks)
  * [ ReducerFunction  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerFunction)
  * [ reduce_null  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_null)
  * [ reduce_list_append  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_list_append)
  * [ reduce_list_extend  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_list_extend)
  * [ reduce_dict_update  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_dict_update)
  * [ SupportsSum  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.SupportsSum)
  * [ reduce_sum  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.reduce_sum)
  * [ ReduceFirstValue  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReduceFirstValue)
    * [ __call__  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReduceFirstValue.__call__)
  * [ Join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join)
    * [ as_node  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join.as_node)
  * [ JoinNode  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode)
    * [ join  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.join)
    * [ inputs  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.inputs)
    * [ run  ](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode.run)


  1. [ Pydantic AI  ](https://ai.pydantic.dev/)
  2. [ API Reference  ](https://ai.pydantic.dev/api/ag_ui/)
  3. [ pydantic_graph  ](https://ai.pydantic.dev/api/pydantic_graph/graph/)
  4. [ Beta API  ](https://ai.pydantic.dev/api/pydantic_graph/beta/)


# `pydantic_graph.beta.join`
Join operations and reducers for graph execution.
This module provides the core components for joining parallel execution paths in a graph, including various reducer types that aggregate data from multiple sources into a single output.
###  JoinState `dataclass`
The state of a join during graph execution associated to a particular fork run.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
31
32
33
34
35
36
37
```
| ```
@dataclass
class JoinState:
    """The state of a join during graph execution associated to a particular fork run."""

    current: Any
    downstream_fork_stack: ForkStack
    cancelled_sibling_tasks: bool = False

```

---|---
###  ReducerContext `dataclass`
Bases: `Generic[](https://docs.python.org/3/library/typing.html#typing.Generic "typing.Generic")[StateT, DepsT]`
Context information passed to reducer functions during graph execution.
The reducer context provides access to the current graph state and dependencies.
Class Type Parameters:
Name | Bound or Constraints | Description | Default
---|---|---|---
`StateT` |  |  The type of the graph state |  _required_
`DepsT` |  |  The type of the dependencies |  _required_
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
```
| ```
@dataclass(init=False)
class ReducerContext(Generic[StateT, DepsT]):
    """Context information passed to reducer functions during graph execution.

    The reducer context provides access to the current graph state and dependencies.

    Type Parameters:
        StateT: The type of the graph state
        DepsT: The type of the dependencies
    """

    _state: StateT
    """The current graph state."""
    _deps: DepsT
    """The dependencies of the current graph run."""
    _join_state: JoinState
    """The JoinState for this reducer context."""

    def __init__(self, *, state: StateT, deps: DepsT, join_state: JoinState):
        self._state = state
        self._deps = deps
        self._join_state = join_state

    @property
    def state(self) -> StateT:
        """The state of the graph run."""
        return self._state

    @property
    def deps(self) -> DepsT:
        """The deps for the graph run."""
        return self._deps

    def cancel_sibling_tasks(self):
        """Cancel all sibling tasks created from the same fork.

        You can call this if you want your join to have early-stopping behavior.
        """
        self._join_state.cancelled_sibling_tasks = True

```

---|---
####  state `property`
```
state: StateT

```

The state of the graph run.
####  deps `property`
```
deps: DepsT

```

The deps for the graph run.
####  cancel_sibling_tasks
```
cancel_sibling_tasks()

```

Cancel all sibling tasks created from the same fork.
You can call this if you want your join to have early-stopping behavior.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
73
74
75
76
77
78
```
| ```
def cancel_sibling_tasks(self):
    """Cancel all sibling tasks created from the same fork.

    You can call this if you want your join to have early-stopping behavior.
    """
    self._join_state.cancelled_sibling_tasks = True

```

---|---
###  ReducerFunction `module-attribute`
```
ReducerFunction = TypeAliasType[](https://typing-extensions.readthedocs.io/en/latest/index.html#typing_extensions.TypeAliasType "typing_extensions.TypeAliasType")(
    "ReducerFunction",
    ContextReducerFunction[StateT, DepsT, InputT, OutputT]
    | PlainReducerFunction[InputT, OutputT],
    type_params=(StateT, DepsT, InputT, OutputT),
)

```

A function used for reducing inputs to a join node.
###  reduce_null
```
reduce_null(current: None, inputs: Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")) -> None

```

A reducer that discards all input data and returns None.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
101
102
103
```
| ```
def reduce_null(current: None, inputs: Any) -> None:
    """A reducer that discards all input data and returns None."""
    return None

```

---|---
###  reduce_list_append
```
reduce_list_append(
    current: list[](https://docs.python.org/3/library/stdtypes.html#list)[T], inputs: T
) -> list[](https://docs.python.org/3/library/stdtypes.html#list)[T]

```

A reducer that appends to a list.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
106
107
108
109
```
| ```
def reduce_list_append(current: list[T], inputs: T) -> list[T]:
    """A reducer that appends to a list."""
    current.append(inputs)
    return current

```

---|---
###  reduce_list_extend
```
reduce_list_extend(
    current: list[](https://docs.python.org/3/library/stdtypes.html#list)[T], inputs: Iterable[](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable "collections.abc.Iterable")[T]
) -> list[](https://docs.python.org/3/library/stdtypes.html#list)[T]

```

A reducer that extends a list.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
112
113
114
115
```
| ```
def reduce_list_extend(current: list[T], inputs: Iterable[T]) -> list[T]:
    """A reducer that extends a list."""
    current.extend(inputs)
    return current

```

---|---
###  reduce_dict_update
```
reduce_dict_update(
    current: dict[](https://docs.python.org/3/library/stdtypes.html#dict)[K, V], inputs: Mapping[](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping "collections.abc.Mapping")[K, V]
) -> dict[](https://docs.python.org/3/library/stdtypes.html#dict)[K, V]

```

A reducer that updates a dict.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
118
119
120
121
```
| ```
def reduce_dict_update(current: dict[K, V], inputs: Mapping[K, V]) -> dict[K, V]:
    """A reducer that updates a dict."""
    current.update(inputs)
    return current

```

---|---
###  SupportsSum
Bases: `Protocol[](https://typing-extensions.readthedocs.io/en/latest/index.html#typing_extensions.Protocol "typing_extensions.Protocol")`
A protocol for a type that supports adding to itself.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
124
125
126
127
128
129
```
| ```
class SupportsSum(Protocol):
    """A protocol for a type that supports adding to itself."""

    @abstractmethod
    def __add__(self, other: Self, /) -> Self:
        pass

```

---|---
###  reduce_sum
```
reduce_sum(current: NumericT, inputs: NumericT) -> NumericT

```

A reducer that sums numbers.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
135
136
137
```
| ```
def reduce_sum(current: NumericT, inputs: NumericT) -> NumericT:
    """A reducer that sums numbers."""
    return current + inputs

```

---|---
###  ReduceFirstValue `dataclass`
Bases: `Generic[](https://docs.python.org/3/library/typing.html#typing.Generic "typing.Generic")[T]`
A reducer that returns the first value it encounters, and cancels all other tasks.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
140
141
142
143
144
145
146
147
```
| ```
@dataclass
class ReduceFirstValue(Generic[T]):
    """A reducer that returns the first value it encounters, and cancels all other tasks."""

    def __call__(self, ctx: ReducerContext[object, object], current: T, inputs: T) -> T:
        """The reducer function."""
        ctx.cancel_sibling_tasks()
        return inputs

```

---|---
####  __call__
```
__call__(
    ctx: ReducerContext[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerContext "ReducerContext



      dataclass
   \(pydantic_graph.beta.join.ReducerContext\)")[object[](https://docs.python.org/3/library/functions.html#object), object[](https://docs.python.org/3/library/functions.html#object)],
    current: T,
    inputs: T,
) -> T

```

The reducer function.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
144
145
146
147
```
| ```
def __call__(self, ctx: ReducerContext[object, object], current: T, inputs: T) -> T:
    """The reducer function."""
    ctx.cancel_sibling_tasks()
    return inputs

```

---|---
###  Join `dataclass`
Bases: `Generic[](https://docs.python.org/3/library/typing.html#typing.Generic "typing.Generic")[StateT, DepsT, InputT, OutputT]`
A join operation that synchronizes and aggregates parallel execution paths.
A join defines how to combine outputs from multiple parallel execution paths using a [`ReducerFunction`](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.ReducerFunction "ReducerFunction



      module-attribute
  "). It specifies which fork it joins (if any) and manages the initialization of reducers.
Class Type Parameters:
Name | Bound or Constraints | Description | Default
---|---|---|---
`StateT` |  |  The type of the graph state |  _required_
`DepsT` |  |  The type of the dependencies |  _required_
`InputT` |  |  The type of input data to join |  _required_
`OutputT` |  |  The type of the final joined output |  _required_
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
```
| ```
@dataclass(init=False)
class Join(Generic[StateT, DepsT, InputT, OutputT]):
    """A join operation that synchronizes and aggregates parallel execution paths.

    A join defines how to combine outputs from multiple parallel execution paths
    using a [`ReducerFunction`][pydantic_graph.beta.join.ReducerFunction]. It specifies which fork
    it joins (if any) and manages the initialization of reducers.

    Type Parameters:
        StateT: The type of the graph state
        DepsT: The type of the dependencies
        InputT: The type of input data to join
        OutputT: The type of the final joined output
    """

    id: JoinID
    _reducer: ReducerFunction[StateT, DepsT, InputT, OutputT]
    _initial_factory: Callable[[], OutputT]
    parent_fork_id: ForkID | None
    preferred_parent_fork: Literal['closest', 'farthest']

    def __init__(
        self,
        *,
        id: JoinID,
        reducer: ReducerFunction[StateT, DepsT, InputT, OutputT],
        initial_factory: Callable[[], OutputT],
        parent_fork_id: ForkID | None = None,
        preferred_parent_fork: Literal['farthest', 'closest'] = 'farthest',
    ):
        self.id = id
        self._reducer = reducer
        self._initial_factory = initial_factory
        self.parent_fork_id = parent_fork_id
        self.preferred_parent_fork = preferred_parent_fork

    @property
    def reducer(self):
        return self._reducer

    @property
    def initial_factory(self):
        return self._initial_factory

    def reduce(self, ctx: ReducerContext[StateT, DepsT], current: OutputT, inputs: InputT) -> OutputT:
        n_parameters = len(inspect.signature(self.reducer).parameters)
        if n_parameters == 2:
            return cast(PlainReducerFunction[InputT, OutputT], self.reducer)(current, inputs)
        else:
            return cast(ContextReducerFunction[StateT, DepsT, InputT, OutputT], self.reducer)(ctx, current, inputs)

    @overload
    def as_node(self, inputs: None = None) -> JoinNode[StateT, DepsT]: ...

    @overload
    def as_node(self, inputs: InputT) -> JoinNode[StateT, DepsT]: ...

    def as_node(self, inputs: InputT | None = None) -> JoinNode[StateT, DepsT]:
        """Create a step node with bound inputs.

        Args:
            inputs: The input data to bind to this step, or None

        Returns:
            A [`StepNode`][pydantic_graph.beta.step.StepNode] with this step and the bound inputs
        """
        return JoinNode(self, inputs)

```

---|---
####  as_node
```
as_node(inputs: None = None) -> JoinNode[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode "JoinNode



      dataclass
   \(pydantic_graph.beta.join.JoinNode\)")[StateT, DepsT]

```

```
as_node(inputs: InputT) -> JoinNode[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode "JoinNode



      dataclass
   \(pydantic_graph.beta.join.JoinNode\)")[StateT, DepsT]

```

```
as_node(
    inputs: InputT | None = None,
) -> JoinNode[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode "JoinNode



      dataclass
   \(pydantic_graph.beta.join.JoinNode\)")[StateT, DepsT]

```

Create a step node with bound inputs.
Parameters:
Name | Type | Description | Default
---|---|---|---
`inputs` |  `InputT | None` |  The input data to bind to this step, or None |  `None`
Returns:
Type | Description
---|---
`JoinNode[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.JoinNode "JoinNode



      dataclass
   \(pydantic_graph.beta.join.JoinNode\)")[StateT, DepsT]` |  A [`StepNode`](https://ai.pydantic.dev/api/pydantic_graph/beta_step/#pydantic_graph.beta.step.StepNode "StepNode



      dataclass
  ") with this step and the bound inputs
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
207
208
209
210
211
212
213
214
215
216
```
| ```
def as_node(self, inputs: InputT | None = None) -> JoinNode[StateT, DepsT]:
    """Create a step node with bound inputs.

    Args:
        inputs: The input data to bind to this step, or None

    Returns:
        A [`StepNode`][pydantic_graph.beta.step.StepNode] with this step and the bound inputs
    """
    return JoinNode(self, inputs)

```

---|---
###  JoinNode `dataclass`
Bases: `BaseNode[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.BaseNode "BaseNode \(pydantic_graph.BaseNode\)")[StateT, DepsT, Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")]`
A base node that represents a join item with bound inputs.
JoinNode bridges between the v1 and v2 graph execution systems by wrapping a [`Join`](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join "Join



      dataclass
  ") with bound inputs in a BaseNode interface. It is not meant to be run directly but rather used to indicate transitions to v2-style steps.
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
```
| ```
@dataclass
class JoinNode(BaseNode[StateT, DepsT, Any]):
    """A base node that represents a join item with bound inputs.

    JoinNode bridges between the v1 and v2 graph execution systems by wrapping
    a [`Join`][pydantic_graph.beta.join.Join] with bound inputs in a BaseNode interface.
    It is not meant to be run directly but rather used to indicate transitions
    to v2-style steps.
    """

    join: Join[StateT, DepsT, Any, Any]
    """The step to execute."""

    inputs: Any
    """The inputs bound to this step."""

    async def run(self, ctx: GraphRunContext[StateT, DepsT]) -> BaseNode[StateT, DepsT, Any] | End[Any]:
        """Attempt to run the join node.

        Args:
            ctx: The graph execution context

        Returns:
            The result of step execution

        Raises:
            NotImplementedError: Always raised as StepNode is not meant to be run directly
        """
        raise NotImplementedError(
            '`JoinNode` is not meant to be run directly, it is meant to be used in `BaseNode` subclasses to indicate a transition to v2-style steps.'
        )

```

---|---
####  join `instance-attribute`
```
join: Join[](https://ai.pydantic.dev/api/pydantic_graph/beta_join/#pydantic_graph.beta.join.Join "Join



      dataclass
   \(pydantic_graph.beta.join.Join\)")[StateT, DepsT, Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any"), Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")]

```

The step to execute.
####  inputs `instance-attribute`
```
inputs: Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")

```

The inputs bound to this step.
####  run `async`
```
run(
    ctx: GraphRunContext[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.GraphRunContext "GraphRunContext



      dataclass
   \(pydantic_graph.GraphRunContext\)")[StateT, DepsT],
) -> BaseNode[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.BaseNode "BaseNode \(pydantic_graph.BaseNode\)")[StateT, DepsT, Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")] | End[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.End "End



      dataclass
   \(pydantic_graph.End\)")[Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")]

```

Attempt to run the join node.
Parameters:
Name | Type | Description | Default
---|---|---|---
`ctx` |  `GraphRunContext[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.GraphRunContext "GraphRunContext



      dataclass
   \(pydantic_graph.GraphRunContext\)")[StateT, DepsT]` |  The graph execution context |  _required_
Returns:
Type | Description
---|---
`BaseNode[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.BaseNode "BaseNode \(pydantic_graph.BaseNode\)")[StateT, DepsT, Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")] | End[](https://ai.pydantic.dev/api/pydantic_graph/nodes/#pydantic_graph.nodes.End "End



      dataclass
   \(pydantic_graph.End\)")[Any[](https://docs.python.org/3/library/typing.html#typing.Any "typing.Any")]` |  The result of step execution
Raises:
Type | Description
---|---
`NotImplementedError[](https://docs.python.org/3/library/exceptions.html#NotImplementedError)` |  Always raised as StepNode is not meant to be run directly
Source code in `pydantic_graph/pydantic_graph/beta/join.py`
```
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
```
| ```
async def run(self, ctx: GraphRunContext[StateT, DepsT]) -> BaseNode[StateT, DepsT, Any] | End[Any]:
    """Attempt to run the join node.

    Args:
        ctx: The graph execution context

    Returns:
        The result of step execution

    Raises:
        NotImplementedError: Always raised as StepNode is not meant to be run directly
    """
    raise NotImplementedError(
        '`JoinNode` is not meant to be run directly, it is meant to be used in `BaseNode` subclasses to indicate a transition to v2-style steps.'
    )

```

---|---
© Pydantic Services Inc. 2024 to present
