-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1792 from langchain-ai/nc/21sep/docstrings-comments
Add more comments and docstrings
- Loading branch information
Showing
33 changed files
with
852 additions
and
612 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,133 +1,109 @@ | ||
from dataclasses import dataclass | ||
from types import MappingProxyType | ||
from typing import Any, Literal, Mapping | ||
from typing import Any, Mapping | ||
|
||
from langgraph.types import Interrupt, Send # noqa: F401 | ||
|
||
# Interrupt, Send re-exported for backwards compatibility | ||
|
||
|
||
# --- Empty read-only containers --- | ||
EMPTY_MAP: Mapping[str, Any] = MappingProxyType({}) | ||
EMPTY_SEQ: tuple[str, ...] = tuple() | ||
|
||
# --- Public constants --- | ||
TAG_HIDDEN = "langsmith:hidden" | ||
# tag to hide a node/edge from certain tracing/streaming environments | ||
START = "__start__" | ||
# the first (maybe virtual) node in graph-style Pregel | ||
END = "__end__" | ||
# the last (maybe virtual) node in graph-style Pregel | ||
|
||
# --- Reserved write keys --- | ||
INPUT = "__input__" | ||
# for values passed as input to the graph | ||
INTERRUPT = "__interrupt__" | ||
# for dynamic interrupts raised by nodes | ||
ERROR = "__error__" | ||
# for errors raised by nodes | ||
NO_WRITES = "__no_writes__" | ||
# marker to signal node didn't write anything | ||
SCHEDULED = "__scheduled__" | ||
# marker to signal node was scheduled (in distributed mode) | ||
TASKS = "__pregel_tasks" | ||
# for Send objects returned by nodes/edges, corresponds to PUSH below | ||
|
||
# --- Reserved config.configurable keys --- | ||
CONFIG_KEY_SEND = "__pregel_send" | ||
# holds the `write` function that accepts writes to state/edges/reserved keys | ||
CONFIG_KEY_READ = "__pregel_read" | ||
# holds the `read` function that returns a copy of the current state | ||
CONFIG_KEY_CHECKPOINTER = "__pregel_checkpointer" | ||
# holds a `BaseCheckpointSaver` passed from parent graph to child graphs | ||
CONFIG_KEY_STREAM = "__pregel_stream" | ||
# holds a `StreamProtocol` passed from parent graph to child graphs | ||
CONFIG_KEY_STREAM_WRITER = "__pregel_stream_writer" | ||
# holds a `StreamWriter` for stream_mode=custom | ||
CONFIG_KEY_STORE = "__pregel_store" | ||
# holds a `BaseStore` made available to managed values | ||
CONFIG_KEY_RESUMING = "__pregel_resuming" | ||
# holds a boolean indicating if subgraphs should resume from a previous checkpoint | ||
CONFIG_KEY_TASK_ID = "__pregel_task_id" | ||
# holds the task ID for the current task | ||
CONFIG_KEY_DEDUPE_TASKS = "__pregel_dedupe_tasks" | ||
# holds a boolean indicating if tasks should be deduplicated (for distributed mode) | ||
CONFIG_KEY_ENSURE_LATEST = "__pregel_ensure_latest" | ||
# holds a boolean indicating whether to assert the requested checkpoint is the latest | ||
# (for distributed mode) | ||
CONFIG_KEY_DELEGATE = "__pregel_delegate" | ||
# this one part of public API so more readable | ||
# holds a boolean indicating whether to delegate subgraphs (for distributed mode) | ||
CONFIG_KEY_CHECKPOINT_MAP = "checkpoint_map" | ||
INTERRUPT = "__interrupt__" | ||
ERROR = "__error__" | ||
NO_WRITES = "__no_writes__" | ||
SCHEDULED = "__scheduled__" | ||
TASKS = "__pregel_tasks" # for backwards compat, this is the original name of PUSH | ||
# holds a mapping of checkpoint_ns -> checkpoint_id for parent graphs | ||
CONFIG_KEY_CHECKPOINT_ID = "checkpoint_id" | ||
# holds the current checkpoint_id, if any | ||
CONFIG_KEY_CHECKPOINT_NS = "checkpoint_ns" | ||
# holds the current checkpoint_ns, "" for root graph | ||
|
||
# --- Other constants --- | ||
PUSH = "__pregel_push" | ||
# denotes push-style tasks, ie. those created by Send objects | ||
PULL = "__pregel_pull" | ||
# denotes pull-style tasks, ie. those triggered by edges | ||
RUNTIME_PLACEHOLDER = "__pregel_runtime_placeholder__" | ||
# placeholder for managed values replaced at runtime | ||
NS_SEP = "|" | ||
# for checkpoint_ns, separates each level (ie. graph|subgraph|subsubgraph) | ||
NS_END = ":" | ||
# for checkpoint_ns, for each level, separates the namespace from the task_id | ||
|
||
RESERVED = { | ||
SCHEDULED, | ||
TAG_HIDDEN, | ||
# reserved write keys | ||
INPUT, | ||
INTERRUPT, | ||
ERROR, | ||
NO_WRITES, | ||
SCHEDULED, | ||
TASKS, | ||
PUSH, | ||
PULL, | ||
# reserved config.configurable keys | ||
CONFIG_KEY_SEND, | ||
CONFIG_KEY_READ, | ||
CONFIG_KEY_CHECKPOINTER, | ||
CONFIG_KEY_CHECKPOINT_MAP, | ||
CONFIG_KEY_STREAM, | ||
CONFIG_KEY_STREAM_WRITER, | ||
CONFIG_KEY_STORE, | ||
CONFIG_KEY_CHECKPOINT_MAP, | ||
CONFIG_KEY_RESUMING, | ||
CONFIG_KEY_TASK_ID, | ||
CONFIG_KEY_DEDUPE_TASKS, | ||
CONFIG_KEY_ENSURE_LATEST, | ||
CONFIG_KEY_DELEGATE, | ||
INPUT, | ||
CONFIG_KEY_CHECKPOINT_MAP, | ||
CONFIG_KEY_CHECKPOINT_ID, | ||
CONFIG_KEY_CHECKPOINT_NS, | ||
# other constants | ||
PUSH, | ||
PULL, | ||
RUNTIME_PLACEHOLDER, | ||
NS_SEP, | ||
NS_END, | ||
} | ||
TAG_HIDDEN = "langsmith:hidden" | ||
|
||
START = "__start__" | ||
END = "__end__" | ||
|
||
NS_SEP = "|" | ||
NS_END = ":" | ||
|
||
EMPTY_MAP: Mapping[str, Any] = MappingProxyType({}) | ||
|
||
|
||
class Send: | ||
"""A message or packet to send to a specific node in the graph. | ||
The `Send` class is used within a `StateGraph`'s conditional edges to | ||
dynamically invoke a node with a custom state at the next step. | ||
Importantly, the sent state can differ from the core graph's state, | ||
allowing for flexible and dynamic workflow management. | ||
One such example is a "map-reduce" workflow where your graph invokes | ||
the same node multiple times in parallel with different states, | ||
before aggregating the results back into the main graph's state. | ||
Attributes: | ||
node (str): The name of the target node to send the message to. | ||
arg (Any): The state or message to send to the target node. | ||
Examples: | ||
>>> from typing import Annotated | ||
>>> import operator | ||
>>> class OverallState(TypedDict): | ||
... subjects: list[str] | ||
... jokes: Annotated[list[str], operator.add] | ||
... | ||
>>> from langgraph.constants import Send | ||
>>> from langgraph.graph import END, START | ||
>>> def continue_to_jokes(state: OverallState): | ||
... return [Send("generate_joke", {"subject": s}) for s in state['subjects']] | ||
... | ||
>>> from langgraph.graph import StateGraph | ||
>>> builder = StateGraph(OverallState) | ||
>>> builder.add_node("generate_joke", lambda state: {"jokes": [f"Joke about {state['subject']}"]}) | ||
>>> builder.add_conditional_edges(START, continue_to_jokes) | ||
>>> builder.add_edge("generate_joke", END) | ||
>>> graph = builder.compile() | ||
>>> | ||
>>> # Invoking with two subjects results in a generated joke for each | ||
>>> graph.invoke({"subjects": ["cats", "dogs"]}) | ||
{'subjects': ['cats', 'dogs'], 'jokes': ['Joke about cats', 'Joke about dogs']} | ||
""" | ||
|
||
node: str | ||
arg: Any | ||
|
||
def __init__(self, /, node: str, arg: Any) -> None: | ||
""" | ||
Initialize a new instance of the Send class. | ||
Args: | ||
node (str): The name of the target node to send the message to. | ||
arg (Any): The state or message to send to the target node. | ||
""" | ||
self.node = node | ||
self.arg = arg | ||
|
||
def __hash__(self) -> int: | ||
return hash((self.node, self.arg)) | ||
|
||
def __repr__(self) -> str: | ||
return f"Send(node={self.node!r}, arg={self.arg!r})" | ||
|
||
def __eq__(self, value: object) -> bool: | ||
return ( | ||
isinstance(value, Send) | ||
and self.node == value.node | ||
and self.arg == value.arg | ||
) | ||
|
||
|
||
@dataclass | ||
class Interrupt: | ||
value: Any | ||
when: Literal["during"] = "during" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.