Compare commits

...
Author SHA1 Message Date
Hunter Lovell 615c280b21 change target language 2025-07-29 20:51:23 -07:00
Hunter Lovell 2180e0f80f chore: ref fixes 2025-07-29 20:51:03 -07:00
Hunter Lovell 4d983036a0 chore: add raw md output hatch 2025-07-29 20:35:15 -07:00
Hunter Lovell 2923e670b9 fix: js nits 2025-07-29 20:34:45 -07:00
17 changed files with 171 additions and 156 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ build-prebuilt:
uv run python -m _scripts.third_party_page.create_third_party_page stats.yml docs/agents/prebuilt.md
build-docs: build-prebuilt
TARGET_LANGUAGE=python uv run python -m mkdocs build --clean -f mkdocs.yml --strict
TARGET_LANGUAGE=js uv run python -m mkdocs build --clean -f mkdocs.yml --strict
llms-text:
uv run python -m _scripts.generate_llms_text docs/llms-full.txt
+4 -3
View File
@@ -65,6 +65,7 @@ PYTHON_LINK_MAP = {
# JavaScript-specific link mappings
JS_LINK_MAP = {
"Auth": "reference/classes/sdk_auth.Auth.html",
"StateGraph": "reference/classes/langgraph.StateGraph.html",
"add_conditional_edges": "reference/functions/langgraph_StateGraph.addConditionalEdges.html",
"add_edge": "reference/functions/langgraph_StateGraph.addEdge.html",
@@ -92,7 +93,7 @@ JS_LINK_MAP = {
"entrypoint.final": "reference/functions/langgraph_func.entrypoint.final.html",
"entrypoint": "reference/functions/langgraph_func.entrypoint.html",
"from_pycryptodome_aes": "reference/functions/langgraph_checkpoint_serde_encrypted.EncryptedSerializer.fromPycryptodomeAes.html",
# "getContextVariable": "<insert-ref>",
"getContextVariable": "https://v03.api.js.langchain.com/functions/_langchain_core.context.getContextVariable.html",
"get_state_history": "reference/functions/langgraph_CompiledStateGraph.getStateHistory.html",
"get_stream_writer": "reference/functions/langgraph_config.getStreamWriter.html",
"HumanInterrupt": "reference/classes/langgraph_prebuilt.HumanInterrupt.html",
@@ -103,8 +104,8 @@ JS_LINK_MAP = {
"JsonPlusSerializer": "reference/classes/langgraph_checkpoint_serde_jsonplus.JsonPlusSerializer.html",
"langgraph.json": "reference/configuration.html",
"LastValue": "reference/classes/langgraph_channels.LastValue.html",
# "MemorySaver": "<insert-ref>",
# "messagesStateReducer": "<insert-ref>",
"MemorySaver": "reference/classes/checkpoint.MemorySaver.html",
"messagesStateReducer": "reference/functions/langgraph.messagesStateReducer.html",
"PostgresSaver": "reference/classes/langgraph_checkpoint_postgres.PostgresSaver.html",
"Pregel": "reference/classes/langgraph.Pregel.html",
"Pregel.stream": "reference/functions/langgraph_Pregel.stream.html",
+21
View File
@@ -286,6 +286,21 @@ def _highlight_code_blocks(markdown: str) -> str:
return markdown
def _save_page_output(markdown: str, output_path: str):
"""Save markdown content to a file, creating parent directories if needed.
Args:
markdown: The markdown content to save
output_path: The file path to save to
"""
# Create parent directories recursively if they don't exist
os.makedirs(os.path.dirname(output_path), exist_ok=True)
# Write the markdown content to the file
with open(output_path, "w", encoding="utf-8") as f:
f.write(markdown)
def _on_page_markdown_with_config(
markdown: str,
page: Page,
@@ -338,6 +353,12 @@ def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]):
**kwargs,
)
page.meta["original_markdown"] = finalized_markdown
output_path = os.environ.get("MD_OUTPUT_PATH")
if output_path:
file_path = os.path.join(output_path, page.file.src_path)
_save_page_output(finalized_markdown, file_path)
return finalized_markdown
+27 -92
View File
@@ -51,38 +51,12 @@ graph.invoke( # (1)!
)
```
:::
:::js
| Type | Description | Mutable? | Lifetime |
| ---------------------------------------------------------------------------- | --------------------------------------------- | -------- | ----------------------- |
| [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run |
| [**Short-term memory (State)**](#short-term-memory-mutable-context) | dynamic data that can change during execution | ✅ | per run or conversation |
| [**Long-term memory (Store)**](#long-term-memory-cross-conversation-context) | data that can be shared between conversations | ✅ | across conversations |
Config is for immutable data like user metadata or API keys. Use this when you have values that don't change mid-run.
Specify configuration using a key called **"configurable"** which is reserved for this purpose.
```typescript
await graph.invoke(
// (1)!
{ messages: [{ role: "user", content: "hi!" }] }, // (2)!
// highlight-next-line
{ configurable: { user_id: "user_123" } } // (3)!
);
```
:::
1. This is the invocation of the agent or graph. The `invoke` method runs the underlying graph with the provided input.
2. This example uses messages as an input, which is common, but your application may use different input structures.
3. This is where you pass the runtime data. The `context` parameter allows you to provide additional dependencies that the agent can use during its execution.
=== "Agent prompt"
:::python
```python
from langchain_core.messages import AnyMessage
from langgraph.runtime import get_runtime
@@ -108,42 +82,11 @@ await graph.invoke(
context={"user_name": "John Smith"}
)
```
:::
:::js
```typescript
import type { BaseMessage } from "@langchain/core/messages";
import type { RunnableConfig } from "@langchain/core/runnables";
import type { AgentState } from "@langchain/langgraph/prebuilt";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
// highlight-next-line
const prompt = (state: AgentState, config: RunnableConfig): BaseMessage[] => {
const userName = config.configurable?.user_name;
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
return [{ role: "system", content: systemMsg }, ...state.messages];
};
const agent = createReactAgent({
llm: model,
tools: [getWeather],
prompt,
});
await agent.invoke(
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
// highlight-next-line
{ configurable: { user_name: "John Smith" } }
);
```
:::
* See [Agents](../agents/agents.md) for details.
=== "Workflow node"
:::python
```python
from langgraph.runtime import Runtime
@@ -152,25 +95,11 @@ await graph.invoke(
user_name = runtime.context.user_name
...
```
:::
:::js
```typescript
import type { RunnableConfig } from "@langchain/core/runnables";
// highlight-next-line
const node = (state: State, config?: RunnableConfig) => {
const userName = config?.configurable?.user_name;
// ...
};
```
:::
* See [the Graph API](https://langchain-ai.github.io/langgraph/how-tos/graph-api/#add-runtime-configuration) for details.
=== "In a tool"
:::python
```python
from langgraph.runtime import get_runtime
@@ -183,27 +112,6 @@ await graph.invoke(
email = get_user_email_from_db(runtime.context.user_name)
return email
```
:::
:::js
```typescript
import type { RunnableConfig } from "@langchain/core/runnables";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
// highlight-next-line
const getUserInfo = tool(
async (_, config: RunnableConfig): Promise<string> => {
const userId = config.configurable?.user_id;
return userId === "user_123" ? "User is John Smith" : "Unknown user";
},
{
name: "get_user_info",
description: "Retrieve user information based on user ID."
}
);
```
:::
See the [tool calling guide](../how-tos/tool-calling.md#configuration) for details.
@@ -212,6 +120,33 @@ await graph.invoke(
The `Runtime` object can be used to access static context and other utilities like the active store and stream writer.
See the [Runtime][langgraph.runtime.Runtime] documentation for details.
:::
:::js
| Context type | Description | Mutability | Lifetime |
| ------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------- | ------------------ |
| [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run |
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run |
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation |
## Config (static context)
Config is for immutable data like user metadata or API keys. Use this when you have values that don't change mid-run.
Specify configuration using a key called **"configurable"** which is reserved for this purpose.
```typescript
await graph.invoke(
// (1)!
{ messages: [{ role: "user", content: "hi!" }] }, // (2)!
// highlight-next-line
{ configurable: { user_id: "user_123" } } // (3)!
);
```
:::
## Dynamic runtime context (state)
**Dynamic runtime context** represents mutable data that can evolve during a single run and is managed through the LangGraph state object. This includes conversation history, intermediate results, and values derived from tools or LLM outputs. In LangGraph, the state object acts as [short-term memory](../concepts/memory.md) during a run.
+3 -3
View File
@@ -208,12 +208,12 @@ The high-level components are organized into several packages, each with a speci
## Visualize an agent graph
Use the following tool to visualize the graph generated by [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html) and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of:
Use the following tool to visualize the graph generated by @[`createReactAgent`][create_react_agent] and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of:
- [`tools`](./tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
- `preModelHook`: A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
- `postModelHook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
- [`responseFormat`](./agents.md#structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
- [`responseFormat`](./agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
<div class="agent-layout">
<div class="agent-graph-features-container">
@@ -232,7 +232,7 @@ Use the following tool to visualize the graph generated by [`createReactAgent`](
</div>
</div>
The following code snippet shows how to create the above agent (and underlying graph) with [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html):
The following code snippet shows how to create the above agent (and underlying graph) with @[`createReactAgent`][create_react_agent]:
<div class="language-typescript">
<pre><code id="agent-code" class="language-typescript"></code></pre>
@@ -43,7 +43,9 @@ First, as a brief refresher on the concept of runtime context, consider the foll
}
```
:::python
For more information on runtime context, [see here](../../concepts/low_level.md#runtime-context).
:::
## Create an assistant
@@ -327,4 +329,4 @@ If you now run your graph and pass in this assistant id, it will use the first v
If using LangGraph Studio, to set the active version of your assistant, click the "Manage Assistants" button and locate the assistant you would like to use. Select the assistant and the version, and then click the "Active" toggle. This will update the assistant to make the selected version active.
!!! warning "Deleting Assistants"
Deleting as assistant will delete ALL of its versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use.
Deleting as assistant will delete ALL of its versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use.
+3
View File
@@ -14,7 +14,10 @@ The LangGraph Cloud API provides several endpoints for creating and managing ass
## Configuration
:::python
Assistants build on the LangGraph open source concepts of configuration and [runtime context](low_level.md#runtime-context).
:::
While these features are available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default context and configuration settings.
In practice, an assistant is just an _instance_ of a graph with a specific configuration. Therefore, multiple assistants can reference the same graph but can contain different configurations (e.g. prompts, models, tools). The LangGraph Server API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants.
+5 -5
View File
@@ -1154,15 +1154,15 @@ Under the hood, checkpointing is powered by checkpointer objects that conform to
- `langgraph-checkpoint`: The base interface for checkpointer savers (@[BaseCheckpointSaver]) and serialization/deserialization interface (@[SerializerProtocol][SerializerProtocol]). Includes in-memory checkpointer implementation (@[InMemorySaver][InMemorySaver]) for experimentation. LangGraph comes with `langgraph-checkpoint` included.
- `langgraph-checkpoint-sqlite`: An implementation of LangGraph checkpointer that uses SQLite database (@[SqliteSaver][SqliteSaver] / @[AsyncSqliteSaver]). Ideal for experimentation and local workflows. Needs to be installed separately.
- `langgraph-checkpoint-postgres`: An advanced checkpointer that uses Postgres database (@[PostgresSaver][PostgresSaver] / @[AsyncPostgresSaver]), used in LangGraph Platform. Ideal for using in production. Needs to be installed separately.
:::
:::js
- `@langchain/langgraph-checkpoint`: The base interface for checkpointer savers (@[BaseCheckpointSaver][BaseCheckpointSaver]) and serialization/deserialization interface (@[SerializerProtocol][SerializerProtocol]). Includes in-memory checkpointer implementation (@[InMemorySaver) for experimentation. LangGraph comes with `@langchain/langgraph-checkpoint` included.
- `@langchain/langgraph-checkpoint`: The base interface for checkpointer savers (@[BaseCheckpointSaver][BaseCheckpointSaver]) and serialization/deserialization interface (@[SerializerProtocol][SerializerProtocol]). Includes in-memory checkpointer implementation (@[MemorySaver]) for experimentation. LangGraph comes with `@langchain/langgraph-checkpoint` included.
- `@langchain/langgraph-checkpoint-sqlite`: An implementation of LangGraph checkpointer that uses SQLite database (@[SqliteSaver]). Ideal for experimentation and local workflows. Needs to be installed separately.
- `@langchain/langgraph-checkpoint-postgres`: An advanced checkpointer that uses Postgres database (@[PostgresSaver]), used in LangGraph Platform. Ideal for using in production. Needs to be installed separately.
:::
### Checkpointer interface
@@ -1177,7 +1177,7 @@ Each checkpointer conforms to @[BaseCheckpointSaver] interface and implements th
If the checkpointer is used with asynchronous graph execution (i.e. executing the graph via `.ainvoke`, `.astream`, `.abatch`), asynchronous versions of the above methods will be used (`.aput`, `.aput_writes`, `.aget_tuple`, `.alist`).
!!! note
!!! note
For running your graph asynchronously, you can use `InMemorySaver`, or async versions of Sqlite/Postgres checkpointers -- `AsyncSqliteSaver` / `AsyncPostgresSaver` checkpointers.
@@ -1190,7 +1190,7 @@ Each checkpointer conforms to the @[BaseCheckpointSaver][BaseCheckpointSaver] in
- `.putWrites` - Store intermediate writes linked to a checkpoint (i.e. [pending writes](#pending-writes)).
- `.getTuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `checkpoint_id`). This is used to populate `StateSnapshot` in `graph.getState()`.
- `.list` - List checkpoints that match a given configuration and filter criteria. This is used to populate state history in `graph.getStateHistory()`
:::
:::
### Serializer
+2
View File
@@ -89,7 +89,9 @@ After deployment, you can update the name and description using the LangGraph SD
Define clear, minimal input and output schemas to avoid exposing unnecessary internal complexity to the LLM.
:::python
The default [MessagesState](./low_level.md#messagesstate) uses `AnyMessage`, which supports many message types but is too general for direct LLM exposure.
:::
Instead, define **custom agents or workflows** that use explicitly typed input and output structures.
+21 -1
View File
@@ -137,7 +137,8 @@ def my_node(state, config):
```
!!! note
Fetch user credentials from a secure secret store. Storing secrets in graph state is not recommended.
Fetch user credentials from a secure secret store. Storing secrets in graph state is not recommended.
### Authorizing a Studio user
@@ -264,6 +265,25 @@ Only use this if you want to permit developer access to a graph deployed on the
curl -H "Authorization: Bearer ${your-token}" http://localhost:2024/threads
```
## Enable agent authentication
After [authentication](#add-custom-authentication-to-your-deployment), the platform creates a special configuration object (`config`) that is passed to LangGraph Platform deployment. This object contains information about the current user, including any custom fields you return from your `authenticate` handler.
To allow an agent to perform authenticated actions on behalf of the user, access this object in your graph with the `langgraph_auth_user` key:
```ts
async function myNode(state, config) {
const userConfig = config["configurable"]["langgraph_auth_user"];
// token was resolved during the authenticate function
const token = userConfig["github_token"];
...
}
```
!!! note
Fetch user credentials from a secure secret store. Storing secrets in graph state is not recommended.
:::
## Learn more
+60 -41
View File
@@ -11,7 +11,7 @@ pip install -U langgraph
```
!!! tip "Set up LangSmith for better debugging"
Sign up for [LangSmith](https://smith.langchain.com) to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started in the [docs](https://docs.smith.langchain.com).
Sign up for [LangSmith](https://smith.langchain.com) to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started in the [docs](https://docs.smith.langchain.com).
## Define and update state
@@ -26,7 +26,9 @@ Here we show how to define and update [state](../concepts/low_level.md#state) in
By default, graphs will have the same input and output schema, and the state determines that schema. See [this section](#define-input-and-output-schemas) for how to define distinct input and output schemas.
:::python
Let's consider a simple example using [messages](../concepts/low_level.md#messagesstate). This represents a versatile formulation of state for many LLM applications. See our [concepts page](../concepts/low_level.md#working-with-messages-in-graph-state) for more detail.
:::
```python
from langchain_core.messages import AnyMessage
@@ -55,7 +57,7 @@ def node(state: State):
This node simply appends a message to our message list, and populates an extra field.
!!! important
Nodes should return updates to the state directly, instead of mutating the state.
Nodes should return updates to the state directly, instead of mutating the state.
Let's next define a simple graph containing this node. We use [StateGraph](../concepts/low_level.md#stategraph) to define a graph that operates on this state. We then use [add_node](../concepts/low_level.md#nodes) populate our graph.
@@ -86,6 +88,7 @@ from langchain_core.messages import HumanMessage
result = graph.invoke({"messages": [HumanMessage("Hi")]})
result
```
```
{'messages': [HumanMessage(content='Hi'), AIMessage(content='Hello!')], 'extra_field': 10}
```
@@ -101,6 +104,7 @@ For convenience, we frequently inspect the content of [message objects](https://
for message in result["messages"]:
message.pretty_print()
```
```
================================ Human Message ================================
@@ -139,6 +143,7 @@ def node(state: State):
# highlight-next-line
return {"messages": [new_message], "extra_field": 10}
```
```python
from langgraph.graph import START
@@ -149,6 +154,7 @@ result = graph.invoke({"messages": [HumanMessage("Hi")]})
for message in result["messages"]:
message.pretty_print()
```
```
================================ Human Message ================================
@@ -191,6 +197,7 @@ result = graph.invoke({"messages": [input_message]})
for message in result["messages"]:
message.pretty_print()
```
```
================================ Human Message ================================
@@ -248,6 +255,7 @@ graph = builder.compile() # Compile the graph
# Invoke the graph with an input and print the result
print(graph.invoke({"question": "hi"}))
```
```
{'answer': 'bye'}
```
@@ -310,6 +318,7 @@ response = graph.invoke(
print()
print(f"Output of graph invocation: {response}")
```
```
Entered node `node_1`:
Input: {'a': 'set at start'}.
@@ -332,11 +341,7 @@ In our examples, we typically use a python-native `TypedDict` or [`dataclass`](h
Here, we'll see how a [Pydantic BaseModel](https://docs.pydantic.dev/latest/api/base_model/) can be used for `state_schema` to add run-time validation on **inputs**.
!!! note "Known Limitations"
- Currently, the output of the graph will **NOT** be an instance of a pydantic model.
- Run-time validation only occurs on inputs into nodes, not on the outputs.
- The validation error trace from pydantic does not show which node the error arises in.
- Pydantic's recursive validation can be slow. For performance-sensitive applications, you may want to consider using a `dataclass` instead.
!!! note "Known Limitations" - Currently, the output of the graph will **NOT** be an instance of a pydantic model. - Run-time validation only occurs on inputs into nodes, not on the outputs. - The validation error trace from pydantic does not show which node the error arises in. - Pydantic's recursive validation can be slow. For performance-sensitive applications, you may want to consider using a `dataclass` instead.
```python
from langgraph.graph import StateGraph, START, END
@@ -370,6 +375,7 @@ except Exception as e:
print("An exception was raised because `a` is an integer rather than a string.")
print(e)
```
```
An exception was raised because `a` is an integer rather than a string.
1 validation error for OverallState
@@ -503,7 +509,7 @@ See below for additional features of Pydantic model state:
## Add runtime configuration
Sometimes you want to be able to configure your graph when calling it. For example, you might want to be able to specify what LLM or system prompt to use at runtime, *without polluting the graph state with these parameters*.
Sometimes you want to be able to configure your graph when calling it. For example, you might want to be able to specify what LLM or system prompt to use at runtime, _without polluting the graph state with these parameters_.
To add runtime configuration:
@@ -551,13 +557,14 @@ print(graph.invoke({}, context={"my_runtime_value": "a"}))
# highlight-next-line
print(graph.invoke({}, context={"my_runtime_value": "b"}))
```
```
{'my_state_value': 1}
{'my_state_value': 2}
```
??? example "Extended example: specifying LLM at runtime"
Below we demonstrate a practical example in which we configure what LLM to use at runtime. We will use both OpenAI and Anthropic models.
Below we demonstrate a practical example in which we configure what LLM to use at runtime. We will use both OpenAI and Anthropic models.
```python
from dataclasses import dataclass
@@ -604,7 +611,7 @@ print(graph.invoke({}, context={"my_runtime_value": "b"}))
```
??? example "Extended example: specifying model and system message at runtime"
Below we demonstrate a practical example in which we configure two parameters: the LLM and system message to use at runtime.
Below we demonstrate a practical example in which we configure two parameters: the LLM and system message to use at runtime.
```python
from dataclasses import dataclass
@@ -673,23 +680,23 @@ builder.add_node(
By default, the `retry_on` parameter uses the `default_retry_on` function, which retries on any exception except for the following:
* `ValueError`
* `TypeError`
* `ArithmeticError`
* `ImportError`
* `LookupError`
* `NameError`
* `SyntaxError`
* `RuntimeError`
* `ReferenceError`
* `StopIteration`
* `StopAsyncIteration`
* `OSError`
- `ValueError`
- `TypeError`
- `ArithmeticError`
- `ImportError`
- `LookupError`
- `NameError`
- `SyntaxError`
- `RuntimeError`
- `ReferenceError`
- `StopIteration`
- `StopAsyncIteration`
- `OSError`
In addition, for exceptions from popular http request libraries such as `requests` and `httpx` it only retries on 5xx status codes.
??? example "Extended example: customizing retry policies"
Consider an example in which we are reading from a SQL database. Below we pass two different retry policies to nodes:
Consider an example in which we are reading from a SQL database. Below we pass two different retry policies to nodes:
```python
import sqlite3
@@ -752,7 +759,7 @@ graph = builder.compile(cache=InMemoryCache())
## Create a sequence of steps
!!! info "Prerequisites"
This guide assumes familiarity with the above section on [state](#define-and-update-state).
This guide assumes familiarity with the above section on [state](#define-and-update-state).
Here we demonstrate how to construct a simple sequence of steps. We will show:
@@ -785,8 +792,8 @@ builder.add_edge(START, "step_1")
```
??? info "Why split application steps into a sequence with LangGraph?"
LangGraph makes it easy to add an underlying persistence layer to your application.
This allows state to be checkpointed in between the execution of nodes, so your LangGraph nodes govern:
LangGraph makes it easy to add an underlying persistence layer to your application.
This allows state to be checkpointed in between the execution of nodes, so your LangGraph nodes govern:
- How state updates are [checkpointed](../concepts/persistence.md)
- How interruptions are resumed in [human-in-the-loop](../concepts/human_in_the_loop.md) workflows
@@ -828,13 +835,15 @@ def step_3(state: State):
```
!!! note
Note that when issuing updates to the state, each node can just specify the value of the key it wishes to update.
Note that when issuing updates to the state, each node can just specify the value of the key it wishes to update.
By default, this will **overwrite** the value of the corresponding key. You can also use [reducers](../concepts/low_level.md#reducers) to control how updates are processed— for example, you can append successive updates to a key instead. See [this section](#process-state-updates-with-reducers) for more detail.
Finally, we define the graph. We use [StateGraph](../concepts/low_level.md#stategraph) to define a graph that operates on this state.
:::python
We will then use [add_node](../concepts/low_level.md#messagesstate) and [add_edge](../concepts/low_level.md#edges) to populate our graph and define its control flow.
:::
```python
from langgraph.graph import START, StateGraph
@@ -853,7 +862,7 @@ builder.add_edge("step_2", "step_3")
```
!!! tip "Specifying custom names"
You can specify custom names for nodes using `.add_node`:
You can specify custom names for nodes using `.add_node`:
```python
builder.add_node("my_node", step_1)
@@ -886,6 +895,7 @@ Let's proceed with a simple invocation:
```python
graph.invoke({"value_1": "c"})
```
```
{'value_1': 'a b', 'value_2': 10}
```
@@ -898,16 +908,16 @@ Note that:
- The third node populated a different value.
!!! tip "Built-in shorthand"
`langgraph>=0.2.46` includes a built-in short-hand `add_sequence` for adding node sequences. You can compile the same graph as follows:
`langgraph>=0.2.46` includes a built-in short-hand `add_sequence` for adding node sequences. You can compile the same graph as follows:
```python
# highlight-next-line
builder = StateGraph(State).add_sequence([step_1, step_2, step_3])
builder.add_edge(START, "step_1")
graph = builder.compile()
graph.invoke({"value_1": "c"})
graph.invoke({"value_1": "c"})
```
## Create branches
@@ -971,6 +981,7 @@ With the reducer, you can see that the values added in each node are accumulated
```python
graph.invoke({"aggregate": []}, {"configurable": {"thread_id": "foo"}})
```
```
Adding "A" to []
Adding "B" to ['A']
@@ -979,12 +990,12 @@ Adding "D" to ['A', 'B', 'C']
```
!!! note
In the above example, nodes `"b"` and `"c"` are executed concurrently in the same [superstep](../concepts/low_level.md#graphs). Because they are in the same step, node `"d"` executes after both `"b"` and `"c"` are finished.
In the above example, nodes `"b"` and `"c"` are executed concurrently in the same [superstep](../concepts/low_level.md#graphs). Because they are in the same step, node `"d"` executes after both `"b"` and `"c"` are finished.
Importantly, updates from a parallel superstep may not be ordered consistently. If you need a consistent, predetermined ordering of updates from a parallel superstep, you should write the outputs to a separate field in the state together with a value with which to order them.
??? note "Exception handling?"
LangGraph executes nodes within [supersteps](../concepts/low_level.md#graphs), meaning that while parallel branches are executed in parallel, the entire superstep is **transactional**. If any of these branches raises an exception, **none** of the updates are applied to the state (the entire superstep errors).
LangGraph executes nodes within [supersteps](../concepts/low_level.md#graphs), meaning that while parallel branches are executed in parallel, the entire superstep is **transactional**. If any of these branches raises an exception, **none** of the updates are applied to the state (the entire superstep errors).
Importantly, when using a [checkpointer](../concepts/persistence.md), results from successful nodes within a superstep are saved, and don't repeat when resumed.
@@ -1059,6 +1070,7 @@ display(Image(graph.get_graph().draw_mermaid_png()))
```python
graph.invoke({"aggregate": []})
```
```
Adding "A" to []
Adding "B" to ['A']
@@ -1129,6 +1141,7 @@ display(Image(graph.get_graph().draw_mermaid_png()))
result = graph.invoke({"aggregate": []})
print(result)
```
```
Adding "A" to []
Adding "C" to ['A']
@@ -1136,7 +1149,7 @@ Adding "C" to ['A']
```
!!! tip
Your conditional edges can route to multiple destination nodes. For example:
Your conditional edges can route to multiple destination nodes. For example:
```python
def route_bc_or_cd(state: State) -> Sequence[str]:
@@ -1203,6 +1216,7 @@ display(Image(graph.get_graph().draw_mermaid_png()))
for step in graph.stream({"topic": "animals"}):
print(step)
```
```
{'generate_topics': {'subjects': ['lions', 'elephants', 'penguins']}}
{'generate_joke': {'jokes': ["Why don't lions like fast food? Because they can't catch it!"]}}
@@ -1220,7 +1234,7 @@ You can also set the graph recursion limit when invoking or streaming the graph.
Let's consider a simple graph with a loop to better understand how these mechanisms work.
!!! tip
To return the last value of your state instead of receiving a recursion limit error, see the [next section](#impose-a-recursion-limit).
To return the last value of your state instead of receiving a recursion limit error, see the [next section](#impose-a-recursion-limit).
When creating a loop, you can include a conditional edge that specifies a termination condition:
@@ -1307,6 +1321,7 @@ Invoking the graph, we see that we alternate between nodes `"a"` and `"b"` befor
```python
graph.invoke({"aggregate": []})
```
```
Node A sees []
Node B sees ['A']
@@ -1329,6 +1344,7 @@ try:
except GraphRecursionError:
print("Recursion Error")
```
```
Node A sees []
Node B sees ['A']
@@ -1535,7 +1551,7 @@ result = await graph.ainvoke({"messages": [input_message]}) # (3)!
3. Use async invocations on the graph object itself.
!!! tip "Async streaming"
See the [streaming guide](./streaming.md) for examples of streaming with async.
See the [streaming guide](./streaming.md) for examples of streaming with async.
## Combine control flow and state updates with `Command`
@@ -1605,7 +1621,7 @@ graph = builder.compile()
```
!!! important
You might have noticed that we used `Command` as a return type annotation, e.g. `Command[Literal["node_b", "node_c"]]`. This is necessary for the graph rendering and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`.
You might have noticed that we used `Command` as a return type annotation, e.g. `Command[Literal["node_b", "node_c"]]`. This is necessary for the graph rendering and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`.
```python
from IPython.display import display, Image
@@ -1620,6 +1636,7 @@ If we run the graph multiple times, we'd see it take different paths (A -> B or
```python
graph.invoke({"foo": ""})
```
```
Called A
Called C
@@ -1641,7 +1658,7 @@ def my_node(state: State) -> Command[Literal["my_other_node"]]:
Let's demonstrate this using the above example. We'll do so by changing `node_a` in the above example into a single-node graph that we'll add as a subgraph to our parent graph.
!!! important "State updates with `Command.PARENT`"
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](../concepts/low_level.md#schema), you **must** define a [reducer](../concepts/low_level.md#reducers) for the key you're updating in the parent graph state. See the example below.
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](../concepts/low_level.md#schema), you **must** define a [reducer](../concepts/low_level.md#reducers) for the key you're updating in the parent graph state. See the example below.
```python
import operator
@@ -1698,6 +1715,7 @@ graph = builder.compile()
```python
graph.invoke({"foo": ""})
```
```
Called A
Called C
@@ -1723,7 +1741,7 @@ def lookup_user_info(tool_call_id: Annotated[str, InjectedToolCallId], config: R
```
!!! important
You MUST include `messages` (or any state key used for the message history) in `Command.update` when returning `Command` from a tool and the list of messages in `messages` MUST contain a `ToolMessage`. This is necessary for the resulting message history to be valid (LLM providers require AI messages with tool calls to be followed by the tool result messages).
You MUST include `messages` (or any state key used for the message history) in `Command.update` when returning `Command` from a tool and the list of messages in `messages` MUST contain a `ToolMessage`. This is necessary for the resulting message history to be valid (LLM providers require AI messages with tool calls to be followed by the tool result messages).
If you are using tools that update state via `Command`, we recommend using prebuilt [`ToolNode`](../reference/agents.md#langgraph.prebuilt.tool_node.ToolNode) which automatically handles tools returning `Command` objects and propagates them to the graph state. If you're writing a custom node that calls tools, you would need to manually propagate `Command` objects returned by the tools as the update from the node.
@@ -1794,6 +1812,7 @@ We can also convert a graph class into Mermaid syntax.
```python
print(app.get_graph().draw_mermaid())
```
```
%%{init: {'flowchart': {'curve': 'linear'}}}%%
graph TD;
@@ -1827,7 +1846,7 @@ graph TD;
### PNG
If preferred, we could render the Graph into a `.png`. Here we could use three options:
If preferred, we could render the Graph into a `.png`. Here we could use three options:
- Using Mermaid.ink API (does not require additional packages)
- Using Mermaid + Pyppeteer (requires `pip install pyppeteer`)
+1 -1
View File
@@ -1973,7 +1973,7 @@ def delete_messages(state):
:::
:::js
To delete messages from the graph state, you can use the `RemoveMessage`. For `RemoveMessage` to work, you need to use a state key with @[`messagesStateReducer`][messagesStateReducer] [reducer](../../concepts/low_level.md#reducers), like [`MessagesZodState`](../../concepts/low_level.md#messageszodstate).
To delete messages from the graph state, you can use the `RemoveMessage`. For `RemoveMessage` to work, you need to use a state key with @[`messagesStateReducer`][messagesStateReducer] [reducer](../../concepts/low_level.md#reducers), like `MessagesZodState`.
To remove specific messages:
@@ -34,7 +34,7 @@ There could be a few reasons you're seeing this error:
This interrupt could have been triggered in one of the following ways:
- You manually set `interruptBefore: ['tools']` in `createReactAgent`
- One of the tools raised an error that wasn't handled by the [ToolNode][ToolNode] (`"tools"`)
- One of the tools raised an error that wasn't handled by the @[ToolNode][ToolNode] (`"tools"`)
:::
+7 -3
View File
@@ -212,7 +212,7 @@ The handler receives two parameters:
:::js
The handler receives an object with the following properties:
1. `user` ([ProxyUser](../../cloud/reference/sdk/js_ts_sdk_ref.md#langgraph_sdk.auth.types.ProxyUser)): contains info about the current `user`, the user's `permissions`, the `resource` ("threads", "crons", "assistants")
1. `user` contains info about the current `user`, the user's `permissions`, the `resource` ("threads", "crons", "assistants")
2. `action` contains information about the action being taken ("create", "read", "update", "delete", "search", "create_run")
3. `value` (`Record<string, any>`): data that is being created or accessed. The contents of this object depend on the resource and action being accessed. See [adding scoped authorization handlers](#scoped-authorization) below for information on how to get more tightly scoped access control.
:::
@@ -588,10 +588,14 @@ Now that you can control access to resources, you might want to:
1. Move on to [Connect an authentication provider](add_auth_server.md) to add real user accounts.
2. Read more about [authorization patterns](../../concepts/auth.md#authorization).
:::python
:::python
3. Check out the [API reference](../../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth) for details about the interfaces and methods used in this tutorial.
:::
:::js
:::js
3. Check out the [API reference](../../cloud/reference/sdk/js_sdk_ref.md#langgraph_sdk.auth.Auth) for details about the interfaces and methods used in this tutorial.
:::
@@ -109,7 +109,15 @@ Now that we have our split documents, we can index them into a vector store that
## 3. Generate query
Now we will start building components ([nodes](../../concepts/low_level.md#nodes) and [edges](../../concepts/low_level.md#edges)) for our agentic RAG graph. Note that the components will operate on the [`MessagesState`](../../concepts/low_level.md#messagesstate) — graph state that contains a `messages` key with a list of [chat messages](https://python.langchain.com/docs/concepts/messages/).
Now we will start building components ([nodes](../../concepts/low_level.md#nodes) and [edges](../../concepts/low_level.md#edges)) for our agentic RAG graph.
:::python
Note that the components will operate on the [`MessagesState`](../../concepts/low_level.md#messagesstate) — graph state that contains a `messages` key with a list of [chat messages](https://python.langchain.com/docs/concepts/messages/).
:::
:::js
Note that the components will operate on the `MessagesZodState` — graph state that contains a `messages` key with a list of [chat messages](https://js.langchain.com/docs/concepts/messages/).
:::
1. Build a `generate_query_or_respond` node. It will call an LLM to generate a response based on the current graph state (list of messages). Given the input messages, it will decide to retrieve using the retriever tool, or respond directly to the user. Note that we're giving the chat model access to the `retriever_tool` we created earlier via `.bind_tools`:
+1 -1
View File
@@ -1274,7 +1274,7 @@ With orchestrator-worker, an orchestrator breaks down a task and delegates each
**Creating Workers in LangGraph**
Because orchestrator-worker workflows are common, LangGraph **has the `Send` API to support this**. It lets you dynamically create worker nodes and send each one a specific input. Each worker has its own state, and all worker outputs are written to a *shared state key* that is accessible to the orchestrator graph. This gives the orchestrator access to all worker output and allows it to synthesize them into a final output. As you can see below, we iterate over a list of sections and `Send` each to a worker node. See further documentation [here](../how-tos/map-reduce/) and [here](../concepts/low_level/#send).
Because orchestrator-worker workflows are common, LangGraph **has the `Send` API to support this**. It lets you dynamically create worker nodes and send each one a specific input. Each worker has its own state, and all worker outputs are written to a *shared state key* that is accessible to the orchestrator graph. This gives the orchestrator access to all worker output and allows it to synthesize them into a final output. As you can see below, we iterate over a list of sections and `Send` each to a worker node. See further documentation [here](https://langchain-ai.github.io/langgraph/how-tos/map-reduce/) and [here](https://langchain-ai.github.io/langgraph/concepts/low_level/#send).
```typescript
import { withLangGraph } from "@langchain/langgraph/zod";
Generated
+2 -2
View File
@@ -2337,7 +2337,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "0.6.0"
version = "0.6.1"
source = { editable = "../libs/langgraph" }
dependencies = [
{ name = "langchain-core" },
@@ -2641,7 +2641,7 @@ test = [
[[package]]
name = "langgraph-prebuilt"
version = "0.6.0"
version = "0.6.1"
source = { editable = "../libs/prebuilt" }
dependencies = [
{ name = "langchain-core" },