Compare commits

..
Author SHA1 Message Date
Eugene Yurtsev 15446cfac8 x 2025-06-27 12:02:27 -04:00
22 changed files with 639 additions and 1341 deletions
-1
View File
@@ -111,7 +111,6 @@ REDIRECT_MAP = {
"concepts/v0-human-in-the-loop.md": "concepts/human-in-the-loop.md",
"how-tos/index.md": "index.md",
"tutorials/introduction.ipynb": "concepts/why-langgraph.md",
"agents/deployment.md": "tutorials/langgraph-platform/local-server.md",
# deployment redirects
"how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
+92
View File
@@ -0,0 +1,92 @@
---
search:
boost: 2
tags:
- agent
hide:
- tags
---
# Deployment
To deploy your LangGraph agent, create and configure a LangGraph app. This setup supports both local development and production deployments.
Features:
* 🖥️ Local server for development
* 🧩 Studio Web UI for visual debugging
* ☁️ Cloud and 🔧 self-hosted deployment options
* 📊 LangSmith integration for tracing and observability
!!! info "Requirements"
- ✅ You **must** have a [LangSmith account](https://www.langchain.com/langsmith). You can sign up for **free** and get started with the free tier.
## Create a LangGraph app
```bash
pip install -U "langgraph-cli[inmem]"
langgraph new path/to/your/app --template new-langgraph-project-python
```
This will create an empty LangGraph project. You can modify it by replacing the code in `src/agent/graph.py` with your agent code. For example:
```python
from langgraph.prebuilt import create_react_agent
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
graph = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
prompt="You are a helpful assistant"
)
```
### Install dependencies
In the root of your new LangGraph app, install the dependencies in `edit` mode so your local changes are used by the server:
```shell
pip install -e .
```
### Create an `.env` file
You will find a `.env.example` in the root of your new LangGraph app. Create
a `.env` file in the root of your new LangGraph app and copy the contents of the `.env.example` file into it, filling in the necessary API keys:
```bash
LANGSMITH_API_KEY=lsv2...
ANTHROPIC_API_KEY=sk-
```
## Launch LangGraph server locally
```shell
langgraph dev
```
This will start up the LangGraph API server locally. If this runs successfully, you should see something like:
> Ready!
>
> - API: [http://localhost:2024](http://localhost:2024/)
>
> - Docs: http://localhost:2024/docs
>
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
See this [tutorial](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/) to learn more about running LangGraph app locally.
## LangGraph Studio Web UI
LangGraph Studio Web is a specialized UI that you can connect to LangGraph API server to enable visualization, interaction, and debugging of your application locally. Test your graph in the LangGraph Studio Web UI by visiting the URL provided in the output of the `langgraph dev` command.
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
## Deployment
Once your LangGraph app is running locally, you can deploy it using LangGraph Platform. Refer to the [deployment options guide](../concepts/deployment_options.md) for detailed instructions on all supported deployment models.
+2 -2
View File
@@ -8,9 +8,9 @@ hide:
- tags
---
# Agent development using prebuilt components
# Agent development with LangGraph
LangGraph provides both low-level primitives and high-level prebuilt components for building agent-based applications. This section focuses on the prebuilt, ready-to-use components designed to help you construct agentic systems quickly and reliably—without the need to implement orchestration, memory, or human feedback handling from scratch.
**LangGraph** provides both low-level primitives and high-level prebuilt components for building agent-based applications. This section focuses on the **prebuilt**, **reusable** components designed to help you construct agentic systems quickly and reliably—without the need to implement orchestration, memory, or human feedback handling from scratch.
## What is an agent?
@@ -15,15 +15,11 @@ Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](.
### Prerequisites
1. `KEDA` is installed on your cluster.
helm repo add kedacore https://kedacore.github.io/charts
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
1. A valid `Ingress` controller is installed on your cluster.
1. You have slack space in your cluster for multiple deployments. `Cluster-Autoscaler` is recommended to automatically provision new nodes.
1. You will need to enable egress to two control plane URLs. The listener polls these endpoints for deployments:
https://api.host.langchain.com
https://api.smith.langchain.com
### Setup
+12 -14
View File
@@ -18,21 +18,10 @@ The Functional API uses two key building blocks:
This provides a minimal abstraction for building workflows with state management and streaming.
!!! tip
For information on how to use the functional API, see [Use Functional API](../how-tos/use-functional-api.md).
## Functional API vs. Graph API
For users who prefer a more declarative approach, LangGraph's [Graph API](./low_level.md) allows you to define workflows using a Graph paradigm. Both APIs share the same underlying runtime, so you can use them together in the same application.
Here are some key differences:
- **Control flow**: The Functional API does not require thinking about graph structure. You can use standard Python constructs to define workflows. This will usually trim the amount of code you need to write.
- **Short-term memory**: The **GraphAPI** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions.
- **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint.
- **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime.
!!! tip
For users who prefer a more declarative approach, LangGraph's [Graph API](./low_level.md) allows you to define workflows using a Graph paradigm. Both APIs share the same underlying runtime, so you can use them together in the same application.
Please see the [Functional API vs. Graph API](#functional-api-vs-graph-api) section for a comparison of the two paradigms.
## Example
@@ -543,6 +532,15 @@ While different runs of a workflow can produce different results, resuming a **s
Idempotency ensures that running the same operation multiple times produces the same result. This helps prevent duplicate API calls and redundant processing if a step is rerun due to a failure. Always place API calls inside **tasks** functions for checkpointing, and design them to be idempotent in case of re-execution. Re-execution can occur if a **task** starts, but does not complete successfully. Then, if the workflow is resumed, the **task** will run again. Use idempotency keys or verify existing results to avoid duplication.
## Functional API vs. Graph API
The **Functional API** and the [Graph APIs (StateGraph)](./low_level.md#stategraph) provide two different paradigms to create applications with LangGraph. Here are some key differences:
- **Control flow**: The Functional API does not require thinking about graph structure. You can use standard Python constructs to define workflows. This will usually trim the amount of code you need to write.
- **Short-term memory**: The **GraphAPI** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions.
- **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint.
- **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime.
## Common Pitfalls
### Handling side effects
@@ -19,7 +19,7 @@ The Standalone Container deployment option is the least restrictive model for de
!!! warning
LangGraph Platform should not be deployed in serverless environments. Scale to zero may cause task loss and scaling up will not work reliably.
LangGraph Platform should not be deployed in serverless environments.
## Architecture
+1 -8
View File
@@ -1,12 +1,5 @@
# Use the functional API
The [**Functional API**](../concepts/functional_api.md) allows you to add LangGraph's key features — [persistence](../concepts/persistence.md), [memory](../how-tos/memory/add-memory.md), [human-in-the-loop](../concepts/human_in_the_loop.md), and [streaming](../concepts/streaming.md) — to your applications with minimal changes to your existing code.
!!! tip
For conceptual information on the functional API, see [Functional API](../concepts/functional_api.md).
## Creating a simple workflow
When defining an `entrypoint`, input is restricted to the first argument of the function. To pass multiple inputs, you can use a dictionary.
@@ -839,4 +832,4 @@ for chunk in workflow.stream([input_message], config, stream_mode="values"):
## Integrate with other libraries
* [Add LangGraph's features to other frameworks using the functional API](./autogen-integration-functional.ipynb): Add LangGraph features like persistence, memory and streaming to other agent frameworks that do not provide them out of the box.
* [Add LangGraph's features to other frameworks using the functional API](./autogen-integration-functional.ipynb): Add LangGraph features like persistence, memory and streaming to other agent frameworks that do not provide them out of the box.
@@ -1,4 +1,4 @@
# Run a local server
# LangGraph Platform quickstart
This guide shows you how to run a LangGraph application locally.
+113 -124
View File
@@ -92,75 +92,38 @@ nav:
- Get started:
- index.md
- Quickstarts:
- Start with a prebuilt agent: agents/agents.md
- Build a custom workflow:
- Agent: agents/agents.md
- LangGraph basics:
- concepts/why-langgraph.md
- 1. Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md
- 2. Add tools: tutorials/get-started/2-add-tools.md
- 3. Add memory: tutorials/get-started/3-add-memory.md
- 4. Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md
- 5. Customize state: tutorials/get-started/5-customize-state.md
- 6. Time travel: tutorials/get-started/6-time-travel.md
- Run a local server: tutorials/langgraph-platform/local-server.md
- Agent development:
- Workflows & agents: tutorials/workflows.md
- Prebuilt components: agents/overview.md
- Run an agent: agents/run_agents.md
- Agent architectures: concepts/agentic_concepts.md
- Guides:
- LangGraph APIs:
- Graph API:
- Overview: concepts/low_level.md
- Use the Graph API: how-tos/graph-api.ipynb
- Functional API:
- Overview: concepts/functional_api.md
- Use the Functional API: how-tos/use-functional-api.md
- Runtime: concepts/pregel.md
- Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md
- tutorials/get-started/2-add-tools.md
- tutorials/get-started/3-add-memory.md
- Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md
- tutorials/get-started/5-customize-state.md
- tutorials/get-started/6-time-travel.md
- Local server: tutorials/langgraph-platform/local-server.md
- Deployment: cloud/quick_start.md
- General concepts:
- Common patterns:
- Agent architectures: concepts/agentic_concepts.md
- Workflows & agents: tutorials/workflows.md
- Agent development: agents/overview.md
- Workflow orchestration:
- Graph API: concepts/low_level.md
- Subgraphs: concepts/subgraphs.md
- Runtime: concepts/pregel.md
- Functional API: concepts/functional_api.md
- Core capabilities:
- Streaming:
- Overview: concepts/streaming.md
- Stream outputs: how-tos/streaming.md
- Use Server API: cloud/how-tos/streaming.md
- Persistence:
- Overview: concepts/persistence.md
- Durable execution:
- Overview: concepts/durable_execution.md
- Memory:
- Overview: concepts/memory.md
- Add memory: how-tos/memory/add-memory.md
- Context:
- Add context: agents/context.md
- Models:
- Configure model: agents/models.md
- Tools:
- Overview: concepts/tools.md
- Call tools: how-tos/tool-calling.md
- Human-in-the-loop:
- Overview: concepts/human_in_the_loop.md
- Add human intervention: how-tos/human_in_the_loop/add-human-in-the-loop.md
- Use Server API: cloud/how-tos/add-human-in-the-loop.md
- Breakpoints:
- Overview: concepts/breakpoints.md
- Set breakpoints: how-tos/human_in_the_loop/breakpoints.md
- Use Server API: cloud/how-tos/human_in_the_loop_breakpoint.md
- Time travel:
- Overview: concepts/time-travel.md
- Use time travel: how-tos/human_in_the_loop/time-travel.md
- Use Server API: cloud/how-tos/human_in_the_loop_time_travel.md
- Subgraphs:
- Overview: concepts/subgraphs.md
- Use subgraphs: how-tos/subgraph.ipynb
- Multi-agent:
- Overview: concepts/multi_agent.md
- Prebuilt implementation: agents/multi-agent.md
- Custom implementation: how-tos/multi_agent.ipynb
- MCP:
- Use MCP: agents/mcp.md
- Server API: concepts/server-mcp.md
- Evaluation:
- Basic implementation: agents/evals.md
- Platform-only capabilities:
- Streaming: concepts/streaming.md
- Persistence: concepts/persistence.md
- Durable execution: concepts/durable_execution.md
- Memory: concepts/memory.md
- Tools: concepts/tools.md
- Human-in-the-loop: concepts/human_in_the_loop.md
- Breakpoints: concepts/breakpoints.md
- Time travel: concepts/time-travel.md
- Multi-agent: concepts/multi_agent.md
- Platform capabilities:
- LangGraph Platform:
- Overview: concepts/langgraph_platform.md
- Components:
@@ -170,72 +133,97 @@ nav:
- Data plane: concepts/langgraph_data_plane.md
- Control plane: concepts/langgraph_control_plane.md
- LangGraph CLI: concepts/langgraph_cli.md
- LangGraph Studio:
- Overview: concepts/langgraph_studio.md
- Quickstart: cloud/how-tos/studio/quick_start.md
- cloud/how-tos/invoke_studio.md
- cloud/how-tos/studio/manage_assistants.md
- cloud/how-tos/threads_studio.md
- cloud/how-tos/iterate_graph_studio.md
- cloud/how-tos/studio/run_evals.md
- cloud/how-tos/clone_traces_studio.md
- cloud/how-tos/datasets_studio.md
- LangGraph Studio: concepts/langgraph_studio.md
- LangGraph SDK: concepts/sdk.md
- Plans & pricing: concepts/plans.md
- Application structure: concepts/application_structure.md
- Scalability & resilience: concepts/scalability_and_resilience.md
- Authentication & access control:
- Overview: concepts/auth.md
- how-tos/auth/custom_auth.md
- how-tos/auth/openapi_security.md
- Assistants:
- Overview: concepts/assistants.md
- cloud/how-tos/configuration_cloud.md
- Threads: cloud/how-tos/use_threads.md
- Runs:
- cloud/how-tos/background_run.md
- cloud/how-tos/same-thread.md
- cloud/how-tos/cron_jobs.md
- cloud/how-tos/stateless_runs.md
- cloud/how-tos/configurable_headers.md
- Double-texting:
- Overview: concepts/double_texting.md
- cloud/how-tos/interrupt_concurrent.md
- cloud/how-tos/rollback_concurrent.md
- cloud/how-tos/reject_concurrent.md
- cloud/how-tos/enqueue_concurrent.md
- Webhooks:
- Overview: cloud/concepts/webhooks.md
- Use webhooks: cloud/how-tos/webhooks.md
- Cron jobs:
- Overview: cloud/concepts/cron_jobs.md
- cloud/how-tos/cron_jobs.md
- Authentication & access control: concepts/auth.md
- Assistants: concepts/assistants.md
- Double-texting: concepts/double_texting.md
- Webhooks: cloud/concepts/webhooks.md
- Cron jobs: cloud/concepts/cron_jobs.md
- Deployment:
- Overview: concepts/deployment_options.md
- Deployment options:
- Cloud SaaS: concepts/langgraph_cloud.md
- Self-Hosted Data Plane: concepts/langgraph_self_hosted_data_plane.md
- Self-Hosted Control Plane: concepts/langgraph_self_hosted_control_plane.md
- Standalone Container: concepts/langgraph_standalone_container.md
- Guides:
- Core Capabilities:
- Use the Graph API: how-tos/graph-api.ipynb
- Use the Functional API: how-tos/use-functional-api.md
- Models: agents/models.md
- Streaming: how-tos/streaming.md
- Context: agents/context.md
- Memory: how-tos/memory/add-memory.md
- Human-in-the-loop: how-tos/human_in_the_loop/add-human-in-the-loop.md
- Time travel: how-tos/human_in_the_loop/time-travel.md
- Breakpoints: how-tos/human_in_the_loop/breakpoints.md
- Tools: how-tos/tool-calling.md
- Subgraphs: how-tos/subgraph.ipynb
- Multi-agent:
- Prebuilt implementation: agents/multi-agent.md
- Custom implementation: how-tos/multi_agent.ipynb
- MCP: agents/mcp.md
- Evaluation:
- Basic implementation: agents/evals.md
- Platform capabilities:
- Deployment:
- Basic deployment: agents/deployment.md
- Set up your application:
- Use requirements.txt: cloud/deployment/setup.md
- Use pyproject.toml: cloud/deployment/setup_pyproject.md
- Use JavaScript: cloud/deployment/setup_javascript.md
- Use custom Docker: cloud/deployment/custom_docker.md
- Rebuild graph at runtime: cloud/deployment/graph_rebuild.md
- Deploy to production:
- Cloud SaaS: cloud/deployment/cloud.md
- Self-Hosted Data Plane: cloud/deployment/self_hosted_data_plane.md
- Self-Hosted Control Plane: cloud/deployment/self_hosted_control_plane.md
- Standalone Container: cloud/deployment/standalone_container.md
- LangGraph Studio:
- Quickstart: cloud/how-tos/studio/quick_start.md
- cloud/how-tos/invoke_studio.md
- cloud/how-tos/studio/manage_assistants.md
- cloud/how-tos/threads_studio.md
- cloud/how-tos/iterate_graph_studio.md
- cloud/how-tos/studio/run_evals.md
- cloud/how-tos/clone_traces_studio.md
- cloud/how-tos/datasets_studio.md
- Server customization:
- how-tos/http/custom_lifespan.md
- how-tos/http/custom_middleware.md
- how-tos/http/custom_routes.md
- Authentication & access control:
- how-tos/auth/custom_auth.md
- how-tos/auth/openapi_security.md
- Data management:
- Add semantic search: cloud/deployment/semantic_search.md
- Add TTLs: how-tos/ttl/configure_ttl.md
- Deployment:
- Overview: concepts/deployment_options.md
- Quickstart: cloud/quick_start.md
- Set up your application:
- Use requirements.txt: cloud/deployment/setup.md
- Use pyproject.toml: cloud/deployment/setup_pyproject.md
- Use JavaScript: cloud/deployment/setup_javascript.md
- Use custom Docker: cloud/deployment/custom_docker.md
- Rebuild graph at runtime: cloud/deployment/graph_rebuild.md
- Deployment options:
- Cloud SaaS: concepts/langgraph_cloud.md
- Self-Hosted Data Plane: concepts/langgraph_self_hosted_data_plane.md
- Self-Hosted Control Plane: concepts/langgraph_self_hosted_control_plane.md
- Standalone Container: concepts/langgraph_standalone_container.md
- Deploy to production:
- Cloud SaaS: cloud/deployment/cloud.md
- Self-Hosted Data Plane: cloud/deployment/self_hosted_data_plane.md
- Self-Hosted Control Plane: cloud/deployment/self_hosted_control_plane.md
- Standalone Container: cloud/deployment/standalone_container.md
- Add semantic search: cloud/deployment/semantic_search.md
- Add TTLs: how-tos/ttl/configure_ttl.md
- Assistants:
- cloud/how-tos/configuration_cloud.md
- Threads: cloud/how-tos/use_threads.md
- Runs:
- cloud/how-tos/background_run.md
- cloud/how-tos/same-thread.md
- cloud/how-tos/cron_jobs.md
- cloud/how-tos/stateless_runs.md
- cloud/how-tos/configurable_headers.md
- Double-texting:
- cloud/how-tos/interrupt_concurrent.md
- cloud/how-tos/rollback_concurrent.md
- cloud/how-tos/reject_concurrent.md
- cloud/how-tos/enqueue_concurrent.md
- Streaming: cloud/how-tos/streaming.md
- Human in the loop: cloud/how-tos/add-human-in-the-loop.md
- Time-travel: cloud/how-tos/human_in_the_loop_time_travel.md
- Breakpoints: cloud/how-tos/human_in_the_loop_breakpoint.md
- Webhooks: cloud/how-tos/webhooks.md
- Cron jobs: cloud/how-tos/cron_jobs.md
- MCP: concepts/server-mcp.md
- Reference:
- reference/index.md
@@ -265,6 +253,7 @@ nav:
- Environment variables: cloud/reference/env_var.md
- Examples:
- agents/run_agents.md
- Template applications: concepts/template_applications.md # TODO: make tutorial
- Agentic RAG: tutorials/rag/langgraph_agentic_rag.ipynb
- Agent Supervisor: tutorials/multi_agent/agent_supervisor.ipynb
Generated
+3 -3
View File
@@ -2590,7 +2590,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "0.5.0"
version = "0.5.0rc1"
source = { editable = "../libs/langgraph" }
dependencies = [
{ name = "langchain-core" },
@@ -2894,7 +2894,7 @@ test = [
[[package]]
name = "langgraph-prebuilt"
version = "0.5.1"
version = "0.5.0rc0"
source = { editable = "../libs/prebuilt" }
dependencies = [
{ name = "langchain-core" },
@@ -2925,7 +2925,7 @@ dev = [
[[package]]
name = "langgraph-sdk"
version = "0.1.72"
version = "0.1.70"
source = { editable = "../libs/sdk-py" }
dependencies = [
{ name = "httpx" },
@@ -223,9 +223,10 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
Yields:
An SQLite cursor object.
"""
if not self.is_setup:
await self.setup()
async with self.lock:
if not self.is_setup:
await self.setup()
if transaction:
await self.conn.execute("BEGIN")
@@ -981,9 +981,10 @@ class SqliteStore(BaseSqliteStore, BaseStore):
Args:
transaction (bool): whether to use transaction for the DB operations
"""
if not self.is_setup:
self.setup()
with self.lock:
if not self.is_setup:
self.setup()
if transaction:
self.conn.execute("BEGIN")
@@ -1001,10 +1002,10 @@ class SqliteStore(BaseSqliteStore, BaseStore):
This method creates the necessary tables in the SQLite database if they don't
already exist and runs database migrations. It should be called before first use.
"""
if self.is_setup:
return
with self.lock:
if self.is_setup:
return
# Create migrations table if it doesn't exist
self.conn.executescript(
"""
File diff suppressed because one or more lines are too long
+8 -8
View File
@@ -1183,7 +1183,7 @@ wheels = [
[[package]]
name = "langchain-core"
version = "0.3.67"
version = "0.3.63"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonpatch" },
@@ -1194,9 +1194,9 @@ dependencies = [
{ name = "tenacity" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c2/40/875af0194024d0006874f061958fa417d3500bbfdc9a57e1bd1c2f4e6ed2/langchain_core-0.3.67.tar.gz", hash = "sha256:2c14aa44a0e78e014e96d7f2f8916ac109d0a0ba87ed67ee25bf7296bed7e7ba", size = 561952, upload-time = "2025-06-30T17:09:35.142Z" }
sdist = { url = "https://files.pythonhosted.org/packages/b9/0a/b71a9a5d42e743d6876cce23d803e284b191ed4d6544e2f7fe1b37f7854c/langchain_core-0.3.63.tar.gz", hash = "sha256:e2e30cfbb7684a5a0319f6cbf065fc3c438bfd1060302f085a122527890fb01e", size = 558302, upload-time = "2025-05-29T18:57:19.933Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/2b/a0d283089c6d08c12d47dca39a55029ff714e939ec04f4560420426ab613/langchain_core-0.3.67-py3-none-any.whl", hash = "sha256:b699f1f24b24fa2747c05e2daa280aa64478a51e01a4e82c7f8e20b6167dfa99", size = 440237, upload-time = "2025-06-30T17:09:33.323Z" },
{ url = "https://files.pythonhosted.org/packages/5c/71/a748861e6a69ab6ef50ab8e65120422a1f36245c71a0dd0f02de49c208e1/langchain_core-0.3.63-py3-none-any.whl", hash = "sha256:f91db8221b1bc6808f70b2e72fded1a94d50ee3f1dff1636fb5a5a514c64b7f5", size = 438468, upload-time = "2025-05-29T18:57:17.424Z" },
]
[[package]]
@@ -1423,7 +1423,7 @@ inmem = [
[[package]]
name = "langgraph-prebuilt"
version = "0.5.2"
version = "0.5.1"
source = { editable = "../prebuilt" }
dependencies = [
{ name = "langchain-core" },
@@ -1432,7 +1432,7 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "langchain-core", specifier = ">=0.3.67" },
{ name = "langchain-core", specifier = ">=0.3.22" },
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
]
@@ -1497,7 +1497,7 @@ dev = [
[[package]]
name = "langsmith"
version = "0.4.4"
version = "0.3.43"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -1508,9 +1508,9 @@ dependencies = [
{ name = "requests-toolbelt" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/c8/8d2e0fc438d2d3d8d4300f7684ea30a754344ed00d7ba9cc2705241d2a5f/langsmith-0.4.4.tar.gz", hash = "sha256:70c53bbff24a7872e88e6fa0af98270f4986a6e364f9e85db1cc5636defa4d66", size = 352105, upload-time = "2025-06-27T19:20:36.207Z" }
sdist = { url = "https://files.pythonhosted.org/packages/02/21/df84fe8b5c16971999650cbfc95a49f176d044a606e2b4eb957bbc122e1c/langsmith-0.3.43.tar.gz", hash = "sha256:7dab99b635859e24a1a252ad4f7e23170a45f4ea742567a10b4b26c50478ed43", size = 346328, upload-time = "2025-05-29T00:21:11.637Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/33/a3337eb70d795495a299a1640d7a75f17fb917155a64309b96106e7b9452/langsmith-0.4.4-py3-none-any.whl", hash = "sha256:014c68329bd085bd6c770a6405c61bb6881f82eb554ce8c4d1984b0035fd1716", size = 367687, upload-time = "2025-06-27T19:20:33.839Z" },
{ url = "https://files.pythonhosted.org/packages/e2/72/f5304de3e7e80e6dc266c161230aecb7895958f78b5af1541317d7615fc6/langsmith-0.3.43-py3-none-any.whl", hash = "sha256:2d4558068abf2eeb60ff80871187724e07f5e657d7d6be9e0c603df36c41140a", size = 361148, upload-time = "2025-05-29T00:21:08.759Z" },
]
[[package]]
@@ -30,10 +30,7 @@ from langchain_core.runnables.config import (
)
from langchain_core.tools import BaseTool, InjectedToolArg
from langchain_core.tools import tool as create_tool
from langchain_core.tools.base import (
TOOL_MESSAGE_BLOCK_TYPES,
get_all_basemodel_annotations,
)
from langchain_core.tools.base import get_all_basemodel_annotations
from pydantic import BaseModel
from typing_extensions import Annotated, get_args, get_origin
@@ -49,11 +46,12 @@ TOOL_CALL_ERROR_TEMPLATE = "Error: {error}\n Please fix your mistakes."
def msg_content_output(output: Any) -> Union[str, list[dict]]:
recognized_content_block_types = ("image", "image_url", "text", "json")
if isinstance(output, str):
return output
elif isinstance(output, list) and all(
[
isinstance(x, dict) and x.get("type") in TOOL_MESSAGE_BLOCK_TYPES
isinstance(x, dict) and x.get("type") in recognized_content_block_types
for x in output
]
):
+2 -2
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph-prebuilt"
version = "0.5.2"
version = "0.5.1"
description = "Library with high-level APIs for creating and executing LangGraph agents and tools."
authors = []
requires-python = ">=3.9"
@@ -13,7 +13,7 @@ license = "MIT"
license-files = ['LICENSE']
dependencies = [
"langgraph-checkpoint>=2.1.0",
"langchain-core>=0.3.67",
"langchain-core>=0.3.22",
]
[project.urls]
+8 -8
View File
@@ -302,7 +302,7 @@ wheels = [
[[package]]
name = "langchain-core"
version = "0.3.67"
version = "0.3.60"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jsonpatch" },
@@ -313,9 +313,9 @@ dependencies = [
{ name = "tenacity" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c2/40/875af0194024d0006874f061958fa417d3500bbfdc9a57e1bd1c2f4e6ed2/langchain_core-0.3.67.tar.gz", hash = "sha256:2c14aa44a0e78e014e96d7f2f8916ac109d0a0ba87ed67ee25bf7296bed7e7ba", size = 561952, upload-time = "2025-06-30T17:09:35.142Z" }
sdist = { url = "https://files.pythonhosted.org/packages/5b/75/95129aaada92980a002a31e002610a80af3c8967ae7884710372e89cdde0/langchain_core-0.3.60.tar.gz", hash = "sha256:63dd1bdf7939816115399522661ca85a2f3686a61440f2f46ebd86d1b028595b", size = 557456, upload-time = "2025-05-15T15:23:23.642Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/2b/a0d283089c6d08c12d47dca39a55029ff714e939ec04f4560420426ab613/langchain_core-0.3.67-py3-none-any.whl", hash = "sha256:b699f1f24b24fa2747c05e2daa280aa64478a51e01a4e82c7f8e20b6167dfa99", size = 440237, upload-time = "2025-06-30T17:09:33.323Z" },
{ url = "https://files.pythonhosted.org/packages/2d/bc/344f5b11fdfe0e27f7064d2e829921a791461dc32e5ed285fe6325518c26/langchain_core-0.3.60-py3-none-any.whl", hash = "sha256:2ccdf06b12e699b1b0962bc02837056c075b4981c3d13f82a4d4c30bb22ea3dc", size = 437890, upload-time = "2025-05-15T15:23:22.278Z" },
]
[[package]]
@@ -464,7 +464,7 @@ dev = [
[[package]]
name = "langgraph-prebuilt"
version = "0.5.2"
version = "0.5.1"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },
@@ -489,7 +489,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "langchain-core", specifier = ">=0.3.67" },
{ name = "langchain-core", specifier = ">=0.3.22" },
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
]
@@ -537,7 +537,7 @@ dev = [
[[package]]
name = "langsmith"
version = "0.4.4"
version = "0.3.42"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -548,9 +548,9 @@ dependencies = [
{ name = "requests-toolbelt" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/20/c8/8d2e0fc438d2d3d8d4300f7684ea30a754344ed00d7ba9cc2705241d2a5f/langsmith-0.4.4.tar.gz", hash = "sha256:70c53bbff24a7872e88e6fa0af98270f4986a6e364f9e85db1cc5636defa4d66", size = 352105, upload-time = "2025-06-27T19:20:36.207Z" }
sdist = { url = "https://files.pythonhosted.org/packages/3a/44/fe171c0b0fb0377b191aebf0b7779e0c7b2a53693c6a01ddad737212495d/langsmith-0.3.42.tar.gz", hash = "sha256:2b5cbc450ab808b992362aac6943bb1d285579aa68a3a8be901d30a393458f25", size = 345619, upload-time = "2025-05-03T03:07:17.873Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/33/a3337eb70d795495a299a1640d7a75f17fb917155a64309b96106e7b9452/langsmith-0.4.4-py3-none-any.whl", hash = "sha256:014c68329bd085bd6c770a6405c61bb6881f82eb554ce8c4d1984b0035fd1716", size = 367687, upload-time = "2025-06-27T19:20:33.839Z" },
{ url = "https://files.pythonhosted.org/packages/89/8e/e8a58e0abaae3f3ac4702e9ca35d1fc6159711556b64ffd0e247771a3f12/langsmith-0.3.42-py3-none-any.whl", hash = "sha256:18114327f3364385dae4026ebfd57d1c1cb46d8f80931098f0f10abe533475ff", size = 360334, upload-time = "2025-05-03T03:07:15.491Z" },
]
[[package]]
+2 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@langchain/langgraph-sdk",
"version": "0.0.87",
"version": "0.0.86",
"description": "Client library for interacting with the LangGraph API",
"type": "module",
"packageManager": "yarn@1.22.19",
@@ -22,9 +22,7 @@
"uuid": "^9.0.0"
},
"devDependencies": {
"@langchain/langgraph-api": "~0.0.41",
"@langchain/core": "^0.3.61",
"@langchain/langgraph": "^0.3.5",
"@langchain/core": "^0.3.31",
"@langchain/scripts": "^0.1.4",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
@@ -37,7 +35,6 @@
"@types/uuid": "^9.0.1",
"@vitejs/plugin-react": "^4.4.1",
"concat-md": "^0.5.1",
"hono": "^4.8.2",
"jsdom": "^26.1.0",
"msw": "^2.8.2",
"prettier": "^3.2.5",
-30
View File
@@ -1658,30 +1658,7 @@ export class Client<
*/
public "~ui": UiClient;
/**
* @internal Used to obtain a stable key representing the client.
*/
private "~configHash": string | undefined;
constructor(config?: ClientConfig) {
this["~configHash"] = (() =>
JSON.stringify({
apiUrl: config?.apiUrl,
apiKey: config?.apiKey,
timeoutMs: config?.timeoutMs,
defaultHeaders: config?.defaultHeaders,
maxConcurrency: config?.callerOptions?.maxConcurrency,
maxRetries: config?.callerOptions?.maxRetries,
callbacks: {
onFailedResponseHook:
config?.callerOptions?.onFailedResponseHook != null,
onRequest: config?.onRequest != null,
fetch: config?.callerOptions?.fetch != null,
},
}))();
this.assistants = new AssistantsClient(config);
this.threads = new ThreadsClient(config);
this.runs = new RunsClient(config);
@@ -1690,10 +1667,3 @@ export class Client<
this["~ui"] = new UiClient(config);
}
}
/**
* @internal Used to obtain a stable key representing the client.
*/
export function getClientConfigHash(client: Client): string | undefined {
return client["~configHash"];
}
+4 -18
View File
@@ -1,7 +1,7 @@
/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */
"use client";
import { Client, getClientConfigHash, type ClientConfig } from "../client.js";
import { Client, type ClientConfig } from "../client.js";
import type {
Command,
DisconnectMode,
@@ -321,16 +321,11 @@ function useThreadHistory<StateType extends Record<string, unknown>>(
) {
const [history, setHistory] = useState<ThreadState<StateType>[]>([]);
const clientHash = getClientConfigHash(client);
const clientRef = useRef(client);
clientRef.current = client;
const fetcher = useCallback(
(
threadId: string | undefined | null,
): Promise<ThreadState<StateType>[]> => {
if (threadId != null) {
const client = clientRef.current;
return fetchHistory<StateType>(client, threadId).then((history) => {
setHistory(history);
return history;
@@ -347,7 +342,7 @@ function useThreadHistory<StateType extends Record<string, unknown>>(
useEffect(() => {
if (submittingRef.current) return;
fetcher(threadId);
}, [fetcher, clientHash, submittingRef, threadId]);
}, [fetcher, submittingRef, threadId]);
return {
data: history,
@@ -621,11 +616,7 @@ export interface UseStream<
/**
* Join an active stream.
*/
joinStream: (
runId: string,
lastEventId?: string,
options?: { streamMode?: StreamMode | StreamMode[] },
) => Promise<void>;
joinStream: (runId: string) => Promise<void>;
}
type ConfigWithConfigurable<ConfigurableType extends Record<string, unknown>> =
@@ -966,18 +957,13 @@ export function useStream<
}
}
const joinStream = async (
runId: string,
lastEventId?: string,
options?: { streamMode?: StreamMode | StreamMode[] },
) => {
const joinStream = async (runId: string, lastEventId?: string) => {
lastEventId ??= "-1";
if (!threadId) return;
await consumeStream(async (signal: AbortSignal) => {
const stream = client.runs.joinStream(threadId, runId, {
signal,
lastEventId,
streamMode: options?.streamMode,
}) as AsyncGenerator<EventStreamEvent>;
return {
+354 -52
View File
@@ -1,61 +1,14 @@
import "@testing-library/jest-dom/vitest";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { setupServer } from "msw/node";
import { http } from "msw";
import { http, HttpResponse } from "msw";
import { useStream } from "../react/stream.js";
import { StateGraph, MessagesAnnotation, START } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph-checkpoint";
import { FakeStreamingChatModel } from "@langchain/core/utils/testing";
import { AIMessage, BaseMessageLike } from "@langchain/core/messages";
import { Hono } from "hono";
import { logger } from "hono/logger";
import { createEmbedServer } from "@langchain/langgraph-api/experimental/embed";
const threads = (() => {
const THREADS: Record<
string,
{ thread_id: string; metadata: Record<string, unknown> }
> = {};
return {
get: async (id: string) => THREADS[id],
put: async (
threadId: string,
{ metadata }: { metadata?: Record<string, unknown> },
) => {
THREADS[threadId] = { thread_id: threadId, metadata: metadata ?? {} };
},
delete: async (threadId: string) => {
delete THREADS[threadId];
},
};
})();
const checkpointer = new MemorySaver();
const model = new FakeStreamingChatModel({ responses: [new AIMessage("Hey")] });
const agent = new StateGraph(MessagesAnnotation)
.addNode("agent", async (state: { messages: BaseMessageLike[] }) => {
const response = await model.invoke(state.messages);
return { messages: [response] };
})
.addEdge(START, "agent")
.compile();
const app = new Hono();
app.use(logger());
app.route("/", createEmbedServer({ graph: { agent }, checkpointer, threads }));
const server = setupServer(http.all("*", (ctx) => app.fetch(ctx.request)));
import "@testing-library/jest-dom/vitest";
function TestChatComponent() {
const { messages, isLoading, error, submit, stop } = useStream({
assistantId: "agent",
assistantId: "test-assistant",
apiKey: "test-api-key",
});
@@ -89,6 +42,353 @@ function TestChatComponent() {
);
}
// Mock server setup
const server = setupServer(
// Mock thread creation
http.post("*/threads", () => {
return HttpResponse.json({ thread_id: "test-thread-id" });
}),
// Mock stream endpoint
http.post("*/threads/:threadId/runs/stream", async () => {
const encoder = new TextEncoder();
const sendSSE = (event: string, data: unknown) =>
encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
const stream = new ReadableStream({
async start(controller) {
await new Promise((resolve) => setTimeout(resolve, 10));
controller.enqueue(
sendSSE("metadata", {
run_id: "1f03278a-1734-6518-80a4-3390db59f960",
attempt: 1,
}),
);
controller.enqueue(
sendSSE("values", {
messages: [
{
content: "Hey",
additional_kwargs: {},
response_metadata: {},
type: "human",
name: null,
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
example: false,
},
],
}),
);
controller.enqueue(
sendSSE("messages", [
{
content: "",
additional_kwargs: {},
response_metadata: { model_name: "claude-3-7-sonnet-latest" },
type: "AIMessageChunk",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
tool_calls: [],
invalid_tool_calls: [],
tool_call_chunks: [],
},
{ run_attempt: 1 },
]),
);
controller.enqueue(
sendSSE("messages", [
{
content: "Hello",
additional_kwargs: {},
response_metadata: { model_name: "claude-3-7-sonnet-latest" },
type: "AIMessageChunk",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
tool_calls: [],
invalid_tool_calls: [],
tool_call_chunks: [],
},
{ run_attempt: 1 },
]),
);
controller.enqueue(
sendSSE("messages", [
{
content: "! How can I assist you today?",
additional_kwargs: {},
response_metadata: { model_name: "claude-3-7-sonnet-latest" },
type: "AIMessageChunk",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
tool_calls: [],
invalid_tool_calls: [],
tool_call_chunks: [],
},
{ run_attempt: 1 },
]),
);
controller.enqueue(
sendSSE("messages", [
{
content: "",
additional_kwargs: {},
response_metadata: {
stop_reason: "end_turn",
stop_sequence: null,
},
type: "AIMessageChunk",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
tool_calls: [],
invalid_tool_calls: [],
tool_call_chunks: [],
},
{ run_attempt: 1 },
]),
);
controller.enqueue(
sendSSE("values", {
messages: [
{
content: "Hey",
additional_kwargs: {},
response_metadata: {},
type: "human",
name: null,
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
example: false,
},
{
content: "Hello! How can I assist you today?",
additional_kwargs: {},
response_metadata: {
model_name: "claude-3-7-sonnet-latest",
stop_reason: "end_turn",
stop_sequence: null,
},
type: "ai",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
tool_calls: [],
invalid_tool_calls: [],
},
],
}),
);
controller.close();
},
});
server.use(
http.post("*/threads/:threadId/history", () => {
return HttpResponse.json([
{
values: {
messages: [
{
content: "Hey",
additional_kwargs: {},
response_metadata: {},
type: "human",
name: null,
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
example: false,
},
{
content: "Hello! How can I assist you today?",
additional_kwargs: {},
response_metadata: {
model_name: "claude-3-7-sonnet-latest",
stop_reason: "end_turn",
stop_sequence: null,
},
type: "ai",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
example: false,
tool_calls: [],
invalid_tool_calls: [],
},
],
},
next: [],
tasks: [],
metadata: {
run_attempt: 1,
source: "loop",
writes: {
agent: {
messages: [
{
content: "Hello! How can I assist you today?",
additional_kwargs: {},
response_metadata: {
model_name: "claude-3-7-sonnet-latest",
stop_reason: "end_turn",
stop_sequence: null,
},
type: "ai",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
example: false,
tool_calls: [],
invalid_tool_calls: [],
},
],
},
},
step: 1,
parents: {},
},
created_at: "2025-05-16T17:10:16.987537+00:00",
checkpoint: {
checkpoint_id: "1f03278a-38cf-6c68-8001-22b77ac43ff6",
thread_id: "b06fd92a-955c-446e-b233-7977716c4a9c",
checkpoint_ns: "",
},
parent_checkpoint: {
checkpoint_id: "1f03278a-206b-67c6-8000-ac34a0872e1a",
thread_id: "b06fd92a-955c-446e-b233-7977716c4a9c",
checkpoint_ns: "",
},
checkpoint_id: "1f03278a-38cf-6c68-8001-22b77ac43ff6",
parent_checkpoint_id: "1f03278a-206b-67c6-8000-ac34a0872e1a",
},
{
values: {
messages: [
{
content: "Hey",
additional_kwargs: {},
response_metadata: {},
type: "human",
name: null,
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
example: false,
},
],
},
next: ["agent"],
tasks: [
{
id: "e1b7b52b-a78e-4b32-0c89-e06bf46405ed",
name: "agent",
path: ["__pregel_pull", "agent"],
error: null,
interrupts: [],
checkpoint: null,
state: null,
result: {
messages: [
{
content: "Hello! How can I assist you today?",
additional_kwargs: {},
response_metadata: {
model_name: "claude-3-7-sonnet-latest",
stop_reason: "end_turn",
stop_sequence: null,
},
type: "ai",
name: null,
id: "run-3e90ba6a-71d6-49e7-94a8-6bcac2fd0f40",
example: false,
tool_calls: [],
invalid_tool_calls: [],
},
],
},
},
],
metadata: {
run_attempt: 1,
},
created_at: "2025-05-16T17:10:14.429889+00:00",
checkpoint: {
checkpoint_id: "1f03278a-206b-67c6-8000-ac34a0872e1a",
thread_id: "b06fd92a-955c-446e-b233-7977716c4a9c",
checkpoint_ns: "",
},
parent_checkpoint: {
checkpoint_id: "1f03278a-2067-6590-bfff-3fb740466fc3",
thread_id: "b06fd92a-955c-446e-b233-7977716c4a9c",
checkpoint_ns: "",
},
checkpoint_id: "1f03278a-206b-67c6-8000-ac34a0872e1a",
parent_checkpoint_id: "1f03278a-2067-6590-bfff-3fb740466fc3",
},
{
values: {
messages: [],
},
next: ["__start__"],
tasks: [
{
id: "291af033-2ddc-3320-8bbc-28060057cae5",
name: "__start__",
path: ["__pregel_pull", "__start__"],
error: null,
interrupts: [],
checkpoint: null,
state: null,
result: {
messages: [
{
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
type: "human",
content: "Hey",
},
],
},
},
],
metadata: {
run_attempt: 1,
source: "input",
writes: {
__start__: {
messages: [
{
id: "2d8c0d9f-a614-4e44-b474-6a56e9471cf5",
type: "human",
content: "Hey",
},
],
},
},
step: -1,
parents: {},
},
created_at: "2025-05-16T17:10:14.428191+00:00",
checkpoint: {
checkpoint_id: "1f03278a-2067-6590-bfff-3fb740466fc3",
thread_id: "b06fd92a-955c-446e-b233-7977716c4a9c",
checkpoint_ns: "",
},
parent_checkpoint: null,
checkpoint_id: "1f03278a-2067-6590-bfff-3fb740466fc3",
parent_checkpoint_id: null,
},
]);
}),
);
return new HttpResponse(stream, {
headers: { "Content-Type": "text/event-stream" },
});
}),
);
server.use;
describe("useStream", () => {
beforeEach(() => server.listen());
@@ -117,8 +417,10 @@ describe("useStream", () => {
// Wait for messages to appear
await waitFor(() => {
expect(screen.getByTestId("message-0")).toHaveTextContent("Hello");
expect(screen.getByTestId("message-1")).toHaveTextContent("Hey");
expect(screen.getByTestId("message-0")).toHaveTextContent("Hey");
expect(screen.getByTestId("message-1")).toHaveTextContent(
"Hello! How can I assist you today?",
);
});
// Check final state
+22 -1046
View File
File diff suppressed because it is too large Load Diff