mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-27 12:04:58 +02:00
Support multiple resume values with Command.resume (#4406)
* Adding support for mapping interrupt ids -> resume values with the
`Command.resume_map` argument, like:
```py
resume_map = {
i.interrupt_id: f"human input for prompt {i.value}"
for i in parent_graph.get_state(thread_config).interrupts
}
parent_graph.invoke(Command(resume=resume_map), config=thread_config)
```
* Adds an `interrupts` attribute on `StateSnapshot` so that we can
access that directly rather than having to do
`get_state(thread_config).tasks` and then iterate over tasks to find
interrupts
* Deprecates undocumented feature where (if interrupting a graph from
the level of an interrupt), you could pass a dict mapping task ids ->
resume values. Now we recommend and endorse the `interrupt_id` approach
above.
I'll note, from an internal perspective, I would love if we didn't have
to pass around this map, but it seems like the best way right now to
make the necessary resume information necessary at different levels in a
graph with subgraphs.
Fix https://github.com/langchain-ai/langgraph/issues/4028
Slotted to be included in our v0.4.0 release early next week!
This commit is contained in:
@@ -440,6 +440,22 @@ Upon **resuming** the graph, the counter will be incremented a second time, resu
|
||||
The value of counter is: 2
|
||||
```
|
||||
|
||||
### Resuming multiple interrupts with one invocation
|
||||
|
||||
If you have multiple interrupts in the task queue, you can use `Command.resume` with a dictionary mapping
|
||||
of interrupt ids to resume values to resume multiple interrupts with a single `invoke` / `stream` call.
|
||||
|
||||
For example, once your graph has been interrupted (multiple times, theoretically) and is stalled:
|
||||
|
||||
```python
|
||||
resume_map = {
|
||||
i.interrupt_id: f"human input for prompt {i.value}"
|
||||
for i in parent.get_state(thread_config).interrupts
|
||||
}
|
||||
|
||||
parent_graph.invoke(Command(resume=resume_map), config=thread_config)
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Side-effects
|
||||
|
||||
@@ -102,6 +102,8 @@ CONF = cast(Literal["configurable"], sys.intern("configurable"))
|
||||
# key for the configurable dict in RunnableConfig
|
||||
NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
|
||||
# the task_id to use for writes that are not associated with a task
|
||||
CONFIG_KEY_RESUME_MAP = sys.intern("__pregel_resume_map")
|
||||
# holds a mapping of task ns -> resume value for resuming tasks
|
||||
|
||||
RESERVED = {
|
||||
TAG_HIDDEN,
|
||||
|
||||
@@ -853,6 +853,7 @@ class Pregel(PregelProtocol):
|
||||
created_at=None,
|
||||
parent_config=None,
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# migrate checkpoint if needed
|
||||
@@ -937,6 +938,12 @@ class Pregel(PregelProtocol):
|
||||
next_tasks[tid].writes.append((k, v))
|
||||
if tasks := [t for t in next_tasks.values() if t.writes]:
|
||||
apply_writes(saved.checkpoint, channels, tasks, None)
|
||||
tasks_with_writes = tasks_w_writes(
|
||||
next_tasks.values(),
|
||||
saved.pending_writes,
|
||||
task_states,
|
||||
self.stream_channels_asis,
|
||||
)
|
||||
# assemble the state snapshot
|
||||
return StateSnapshot(
|
||||
read_channels(channels, self.stream_channels_asis),
|
||||
@@ -945,12 +952,8 @@ class Pregel(PregelProtocol):
|
||||
saved.metadata,
|
||||
saved.checkpoint["ts"],
|
||||
patch_checkpoint_map(saved.parent_config, saved.metadata),
|
||||
tasks_w_writes(
|
||||
next_tasks.values(),
|
||||
saved.pending_writes,
|
||||
task_states,
|
||||
self.stream_channels_asis,
|
||||
),
|
||||
tasks_with_writes,
|
||||
tuple([i for task in tasks_with_writes for i in task.interrupts]),
|
||||
)
|
||||
|
||||
async def _aprepare_state_snapshot(
|
||||
@@ -969,6 +972,7 @@ class Pregel(PregelProtocol):
|
||||
created_at=None,
|
||||
parent_config=None,
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# migrate checkpoint if needed
|
||||
@@ -1056,6 +1060,13 @@ class Pregel(PregelProtocol):
|
||||
next_tasks[tid].writes.append((k, v))
|
||||
if tasks := [t for t in next_tasks.values() if t.writes]:
|
||||
apply_writes(saved.checkpoint, channels, tasks, None)
|
||||
|
||||
tasks_with_writes = tasks_w_writes(
|
||||
next_tasks.values(),
|
||||
saved.pending_writes,
|
||||
task_states,
|
||||
self.stream_channels_asis,
|
||||
)
|
||||
# assemble the state snapshot
|
||||
return StateSnapshot(
|
||||
read_channels(channels, self.stream_channels_asis),
|
||||
@@ -1064,12 +1075,8 @@ class Pregel(PregelProtocol):
|
||||
saved.metadata,
|
||||
saved.checkpoint["ts"],
|
||||
patch_checkpoint_map(saved.parent_config, saved.metadata),
|
||||
tasks_w_writes(
|
||||
next_tasks.values(),
|
||||
saved.pending_writes,
|
||||
task_states,
|
||||
self.stream_channels_asis,
|
||||
),
|
||||
tasks_with_writes,
|
||||
tuple([i for task in tasks_with_writes for i in task.interrupts]),
|
||||
)
|
||||
|
||||
def get_state(
|
||||
|
||||
@@ -40,6 +40,7 @@ from langgraph.constants import (
|
||||
CONFIG_KEY_CHECKPOINTER,
|
||||
CONFIG_KEY_PREVIOUS,
|
||||
CONFIG_KEY_READ,
|
||||
CONFIG_KEY_RESUME_MAP,
|
||||
CONFIG_KEY_SCRATCHPAD,
|
||||
CONFIG_KEY_SEND,
|
||||
CONFIG_KEY_STORE,
|
||||
@@ -594,6 +595,8 @@ def prepare_single_task(
|
||||
config[CONF].get(CONFIG_KEY_SCRATCHPAD),
|
||||
pending_writes,
|
||||
task_id,
|
||||
xxh3_128_hexdigest(task_checkpoint_ns.encode()),
|
||||
config[CONF].get(CONFIG_KEY_RESUME_MAP),
|
||||
),
|
||||
},
|
||||
),
|
||||
@@ -704,6 +707,8 @@ def prepare_single_task(
|
||||
config[CONF].get(CONFIG_KEY_SCRATCHPAD),
|
||||
pending_writes,
|
||||
task_id,
|
||||
xxh3_128_hexdigest(task_checkpoint_ns.encode()),
|
||||
config[CONF].get(CONFIG_KEY_RESUME_MAP),
|
||||
),
|
||||
CONFIG_KEY_PREVIOUS: checkpoint["channel_values"].get(
|
||||
PREVIOUS, None
|
||||
@@ -830,6 +835,8 @@ def prepare_single_task(
|
||||
config[CONF].get(CONFIG_KEY_SCRATCHPAD),
|
||||
pending_writes,
|
||||
task_id,
|
||||
xxh3_128_hexdigest(task_checkpoint_ns.encode()),
|
||||
config[CONF].get(CONFIG_KEY_RESUME_MAP),
|
||||
),
|
||||
CONFIG_KEY_PREVIOUS: checkpoint["channel_values"].get(
|
||||
PREVIOUS, None
|
||||
@@ -881,6 +888,8 @@ def _scratchpad(
|
||||
parent_scratchpad: Optional[PregelScratchpad],
|
||||
pending_writes: list[PendingWrite],
|
||||
task_id: str,
|
||||
namespace_hash: str,
|
||||
resume_map: Optional[dict[str, Any]],
|
||||
) -> PregelScratchpad:
|
||||
if len(pending_writes) > 0:
|
||||
# find global resume value
|
||||
@@ -892,6 +901,7 @@ def _scratchpad(
|
||||
# None cannot be used as a resume value, because it would be difficult to
|
||||
# distinguish from missing when used over http
|
||||
null_resume_write = None
|
||||
|
||||
# find task-specific resume value
|
||||
for w in pending_writes:
|
||||
if w[0] == task_id and w[1] == RESUME:
|
||||
@@ -901,8 +911,13 @@ def _scratchpad(
|
||||
break
|
||||
else:
|
||||
task_resume_write = []
|
||||
# clear var
|
||||
del w
|
||||
|
||||
# find namespace and task-specific resume value
|
||||
if resume_map and namespace_hash in resume_map:
|
||||
mapped_resume_write = resume_map[namespace_hash]
|
||||
task_resume_write.append(mapped_resume_write)
|
||||
|
||||
else:
|
||||
null_resume_write = None
|
||||
task_resume_write = []
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
from collections import Counter
|
||||
from collections.abc import Iterator, Mapping, Sequence
|
||||
from typing import Any, Literal, Optional, TypeVar, Union
|
||||
from uuid import UUID
|
||||
|
||||
from langchain_core.runnables.utils import AddableDict
|
||||
|
||||
from langgraph.channels.base import BaseChannel, EmptyChannelError
|
||||
from langgraph.checkpoint.base import PendingWrite
|
||||
from langgraph.constants import (
|
||||
EMPTY_SEQ,
|
||||
ERROR,
|
||||
@@ -24,15 +22,6 @@ from langgraph.pregel.log import logger
|
||||
from langgraph.types import Command, PregelExecutableTask, Send
|
||||
|
||||
|
||||
def is_task_id(task_id: str) -> bool:
|
||||
"""Check if a string is a valid task id."""
|
||||
try:
|
||||
UUID(task_id)
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def read_channel(
|
||||
channels: Mapping[str, BaseChannel],
|
||||
chan: str,
|
||||
@@ -66,9 +55,7 @@ def read_channels(
|
||||
return values
|
||||
|
||||
|
||||
def map_command(
|
||||
cmd: Command, pending_writes: list[PendingWrite]
|
||||
) -> Iterator[tuple[str, str, Any]]:
|
||||
def map_command(cmd: Command) -> Iterator[tuple[str, str, Any]]:
|
||||
"""Map input chunk to a sequence of pending writes in the form (channel, value)."""
|
||||
if cmd.graph == Command.PARENT:
|
||||
raise InvalidUpdateError("There is no parent graph")
|
||||
@@ -87,15 +74,7 @@ def map_command(
|
||||
f"In Command.goto, expected Send/str, got {type(send).__name__}"
|
||||
)
|
||||
if cmd.resume is not None:
|
||||
if isinstance(cmd.resume, dict) and all(is_task_id(k) for k in cmd.resume):
|
||||
for tid, resume in cmd.resume.items():
|
||||
existing: list[Any] = next(
|
||||
(w[2] for w in pending_writes if w[0] == tid and w[1] == RESUME), []
|
||||
)
|
||||
existing.append(resume)
|
||||
yield (tid, RESUME, existing)
|
||||
else:
|
||||
yield (NULL_TASK_ID, RESUME, cmd.resume)
|
||||
yield (NULL_TASK_ID, RESUME, cmd.resume)
|
||||
if cmd.update:
|
||||
for k, v in cmd._update_as_tuples():
|
||||
yield (NULL_TASK_ID, k, v)
|
||||
|
||||
@@ -47,6 +47,7 @@ from langgraph.constants import (
|
||||
CONFIG_KEY_DEDUPE_TASKS,
|
||||
CONFIG_KEY_DELEGATE,
|
||||
CONFIG_KEY_ENSURE_LATEST,
|
||||
CONFIG_KEY_RESUME_MAP,
|
||||
CONFIG_KEY_RESUMING,
|
||||
CONFIG_KEY_SCRATCHPAD,
|
||||
CONFIG_KEY_STREAM,
|
||||
@@ -112,7 +113,7 @@ from langgraph.pregel.io import (
|
||||
)
|
||||
from langgraph.pregel.manager import AsyncChannelsManager, ChannelsManager
|
||||
from langgraph.pregel.read import PregelNode
|
||||
from langgraph.pregel.utils import get_new_channel_versions
|
||||
from langgraph.pregel.utils import get_new_channel_versions, is_xxh3_128_hexdigest
|
||||
from langgraph.store.base import BaseStore
|
||||
from langgraph.types import (
|
||||
All,
|
||||
@@ -649,14 +650,21 @@ class PregelLoop(LoopProtocol):
|
||||
|
||||
# map command to writes
|
||||
if isinstance(self.input, Command):
|
||||
if self.input.resume is not None and not self.checkpointer:
|
||||
if resume_is_map := (
|
||||
(resume := self.input.resume) is not None
|
||||
and isinstance(resume, dict)
|
||||
and all(is_xxh3_128_hexdigest(k) for k in resume)
|
||||
):
|
||||
self.config[CONF][CONFIG_KEY_RESUME_MAP] = self.input.resume
|
||||
if resume is not None and not self.checkpointer:
|
||||
raise RuntimeError(
|
||||
"Cannot use Command(resume=...) without checkpointer"
|
||||
)
|
||||
writes: defaultdict[str, list[tuple[str, Any]]] = defaultdict(list)
|
||||
# group writes by task ID
|
||||
for tid, c, v in map_command(self.input, self.checkpoint_pending_writes):
|
||||
writes[tid].append((c, v))
|
||||
for tid, c, v in map_command(cmd=self.input):
|
||||
if not (c == RESUME and resume_is_map):
|
||||
writes[tid].append((c, v))
|
||||
if not writes:
|
||||
raise EmptyInputError("Received empty Command input")
|
||||
# save writes
|
||||
|
||||
@@ -241,7 +241,7 @@ class RemoteGraph(PregelProtocol):
|
||||
)
|
||||
|
||||
def _create_state_snapshot(self, state: ThreadState) -> StateSnapshot:
|
||||
tasks = []
|
||||
tasks: list[PregelTask] = []
|
||||
for task in state["tasks"]:
|
||||
interrupts = []
|
||||
for interrupt in task["interrupts"]:
|
||||
@@ -289,6 +289,7 @@ class RemoteGraph(PregelProtocol):
|
||||
if state["parent_checkpoint"]
|
||||
else None,
|
||||
tasks=tuple(tasks),
|
||||
interrupts=tuple([i for task in tasks for i in task.interrupts]),
|
||||
)
|
||||
|
||||
def _get_checkpoint(self, config: Optional[RunnableConfig]) -> Optional[Checkpoint]:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import ast
|
||||
import inspect
|
||||
import re
|
||||
import textwrap
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
@@ -207,3 +208,8 @@ class NonLocals(ast.NodeVisitor):
|
||||
parent = parent.value
|
||||
if isinstance(parent, ast.Name):
|
||||
self.loads.add(parent.id + "." + attr_expr)
|
||||
|
||||
|
||||
def is_xxh3_128_hexdigest(value: str) -> bool:
|
||||
"""Check if the given string matches the format of xxh3_128_hexdigest."""
|
||||
return bool(re.fullmatch(r"[0-9a-f]{32}", value))
|
||||
|
||||
@@ -147,7 +147,7 @@ class Interrupt:
|
||||
"""Generate a unique ID for the interrupt based on its namespace."""
|
||||
if self.ns is None:
|
||||
return "placeholder-id"
|
||||
return xxh3_128_hexdigest("".join(self.ns).encode())
|
||||
return xxh3_128_hexdigest("|".join(self.ns).encode())
|
||||
|
||||
|
||||
class StateUpdate(NamedTuple):
|
||||
@@ -192,19 +192,21 @@ class StateSnapshot(NamedTuple):
|
||||
"""Snapshot of the state of the graph at the beginning of a step."""
|
||||
|
||||
values: Union[dict[str, Any], Any]
|
||||
"""Current values of channels"""
|
||||
"""Current values of channels."""
|
||||
next: tuple[str, ...]
|
||||
"""The name of the node to execute in each task for this step."""
|
||||
config: RunnableConfig
|
||||
"""Config used to fetch this snapshot"""
|
||||
"""Config used to fetch this snapshot."""
|
||||
metadata: Optional[CheckpointMetadata]
|
||||
"""Metadata associated with this snapshot"""
|
||||
"""Metadata associated with this snapshot."""
|
||||
created_at: Optional[str]
|
||||
"""Timestamp of snapshot creation"""
|
||||
"""Timestamp of snapshot creation."""
|
||||
parent_config: Optional[RunnableConfig]
|
||||
"""Config used to fetch the parent snapshot, if any"""
|
||||
"""Config used to fetch the parent snapshot, if any."""
|
||||
tasks: tuple[PregelTask, ...]
|
||||
"""Tasks to execute in this step. If already attempted, may contain an error."""
|
||||
interrupts: tuple[Interrupt, ...]
|
||||
"""Interrupts that occurred in this step that are pending resolution."""
|
||||
|
||||
|
||||
class Send:
|
||||
@@ -294,6 +296,10 @@ class Command(Generic[N], ToolOutputMixin):
|
||||
- Command.PARENT: closest parent graph
|
||||
update: update to apply to the graph's state.
|
||||
resume: value to resume execution with. To be used together with [`interrupt()`][langgraph.types.interrupt].
|
||||
Can be one of the following:
|
||||
|
||||
- mapping of interrupt ids to resume values
|
||||
- a single value with which to resume the next interrupt
|
||||
goto: can be one of the following:
|
||||
|
||||
- name of the node to navigate to next (any node that belongs to the specified `graph`)
|
||||
@@ -304,7 +310,7 @@ class Command(Generic[N], ToolOutputMixin):
|
||||
|
||||
graph: Optional[str] = None
|
||||
update: Optional[Any] = None
|
||||
resume: Optional[Union[Any, dict[str, Any]]] = None
|
||||
resume: Optional[Union[dict[str, Any], Any]] = None
|
||||
goto: Union[Send, Sequence[Union[Send, str]], str] = ()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
||||
@@ -63,6 +63,7 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={
|
||||
@@ -113,6 +114,15 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
else {"answer": "doc1,doc2,doc3,doc4"},
|
||||
),
|
||||
),
|
||||
interrupts=()
|
||||
if exc_task_results
|
||||
else (
|
||||
Interrupt(
|
||||
value="",
|
||||
resumable=True,
|
||||
ns=[AnyStr("qa:")],
|
||||
),
|
||||
),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={
|
||||
@@ -156,6 +166,7 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
result=None if exc_task_results else {"docs": ["doc1", "doc2"]},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"query": "query: what is weather in sf", "docs": []},
|
||||
@@ -206,6 +217,7 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
else {"docs": ["doc3", "doc4"]},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"query": "what is weather in sf", "docs": []},
|
||||
@@ -245,6 +257,7 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
else {"query": "query: what is weather in sf"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"docs": []},
|
||||
@@ -276,6 +289,7 @@ def get_expected_history(*, exc_task_results: int = 0) -> list[StateSnapshot]:
|
||||
result={"query": "what is weather in sf"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1731,6 +1745,7 @@ def test_saved_checkpoint_state_graph(
|
||||
created_at=AnyStr(),
|
||||
parent_config=latest_state.parent_config,
|
||||
tasks=latest_state.tasks,
|
||||
interrupts=latest_state.interrupts,
|
||||
)
|
||||
== history[0]
|
||||
)
|
||||
@@ -1802,6 +1817,7 @@ async def test_saved_checkpoint_state_graph_async(
|
||||
created_at=AnyStr(),
|
||||
parent_config=latest_state.parent_config,
|
||||
tasks=latest_state.tasks,
|
||||
interrupts=latest_state.interrupts,
|
||||
)
|
||||
== history[0]
|
||||
)
|
||||
|
||||
@@ -144,6 +144,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[1].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 4, "output": 4, "input": 3},
|
||||
@@ -165,6 +166,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[2].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 21, "output": 4, "input": 3},
|
||||
@@ -186,6 +188,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[3].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 21, "output": 4, "input": 20},
|
||||
@@ -207,6 +210,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[4].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "output": 4, "input": 20},
|
||||
@@ -228,6 +232,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[5].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "output": 4, "input": 2},
|
||||
@@ -249,6 +254,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[6].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "input": 2},
|
||||
@@ -270,6 +276,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[7].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"input": 2},
|
||||
@@ -291,6 +298,7 @@ def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -358,6 +366,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[1].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=5,
|
||||
@@ -379,6 +388,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[2].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=4,
|
||||
@@ -400,6 +410,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[3].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=3,
|
||||
@@ -421,6 +432,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[4].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=2,
|
||||
@@ -442,6 +454,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[5].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=1,
|
||||
@@ -463,6 +476,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[6].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=0,
|
||||
@@ -484,6 +498,7 @@ def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -776,6 +791,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
assert (
|
||||
app_w_interrupt.checkpointer.get_tuple(config).config["configurable"][
|
||||
@@ -838,6 +854,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -969,6 +986,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test state get/update methods with interrupt_before
|
||||
@@ -1035,6 +1053,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -1091,6 +1110,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -1222,6 +1242,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test re-invoke to continue with interrupt_before
|
||||
@@ -1288,6 +1309,7 @@ def test_conditional_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -1684,6 +1706,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
with assert_ctx_once():
|
||||
@@ -1737,6 +1760,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
with assert_ctx_once():
|
||||
@@ -1824,6 +1848,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test state get/update methods with interrupt_before
|
||||
@@ -1886,6 +1911,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -1938,6 +1964,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -2023,6 +2050,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test w interrupt before all
|
||||
@@ -2066,6 +2094,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -2116,6 +2145,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -2187,6 +2217,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -2260,6 +2291,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -2331,6 +2363,7 @@ def test_conditional_state_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -3071,6 +3104,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -3135,6 +3169,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -3254,6 +3289,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -3315,6 +3351,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# interrupt before tools
|
||||
@@ -3404,6 +3441,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -3462,6 +3500,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -3579,6 +3618,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -3640,6 +3680,7 @@ def test_state_graph_packets(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*app_w_interrupt.checkpointer.list(config, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -3936,6 +3977,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -3987,6 +4029,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -4080,6 +4123,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -4131,6 +4175,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt = workflow.compile(
|
||||
@@ -4206,6 +4251,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -4263,6 +4309,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -4356,6 +4403,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -4408,6 +4456,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# add an extra message as if it came from "tools" node
|
||||
@@ -4460,6 +4509,7 @@ def test_message_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -4759,6 +4809,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -4810,6 +4861,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -4904,6 +4956,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -4956,6 +5009,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt = workflow.compile(
|
||||
@@ -5031,6 +5085,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -5088,6 +5143,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config)] == [
|
||||
@@ -5182,6 +5238,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
app_w_interrupt.update_state(
|
||||
@@ -5233,6 +5290,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# add an extra message as if it came from "tools" node
|
||||
@@ -5285,6 +5343,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(app_w_interrupt.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# create new graph with one more state key, reuse previous thread history
|
||||
@@ -5368,6 +5427,7 @@ def test_root_graph(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(new_app.checkpointer.list(config, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# new input is merged to old state
|
||||
@@ -5775,6 +5835,13 @@ def test_dynamic_interrupt(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
# clear the interrupt and next tasks
|
||||
tool_two.update_state(thread1, None, as_node=END)
|
||||
@@ -5803,6 +5870,7 @@ def test_dynamic_interrupt(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -5964,6 +6032,13 @@ def test_copy_checkpoint(
|
||||
if "shallow" in checkpointer_name
|
||||
else [*tool_two.checkpointer.list(thread1, limit=2)][-1].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if "shallow" in checkpointer_name:
|
||||
@@ -6009,6 +6084,7 @@ def test_copy_checkpoint(
|
||||
parent_config=(
|
||||
[*tool_two.checkpointer.list(thread1, limit=2)][-1].parent_config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -6184,6 +6260,13 @@ def test_dynamic_interrupt_subgraph(
|
||||
)
|
||||
)[-1].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:"), AnyStr("do:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
# clear the interrupt and next tasks
|
||||
tool_two.update_state(thread1, None, as_node=END)
|
||||
@@ -6216,6 +6299,7 @@ def test_dynamic_interrupt_subgraph(
|
||||
)
|
||||
)[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -6334,6 +6418,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread1, debug=1) == {
|
||||
@@ -6365,6 +6450,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "2", "assistant_id": "a"}}
|
||||
@@ -6398,6 +6484,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread2, debug=1) == {
|
||||
@@ -6429,6 +6516,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread3 = {"configurable": {"thread_id": "3", "assistant_id": "b"}}
|
||||
@@ -6462,6 +6550,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread3, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# update state
|
||||
tool_two.update_state(thread3, {"my_key": "key"}) # appends to my_key
|
||||
@@ -6490,6 +6579,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread3, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread3, debug=1) == {
|
||||
@@ -6521,6 +6611,7 @@ def test_start_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread3, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -6900,6 +6991,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread1, debug=1) == {
|
||||
@@ -6930,6 +7022,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "2"}}
|
||||
@@ -6962,6 +7055,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread2, debug=1) == {
|
||||
@@ -6992,6 +7086,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
tool_two = tool_two_graph.compile(
|
||||
@@ -7032,6 +7127,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# update state
|
||||
@@ -7063,6 +7159,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
tool_two = tool_two_graph.compile(
|
||||
@@ -7103,6 +7200,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread1, debug=1) == {
|
||||
@@ -7133,6 +7231,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread1, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "22"}}
|
||||
@@ -7165,6 +7264,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread2, debug=1) == {
|
||||
@@ -7195,6 +7295,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread2, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread3 = {"configurable": {"thread_id": "23"}}
|
||||
@@ -7221,6 +7322,7 @@ def test_branch_then(
|
||||
"thread_id": "23",
|
||||
},
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
)
|
||||
# run from this point
|
||||
assert tool_two.invoke(None, thread3) == {
|
||||
@@ -7252,6 +7354,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread3, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert tool_two.invoke(None, thread3, debug=1) == {
|
||||
@@ -7282,6 +7385,7 @@ def test_branch_then(
|
||||
if "shallow" in checkpointer_name
|
||||
else list(tool_two.checkpointer.list(thread3, limit=2))[-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -7423,6 +7527,7 @@ def test_send_dedupe_on_resume(
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[
|
||||
@@ -7469,6 +7574,7 @@ def test_send_dedupe_on_resume(
|
||||
result=["3"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[
|
||||
@@ -7536,6 +7642,7 @@ def test_send_dedupe_on_resume(
|
||||
result=["3"],
|
||||
),
|
||||
),
|
||||
interrupts=(Interrupt(value="Bahh", resumable=False, ns=None),),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=["0", "1"],
|
||||
@@ -7591,6 +7698,7 @@ def test_send_dedupe_on_resume(
|
||||
result=["3.1"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=["0"],
|
||||
@@ -7628,6 +7736,7 @@ def test_send_dedupe_on_resume(
|
||||
result=["1"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[],
|
||||
@@ -7648,6 +7757,7 @@ def test_send_dedupe_on_resume(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -7762,6 +7872,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# now, get_state with subgraphs state
|
||||
assert app.get_state(config, subgraphs=True) == StateSnapshot(
|
||||
@@ -7828,6 +7939,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -7858,6 +7970,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# get_state_history returns outer graph checkpoints
|
||||
history = list(app.get_state_history(config))
|
||||
@@ -7904,6 +8017,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -7938,6 +8052,7 @@ def test_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -7966,6 +8081,7 @@ def test_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -8022,6 +8138,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(PregelTask(AnyStr(), "inner_2", (PULL, "inner_2")),),
|
||||
),
|
||||
StateSnapshot(
|
||||
@@ -8071,6 +8188,7 @@ def test_nested_graph_state(
|
||||
},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -8099,6 +8217,7 @@ def test_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
AnyStr(),
|
||||
@@ -8150,6 +8269,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# test full history at the end
|
||||
actual_history = list(app.get_state_history(config))
|
||||
@@ -8186,6 +8306,7 @@ def test_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here and there"},
|
||||
@@ -8220,6 +8341,7 @@ def test_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -8257,6 +8379,7 @@ def test_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -8291,6 +8414,7 @@ def test_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -8319,6 +8443,7 @@ def test_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
if "shallow" in checkpointer_name:
|
||||
@@ -8439,6 +8564,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
child_state = app.get_state(outer_state.tasks[0].state)
|
||||
assert child_state == StateSnapshot(
|
||||
@@ -8500,6 +8626,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
grandchild_state = app.get_state(child_state.tasks[0].state)
|
||||
assert grandchild_state == StateSnapshot(
|
||||
@@ -8562,6 +8689,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# get state with subgraphs
|
||||
assert app.get_state(config, subgraphs=True) == StateSnapshot(
|
||||
@@ -8649,6 +8777,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -8690,6 +8819,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -8720,6 +8850,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# # resume
|
||||
assert [c for c in app.stream(None, config, subgraphs=True)] == [
|
||||
@@ -8767,6 +8898,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8804,6 +8936,7 @@ def test_doubly_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here and there"},
|
||||
@@ -8838,6 +8971,7 @@ def test_doubly_nested_graph_state(
|
||||
result={"my_key": "hi my value here and there and back again"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -8878,6 +9012,7 @@ def test_doubly_nested_graph_state(
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -8912,6 +9047,7 @@ def test_doubly_nested_graph_state(
|
||||
result={"my_key": "hi my value"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -8932,6 +9068,7 @@ def test_doubly_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -8982,6 +9119,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -9033,6 +9171,7 @@ def test_doubly_nested_graph_state(
|
||||
result={"my_key": "hi my value here and there"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -9061,6 +9200,7 @@ def test_doubly_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -9127,6 +9267,7 @@ def test_doubly_nested_graph_state(
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here"},
|
||||
@@ -9188,6 +9329,7 @@ def test_doubly_nested_graph_state(
|
||||
result={"my_key": "hi my value here and there"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -9249,6 +9391,7 @@ def test_doubly_nested_graph_state(
|
||||
result={"my_key": "hi my value here"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -9289,6 +9432,7 @@ def test_doubly_nested_graph_state(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -9565,6 +9709,7 @@ def test_send_react_interrupt(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -9628,6 +9773,7 @@ def test_send_react_interrupt(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(),
|
||||
)
|
||||
|
||||
@@ -9725,6 +9871,7 @@ def test_send_react_interrupt(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -9816,6 +9963,7 @@ def test_send_react_interrupt(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -10046,6 +10194,7 @@ def test_send_react_interrupt_control(
|
||||
result=None,
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# remove the tool call, clearing the pending task
|
||||
@@ -10098,6 +10247,7 @@ def test_send_react_interrupt_control(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(),
|
||||
)
|
||||
|
||||
@@ -10300,6 +10450,7 @@ def test_weather_subgraph(
|
||||
},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# update
|
||||
@@ -10442,9 +10593,11 @@ def test_weather_subgraph(
|
||||
path=(PULL, "weather_node"),
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
graph.update_state(
|
||||
state.tasks[0].state.config,
|
||||
@@ -10547,10 +10700,12 @@ def test_weather_subgraph(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
assert [
|
||||
c
|
||||
|
||||
@@ -141,6 +141,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[1].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 4, "output": 4, "input": 3},
|
||||
@@ -164,6 +165,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[2].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 21, "output": 4, "input": 3},
|
||||
@@ -187,6 +189,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[3].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 21, "output": 4, "input": 20},
|
||||
@@ -208,6 +211,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[4].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "output": 4, "input": 20},
|
||||
@@ -231,6 +235,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[5].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "output": 4, "input": 2},
|
||||
@@ -252,6 +257,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[6].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"inbox": 3, "input": 2},
|
||||
@@ -275,6 +281,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[7].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"input": 2},
|
||||
@@ -298,6 +305,7 @@ async def test_invoke_two_processes_in_out_interrupt(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -374,6 +382,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[1].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=5,
|
||||
@@ -395,6 +404,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[2].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=4,
|
||||
@@ -416,6 +426,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[3].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=3,
|
||||
@@ -437,6 +448,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[4].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=2,
|
||||
@@ -458,6 +470,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[5].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=1,
|
||||
@@ -479,6 +492,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=history[6].config,
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=0,
|
||||
@@ -502,6 +516,7 @@ async def test_fork_always_re_runs_nodes(
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -858,6 +873,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -916,6 +932,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -1049,6 +1066,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test state get/update methods with interrupt_before
|
||||
@@ -1124,6 +1142,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -1182,6 +1201,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -1315,6 +1335,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test re-invoke to continue with interrupt_before
|
||||
@@ -1390,6 +1411,7 @@ async def test_conditional_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -1819,6 +1841,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
async with assert_ctx_once():
|
||||
@@ -1874,6 +1897,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
async with assert_ctx_once():
|
||||
@@ -1963,6 +1987,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# test state get/update methods with interrupt_before
|
||||
@@ -2031,6 +2056,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -2085,6 +2111,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -2172,6 +2199,7 @@ async def test_conditional_graph_state(
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -2796,6 +2824,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -2854,6 +2883,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -2968,6 +2998,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -3022,6 +3053,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# interrupt before tools
|
||||
@@ -3109,6 +3141,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -3167,6 +3200,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -3281,6 +3315,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -3335,6 +3370,7 @@ async def test_state_graph_packets(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -3600,6 +3636,7 @@ async def test_message_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# modify ai message
|
||||
@@ -3654,6 +3691,7 @@ async def test_message_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c async for c in app_w_interrupt.astream(None, config)] == [
|
||||
@@ -3744,6 +3782,7 @@ async def test_message_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
await app_w_interrupt.aupdate_state(
|
||||
@@ -3792,6 +3831,7 @@ async def test_message_graph(checkpointer_name: str) -> None:
|
||||
c async for c in app_w_interrupt.checkpointer.alist(config, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -4131,6 +4171,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread1, debug=1) == {
|
||||
@@ -4164,6 +4205,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "2", "assistant_id": "a"}}
|
||||
@@ -4199,6 +4241,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread2, debug=1) == {
|
||||
@@ -4232,6 +4275,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread3 = {"configurable": {"thread_id": "3", "assistant_id": "b"}}
|
||||
@@ -4267,6 +4311,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# update state
|
||||
await tool_two.aupdate_state(thread3, {"my_key": "key"}) # appends to my_key
|
||||
@@ -4297,6 +4342,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread3, debug=1) == {
|
||||
@@ -4330,6 +4376,7 @@ async def test_start_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -4872,6 +4919,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread1, debug=1) == {
|
||||
@@ -4904,6 +4952,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "12"}}
|
||||
@@ -4938,6 +4987,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread2, debug=1) == {
|
||||
@@ -4970,6 +5020,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
tool_two = tool_two_graph.compile(
|
||||
@@ -5012,6 +5063,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread1, debug=1) == {
|
||||
@@ -5044,6 +5096,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread2 = {"configurable": {"thread_id": "22"}}
|
||||
@@ -5078,6 +5131,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread2, debug=1) == {
|
||||
@@ -5110,6 +5164,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
thread3 = {"configurable": {"thread_id": "23"}}
|
||||
@@ -5132,6 +5187,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
"thread_id": "23",
|
||||
},
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
)
|
||||
# run from this point
|
||||
assert await tool_two.ainvoke(None, thread3) == {
|
||||
@@ -5159,6 +5215,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
"thread_id": "23",
|
||||
},
|
||||
parent_config=(None if "shallow" in checkpointer_name else uconfig),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume, for same result as above
|
||||
assert await tool_two.ainvoke(None, thread3, debug=1) == {
|
||||
@@ -5191,6 +5248,7 @@ async def test_branch_then(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -5287,6 +5345,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# now, get_state with subgraphs state
|
||||
assert await app.aget_state(config, subgraphs=True) == StateSnapshot(
|
||||
@@ -5353,6 +5412,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -5383,6 +5443,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# get_state_history returns outer graph checkpoints
|
||||
history = [c async for c in app.aget_state_history(config)]
|
||||
@@ -5429,6 +5490,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -5463,6 +5525,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -5491,6 +5554,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -5550,6 +5614,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
),
|
||||
tasks=(PregelTask(AnyStr(), "inner_2", (PULL, "inner_2")),),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -5598,6 +5663,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -5634,6 +5700,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -5677,6 +5744,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# test full history at the end
|
||||
actual_history = [c async for c in app.aget_state_history(config)]
|
||||
@@ -5715,6 +5783,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here and there"},
|
||||
@@ -5749,6 +5818,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -5789,6 +5859,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -5823,6 +5894,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -5851,6 +5923,7 @@ async def test_nested_graph_state(checkpointer_name: str) -> None:
|
||||
},
|
||||
created_at=AnyStr(),
|
||||
parent_config=None,
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
if "shallow" in checkpointer_name:
|
||||
@@ -5970,6 +6043,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
child_state = await app.aget_state(outer_state.tasks[0].state)
|
||||
assert child_state == StateSnapshot(
|
||||
@@ -6031,6 +6105,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
grandchild_state = await app.aget_state(child_state.tasks[0].state)
|
||||
assert grandchild_state == StateSnapshot(
|
||||
@@ -6095,6 +6170,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# get state with subgraphs
|
||||
assert await app.aget_state(config, subgraphs=True) == StateSnapshot(
|
||||
@@ -6186,6 +6262,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -6229,6 +6306,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -6259,6 +6337,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# resume
|
||||
assert [c async for c in app.astream(None, config, subgraphs=True)] == [
|
||||
@@ -6311,6 +6390,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -6352,6 +6432,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here and there"},
|
||||
@@ -6383,6 +6464,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
id=AnyStr(), name="parent_2", path=(PULL, "parent_2")
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -6422,6 +6504,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
"checkpoint_id": AnyStr(),
|
||||
}
|
||||
},
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "my value"},
|
||||
@@ -6453,6 +6536,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
id=AnyStr(), name="parent_1", path=(PULL, "parent_1")
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -6478,6 +6562,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
id=AnyStr(), name="__start__", path=(PULL, "__start__")
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
][0]
|
||||
)
|
||||
@@ -6523,6 +6608,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -6574,6 +6660,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value here and there"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -6610,6 +6697,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
# get grandchild graph history
|
||||
@@ -6674,6 +6762,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value here"},
|
||||
@@ -6737,6 +6826,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value here and there"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={"my_key": "hi my value"},
|
||||
@@ -6800,6 +6890,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value here"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values={},
|
||||
@@ -6850,6 +6941,7 @@ async def test_doubly_nested_graph_state(checkpointer_name: str) -> None:
|
||||
result={"my_key": "hi my value"},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -7131,6 +7223,7 @@ async def test_weather_subgraph(
|
||||
},
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
# confirm that list() delegates to alist() correctly
|
||||
assert await asyncio.to_thread(get_first_in_list) == state
|
||||
@@ -7270,6 +7363,7 @@ async def test_weather_subgraph(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -7280,6 +7374,7 @@ async def test_weather_subgraph(
|
||||
),
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
await graph.aupdate_state(
|
||||
state.tasks[0].state.config,
|
||||
@@ -7319,6 +7414,7 @@ async def test_weather_subgraph(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
tasks=(
|
||||
PregelTask(
|
||||
id=AnyStr(),
|
||||
@@ -7385,6 +7481,7 @@ async def test_weather_subgraph(
|
||||
}
|
||||
),
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -2491,6 +2491,7 @@ def test_in_one_fan_out_state_graph_waiting_edge(
|
||||
"thread_id": "2",
|
||||
},
|
||||
parent_config=expected_parent_config,
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
assert [c for c in app_w_interrupt.stream(None, config, debug=1)] == [
|
||||
@@ -5224,6 +5225,7 @@ def test_parent_command(request: pytest.FixtureRequest, checkpointer_name: str)
|
||||
}
|
||||
),
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -650,6 +650,13 @@ async def test_dynamic_interrupt(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# clear the interrupt and next tasks
|
||||
@@ -676,6 +683,7 @@ async def test_dynamic_interrupt(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -848,6 +856,13 @@ async def test_dynamic_interrupt_subgraph(checkpointer_name: str) -> None:
|
||||
c async for c in tool_two.checkpointer.alist(thread1root, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:"), AnyStr("do:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# clear the interrupt and next tasks
|
||||
@@ -874,6 +889,7 @@ async def test_dynamic_interrupt_subgraph(checkpointer_name: str) -> None:
|
||||
c async for c in tool_two.checkpointer.alist(thread1root, limit=2)
|
||||
][-1].config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1047,6 +1063,13 @@ async def test_copy_checkpoint(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].config
|
||||
),
|
||||
interrupts=(
|
||||
Interrupt(
|
||||
value="Just because...",
|
||||
resumable=True,
|
||||
ns=[AnyStr("tool_two:")],
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if "shallow" in checkpointer_name:
|
||||
@@ -1088,6 +1111,7 @@ async def test_copy_checkpoint(checkpointer_name: str) -> None:
|
||||
-1
|
||||
].parent_config
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -2900,6 +2924,7 @@ async def test_send_dedupe_on_resume(
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[
|
||||
@@ -2946,6 +2971,7 @@ async def test_send_dedupe_on_resume(
|
||||
result=["3"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[
|
||||
@@ -3013,6 +3039,7 @@ async def test_send_dedupe_on_resume(
|
||||
result=["3"],
|
||||
),
|
||||
),
|
||||
interrupts=(Interrupt(value="Bahh", resumable=False, ns=None),),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=["0", "1"],
|
||||
@@ -3068,6 +3095,7 @@ async def test_send_dedupe_on_resume(
|
||||
result=["3.1"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=["0"],
|
||||
@@ -3105,6 +3133,7 @@ async def test_send_dedupe_on_resume(
|
||||
result=["1"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
StateSnapshot(
|
||||
values=[],
|
||||
@@ -3136,6 +3165,7 @@ async def test_send_dedupe_on_resume(
|
||||
result=["0"],
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
),
|
||||
]
|
||||
if checkpoint_during:
|
||||
@@ -3338,6 +3368,7 @@ async def test_send_react_interrupt(checkpointer_name: str) -> None:
|
||||
result=None,
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# remove the tool call, clearing the pending task
|
||||
@@ -3391,6 +3422,7 @@ async def test_send_react_interrupt(checkpointer_name: str) -> None:
|
||||
}
|
||||
),
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# tool call not executed
|
||||
@@ -3496,6 +3528,7 @@ async def test_send_react_interrupt(checkpointer_name: str) -> None:
|
||||
result=None,
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# replace the tool call, should clear previous send, create new one
|
||||
@@ -3587,6 +3620,7 @@ async def test_send_react_interrupt(checkpointer_name: str) -> None:
|
||||
result=None,
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# prev tool call not executed, new tool call is
|
||||
@@ -3804,6 +3838,7 @@ async def test_send_react_interrupt_control(
|
||||
result=None,
|
||||
),
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# remove the tool call, clearing the pending task
|
||||
@@ -3857,6 +3892,7 @@ async def test_send_react_interrupt_control(
|
||||
}
|
||||
),
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
# tool call not executed
|
||||
@@ -4937,6 +4973,7 @@ async def test_in_one_fan_out_state_graph_waiting_edge_custom_state_class(
|
||||
}
|
||||
}
|
||||
),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
async with assert_ctx_once():
|
||||
@@ -6635,6 +6672,7 @@ async def test_parent_command(checkpointer_name: str) -> None:
|
||||
}
|
||||
),
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ def test_get_state():
|
||||
created_at="timestamp",
|
||||
parent_config=None,
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -240,6 +241,7 @@ async def test_aget_state():
|
||||
}
|
||||
},
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -290,6 +292,7 @@ def test_get_state_history():
|
||||
created_at="timestamp",
|
||||
parent_config=None,
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
@@ -343,6 +346,7 @@ async def test_aget_state_history():
|
||||
created_at="timestamp",
|
||||
parent_config=None,
|
||||
tasks=(),
|
||||
interrupts=(),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user