Skip to content

Commit 819f56b

Browse files
feat: update Command docs (#2846)
* emphasis on highlighting the 2 use cases for command - updates / control flow from a node (or tool) and resuming an interrupted graph * specifically warning against using `Command(update=)` as input to a graph preview: https://langchain-5e9cc07a-preview-srcomm-1772228869-09398c4.mintlify.app/oss/python/langgraph/graph-api#command
1 parent 8287b28 commit 819f56b

2 files changed

Lines changed: 138 additions & 51 deletions

File tree

src/oss/langgraph/graph-api.mdx

Lines changed: 124 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,8 +1041,26 @@ graph.addConditionalEdges("nodeA", (state) => {
10411041

10421042
## `Command`
10431043

1044+
@[`Command`] is a versatile primitive for controlling graph execution. It accepts four parameters:
1045+
1046+
- `update`: Apply state updates (similar to returning updates from a node).
1047+
- `goto`: Navigate to specific nodes (similar to [conditional edges](#conditional-edges)).
1048+
- `graph`: Target a parent graph when navigating from [subgraphs](/oss/langgraph/use-subgraphs).
1049+
- `resume`: Provide a value to resume execution after an [interrupt](/oss/langgraph/interrupts).
1050+
1051+
`Command` is used in three contexts:
1052+
1053+
- **[Return from nodes](#return-from-nodes)**: Use `update`, `goto`, and `graph` to combine state updates with control flow.
1054+
- **[Input to `invoke`/`stream`](#input-to-invokestream)**: Use `resume` to continue execution after an interrupt.
1055+
- **[Return from tools](#return-from-tools)**: Similar to return from nodes, combine state updates and control flow from inside a tool.
1056+
1057+
### Return from nodes
1058+
1059+
#### `update` and `goto`
1060+
1061+
Return @[`Command`] from node functions to update state and route to the next node in a single step:
1062+
10441063
:::python
1045-
It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a @[`Command`] object from node functions:
10461064

10471065
```python
10481066
def my_node(state: State) -> Command[Literal["my_other_node"]]:
@@ -1062,20 +1080,7 @@ def my_node(state: State) -> Command[Literal["my_other_node"]]:
10621080
return Command(update={"foo": "baz"}, goto="my_other_node")
10631081
```
10641082

1065-
Note that @[`Command`] only adds dynamic edges, while static edges will still execute. In other words, @[`Command`] doesn't override static edges.
1066-
1067-
```python
1068-
def node_a(state: State) -> Command[Literal["my_other_node"]]:
1069-
if state["foo"] == "bar":
1070-
return Command(update={"foo": "baz"}, goto="my_other_node")
1071-
1072-
# Add a static edge from "node_a" to "node_b"
1073-
graph.add_edge("node_a", "node_b")
1074-
1075-
# Command will NOT prevent "node_a" from going to "node_b"
1076-
```
1077-
1078-
In the example above, **"node_a"** will go to both **"node_b"** and **"my_other_node"**.
1083+
Use @[`Command`] when you need to **both** update state **and** route to a different node. If you only need to route without updating state, use [conditional edges](#conditional-edges) instead.
10791084

10801085
<Note>
10811086

@@ -1086,7 +1091,6 @@ When returning @[`Command`] in your node functions, you must add return type ann
10861091
:::
10871092

10881093
:::js
1089-
It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a @[`Command`] object from node functions:
10901094

10911095
```typescript
10921096
import { Command } from "@langchain/langgraph";
@@ -1114,25 +1118,7 @@ graph.addNode("myNode", (state) => {
11141118
});
11151119
```
11161120

1117-
Note that @[Command] only adds dynamic edges, while static edges will still execute. In other words, @[Command] doesn't override static edges.
1118-
1119-
```typescript
1120-
graph.addNode("nodeA", (state) => {
1121-
if (state.foo === "bar") {
1122-
return new Command({
1123-
update: { foo: "baz" },
1124-
goto: "myOtherNode",
1125-
});
1126-
}
1127-
});
1128-
1129-
// Add a static edge from "nodeA" to "nodeB"
1130-
graph.addEdge("nodeA", "nodeB")
1131-
1132-
// Command will NOT prevent "nodeA" from going to "nodeB"
1133-
```
1134-
1135-
In the example above, **"nodeA"** will go to both **"nodeB"** and **"myOtherNode"**.
1121+
Use @[`Command`] when you need to **both** update state **and** route to a different node. If you only need to route without updating state, use [conditional edges](#conditional-edges) instead.
11361122

11371123
When using @[`Command`] in your node functions, you must add the `ends` parameter when adding the node to specify which nodes it can route to:
11381124

@@ -1144,17 +1130,18 @@ builder.addNode("myNode", myNode, {
11441130

11451131
:::
11461132

1147-
Check out this [how-to guide](/oss/langgraph/use-graph-api#combine-control-flow-and-state-updates-with-command) for an end-to-end example of how to use @[`Command`].
1133+
<Warning>
11481134

1149-
### When should I use command instead of conditional edges?
1135+
@[`Command`] only adds dynamic edges — static edges defined with `add_edge` / `addEdge` still execute. For example, if `node_a` returns `Command(goto="my_other_node")` and you also have `graph.add_edge("node_a", "node_b")`, both `node_b` and `my_other_node` will run.
1136+
1137+
</Warning>
11501138

1151-
- Use @[`Command`] when you need to **both** update the graph state **and** route to a different node. For example, when implementing [multi-agent handoffs](/oss/langchain/multi-agent/handoffs) where it's important to route to a different agent and pass some information to that agent.
1152-
- Use [conditional edges](#conditional-edges) to route between nodes conditionally without updating the state.
1139+
Check out this [how-to guide](/oss/langgraph/use-graph-api#combine-control-flow-and-state-updates-with-command) for an end-to-end example of how to use @[`Command`].
11531140

1154-
### Navigating to a node in a parent graph
1141+
#### `graph`
11551142

11561143
:::python
1157-
If you are using [subgraphs](/oss/langgraph/use-subgraphs), you might want to navigate from a node within a subgraph to a different subgraph (i.e. a different node in the parent graph). To do so, you can specify `graph=Command.PARENT` in @[`Command`]:
1144+
If you are using [subgraphs](/oss/langgraph/use-subgraphs), you can navigate from a node within a subgraph to a different node in the parent graph by specifying `graph=Command.PARENT` in @[`Command`]:
11581145

11591146
```python
11601147
def my_node(state: State) -> Command[Literal["other_subgraph"]]:
@@ -1169,15 +1156,14 @@ def my_node(state: State) -> Command[Literal["other_subgraph"]]:
11691156

11701157
Setting `graph` to `Command.PARENT` will navigate to the closest parent graph.
11711158

1172-
11731159
When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](#schema), you **must** define a [reducer](#reducers) for the key you're updating in the parent graph state. See this [example](/oss/langgraph/use-graph-api#navigate-to-a-node-in-a-parent-graph).
11741160

11751161
</Note>
11761162

11771163
:::
11781164

11791165
:::js
1180-
If you are using [subgraphs](/oss/langgraph/use-subgraphs), you might want to navigate from a node within a subgraph to a different subgraph (i.e. a different node in the parent graph). To do so, you can specify `graph: Command.PARENT` in `Command`:
1166+
If you are using [subgraphs](/oss/langgraph/use-subgraphs), you can navigate from a node within a subgraph to a different node in the parent graph by specifying `graph: Command.PARENT` in `Command`:
11811167

11821168
```typescript
11831169
import { Command } from "@langchain/langgraph";
@@ -1201,26 +1187,113 @@ When you send updates from a subgraph node to a parent graph node for a key that
12011187

12021188
:::
12031189

1204-
This is particularly useful when implementing [multi-agent handoffs](/oss/langchain/multi-agent/handoffs).
1190+
This is particularly useful when implementing [multi-agent handoffs](/oss/langchain/multi-agent/handoffs). Check out [this guide](/oss/langgraph/use-graph-api#navigate-to-a-node-in-a-parent-graph) for detail.
12051191

1206-
Check out [this guide](/oss/langgraph/use-graph-api#navigate-to-a-node-in-a-parent-graph) for detail.
1192+
### Input to `invoke`/`stream`
12071193

1208-
### Using inside tools
1194+
:::python
12091195

1210-
A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer information based on their account number or ID in the beginning of the conversation.
1196+
<Warning>
12111197

1212-
Refer to [this guide](/oss/langgraph/use-graph-api#use-inside-tools) for detail.
1198+
`Command(resume=...)` is the **only** `Command` pattern intended as input to `invoke()`/`stream()`. Do not use `Command(update=...)` as input to continue multi-turn conversations — because passing any `Command` as input resumes from the latest checkpoint (i.e. the last step that ran, not `__start__`), the graph will appear stuck if it already finished. To continue a conversation on an existing thread, pass a plain input dict:
12131199

1214-
### Human-in-the-loop
1200+
```python
1201+
# WRONG — graph resumes from the latest checkpoint
1202+
# (last step that ran), appears stuck
1203+
graph.invoke(Command(update={ # [!code --]
1204+
"messages": [{"role": "user", "content": "follow up"}] # [!code --]
1205+
}), config) # [!code --]
1206+
1207+
# CORRECT — plain dict restarts from __start__
1208+
graph.invoke( { # [!code ++]
1209+
"messages": [{"role": "user", "content": "follow up"}] # [!code ++]
1210+
}, config) # [!code ++]
1211+
```
1212+
1213+
</Warning>
1214+
1215+
:::
1216+
1217+
:::js
1218+
1219+
<Warning>
1220+
1221+
`new Command({ resume: ... })` is the **only** `Command` pattern intended as input to `invoke()`/`stream()`. Do not use `new Command({ update: ... })` as input to continue multi-turn conversations — because passing any `Command` as input resumes from the latest checkpoint (i.e. the last step that ran, not `__start__`), the graph will appear stuck if it already finished. To continue a conversation on an existing thread, pass a plain input object:
1222+
1223+
```typescript
1224+
// WRONG — graph resumes from the latest checkpoint
1225+
// (last step that ran), appears stuck
1226+
await graph.invoke(new Command({ update: { messages: [{ role: "user", content: "follow up" }] } }), config); // [!code --]
1227+
1228+
// CORRECT — plain object restarts from __start__
1229+
await graph.invoke({ messages: [{ role: "user", content: "follow up" }] }, config); // [!code ++]
1230+
```
1231+
1232+
</Warning>
1233+
1234+
:::
1235+
1236+
#### `resume`
12151237

12161238
:::python
1217-
@[`Command`] is an important part of human-in-the-loop workflows: when using `interrupt()` to collect user input, @[`Command`] is then used to supply the input and resume execution via `Command(resume="User input")`. Check out [this conceptual guide](/oss/langgraph/interrupts) for more information.
1239+
1240+
Use `Command(resume=...)` to provide a value and resume graph execution after an [interrupt](/oss/langgraph/interrupts). The value passed to `resume` becomes the return value of the `interrupt()` call inside the paused node:
1241+
1242+
```python
1243+
from langgraph.types import Command, interrupt
1244+
1245+
def human_review(state: State):
1246+
# Pauses the graph and waits for a value
1247+
answer = interrupt("Do you approve?")
1248+
return {"messages": [{"role": "user", "content": answer}]}
1249+
1250+
# First invocation — hits the interrupt and pauses
1251+
result = graph.invoke({"messages": [...]}, config)
1252+
1253+
# Resume with a value — the interrupt() call returns "yes"
1254+
result = graph.invoke(Command(resume="yes"), config)
1255+
```
1256+
1257+
Check out the [interrupts conceptual guide](/oss/langgraph/interrupts) for full details on interrupt patterns, including multiple interrupts and validation loops.
1258+
12181259
:::
12191260

12201261
:::js
1221-
@[`Command`] is an important part of human-in-the-loop workflows: when using `interrupt()` to collect user input, @[`Command`] is then used to supply the input and resume execution via `new Command({ resume: "User input" })`. Check out the [human-in-the-loop conceptual guide](/oss/langgraph/interrupts) for more information.
1262+
1263+
Use `new Command({ resume: ... })` to provide a value and resume graph execution after an [interrupt](/oss/langgraph/interrupts). The value passed to `resume` becomes the return value of the `interrupt()` call inside the paused node:
1264+
1265+
```typescript
1266+
import { Command, interrupt } from "@langchain/langgraph";
1267+
1268+
const humanReview = async (state: typeof StateAnnotation.State) => {
1269+
// Pauses the graph and waits for a value
1270+
const answer = interrupt("Do you approve?");
1271+
return { messages: [{ role: "user", content: answer }] };
1272+
};
1273+
1274+
// First invocation — hits the interrupt and pauses
1275+
const result = await graph.invoke({ messages: [...] }, config);
1276+
1277+
// Resume with a value — the interrupt() call returns "yes"
1278+
const resumed = await graph.invoke(new Command({ resume: "yes" }), config);
1279+
```
1280+
1281+
Check out the [interrupts conceptual guide](/oss/langgraph/interrupts) for full details on interrupt patterns, including multiple interrupts and validation loops.
1282+
12221283
:::
12231284

1285+
### Return from tools
1286+
1287+
You can return @[`Command`] from tools to update graph state and control flow. Use `update` to modify state (e.g., saving customer information looked up during a conversation) and `goto` to route to a specific node after the tool completes.
1288+
1289+
<Warning>
1290+
1291+
When used inside tools, `goto` adds a dynamic edge — any static edges already defined on the node that called the tool will still execute.
1292+
1293+
</Warning>
1294+
1295+
Refer to [this guide](/oss/langgraph/use-graph-api#use-inside-tools) for detail.
1296+
12241297
## Graph migrations
12251298

12261299
LangGraph can easily handle migrations of graph definitions (nodes, edges, and state) even when using a checkpointer to track state.

src/oss/langgraph/interrupts.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ graph.invoke(Command(resume=True), config=config)
9494
- The value passed to `Command(resume=...)` becomes the return value of the @[`interrupt`] call
9595
- The node restarts from the beginning of the node where the @[`interrupt`] was called when resumed, so any code before the @[`interrupt`] runs again
9696
- You can pass any JSON-serializable value as the resume value
97+
98+
<Warning>
99+
100+
`Command(resume=...)` is the **only** `Command` pattern intended as input to `invoke()`/`stream()`. The other `Command` parameters (`update`, `goto`, `graph`) are designed for [returning from node functions](/oss/langgraph/graph-api#command). Do not pass `Command(update=...)` as input to continue multi-turn conversations — pass a plain input dict instead.
101+
102+
</Warning>
103+
97104
:::
98105

99106
:::js
@@ -121,6 +128,13 @@ await graph.invoke(new Command({ resume: true }), config);
121128
- The value passed to `new Command({ resume: ... })` becomes the return value of the @[`interrupt`] call
122129
- The node restarts from the beginning of the node where the @[`interrupt`] was called when resumed, so any code before the @[`interrupt`] runs again
123130
- You can pass any JSON-serializable value as the resume value
131+
132+
<Warning>
133+
134+
`new Command({ resume: ... })` is the **only** `Command` pattern intended as input to `invoke()`/`stream()`. The other `Command` parameters (`update`, `goto`, `graph`) are designed for [returning from node functions](/oss/langgraph/graph-api#command). Do not pass `new Command({ update: ... })` as input to continue multi-turn conversations — pass a plain input object instead.
135+
136+
</Warning>
137+
124138
:::
125139

126140
## Common patterns

0 commit comments

Comments
 (0)