Compare commits

..
Author SHA1 Message Date
open-swe-dev[bot] 72bfad91cf Apply patch 2025-07-15 23:46:30 +00:00
open-swe-dev[bot] 7fcb4330ec Apply patch 2025-07-15 23:39:24 +00:00
open-swe-dev[bot] 2126380cf1 Apply patch 2025-07-15 23:37:47 +00:00
open-swe-dev[bot] 290313b7bd Apply patch 2025-07-15 23:36:03 +00:00
open-swe-dev[bot] 5107729c0a Apply patch 2025-07-15 23:34:31 +00:00
24 changed files with 63 additions and 234 deletions
+1 -1
View File
@@ -58,7 +58,7 @@ The `langchain-mcp-adapters` package enables agents to use tools defined across
```python title="Workflow using MCP tools with ToolNode"
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.graph import StateGraph, MessagesState, START
from langgraph.prebuilt import ToolNode
# Initialize the model
-3
View File
@@ -28,9 +28,6 @@ Specify `DD_API_KEY` (your [Datadog API Key](https://docs.datadoghq.com/account_
If `DD_API_KEY` is specified, the application process is wrapped in the [`ddtrace-run` command](https://ddtrace.readthedocs.io/en/stable/installation_quickstart.html). Other `DD_*` environment variables (e.g. `DD_SITE`, `DD_ENV`, `DD_SERVICE`, `DD_TRACE_ENABLED`) are typically needed to properly configure the tracing instrumentation. See [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) for more details.
!!! note
Enabling `DD_API_KEY` (and thus `ddtrace-run`) can override or interfere with other auto-instrumentation solutions (such as OpenTelemetry) that you may have instrumented into your application code.
## `LANGCHAIN_TRACING_SAMPLING_RATE`
Sampling rate for traces sent to LangSmith. Valid values: Any float between `0` and `1`.
@@ -4,23 +4,6 @@
---
## v0.2.94 (2025-07-16)
- Improved performance by omitting pending sends for langgraph versions 0.5 and above.
- Improved server startup logs to provide clearer warnings when the DD_API_KEY environment variable is set.
## v0.2.93 (2025-07-16)
- Removed the GIN index for run metadata to improve performance.
## v0.2.92 (2025-07-16)
- Enabled copying functionality for blobs and checkpoints, improving data management flexibility.
## v0.2.91 (2025-07-16)
- Reduced writes to the `checkpoint_blobs` table by inlining small values (null, numeric, str, etc.). This means we don't need to store extra values for channels that haven't been updated.
## v0.2.90 (2025-07-16)
- Improve checkpoint writes via node-local background queueing.
## v0.2.89 (2025-07-15)
- Decoupled checkpoint writing from thread/run state by removing foreign keys and updated logger to prevent timeout-related failures.
+1 -1
View File
@@ -45,7 +45,7 @@ The first thing you do when you define a graph is define the `State` of the grap
### Schema
The main documented way to specify the schema of a graph is by using a [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict). If you want to provide default values in your state, use a [`dataclass`](https://docs.python.org/3/library/dataclasses.html). We also support using a Pydantic [BaseModel](../how-tos/graph-api.md#use-pydantic-models-for-graph-state) as your graph state if you want recursive data validation (though note that pydantic is less performant than a `TypedDict` or `dataclass`).
The main documented way to specify the schema of a graph is by using `TypedDict`. However, we also support [using a Pydantic BaseModel](../how-tos/graph-api.md#use-pydantic-models-for-graph-state) as your graph state to add **default values** and additional data validation.
By default, the graph will have the same input and output schemas. If you want to change this, you can also specify explicit input and output schemas directly. This is useful when you have a lot of keys, and some are explicitly for input and others for output. See the [guide here](../how-tos/graph-api.md#define-input-and-output-schemas) for how to use.
-17
View File
@@ -1,17 +0,0 @@
# Tracing
Traces are a series of steps that your application takes to go from input to output. Each of these individual steps is represented by a run. You can use [LangSmith](https://smith.langchain.com/) to visualize these execution steps. To use it, [enable tracing for your application](../how-tos/enable-tracing.md). This enables you to do the following:
- [Debug a locally running application](../cloud/how-tos/clone_traces_studio.md).
- [Evaluate the application performance](../agents/evals.md).
- [Monitor the application](https://docs.smith.langchain.com/observability/how_to_guides/dashboards).
To get started, sign up for a free account at [LangSmith](https://smith.langchain.com/).
## Learn more
- [Graph runs in LangSmith](../how-tos/run-id-langsmith.md)
- [LangSmith Observability quickstart](https://docs.smith.langchain.com/observability)
- [Trace with LangGraph](https://docs.smith.langchain.com/observability/how_to_guides/trace_with_langgraph)
- [Tracing conceptual guide](https://docs.smith.langchain.com/observability/concepts#traces)
-16
View File
@@ -1,16 +0,0 @@
# Enable tracing for your application
To enable [tracing](../concepts/tracing.md) for your application, set the following environment variables:
```python
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=<your-api-key>
```
For more information, see [Trace with LangGraph](https://docs.smith.langchain.com/observability/how_to_guides/trace_with_langgraph).
## Learn more
- [Graph runs in LangSmith](../how-tos/run-id-langsmith.md)
- [LangSmith Observability quickstart](https://docs.smith.langchain.com/observability)
- [Tracing conceptual guide](https://docs.smith.langchain.com/observability/concepts#traces)
+2 -3
View File
@@ -328,15 +328,14 @@ Output of graph invocation: {'a': 'set by node_3'}
A [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs.md#langgraph.graph.StateGraph) accepts a `state_schema` argument on initialization that specifies the "shape" of the state that the nodes in the graph can access and update.
In our examples, we typically use a python-native `TypedDict` or [`dataclass`](https://docs.python.org/3/library/dataclasses.html) for `state_schema`, but `state_schema` can be any [type](https://docs.python.org/3/library/stdtypes.html#type-objects).
In our examples, we typically use a python-native `TypedDict` for `state_schema`, but `state_schema` can be any [type](https://docs.python.org/3/library/stdtypes.html#type-objects).
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**.
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.
```python
from langgraph.graph import StateGraph, START, END
+2 -4
View File
@@ -157,10 +157,8 @@ nav:
- Overview: concepts/mcp.md
- Use MCP: agents/mcp.md
- Server API: concepts/server-mcp.md
- Tracing:
- Overview: concepts/tracing.md
- Enable tracing: how-tos/enable-tracing.md
- Evaluate performance: agents/evals.md
- Evaluation:
- Basic implementation: agents/evals.md
- Platform-only capabilities:
- LangGraph Platform:
- Overview: concepts/langgraph_platform.md
@@ -289,7 +289,6 @@ class PostgresSaver(BasePostgresSaver):
)
copy = checkpoint.copy()
copy["channel_values"] = copy["channel_values"].copy()
next_config = {
"configurable": {
"thread_id": thread_id,
@@ -298,28 +297,16 @@ class PostgresSaver(BasePostgresSaver):
}
}
# inline primitive values in checkpoint table
# others are stored in blobs table
blob_values = {}
for k, v in checkpoint["channel_values"].items():
if v is None or isinstance(v, (str, int, float, bool)):
pass
else:
blob_values[k] = copy["channel_values"].pop(k)
with self._cursor(pipeline=True) as cur:
if blob_versions := {
k: v for k, v in new_versions.items() if k in blob_values
}:
cur.executemany(
self.UPSERT_CHECKPOINT_BLOBS_SQL,
self._dump_blobs(
thread_id,
checkpoint_ns,
blob_values,
blob_versions,
),
)
cur.executemany(
self.UPSERT_CHECKPOINT_BLOBS_SQL,
self._dump_blobs(
thread_id,
checkpoint_ns,
copy.pop("channel_values"), # type: ignore[misc]
new_versions,
),
)
cur.execute(
self.UPSERT_CHECKPOINTS_SQL,
(
@@ -327,7 +314,7 @@ class PostgresSaver(BasePostgresSaver):
checkpoint_ns,
checkpoint["id"],
checkpoint_id,
Jsonb(copy),
Jsonb(self.serde.dumps_typed(copy)[1]),
Jsonb(get_checkpoint_metadata(config, metadata)),
),
)
@@ -452,10 +439,7 @@ class PostgresSaver(BasePostgresSaver):
},
{
**value["checkpoint"],
"channel_values": {
**value["checkpoint"].get("channel_values"),
**self._load_blobs(value["channel_values"]),
},
"channel_values": self._load_blobs(value["channel_values"]),
},
value["metadata"],
(
@@ -245,7 +245,6 @@ class AsyncPostgresSaver(BasePostgresSaver):
)
copy = checkpoint.copy()
copy["channel_values"] = copy["channel_values"].copy()
next_config = {
"configurable": {
"thread_id": thread_id,
@@ -254,29 +253,17 @@ class AsyncPostgresSaver(BasePostgresSaver):
}
}
# inline primitive values in checkpoint table
# others are stored in blobs table
blob_values = {}
for k, v in checkpoint["channel_values"].items():
if v is None or isinstance(v, (str, int, float, bool)):
pass
else:
blob_values[k] = copy["channel_values"].pop(k)
async with self._cursor(pipeline=True) as cur:
if blob_versions := {
k: v for k, v in new_versions.items() if k in blob_values
}:
await cur.executemany(
self.UPSERT_CHECKPOINT_BLOBS_SQL,
await asyncio.to_thread(
self._dump_blobs,
thread_id,
checkpoint_ns,
blob_values,
blob_versions,
),
)
await cur.executemany(
self.UPSERT_CHECKPOINT_BLOBS_SQL,
await asyncio.to_thread(
self._dump_blobs,
thread_id,
checkpoint_ns,
copy.pop("channel_values"), # type: ignore[misc]
new_versions,
),
)
await cur.execute(
self.UPSERT_CHECKPOINTS_SQL,
(
@@ -284,7 +271,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
checkpoint_ns,
checkpoint["id"],
checkpoint_id,
Jsonb(copy),
Jsonb(self.serde.dumps_typed(copy)[1]),
Jsonb(get_checkpoint_metadata(config, metadata)),
),
)
@@ -410,10 +397,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
},
{
**value["checkpoint"],
"channel_values": {
**value["checkpoint"].get("channel_values"),
**self._load_blobs(value["channel_values"]),
},
"channel_values": self._load_blobs(value["channel_values"]),
},
value["metadata"],
(
@@ -440,7 +440,7 @@ class ShallowPostgresSaver(BasePostgresSaver):
(
thread_id,
checkpoint_ns,
Jsonb(copy),
Jsonb(self.serde.dumps_typed(copy)[1]),
Jsonb(get_checkpoint_metadata(config, metadata)),
),
)
@@ -773,7 +773,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
(
thread_id,
checkpoint_ns,
Jsonb(copy),
Jsonb(self.serde.dumps_typed(copy)[1]),
Jsonb(get_checkpoint_metadata(config, metadata)),
),
)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph-checkpoint-postgres"
version = "2.0.23"
version = "2.0.22"
description = "Library with a Postgres implementation of LangGraph checkpoint saver."
authors = []
requires-python = ">=3.9"
+2 -2
View File
@@ -304,7 +304,7 @@ wheels = [
[[package]]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
source = { editable = "../checkpoint" }
dependencies = [
{ name = "langchain-core" },
@@ -334,7 +334,7 @@ dev = [
[[package]]
name = "langgraph-checkpoint-postgres"
version = "2.0.23"
version = "2.0.22"
source = { editable = "." }
dependencies = [
{ name = "langgraph-checkpoint" },
@@ -29,7 +29,7 @@ _AIO_ERROR_MSG = (
"from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver\n"
"Note: AsyncSqliteSaver requires the aiosqlite package to use.\n"
"Install with:\n`pip install aiosqlite`\n"
"See https://langchain-ai.github.io/langgraph/reference/checkpoints/#langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver"
"See https://langchain-ai.github.io/langgraph/reference/checkpoints/asyncsqlitesaver"
"for more information."
)
+1 -1
View File
@@ -316,7 +316,7 @@ wheels = [
[[package]]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
source = { editable = "../checkpoint" }
dependencies = [
{ name = "langchain-core" },
@@ -343,14 +343,10 @@ async def _run(
# set the results of each operation
for fut, result in zip(futs, results):
# guard against future being done (e.g. cancelled)
if not fut.done():
fut.set_result(result)
fut.set_result(result)
except Exception as e:
for fut in futs:
# guard against future being done (e.g. cancelled)
if not fut.done():
fut.set_exception(e)
fut.set_exception(e)
finally:
# remove strong ref to store
del s
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
description = "Library with base interfaces for LangGraph checkpoint savers."
authors = []
requires-python = ">=3.9"
-37
View File
@@ -155,43 +155,6 @@ async def test_async_batch_store(mocker: MockerFixture) -> None:
]
async def test_async_batch_store_handles_cancellation() -> None:
class MockStore(AsyncBatchedBaseStore):
def batch(self, ops: Iterable[Op]) -> list[Result]:
raise NotImplementedError
async def abatch(self, ops: Iterable[Op]) -> list[Result]:
assert all(isinstance(op, GetOp) for op in ops)
return [
Item(
value={},
key=getattr(op, "key", ""),
namespace=getattr(op, "namespace", ()),
created_at=datetime(2024, 9, 24, 17, 29, 10, 128397),
updated_at=datetime(2024, 9, 24, 17, 29, 10, 128397),
)
for op in ops
]
store = MockStore()
# Simulate cancellation
task = asyncio.create_task(store.aget(namespace=("a",), key="b"))
await asyncio.sleep(0)
task.cancel()
await asyncio.sleep(0)
# Cancelling individual queries against the store should not break the store
result = await store.aget(namespace=("c",), key="d")
assert result == Item(
value={},
key="d",
namespace=("c",),
created_at=datetime(2024, 9, 24, 17, 29, 10, 128397),
updated_at=datetime(2024, 9, 24, 17, 29, 10, 128397),
)
def test_list_namespaces_basic() -> None:
store = InMemoryStore()
+1 -1
View File
@@ -323,7 +323,7 @@ wheels = [
[[package]]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },
+2 -2
View File
@@ -1301,7 +1301,7 @@ wheels = [
[[package]]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
source = { editable = "../checkpoint" }
dependencies = [
{ name = "langchain-core" },
@@ -1331,7 +1331,7 @@ dev = [
[[package]]
name = "langgraph-checkpoint-postgres"
version = "2.0.23"
version = "2.0.22"
source = { editable = "../checkpoint-postgres" }
dependencies = [
{ name = "langgraph-checkpoint" },
+3 -7
View File
@@ -1,4 +1,4 @@
.PHONY: all format lint test test-fast test_watch integration_tests spell_check spell_fix benchmark profile
.PHONY: all format lint test test_watch integration_tests spell_check spell_fix benchmark profile
# Default target executed when no arguments are given to make.
all: help
@@ -15,17 +15,14 @@ stop-postgres:
TEST ?= .
test-fast:
LANGGRAPH_TEST_FAST=1 uv run pytest $(TEST)
test:
make start-postgres && LANGGRAPH_TEST_FAST=0 uv run pytest $(TEST); \
make start-postgres && uv run pytest $(TEST); \
EXIT_CODE=$$?; \
make stop-postgres; \
exit $$EXIT_CODE
test_watch:
make start-postgres && LANGGRAPH_TEST_FAST=0 uv run ptw $(TEST); \
make start-postgres && uv run ptw $(TEST); \
EXIT_CODE=$$?; \
make stop-postgres; \
exit $$EXIT_CODE
@@ -77,6 +74,5 @@ help:
@echo '-- TESTS --'
@echo 'coverage - run unit tests and generate coverage report'
@echo 'test - run unit tests'
@echo 'test-fast - run unit tests with in-memory checkpointer only'
@echo 'test TEST_FILE=<test_file> - run all tests in file'
@echo 'test_watch - run unit tests in watch mode'
+16 -54
View File
@@ -1,4 +1,3 @@
import os
from collections.abc import AsyncIterator, Iterator
from uuid import UUID
@@ -30,55 +29,6 @@ from tests.conftest_store import (
pytest.register_assert_rewrite("tests.memory_assert")
# Global variables for checkpointer and store configurations
FAST_MODE = os.getenv("LANGGRAPH_TEST_FAST", "true").lower() in ("true", "1", "yes")
SYNC_CHECKPOINTER_PARAMS = (
["memory"]
if FAST_MODE
else [
"memory",
"sqlite",
"postgres",
"postgres_pipe",
"postgres_pool",
]
)
ASYNC_CHECKPOINTER_PARAMS = (
["memory"]
if FAST_MODE
else [
"memory",
"sqlite_aio",
"postgres_aio",
"postgres_aio_pipe",
"postgres_aio_pool",
]
)
SYNC_STORE_PARAMS = (
["in_memory"]
if FAST_MODE
else [
"in_memory",
"postgres",
"postgres_pipe",
"postgres_pool",
]
)
ASYNC_STORE_PARAMS = (
["in_memory"]
if FAST_MODE
else [
"in_memory",
"postgres_aio",
"postgres_aio_pipe",
"postgres_aio_pool",
]
)
@pytest.fixture
def anyio_backend():
@@ -98,7 +48,7 @@ def deterministic_uuids(mocker: MockerFixture) -> MockerFixture:
@pytest.fixture(
scope="function",
params=SYNC_STORE_PARAMS,
params=["in_memory", "postgres", "postgres_pipe", "postgres_pool"],
)
def sync_store(request: pytest.FixtureRequest) -> Iterator[BaseStore]:
store_name = request.param
@@ -122,7 +72,7 @@ def sync_store(request: pytest.FixtureRequest) -> Iterator[BaseStore]:
@pytest.fixture(
scope="function",
params=ASYNC_STORE_PARAMS,
params=["in_memory", "postgres_aio", "postgres_aio_pipe", "postgres_aio_pool"],
)
async def async_store(request: pytest.FixtureRequest) -> AsyncIterator[BaseStore]:
store_name = request.param
@@ -146,7 +96,13 @@ async def async_store(request: pytest.FixtureRequest) -> AsyncIterator[BaseStore
@pytest.fixture(
scope="function",
params=SYNC_CHECKPOINTER_PARAMS,
params=[
"memory",
"sqlite",
"postgres",
"postgres_pipe",
"postgres_pool",
],
)
def sync_checkpointer(
request: pytest.FixtureRequest,
@@ -173,7 +129,13 @@ def sync_checkpointer(
@pytest.fixture(
scope="function",
params=ASYNC_CHECKPOINTER_PARAMS,
params=[
"memory",
"sqlite_aio",
"postgres_aio",
"postgres_aio_pipe",
"postgres_aio_pool",
],
)
async def async_checkpointer(
request: pytest.FixtureRequest,
+2 -2
View File
@@ -367,7 +367,7 @@ dev = [
[[package]]
name = "langgraph-checkpoint"
version = "2.1.1"
version = "2.1.0"
source = { editable = "../checkpoint" }
dependencies = [
{ name = "langchain-core" },
@@ -397,7 +397,7 @@ dev = [
[[package]]
name = "langgraph-checkpoint-postgres"
version = "2.0.23"
version = "2.0.22"
source = { editable = "../checkpoint-postgres" }
dependencies = [
{ name = "langgraph-checkpoint" },