Compare commits

...
Author SHA1 Message Date
Sam Crowder b2d39a1227 Update changelog via LangGraph Server Changelog Bot 2025-07-30 16:01:03 -07:00
Lauren Hirata SinghandGitHub 9d4dd066e5 docs: Revert "docs: Delete LGP nav Items from docs" (#5753)
Reverts langchain-ai/langgraph#5743
2025-07-30 18:15:19 -04:00
Lauren Hirata SinghandGitHub 81027b2b80 docs: fix redirects to external pages (#5752) 2025-07-30 16:52:13 -04:00
Sydney RunkleandGitHub 296bf5f75e fix(docs): context docs formatting (#5751) 2025-07-30 16:41:49 -04:00
Sydney RunkleandGitHub f43c806736 release(langgraph): 0.6.2 (#5750) 2025-07-30 20:35:27 +00:00
Sydney RunkleandGitHub 36f444dcb6 release(prebuilt): 0.6.2 (#5749) 2025-07-30 20:27:10 +00:00
Sydney RunkleandGitHub 781a115f92 fix(prebuilt): assign context_schema to config_schema with correct condition (#5746) 2025-07-30 20:08:45 +00:00
95d056e735 docs: Delete LGP nav Items from docs (#5743)
Remove the files and nav for LGP docs in the mkdocs site.

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-30 15:49:54 -04:00
open-swe[bot]GitHubopen-swe[bot] <open-swe@users.noreply.github.com>Sydney RunkleSydney RunkleEugene Yurtsev
64adb2bab3 feat: Add context coercion for LangGraph runtime (#5736)
Fixes #5735

Implement context coercion functionality for LangGraph runtime to
improve API usability.

Key changes:
- Added `_coerce_context` function in `pregel/main.py`
- Supports coercion for:
  - Pydantic BaseModel
  - Dataclasses
  - TypedDict
- Comprehensive test coverage added in `tests/test_runtime.py`
- Handles edge cases like None context and missing fields

The implementation allows users to pass dictionaries as context, which
will be automatically converted to the expected schema type, making the
API more flexible and user-friendly.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-30 19:08:45 +00:00
Syed Baqar AbbasandGitHub e87f0fb0cd docs: The notebook redirects to a page that does not exist (#5638)
**docs: The notebook redirects to a page that does not exist**
- **Description:** The current documentation redirects to a file that
does not exist. I have removed the doc to avoid confusion.
  - **Issue:** Fixes #5637
2025-07-30 18:26:28 +00:00
c70f283f83 chore(examples): remove outdated HITL notebooks pointing to 404s (#5731)
**Description:**  
Removed 4 broken notebooks in `examples/human_in_the_loop/` that
referenced missing files (list below). These notebooks displayed
redirect messages but the new paths are either invalid or don’t contain
content.
Filenames:
1. examples/human_in_the_loop/dynamic_breakpoints.ipynb
2. examples/human_in_the_loop/edit-graph-state.ipynb
3. examples/human_in_the_loop/review-tool-calls.ipynb
4. examples/human_in_the_loop/time-travel.ipynb


**Issue:**  
Closes #5642

**Dependencies:**  
None

Co-authored-by: gawhaarya <gawhaneaarya@gmail.com>
2025-07-30 18:25:55 +00:00
Sydney RunkleandGitHub 1d6b0c36e9 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5732) 2025-07-30 14:20:35 -04:00
Hunter LovellandGitHub e5344d35af fix(docs): squash js docs build errors (#5723) 2025-07-30 16:14:51 +00:00
Sam Crowder 9f48bb0b61 Update changelog via LangGraph Server Changelog Bot 2025-07-30 08:39:34 -07:00
Sam CrowderandGitHub 5333fc9c21 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5718) 2025-07-29 21:51:35 -07:00
Sam Crowder da7ff1421d Update changelog via LangGraph Server Changelog Bot 2025-07-29 17:42:16 -07:00
33 changed files with 689 additions and 354 deletions
+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",
+141 -12
View File
@@ -127,6 +127,79 @@ REDIRECT_MAP = {
"how-tos/human_in_the_loop/breakpoints.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_breakpoint.md": "cloud/how-tos/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md",
# mintlify
# "tutorials/auth/getting_started.md": "https://docs.langchain.com/langgraph-platform/",
# "tutorials/auth/resource_auth.md": "https://docs.langchain.com/langgraph-platform/",
# "tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/use-remote-graph.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/autogen-integration.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_platform.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_components.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_server.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_data_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_control_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_cli.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/sdk.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/plans.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/application_structure.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/scalability_and_resilience.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/auth.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/auth/custom_auth.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/auth/openapi_security.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/assistants.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/use_threads.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/background_run.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/same-thread.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/double_texting.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/concepts/webhooks.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/webhooks.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/http/custom_middleware.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/http/custom_routes.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/semantic_search.md": "https://docs.langchain.com/langgraph-platform/",
# "how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/deployment_options.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/quick_start.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/setup.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/custom_docker.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_cloud.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/cloud.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/deployment/standalone_container.md": "https://docs.langchain.com/langgraph-platform/",
# "concepts/server-mcp.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langgraph-platform/",
# "cloud/how-tos/streaming.md": "https://docs.langchain.com/langgraph-platform/",
}
@@ -286,6 +359,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 +426,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
@@ -461,16 +555,51 @@ def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
def on_post_build(config):
use_directory_urls = config.get("use_directory_urls")
for page_old, page_new in REDIRECT_MAP.items():
# Convert .ipynb to .md for path calculation
page_old = page_old.replace(".ipynb", ".md")
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
old_html_path = File(page_old, "", "", use_directory_urls).dest_path.replace(
os.sep, "/"
)
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
_write_html(config["site_dir"], old_html_path, new_html_path)
# Calculate the HTML path for the old page (whether it exists or not)
if use_directory_urls:
# With directory URLs: /path/to/page/ becomes /path/to/page/index.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + "/index.html"
else:
old_html_path = page_old + "/index.html"
else:
# Without directory URLs: /path/to/page.md becomes /path/to/page.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + ".html"
else:
old_html_path = page_old + ".html"
if isinstance(page_new, str) and page_new.startswith("http"):
# Handle external redirects
_write_html(config["site_dir"], old_html_path, page_new)
else:
# Handle internal redirects
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
# Try to get the new path using File class, but fallback to manual calculation
try:
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
except:
# Fallback: calculate relative path manually
if use_directory_urls:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + "/"
else:
new_html_path = page_new_before_hash + "/"
else:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + ".html"
else:
new_html_path = page_new_before_hash + ".html"
new_html_path += hash + suffix
_write_html(config["site_dir"], old_html_path, new_html_path)
+31 -97
View File
@@ -2,13 +2,12 @@
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that an AI application can accomplish a task. Context can be characterized along two key dimensions:
1. By **mutability**:
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
2. By **lifetime**:
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
!!! tip "Runtime context vs LLM context"
@@ -51,38 +50,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 +81,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 +94,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 +111,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 +119,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 | Static | Single 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.
@@ -4,6 +4,19 @@
---
## v0.2.113 (2025-07-30)
- Improved thread search pagination by refining response headers for better navigation and accuracy.
## v0.2.112 (2025-07-30)
- Ensured asynchronous handling for sync logging methods and added a linter to prevent future issues.
- Fixed an issue where JavaScript tasks were not populating correctly in graphs.
## v0.2.111 (2025-07-29)
- Started the heartbeat immediately upon connection to prevent JS graph streaming errors during long startups.
## v0.2.110 (2025-07-29)
- Added interrupts as default values for all operations except streams to maintain consistent behavior.
## v0.2.109 (2025-07-28)
- Fixed an issue where missing config schema occurred when `config_type` was not set.
+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";
+1 -2
View File
@@ -383,5 +383,4 @@ extra_css:
- stylesheets/version_admonitions.css
- stylesheets/logos.css
- stylesheets/sticky_navigation.css
- stylesheets/agent_graph_widget.css
- stylesheets/agent_graph_widget.css
+1 -1
View File
@@ -360,5 +360,5 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
{% endblock %}
{% block announce %}
Our <a href="https://academy.langchain.com/courses/ambient-agents/?utm_medium=internal&utm_source=docs&utm_campaign=q2-2025_ambient-agents_co" target="_blank">Building Ambient Agents with LangGraph</a> course is now available on LangChain Academy!
LangGraph Platform docs are moving! Find the LangGraph Platform docs at the new <a href="https://docs.langchain.com/langgraph-platform" target="_blank">LangChain Docs</a> site!
{% endblock %}
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" },
@@ -1,33 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "b3cec425",
"metadata": {},
"source": [
"This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/how-tos/human_in_the_loop/dynamic_breakpoints.ipynb"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -1,33 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "4876215f",
"metadata": {},
"source": [
"This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/how-tos/human_in_the_loop/edit-graph-state.ipynb"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -1,33 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "b162f1bd",
"metadata": {},
"source": [
"This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/how-tos/human_in_the_loop/review-tool-calls.ipynb"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -1,33 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "84c5f6f1",
"metadata": {},
"source": [
"This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/how-tos/human_in_the_loop/time-travel.ipynb"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -1,33 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "5eb637a4",
"metadata": {},
"source": [
"This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/tutorials/multi_agent/agent_supervisor.ipynb"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+37 -4
View File
@@ -72,7 +72,7 @@ from langgraph._internal._runnable import (
RunnableSeq,
coerce_to_runnable,
)
from langgraph._internal._typing import DeprecatedKwargs
from langgraph._internal._typing import MISSING, DeprecatedKwargs
from langgraph.cache.base import BaseCache
from langgraph.channels.base import BaseChannel
from langgraph.channels.topic import Topic
@@ -636,7 +636,10 @@ class Pregel(
name: str = "LangGraph",
**deprecated_kwargs: Unpack[DeprecatedKwargs],
) -> None:
if config_type := deprecated_kwargs.get("config_type"):
if (
config_type := deprecated_kwargs.get("config_type"),
MISSING,
) is not MISSING:
warnings.warn(
"`config_type` is deprecated and will be removed. Please use `context_schema` instead.",
category=LangGraphDeprecatedSinceV10,
@@ -2571,7 +2574,7 @@ class Pregel(
config[CONF][CONFIG_KEY_DURABILITY] = durability_
runtime = Runtime(
context=context,
context=_coerce_context(self.context_schema, context),
store=store,
stream_writer=stream_writer,
previous=None,
@@ -2866,7 +2869,7 @@ class Pregel(
config[CONF][CONFIG_KEY_DURABILITY] = durability_
runtime = Runtime(
context=context,
context=_coerce_context(self.context_schema, context),
store=store,
stream_writer=stream_writer,
previous=None,
@@ -3224,3 +3227,33 @@ def _output(
yield (ns, payload)
else:
yield payload
def _coerce_context(
context_schema: type[ContextT] | None, context: Any
) -> ContextT | None:
"""Coerce context input to the appropriate schema type.
If context is a dict and context_schema is a dataclass or pydantic model, we coerce.
Else, we return the context as-is.
Args:
context_schema: The schema type to coerce to (BaseModel, dataclass, or TypedDict)
context: The context value to coerce
Returns:
The coerced context value or None if context is None
"""
if context is None:
return None
if context_schema is None:
return context
schema_is_class = issubclass(context_schema, BaseModel) or is_dataclass(
context_schema
)
if isinstance(context, dict) and schema_is_class:
return context_schema(**context) # type: ignore[misc]
return cast(ContextT, context)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph"
version = "0.6.1"
version = "0.6.2"
description = "Building stateful, multi-actor applications with LLMs"
authors = []
requires-python = ">=3.9"
+19 -2
View File
@@ -102,6 +102,7 @@ def test_config_schema_deprecation() -> None:
match="`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
):
builder = StateGraph(PlainState, config_schema=PlainState)
assert builder.context_schema == PlainState
builder.add_node("test_node", lambda state: state)
builder.set_entry_point("test_node")
@@ -111,7 +112,7 @@ def test_config_schema_deprecation() -> None:
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated. Use `get_context_jsonschema` for the relevant schema instead.",
):
graph.config_schema()
assert graph.config_schema() is not None
with pytest.warns(
LangGraphDeprecatedSinceV10,
@@ -120,6 +121,21 @@ def test_config_schema_deprecation() -> None:
graph.get_config_jsonschema()
@pytest.mark.filterwarnings("ignore:`config_schema` is deprecated")
def test_config_schema_deprecation_on_entrypoint() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
):
@entrypoint(config_schema=PlainState) # type: ignore[arg-type]
def my_entrypoint(state: PlainState) -> PlainState:
return state
assert my_entrypoint.context_schema == PlainState
assert my_entrypoint.config_schema() is not None
def test_config_type_deprecation_pregel(mocker: MockerFixture) -> None:
add_one = mocker.Mock(side_effect=lambda x: x + 1)
chain = NodeBuilder().subscribe_only("input").do(add_one).write_to("output")
@@ -128,7 +144,7 @@ def test_config_type_deprecation_pregel(mocker: MockerFixture) -> None:
LangGraphDeprecatedSinceV10,
match="`config_type` is deprecated and will be removed. Please use `context_schema` instead.",
):
Pregel(
instance = Pregel(
nodes={
"one": chain,
},
@@ -140,6 +156,7 @@ def test_config_type_deprecation_pregel(mocker: MockerFixture) -> None:
output_channels="output",
config_type=PlainState,
)
assert instance.context_schema == PlainState
@pytest.mark.filterwarnings("ignore:`interrupt_id` is deprecated. Use `id` instead.")
+283
View File
@@ -1,6 +1,8 @@
from dataclasses import dataclass
from typing import Any
import pytest
from pydantic import BaseModel, ValidationError
from typing_extensions import TypedDict
from langgraph.graph import END, START, StateGraph
@@ -106,3 +108,284 @@ def test_runtime_propogated_to_subgraph() -> None:
context = Context(username="Alice")
result = graph.invoke({}, context=context)
assert result == {"subgraph": "Alice!", "main": "Alice!"}
def test_context_coercion_dataclass() -> None:
"""Test that dict context is coerced to dataclass."""
@dataclass
class Context:
api_key: str
timeout: int = 30
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {
"message": f"api_key: {runtime.context.api_key}, timeout: {runtime.context.timeout}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test dict coercion with all fields
result = compiled.invoke(
{"message": "test"}, context={"api_key": "sk_test", "timeout": 60}
)
assert result == {"message": "api_key: sk_test, timeout: 60"}
# Test dict coercion with default field
result = compiled.invoke({"message": "test"}, context={"api_key": "sk_test2"})
assert result == {"message": "api_key: sk_test2, timeout: 30"}
# Test with actual dataclass instance (should still work)
result = compiled.invoke(
{"message": "test"}, context=Context(api_key="sk_test3", timeout=90)
)
assert result == {"message": "api_key: sk_test3, timeout: 90"}
def test_context_coercion_pydantic() -> None:
"""Test that dict context is coerced to Pydantic model."""
class Context(BaseModel):
api_key: str
timeout: int = 30
tags: list[str] = []
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {
"message": f"api_key: {runtime.context.api_key}, timeout: {runtime.context.timeout}, tags: {runtime.context.tags}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test dict coercion with all fields
result = compiled.invoke(
{"message": "test"},
context={"api_key": "sk_test", "timeout": 60, "tags": ["prod", "v2"]},
)
assert result == {"message": "api_key: sk_test, timeout: 60, tags: ['prod', 'v2']"}
# Test dict coercion with defaults
result = compiled.invoke({"message": "test"}, context={"api_key": "sk_test2"})
assert result == {"message": "api_key: sk_test2, timeout: 30, tags: []"}
# Test with actual Pydantic instance (should still work)
result = compiled.invoke(
{"message": "test"},
context=Context(api_key="sk_test3", timeout=90, tags=["test"]),
)
assert result == {"message": "api_key: sk_test3, timeout: 90, tags: ['test']"}
def test_context_coercion_typeddict() -> None:
"""Test that dict context with TypedDict schema passes through as-is."""
class Context(TypedDict):
api_key: str
timeout: int
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
# TypedDict context is just a dict at runtime
return {
"message": f"api_key: {runtime.context['api_key']}, timeout: {runtime.context['timeout']}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test dict passes through for TypedDict
result = compiled.invoke(
{"message": "test"}, context={"api_key": "sk_test", "timeout": 60}
)
assert result == {"message": "api_key: sk_test, timeout: 60"}
def test_context_coercion_none() -> None:
"""Test that None context is handled properly."""
@dataclass
class Context:
api_key: str
class State(TypedDict):
message: str
def node_without_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
# Should be None when no context provided
return {"message": f"context is None: {runtime.context is None}"}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_without_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test with None context
result = compiled.invoke({"message": "test"}, context=None)
assert result == {"message": "context is None: True"}
# Test without context parameter (defaults to None)
result = compiled.invoke({"message": "test"})
assert result == {"message": "context is None: True"}
def test_context_coercion_errors() -> None:
"""Test error handling for invalid context."""
@dataclass
class Context:
api_key: str # Required field
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {"message": "should not reach here"}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test missing required field
with pytest.raises(TypeError):
compiled.invoke({"message": "test"}, context={"timeout": 60})
# Test invalid dict keys
with pytest.raises(TypeError):
compiled.invoke(
{"message": "test"}, context={"api_key": "test", "invalid_field": "value"}
)
@pytest.mark.anyio
async def test_context_coercion_async() -> None:
"""Test context coercion with async methods."""
@dataclass
class Context:
api_key: str
async_mode: bool = True
class State(TypedDict):
message: str
async def async_node(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {
"message": f"async api_key: {runtime.context.api_key}, async_mode: {runtime.context.async_mode}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", async_node)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test dict coercion with ainvoke
result = await compiled.ainvoke(
{"message": "test"}, context={"api_key": "sk_async", "async_mode": False}
)
assert result == {"message": "async api_key: sk_async, async_mode: False"}
# Test dict coercion with astream
chunks = []
async for chunk in compiled.astream(
{"message": "test"}, context={"api_key": "sk_stream"}
):
chunks.append(chunk)
# Find the chunk with our node output
node_output = None
for chunk in chunks:
if "node" in chunk:
node_output = chunk["node"]
break
assert node_output == {"message": "async api_key: sk_stream, async_mode: True"}
def test_context_coercion_stream() -> None:
"""Test context coercion with sync stream method."""
@dataclass
class Context:
api_key: str
stream_mode: str = "default"
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {
"message": f"stream api_key: {runtime.context.api_key}, mode: {runtime.context.stream_mode}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
# Test dict coercion with stream
chunks = []
for chunk in compiled.stream(
{"message": "test"}, context={"api_key": "sk_stream", "stream_mode": "fast"}
):
chunks.append(chunk)
# Find the chunk with our node output
node_output = None
for chunk in chunks:
if "node" in chunk:
node_output = chunk["node"]
break
assert node_output == {"message": "stream api_key: sk_stream, mode: fast"}
def test_context_coercion_pydantic_validation_errors() -> None:
"""Test that Pydantic validation errors are raised."""
class Context(BaseModel):
api_key: str
timeout: int
class State(TypedDict):
message: str
def node_with_context(state: State, runtime: Runtime[Context]) -> dict[str, Any]:
return {
"message": f"api_key: {runtime.context.api_key}, timeout: {runtime.context.timeout}"
}
graph = StateGraph(state_schema=State, context_schema=Context)
graph.add_node("node", node_with_context)
graph.add_edge(START, "node")
graph.add_edge("node", END)
compiled = graph.compile()
with pytest.raises(ValidationError):
compiled.invoke(
{"message": "test"}, context={"api_key": "sk_test", "timeout": "not_an_int"}
)
+2 -2
View File
@@ -1192,7 +1192,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "0.6.1"
version = "0.6.2"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },
@@ -1433,7 +1433,7 @@ dev = [
[[package]]
name = "langgraph-prebuilt"
version = "0.6.1"
version = "0.6.2"
source = { editable = "../prebuilt" }
dependencies = [
{ name = "langchain-core" },
@@ -459,11 +459,11 @@ def create_react_agent(
config_schema := deprecated_kwargs.pop("config_schema", MISSING)
) is not MISSING:
warn(
"`config_schema` is no longer supported. Use `context_schema` instead.",
"`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
category=LangGraphDeprecatedSinceV10,
)
if context_schema is not None:
if context_schema is None:
context_schema = config_schema
if version not in ("v1", "v2"):
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph-prebuilt"
version = "0.6.1"
version = "0.6.2"
description = "Library with high-level APIs for creating and executing LangGraph agents and tools."
authors = []
requires-python = ">=3.9"
+33
View File
@@ -0,0 +1,33 @@
import pytest
from typing_extensions import TypedDict
from langgraph.prebuilt import create_react_agent
from langgraph.warnings import LangGraphDeprecatedSinceV10
from tests.model import FakeToolCallingModel
class Config(TypedDict):
model: str
@pytest.mark.filterwarnings("ignore:`config_schema` is deprecated")
@pytest.mark.filterwarnings("ignore:`get_config_jsonschema` is deprecated")
def test_config_schema_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
):
agent = create_react_agent(FakeToolCallingModel(), [], config_schema=Config)
assert agent.context_schema == Config
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated. Use `get_context_jsonschema` for the relevant schema instead.",
):
assert agent.config_schema() is not None
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`get_config_jsonschema` is deprecated. Use `get_context_jsonschema` instead.",
):
assert agent.get_config_jsonschema() is not None
+2 -2
View File
@@ -316,7 +316,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "0.6.1"
version = "0.6.2"
source = { editable = "../langgraph" }
dependencies = [
{ name = "langchain-core" },
@@ -460,7 +460,7 @@ dev = [
[[package]]
name = "langgraph-prebuilt"
version = "0.6.1"
version = "0.6.2"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },