Merge pull request #454 from langchain-ai/nc/add-node-single-arg

Add single arg overload for add_node, which takes function/runnable's…
This commit is contained in:
Nuno Campos
2024-05-16 10:59:23 -07:00
committed by GitHub
3 changed files with 67 additions and 19 deletions
+20 -6
View File
@@ -14,6 +14,7 @@ from typing import (
get_args,
get_origin,
get_type_hints,
overload,
)
from langchain_core.runnables import Runnable
@@ -106,18 +107,31 @@ class Graph:
def _all_edges(self) -> set[tuple[str, str]]:
return self.edges
def add_node(self, key: str, action: RunnableLike) -> None:
@overload
def add_node(self, node: RunnableLike) -> None:
...
@overload
def add_node(self, node: str, action: RunnableLike) -> None:
...
def add_node(
self, node: Union[str, RunnableLike], action: Optional[RunnableLike] = None
) -> None:
if self.compiled:
logger.warning(
"Adding a node to a graph that has already been compiled. This will "
"not be reflected in the compiled graph."
)
if key in self.nodes:
raise ValueError(f"Node `{key}` already present.")
if key == END or key == START:
raise ValueError(f"Node `{key}` is reserved.")
if not isinstance(node, str):
action = node
node = getattr(action, "name", action.__name__)
if node in self.nodes:
raise ValueError(f"Node `{node}` already present.")
if node == END or node == START:
raise ValueError(f"Node `{node}` is reserved.")
self.nodes[key] = coerce_to_runnable(action, name=key, trace=False)
self.nodes[node] = coerce_to_runnable(action, name=node, trace=False)
def add_edge(self, start_key: str, end_key: str) -> None:
if self.compiled:
+40 -6
View File
@@ -1,7 +1,16 @@
import logging
from functools import partial
from inspect import signature
from typing import Any, Optional, Sequence, Type, Union, get_origin, get_type_hints
from typing import (
Any,
Optional,
Sequence,
Type,
Union,
get_origin,
get_type_hints,
overload,
)
from langchain_core.pydantic_v1 import BaseModel
from langchain_core.runnables import Runnable, RunnableConfig
@@ -94,11 +103,28 @@ class StateGraph(Graph):
(start, end) for starts, end in self.waiting_edges for start in starts
}
def add_node(self, key: str, action: RunnableLike) -> None:
@overload
def add_node(self, node: RunnableLike) -> None:
"""Adds a new node to the state graph.
Will take the name of the function/runnable as the node name.
Args:
node (RunnableLike): The function or runnable this node will run.
Raises:
ValueError: If the key is already being used as a state key.
Returns:
None
"""
...
@overload
def add_node(self, node: str, action: RunnableLike) -> None:
"""Adds a new node to the state graph.
Args:
key (str): The key of the node.
node (str): The key of the node.
action (RunnableLike): The action associated with the node.
Raises:
@@ -107,9 +133,17 @@ class StateGraph(Graph):
Returns:
None
"""
if key in self.channels:
raise ValueError(f"'{key}' is already being used as a state key")
return super().add_node(key, action)
...
def add_node(
self, node: Union[str, RunnableLike], action: Optional[RunnableLike] = None
) -> None:
if not isinstance(node, str):
action = node
node = getattr(action, "name", action.__name__)
if node in self.channels:
raise ValueError(f"'{node}' is already being used as a state key")
return super().add_node(node, action)
def add_edge(self, start_key: Union[str, list[str]], end_key: str) -> None:
"""Adds a directed edge from the start node to the end node.
+7 -7
View File
@@ -4683,6 +4683,9 @@ def test_in_one_fan_out_state_graph_waiting_edge(snapshot: SnapshotAssertion) ->
answer: str
docs: Annotated[list[str], sorted_add]
workflow = StateGraph(State)
@workflow.add_node
def rewrite_query(data: State) -> State:
return {"query": f'query: {data["query"]}'}
@@ -4698,13 +4701,10 @@ def test_in_one_fan_out_state_graph_waiting_edge(snapshot: SnapshotAssertion) ->
def qa(data: State) -> State:
return {"answer": ",".join(data["docs"])}
workflow = StateGraph(State)
workflow.add_node("rewrite_query", rewrite_query)
workflow.add_node("analyzer_one", analyzer_one)
workflow.add_node("retriever_one", retriever_one)
workflow.add_node("retriever_two", retriever_two)
workflow.add_node("qa", qa)
workflow.add_node(analyzer_one)
workflow.add_node(retriever_one)
workflow.add_node(retriever_two)
workflow.add_node(qa)
workflow.set_entry_point("rewrite_query")
workflow.add_edge("rewrite_query", "analyzer_one")