langgraph-checkpoint-postgres 1.0.4__tar.gz → 1.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/PKG-INFO +1 -1
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/langgraph/checkpoint/postgres/__init__.py +10 -8
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/langgraph/checkpoint/postgres/aio.py +13 -13
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/langgraph/checkpoint/postgres/base.py +27 -21
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/pyproject.toml +2 -2
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/README.md +0 -0
- {langgraph_checkpoint_postgres-1.0.4 → langgraph_checkpoint_postgres-1.0.5}/langgraph/checkpoint/py.typed +0 -0
|
@@ -154,10 +154,11 @@ class PostgresSaver(BasePostgresSaver):
|
|
|
154
154
|
"checkpoint_id": value["checkpoint_id"],
|
|
155
155
|
}
|
|
156
156
|
},
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
self._load_checkpoint(
|
|
158
|
+
value["checkpoint"],
|
|
159
|
+
value["channel_values"],
|
|
160
|
+
value["pending_sends"],
|
|
161
|
+
),
|
|
161
162
|
self._load_metadata(value["metadata"]),
|
|
162
163
|
{
|
|
163
164
|
"configurable": {
|
|
@@ -232,10 +233,11 @@ class PostgresSaver(BasePostgresSaver):
|
|
|
232
233
|
"checkpoint_id": value["checkpoint_id"],
|
|
233
234
|
}
|
|
234
235
|
},
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
self._load_checkpoint(
|
|
237
|
+
value["checkpoint"],
|
|
238
|
+
value["channel_values"],
|
|
239
|
+
value["pending_sends"],
|
|
240
|
+
),
|
|
239
241
|
self._load_metadata(value["metadata"]),
|
|
240
242
|
{
|
|
241
243
|
"configurable": {
|
|
@@ -64,7 +64,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|
|
64
64
|
pipeline (bool): whether to use AsyncPipeline
|
|
65
65
|
|
|
66
66
|
Returns:
|
|
67
|
-
|
|
67
|
+
AsyncPostgresSaver: A new AsyncPostgresSaver instance.
|
|
68
68
|
"""
|
|
69
69
|
async with await AsyncConnection.connect(
|
|
70
70
|
conn_string, autocommit=True, prepare_threshold=0, row_factory=dict_row
|
|
@@ -137,12 +137,12 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|
|
137
137
|
"checkpoint_id": value["checkpoint_id"],
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
"
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
await asyncio.to_thread(
|
|
141
|
+
self._load_checkpoint,
|
|
142
|
+
value["checkpoint"],
|
|
143
|
+
value["channel_values"],
|
|
144
|
+
value["pending_sends"],
|
|
145
|
+
),
|
|
146
146
|
self._load_metadata(value["metadata"]),
|
|
147
147
|
{
|
|
148
148
|
"configurable": {
|
|
@@ -196,12 +196,12 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|
|
196
196
|
"checkpoint_id": value["checkpoint_id"],
|
|
197
197
|
}
|
|
198
198
|
},
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
await asyncio.to_thread(
|
|
200
|
+
self._load_checkpoint,
|
|
201
|
+
value["checkpoint"],
|
|
202
|
+
value["channel_values"],
|
|
203
|
+
value["pending_sends"],
|
|
204
|
+
),
|
|
205
205
|
self._load_metadata(value["metadata"]),
|
|
206
206
|
{
|
|
207
207
|
"configurable": {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from base64 import b64decode, b64encode
|
|
2
1
|
from hashlib import md5
|
|
3
2
|
from typing import Any, List, Optional, Tuple
|
|
4
3
|
|
|
@@ -13,7 +12,7 @@ from langgraph.checkpoint.base import (
|
|
|
13
12
|
get_checkpoint_id,
|
|
14
13
|
)
|
|
15
14
|
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
|
|
16
|
-
from langgraph.checkpoint.serde.types import ChannelProtocol
|
|
15
|
+
from langgraph.checkpoint.serde.types import TASKS, ChannelProtocol
|
|
17
16
|
|
|
18
17
|
MetadataInput = Optional[dict[str, Any]]
|
|
19
18
|
|
|
@@ -58,7 +57,7 @@ MIGRATIONS = [
|
|
|
58
57
|
"ALTER TABLE checkpoint_blobs ALTER COLUMN blob DROP not null;",
|
|
59
58
|
]
|
|
60
59
|
|
|
61
|
-
SELECT_SQL = """
|
|
60
|
+
SELECT_SQL = f"""
|
|
62
61
|
select
|
|
63
62
|
thread_id,
|
|
64
63
|
checkpoint,
|
|
@@ -77,12 +76,20 @@ select
|
|
|
77
76
|
) as channel_values,
|
|
78
77
|
(
|
|
79
78
|
select
|
|
80
|
-
array_agg(array[cw.task_id::text::bytea, cw.channel::bytea, cw.type::bytea, cw.blob])
|
|
79
|
+
array_agg(array[cw.task_id::text::bytea, cw.channel::bytea, cw.type::bytea, cw.blob] order by cw.task_id, cw.idx)
|
|
81
80
|
from checkpoint_writes cw
|
|
82
81
|
where cw.thread_id = checkpoints.thread_id
|
|
83
82
|
and cw.checkpoint_ns = checkpoints.checkpoint_ns
|
|
84
83
|
and cw.checkpoint_id = checkpoints.checkpoint_id
|
|
85
|
-
) as pending_writes
|
|
84
|
+
) as pending_writes,
|
|
85
|
+
(
|
|
86
|
+
select array_agg(array[cw.type::bytea, cw.blob] order by cw.idx)
|
|
87
|
+
from checkpoint_writes cw
|
|
88
|
+
where cw.thread_id = checkpoints.thread_id
|
|
89
|
+
and cw.checkpoint_ns = checkpoints.checkpoint_ns
|
|
90
|
+
and cw.checkpoint_id = checkpoints.parent_checkpoint_id
|
|
91
|
+
and cw.channel = '{TASKS}'
|
|
92
|
+
) as pending_sends
|
|
86
93
|
from checkpoints """
|
|
87
94
|
|
|
88
95
|
UPSERT_CHECKPOINT_BLOBS_SQL = """
|
|
@@ -116,25 +123,23 @@ class BasePostgresSaver(BaseCheckpointSaver):
|
|
|
116
123
|
|
|
117
124
|
jsonplus_serde = JsonPlusSerializer()
|
|
118
125
|
|
|
119
|
-
def _load_checkpoint(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
**checkpoint,
|
|
126
|
-
"pending_sends": self.serde.loads_typed((type, b64decode(bs))),
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return checkpoint
|
|
130
|
-
|
|
131
|
-
def _dump_checkpoint(self, checkpoint: Checkpoint) -> dict[str, Any]:
|
|
132
|
-
type, bs = self.serde.dumps_typed(checkpoint["pending_sends"])
|
|
126
|
+
def _load_checkpoint(
|
|
127
|
+
self,
|
|
128
|
+
checkpoint: dict[str, Any],
|
|
129
|
+
channel_values: list[tuple[bytes, bytes, bytes]],
|
|
130
|
+
pending_sends: list[tuple[bytes, bytes]],
|
|
131
|
+
) -> Checkpoint:
|
|
133
132
|
return {
|
|
134
133
|
**checkpoint,
|
|
135
|
-
"pending_sends":
|
|
134
|
+
"pending_sends": [
|
|
135
|
+
self.serde.loads_typed((c.decode(), b)) for c, b in pending_sends or []
|
|
136
|
+
],
|
|
137
|
+
"channel_values": self._load_blobs(channel_values),
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
def _dump_checkpoint(self, checkpoint: Checkpoint) -> dict[str, Any]:
|
|
141
|
+
return {**checkpoint, "pending_sends": []}
|
|
142
|
+
|
|
138
143
|
def _load_blobs(
|
|
139
144
|
self, blob_values: list[tuple[bytes, bytes, bytes]]
|
|
140
145
|
) -> dict[str, Any]:
|
|
@@ -255,7 +260,8 @@ class BasePostgresSaver(BaseCheckpointSaver):
|
|
|
255
260
|
if config:
|
|
256
261
|
wheres.append("thread_id = %s ")
|
|
257
262
|
param_values.append(config["configurable"]["thread_id"])
|
|
258
|
-
|
|
263
|
+
checkpoint_ns = config["configurable"].get("checkpoint_ns")
|
|
264
|
+
if checkpoint_ns is not None:
|
|
259
265
|
wheres.append("checkpoint_ns = %s")
|
|
260
266
|
param_values.append(checkpoint_ns)
|
|
261
267
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "langgraph-checkpoint-postgres"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.5"
|
|
4
4
|
description = "Library with a Postgres implementation of LangGraph checkpoint saver."
|
|
5
5
|
authors = []
|
|
6
6
|
license = "MIT"
|
|
@@ -16,7 +16,7 @@ psycopg = "^3.0.0"
|
|
|
16
16
|
psycopg-pool = "^3.0.0"
|
|
17
17
|
|
|
18
18
|
[tool.poetry.group.dev.dependencies]
|
|
19
|
-
ruff = "^0.
|
|
19
|
+
ruff = "^0.6.2"
|
|
20
20
|
codespell = "^2.2.0"
|
|
21
21
|
pytest = "^7.2.1"
|
|
22
22
|
anyio = "^4.4.0"
|
|
File without changes
|
|
File without changes
|