mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-22 09:35:07 +02:00
Merge pull request #262 from langchain-ai/nc/1apr/message-graph-coerce
MessageGraph now accepts same shorthand message formats as langchain-core
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import uuid
|
||||
from typing import Annotated, Union
|
||||
|
||||
from langchain_core.messages import AnyMessage, message_chunk_to_message
|
||||
from langchain_core.messages import (
|
||||
AnyMessage,
|
||||
convert_to_messages,
|
||||
message_chunk_to_message,
|
||||
)
|
||||
|
||||
from langgraph.graph.state import StateGraph
|
||||
|
||||
@@ -14,6 +18,9 @@ def add_messages(left: Messages, right: Messages) -> Messages:
|
||||
left = [left]
|
||||
if not isinstance(right, list):
|
||||
right = [right]
|
||||
# coerce to message
|
||||
left = [message_chunk_to_message(m) for m in convert_to_messages(left)]
|
||||
right = [message_chunk_to_message(m) for m in convert_to_messages(right)]
|
||||
# assign missing ids
|
||||
for m in left:
|
||||
if m.id is None:
|
||||
@@ -21,9 +28,6 @@ def add_messages(left: Messages, right: Messages) -> Messages:
|
||||
for m in right:
|
||||
if m.id is None:
|
||||
m.id = str(uuid.uuid4())
|
||||
# coerce to message
|
||||
left = [message_chunk_to_message(m) for m in left]
|
||||
right = [message_chunk_to_message(m) for m in right]
|
||||
# merge
|
||||
left_idx_by_id = {m.id: i for i, m in enumerate(left)}
|
||||
merged = left.copy()
|
||||
|
||||
+36
-11
@@ -2357,10 +2357,7 @@ def test_message_graph(
|
||||
config = {"configurable": {"thread_id": "1"}}
|
||||
|
||||
assert [
|
||||
c
|
||||
for c in app_w_interrupt.stream(
|
||||
HumanMessage(content="what is weather in sf"), config
|
||||
)
|
||||
c for c in app_w_interrupt.stream(("human", "what is weather in sf"), config)
|
||||
] == [
|
||||
{
|
||||
"agent": AIMessage(
|
||||
@@ -2466,7 +2463,7 @@ def test_message_graph(
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
config,
|
||||
AIMessage(content="answer", id="ai2"),
|
||||
AIMessage(content="answer", id="ai2"), # replace existing message
|
||||
)
|
||||
|
||||
# replaces message even if object identity is different, as long as id is the same
|
||||
@@ -2504,12 +2501,7 @@ def test_message_graph(
|
||||
config = {"configurable": {"thread_id": "2"}}
|
||||
model.i = 0 # reset the llm
|
||||
|
||||
assert [
|
||||
c
|
||||
for c in app_w_interrupt.stream(
|
||||
HumanMessage(content="what is weather in sf"), config
|
||||
)
|
||||
] == [
|
||||
assert [c for c in app_w_interrupt.stream("what is weather in sf", config)] == [
|
||||
{
|
||||
"agent": AIMessage(
|
||||
content="",
|
||||
@@ -2651,6 +2643,39 @@ def test_message_graph(
|
||||
config=app_w_interrupt.checkpointer.get_tuple(config).config,
|
||||
)
|
||||
|
||||
# add an extra message as if it came from "action" node
|
||||
app_w_interrupt.update_state(config, ("ai", "an extra message"), as_node="action")
|
||||
|
||||
# extra message is coerced BaseMessge and appended
|
||||
# now the next node is "agent" per the graph edges
|
||||
assert app_w_interrupt.get_state(config) == StateSnapshot(
|
||||
values=[
|
||||
HumanMessage(
|
||||
content="what is weather in sf",
|
||||
id=AnyStr(),
|
||||
),
|
||||
AIMessage(
|
||||
content="",
|
||||
additional_kwargs={
|
||||
"function_call": {
|
||||
"name": "search_api",
|
||||
"arguments": '"a different query"',
|
||||
}
|
||||
},
|
||||
id="ai1",
|
||||
),
|
||||
FunctionMessage(
|
||||
content="result for a different query",
|
||||
name="search_api",
|
||||
id=AnyStr(),
|
||||
),
|
||||
AIMessage(content="answer", id="ai2"),
|
||||
AIMessage(content="an extra message", id=AnyStr()),
|
||||
],
|
||||
next=("agent",),
|
||||
config=app_w_interrupt.checkpointer.get_tuple(config).config,
|
||||
)
|
||||
|
||||
|
||||
def test_in_one_fan_out_out_one_graph_state() -> None:
|
||||
def sorted_add(x: list[str], y: list[str]) -> list[str]:
|
||||
|
||||
Reference in New Issue
Block a user