langchain-postgres 0.0.5__py3-none-any.whl → 0.0.6__py3-none-any.whl
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.
- langchain_postgres/__init__.py +0 -8
- langchain_postgres/vectorstores.py +1 -1
- {langchain_postgres-0.0.5.dist-info → langchain_postgres-0.0.6.dist-info}/METADATA +1 -93
- langchain_postgres-0.0.6.dist-info/RECORD +9 -0
- langchain_postgres/checkpoint.py +0 -587
- langchain_postgres-0.0.5.dist-info/RECORD +0 -10
- {langchain_postgres-0.0.5.dist-info → langchain_postgres-0.0.6.dist-info}/LICENSE +0 -0
- {langchain_postgres-0.0.5.dist-info → langchain_postgres-0.0.6.dist-info}/WHEEL +0 -0
langchain_postgres/__init__.py
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
from importlib import metadata
|
2
2
|
|
3
3
|
from langchain_postgres.chat_message_histories import PostgresChatMessageHistory
|
4
|
-
from langchain_postgres.checkpoint import (
|
5
|
-
CheckpointSerializer,
|
6
|
-
PickleCheckpointSerializer,
|
7
|
-
PostgresSaver,
|
8
|
-
)
|
9
4
|
from langchain_postgres.vectorstores import PGVector
|
10
5
|
|
11
6
|
try:
|
@@ -16,9 +11,6 @@ except metadata.PackageNotFoundError:
|
|
16
11
|
|
17
12
|
__all__ = [
|
18
13
|
"__version__",
|
19
|
-
"CheckpointSerializer",
|
20
14
|
"PostgresChatMessageHistory",
|
21
|
-
"PostgresSaver",
|
22
|
-
"PickleCheckpointSerializer",
|
23
15
|
"PGVector",
|
24
16
|
]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: langchain-postgres
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
4
4
|
Summary: An integration package connecting Postgres and LangChain
|
5
5
|
Home-page: https://github.com/langchain-ai/langchain-postgres
|
6
6
|
License: MIT
|
@@ -12,7 +12,6 @@ Classifier: Programming Language :: Python :: 3.10
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
14
|
Requires-Dist: langchain-core (>=0.1.50,<0.3)
|
15
|
-
Requires-Dist: langgraph (>=0.0.32,<0.0.33)
|
16
15
|
Requires-Dist: numpy (>=1,<2)
|
17
16
|
Requires-Dist: pgvector (>=0.2.5,<0.3.0)
|
18
17
|
Requires-Dist: psycopg (>=3,<4)
|
@@ -48,97 +47,6 @@ pip install -U langchain-postgres
|
|
48
47
|
|
49
48
|
## Usage
|
50
49
|
|
51
|
-
### PostgresSaver (LangGraph Checkpointer)
|
52
|
-
|
53
|
-
The LangGraph checkpointer can be used to add memory to your LangGraph application.
|
54
|
-
|
55
|
-
`PostgresSaver` is an implementation of the checkpointer saver using
|
56
|
-
Postgres as the backend.
|
57
|
-
|
58
|
-
Currently, only the psycopg3 driver is supported.
|
59
|
-
|
60
|
-
Sync usage:
|
61
|
-
|
62
|
-
```python
|
63
|
-
from psycopg_pool import ConnectionPool
|
64
|
-
from langchain_postgres import (
|
65
|
-
PostgresSaver, PickleCheckpointSerializer
|
66
|
-
)
|
67
|
-
|
68
|
-
pool = ConnectionPool(
|
69
|
-
# Example configuration
|
70
|
-
conninfo="postgresql://langchain:langchain@localhost:6024/langchain",
|
71
|
-
max_size=20,
|
72
|
-
)
|
73
|
-
|
74
|
-
PostgresSaver.create_tables(pool)
|
75
|
-
|
76
|
-
checkpointer = PostgresSaver(
|
77
|
-
serializer=PickleCheckpointSerializer(),
|
78
|
-
sync_connection=pool,
|
79
|
-
)
|
80
|
-
|
81
|
-
# Set up the langgraph workflow with the checkpointer
|
82
|
-
workflow = ... # Fill in with your workflow
|
83
|
-
app = workflow.compile(checkpointer=checkpointer)
|
84
|
-
|
85
|
-
# Use with the sync methods of `app` (e.g., `app.stream())
|
86
|
-
|
87
|
-
pool.close() # Remember to close the connection pool.
|
88
|
-
```
|
89
|
-
|
90
|
-
Async usage:
|
91
|
-
|
92
|
-
```python
|
93
|
-
from psycopg_pool import AsyncConnectionPool
|
94
|
-
from langchain_postgres import (
|
95
|
-
PostgresSaver, PickleCheckpointSerializer
|
96
|
-
)
|
97
|
-
|
98
|
-
pool = AsyncConnectionPool(
|
99
|
-
# Example configuration
|
100
|
-
conninfo="postgresql://langchain:langchain@localhost:6024/langchain",
|
101
|
-
max_size=20,
|
102
|
-
)
|
103
|
-
|
104
|
-
# Create the tables in postgres (only needs to be done once)
|
105
|
-
await PostgresSaver.acreate_tables(pool)
|
106
|
-
|
107
|
-
checkpointer = PostgresSaver(
|
108
|
-
serializer=PickleCheckpointSerializer(),
|
109
|
-
async_connection=pool,
|
110
|
-
)
|
111
|
-
|
112
|
-
# Set up the langgraph workflow with the checkpointer
|
113
|
-
workflow = ... # Fill in with your workflow
|
114
|
-
app = workflow.compile(checkpointer=checkpointer)
|
115
|
-
|
116
|
-
# Use with the async methods of `app` (e.g., `app.astream()`)
|
117
|
-
|
118
|
-
await pool.close() # Remember to close the connection pool.
|
119
|
-
```
|
120
|
-
|
121
|
-
#### Testing
|
122
|
-
|
123
|
-
If testing with the postgres checkpointer it may be useful to both create and
|
124
|
-
drop the tables before and after the tests.
|
125
|
-
|
126
|
-
```python
|
127
|
-
from psycopg_pool import ConnectionPool
|
128
|
-
from langchain_postgres import (
|
129
|
-
PostgresSaver
|
130
|
-
)
|
131
|
-
with ConnectionPool(
|
132
|
-
# Example configuration
|
133
|
-
conninfo="postgresql://langchain:langchain@localhost:6024/langchain",
|
134
|
-
max_size=20,
|
135
|
-
) as conn:
|
136
|
-
PostgresSaver.create_tables(conn)
|
137
|
-
PostgresSaver.drop_tables(conn)
|
138
|
-
# Run your unit tests with langgraph
|
139
|
-
```
|
140
|
-
|
141
|
-
|
142
50
|
### ChatMessageHistory
|
143
51
|
|
144
52
|
The chat message history abstraction helps to persist chat message history
|
@@ -0,0 +1,9 @@
|
|
1
|
+
langchain_postgres/__init__.py,sha256=9rXsSowLZpH_dqyWJUhpTVwviQ02wLTZj_kPi6OOfcc,415
|
2
|
+
langchain_postgres/_utils.py,sha256=Johm50HEgA4qScLDaSDIfJfF3DygjA5KTBtNeVcD63I,2914
|
3
|
+
langchain_postgres/chat_message_histories.py,sha256=gh6hjBlrJ5GSo5kePQdh3VhiUYoWWdP37GXtZ1e25a4,14033
|
4
|
+
langchain_postgres/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
langchain_postgres/vectorstores.py,sha256=1LVIONZnVvXRPvFOjKKfjleC8ATMbdbprUJUU3NYFwc,50367
|
6
|
+
langchain_postgres-0.0.6.dist-info/LICENSE,sha256=2btS8uNUDWD_UNjw9ba6ZJt_00aUjEw9CGyK-xIHY8c,1072
|
7
|
+
langchain_postgres-0.0.6.dist-info/METADATA,sha256=Urbd8Cmyu8N1OEP-m6WXm-mAuKruPtSrStCe_kcxj-4,3697
|
8
|
+
langchain_postgres-0.0.6.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
9
|
+
langchain_postgres-0.0.6.dist-info/RECORD,,
|
langchain_postgres/checkpoint.py
DELETED
@@ -1,587 +0,0 @@
|
|
1
|
-
"""Implementation of a langgraph checkpoint saver using Postgres."""
|
2
|
-
import abc
|
3
|
-
import pickle
|
4
|
-
from contextlib import asynccontextmanager, contextmanager
|
5
|
-
from typing import AsyncGenerator, AsyncIterator, Generator, Optional, Union, cast
|
6
|
-
|
7
|
-
import psycopg
|
8
|
-
from langchain_core.runnables import ConfigurableFieldSpec, RunnableConfig
|
9
|
-
from langgraph.checkpoint import BaseCheckpointSaver
|
10
|
-
from langgraph.checkpoint.base import Checkpoint, CheckpointThreadTs, CheckpointTuple
|
11
|
-
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
12
|
-
|
13
|
-
|
14
|
-
class CheckpointSerializer(abc.ABC):
|
15
|
-
"""A serializer for serializing and deserializing objects to and from bytes."""
|
16
|
-
|
17
|
-
@abc.abstractmethod
|
18
|
-
def dumps(self, obj: Checkpoint) -> bytes:
|
19
|
-
"""Serialize an object to bytes."""
|
20
|
-
|
21
|
-
@abc.abstractmethod
|
22
|
-
def loads(self, data: bytes) -> Checkpoint:
|
23
|
-
"""Deserialize an object from bytes."""
|
24
|
-
|
25
|
-
|
26
|
-
class PickleCheckpointSerializer(CheckpointSerializer):
|
27
|
-
"""Use the pickle module to serialize and deserialize objects.
|
28
|
-
|
29
|
-
This serializer uses the pickle module to serialize and deserialize objects.
|
30
|
-
|
31
|
-
While pickling can serialize a wide range of Python objects, it may fail
|
32
|
-
de-serializable objects upon updates of the Python version or the python
|
33
|
-
environment (e.g., the object's class definition changes in LangGraph).
|
34
|
-
|
35
|
-
*Security Warning*: The pickle module can deserialize malicious payloads,
|
36
|
-
only use this serializer with trusted data; e.g., data that you
|
37
|
-
have serialized yourself and can guarantee the integrity of.
|
38
|
-
"""
|
39
|
-
|
40
|
-
def dumps(self, obj: Checkpoint) -> bytes:
|
41
|
-
"""Serialize an object to bytes."""
|
42
|
-
return pickle.dumps(obj)
|
43
|
-
|
44
|
-
def loads(self, data: bytes) -> Checkpoint:
|
45
|
-
"""Deserialize an object from bytes."""
|
46
|
-
return cast(Checkpoint, pickle.loads(data))
|
47
|
-
|
48
|
-
|
49
|
-
@contextmanager
|
50
|
-
def _get_sync_connection(
|
51
|
-
connection: Union[psycopg.Connection, ConnectionPool, None],
|
52
|
-
) -> Generator[psycopg.Connection, None, None]:
|
53
|
-
"""Get the connection to the Postgres database."""
|
54
|
-
if isinstance(connection, psycopg.Connection):
|
55
|
-
yield connection
|
56
|
-
elif isinstance(connection, ConnectionPool):
|
57
|
-
with connection.connection() as conn:
|
58
|
-
yield conn
|
59
|
-
else:
|
60
|
-
raise ValueError(
|
61
|
-
"Invalid sync connection object. Please initialize the check pointer "
|
62
|
-
f"with an appropriate sync connection object. "
|
63
|
-
f"Got {type(connection)}."
|
64
|
-
)
|
65
|
-
|
66
|
-
|
67
|
-
@asynccontextmanager
|
68
|
-
async def _get_async_connection(
|
69
|
-
connection: Union[psycopg.AsyncConnection, AsyncConnectionPool, None],
|
70
|
-
) -> AsyncGenerator[psycopg.AsyncConnection, None]:
|
71
|
-
"""Get the connection to the Postgres database."""
|
72
|
-
if isinstance(connection, psycopg.AsyncConnection):
|
73
|
-
yield connection
|
74
|
-
elif isinstance(connection, AsyncConnectionPool):
|
75
|
-
async with connection.connection() as conn:
|
76
|
-
yield conn
|
77
|
-
else:
|
78
|
-
raise ValueError(
|
79
|
-
"Invalid async connection object. Please initialize the check pointer "
|
80
|
-
f"with an appropriate async connection object. "
|
81
|
-
f"Got {type(connection)}."
|
82
|
-
)
|
83
|
-
|
84
|
-
|
85
|
-
class PostgresSaver(BaseCheckpointSaver):
|
86
|
-
"""LangGraph checkpoint saver for Postgres.
|
87
|
-
|
88
|
-
This implementation of a checkpoint saver uses a Postgres database to save
|
89
|
-
and retrieve checkpoints. It uses the psycopg3 package to interact with the
|
90
|
-
Postgres database.
|
91
|
-
|
92
|
-
The checkpoint accepts either a sync_connection in the form of a psycopg.Connection
|
93
|
-
or a psycopg.ConnectionPool object, or an async_connection in the form of a
|
94
|
-
psycopg.AsyncConnection or psycopg.AsyncConnectionPool object.
|
95
|
-
|
96
|
-
Usage:
|
97
|
-
|
98
|
-
1. First time use: create schema in the database using the `create_tables` method or
|
99
|
-
the async version `acreate_tables` method.
|
100
|
-
2. Create a PostgresCheckpoint object with a serializer and an appropriate
|
101
|
-
connection object.
|
102
|
-
It's recommended to use a connection pool object for the connection.
|
103
|
-
If using a connection object, you are responsible for closing the connection
|
104
|
-
when done.
|
105
|
-
|
106
|
-
Examples:
|
107
|
-
|
108
|
-
|
109
|
-
Sync usage with a connection pool:
|
110
|
-
|
111
|
-
.. code-block:: python
|
112
|
-
|
113
|
-
from psycopg_pool import ConnectionPool
|
114
|
-
from langchain_postgres import (
|
115
|
-
PostgresCheckpoint, PickleCheckpointSerializer
|
116
|
-
)
|
117
|
-
|
118
|
-
pool = ConnectionPool(
|
119
|
-
# Example configuration
|
120
|
-
conninfo="postgresql://user:password@localhost:5432/dbname",
|
121
|
-
max_size=20,
|
122
|
-
)
|
123
|
-
|
124
|
-
# Uses the pickle module for serialization
|
125
|
-
# Make sure that you're only de-serializing trusted data
|
126
|
-
# (e.g., payloads that you have serialized yourself).
|
127
|
-
# Or implement a custom serializer.
|
128
|
-
checkpoint = PostgresCheckpoint(
|
129
|
-
serializer=PickleCheckpointSerializer(),
|
130
|
-
sync_connection=pool,
|
131
|
-
)
|
132
|
-
|
133
|
-
# Use the checkpoint object to put, get, list checkpoints, etc.
|
134
|
-
|
135
|
-
|
136
|
-
Async usage with a connection pool:
|
137
|
-
|
138
|
-
.. code-block:: python
|
139
|
-
|
140
|
-
from psycopg_pool import AsyncConnectionPool
|
141
|
-
from langchain_postgres import (
|
142
|
-
PostgresCheckpoint, PickleCheckpointSerializer
|
143
|
-
)
|
144
|
-
|
145
|
-
pool = AsyncConnectionPool(
|
146
|
-
# Example configuration
|
147
|
-
conninfo="postgresql://user:password@localhost:5432/dbname",
|
148
|
-
max_size=20,
|
149
|
-
)
|
150
|
-
|
151
|
-
# Uses the pickle module for serialization
|
152
|
-
# Make sure that you're only de-serializing trusted data
|
153
|
-
# (e.g., payloads that you have serialized yourself).
|
154
|
-
# Or implement a custom serializer.
|
155
|
-
checkpoint = PostgresCheckpoint(
|
156
|
-
serializer=PickleCheckpointSerializer(),
|
157
|
-
async_connection=pool,
|
158
|
-
)
|
159
|
-
|
160
|
-
# Use the checkpoint object to put, get, list checkpoints, etc.
|
161
|
-
|
162
|
-
|
163
|
-
Async usage with a connection object:
|
164
|
-
|
165
|
-
.. code-block:: python
|
166
|
-
|
167
|
-
from psycopg import AsyncConnection
|
168
|
-
from langchain_postgres import (
|
169
|
-
PostgresCheckpoint, PickleCheckpointSerializer
|
170
|
-
)
|
171
|
-
|
172
|
-
conninfo="postgresql://user:password@localhost:5432/dbname"
|
173
|
-
# Take care of closing the connection when done
|
174
|
-
async with AsyncConnection(conninfo=conninfo) as conn:
|
175
|
-
# Uses the pickle module for serialization
|
176
|
-
# Make sure that you're only de-serializing trusted data
|
177
|
-
# (e.g., payloads that you have serialized yourself).
|
178
|
-
# Or implement a custom serializer.
|
179
|
-
checkpoint = PostgresCheckpoint(
|
180
|
-
serializer=PickleCheckpointSerializer(),
|
181
|
-
async_connection=conn,
|
182
|
-
)
|
183
|
-
|
184
|
-
# Use the checkpoint object to put, get, list checkpoints, etc.
|
185
|
-
...
|
186
|
-
"""
|
187
|
-
|
188
|
-
serializer: CheckpointSerializer
|
189
|
-
"""The serializer for serializing and deserializing objects to and from bytes."""
|
190
|
-
|
191
|
-
sync_connection: Optional[Union[psycopg.Connection, ConnectionPool]] = None
|
192
|
-
"""The synchronous connection or pool to the Postgres database.
|
193
|
-
|
194
|
-
If providing a connection object, please ensure that the connection is open
|
195
|
-
and remember to close the connection when done.
|
196
|
-
"""
|
197
|
-
async_connection: Optional[
|
198
|
-
Union[psycopg.AsyncConnection, AsyncConnectionPool]
|
199
|
-
] = None
|
200
|
-
"""The asynchronous connection or pool to the Postgres database.
|
201
|
-
|
202
|
-
If providing a connection object, please ensure that the connection is open
|
203
|
-
and remember to close the connection when done.
|
204
|
-
"""
|
205
|
-
|
206
|
-
class Config:
|
207
|
-
arbitrary_types_allowed = True
|
208
|
-
extra = "forbid"
|
209
|
-
|
210
|
-
@property
|
211
|
-
def config_specs(self) -> list[ConfigurableFieldSpec]:
|
212
|
-
"""Return the configuration specs for this runnable."""
|
213
|
-
return [
|
214
|
-
ConfigurableFieldSpec(
|
215
|
-
id="thread_id",
|
216
|
-
annotation=Optional[str],
|
217
|
-
name="Thread ID",
|
218
|
-
description=None,
|
219
|
-
default=None,
|
220
|
-
is_shared=True,
|
221
|
-
),
|
222
|
-
CheckpointThreadTs,
|
223
|
-
]
|
224
|
-
|
225
|
-
@contextmanager
|
226
|
-
def _get_sync_connection(self) -> Generator[psycopg.Connection, None, None]:
|
227
|
-
"""Get the connection to the Postgres database."""
|
228
|
-
with _get_sync_connection(self.sync_connection) as connection:
|
229
|
-
yield connection
|
230
|
-
|
231
|
-
@asynccontextmanager
|
232
|
-
async def _get_async_connection(
|
233
|
-
self,
|
234
|
-
) -> AsyncGenerator[psycopg.AsyncConnection, None]:
|
235
|
-
"""Get the connection to the Postgres database."""
|
236
|
-
async with _get_async_connection(self.async_connection) as connection:
|
237
|
-
yield connection
|
238
|
-
|
239
|
-
@staticmethod
|
240
|
-
def create_tables(connection: Union[psycopg.Connection, ConnectionPool], /) -> None:
|
241
|
-
"""Create the schema for the checkpoint saver."""
|
242
|
-
with _get_sync_connection(connection) as conn:
|
243
|
-
with conn.cursor() as cur:
|
244
|
-
cur.execute(
|
245
|
-
"""
|
246
|
-
CREATE TABLE IF NOT EXISTS checkpoints (
|
247
|
-
thread_id TEXT NOT NULL,
|
248
|
-
checkpoint BYTEA NOT NULL,
|
249
|
-
thread_ts TIMESTAMPTZ NOT NULL,
|
250
|
-
parent_ts TIMESTAMPTZ,
|
251
|
-
PRIMARY KEY (thread_id, thread_ts)
|
252
|
-
);
|
253
|
-
"""
|
254
|
-
)
|
255
|
-
|
256
|
-
@staticmethod
|
257
|
-
async def acreate_tables(
|
258
|
-
connection: Union[psycopg.AsyncConnection, AsyncConnectionPool], /
|
259
|
-
) -> None:
|
260
|
-
"""Create the schema for the checkpoint saver."""
|
261
|
-
async with _get_async_connection(connection) as conn:
|
262
|
-
async with conn.cursor() as cur:
|
263
|
-
await cur.execute(
|
264
|
-
"""
|
265
|
-
CREATE TABLE IF NOT EXISTS checkpoints (
|
266
|
-
thread_id TEXT NOT NULL,
|
267
|
-
checkpoint BYTEA NOT NULL,
|
268
|
-
thread_ts TIMESTAMPTZ NOT NULL,
|
269
|
-
parent_ts TIMESTAMPTZ,
|
270
|
-
PRIMARY KEY (thread_id, thread_ts)
|
271
|
-
);
|
272
|
-
"""
|
273
|
-
)
|
274
|
-
|
275
|
-
@staticmethod
|
276
|
-
def drop_tables(connection: psycopg.Connection, /) -> None:
|
277
|
-
"""Drop the table for the checkpoint saver."""
|
278
|
-
with connection.cursor() as cur:
|
279
|
-
cur.execute("DROP TABLE IF EXISTS checkpoints;")
|
280
|
-
|
281
|
-
@staticmethod
|
282
|
-
async def adrop_tables(connection: psycopg.AsyncConnection, /) -> None:
|
283
|
-
"""Drop the table for the checkpoint saver."""
|
284
|
-
async with connection.cursor() as cur:
|
285
|
-
await cur.execute("DROP TABLE IF EXISTS checkpoints;")
|
286
|
-
|
287
|
-
def put(self, config: RunnableConfig, checkpoint: Checkpoint) -> RunnableConfig:
|
288
|
-
"""Put the checkpoint for the given configuration.
|
289
|
-
|
290
|
-
Args:
|
291
|
-
config: The configuration for the checkpoint.
|
292
|
-
A dict with a `configurable` key which is a dict with
|
293
|
-
a `thread_id` key and an optional `thread_ts` key.
|
294
|
-
For example, { 'configurable': { 'thread_id': 'test_thread' } }
|
295
|
-
checkpoint: The checkpoint to persist.
|
296
|
-
|
297
|
-
Returns:
|
298
|
-
The RunnableConfig that describes the checkpoint that was just created.
|
299
|
-
It'll contain the `thread_id` and `thread_ts` of the checkpoint.
|
300
|
-
"""
|
301
|
-
thread_id = config["configurable"]["thread_id"]
|
302
|
-
parent_ts = config["configurable"].get("thread_ts")
|
303
|
-
|
304
|
-
with self._get_sync_connection() as conn:
|
305
|
-
with conn.cursor() as cur:
|
306
|
-
cur.execute(
|
307
|
-
"""
|
308
|
-
INSERT INTO checkpoints
|
309
|
-
(thread_id, thread_ts, parent_ts, checkpoint)
|
310
|
-
VALUES
|
311
|
-
(%(thread_id)s, %(thread_ts)s, %(parent_ts)s, %(checkpoint)s)
|
312
|
-
ON CONFLICT (thread_id, thread_ts)
|
313
|
-
DO UPDATE SET checkpoint = EXCLUDED.checkpoint;
|
314
|
-
""",
|
315
|
-
{
|
316
|
-
"thread_id": thread_id,
|
317
|
-
"thread_ts": checkpoint["ts"],
|
318
|
-
"parent_ts": parent_ts if parent_ts else None,
|
319
|
-
"checkpoint": self.serializer.dumps(checkpoint),
|
320
|
-
},
|
321
|
-
)
|
322
|
-
|
323
|
-
return {
|
324
|
-
"configurable": {
|
325
|
-
"thread_id": thread_id,
|
326
|
-
"thread_ts": checkpoint["ts"],
|
327
|
-
},
|
328
|
-
}
|
329
|
-
|
330
|
-
async def aput(
|
331
|
-
self, config: RunnableConfig, checkpoint: Checkpoint
|
332
|
-
) -> RunnableConfig:
|
333
|
-
"""Put the checkpoint for the given configuration.
|
334
|
-
|
335
|
-
Args:
|
336
|
-
config: The configuration for the checkpoint.
|
337
|
-
A dict with a `configurable` key which is a dict with
|
338
|
-
a `thread_id` key and an optional `thread_ts` key.
|
339
|
-
For example, { 'configurable': { 'thread_id': 'test_thread' } }
|
340
|
-
checkpoint: The checkpoint to persist.
|
341
|
-
|
342
|
-
Returns:
|
343
|
-
The RunnableConfig that describes the checkpoint that was just created.
|
344
|
-
It'll contain the `thread_id` and `thread_ts` of the checkpoint.
|
345
|
-
"""
|
346
|
-
thread_id = config["configurable"]["thread_id"]
|
347
|
-
parent_ts = config["configurable"].get("thread_ts")
|
348
|
-
async with self._get_async_connection() as conn:
|
349
|
-
async with conn.cursor() as cur:
|
350
|
-
await cur.execute(
|
351
|
-
"""
|
352
|
-
INSERT INTO
|
353
|
-
checkpoints (thread_id, thread_ts, parent_ts, checkpoint)
|
354
|
-
VALUES
|
355
|
-
(%(thread_id)s, %(thread_ts)s, %(parent_ts)s, %(checkpoint)s)
|
356
|
-
ON CONFLICT (thread_id, thread_ts)
|
357
|
-
DO UPDATE SET checkpoint = EXCLUDED.checkpoint;
|
358
|
-
""",
|
359
|
-
{
|
360
|
-
"thread_id": thread_id,
|
361
|
-
"thread_ts": checkpoint["ts"],
|
362
|
-
"parent_ts": parent_ts if parent_ts else None,
|
363
|
-
"checkpoint": self.serializer.dumps(checkpoint),
|
364
|
-
},
|
365
|
-
)
|
366
|
-
|
367
|
-
return {
|
368
|
-
"configurable": {
|
369
|
-
"thread_id": thread_id,
|
370
|
-
"thread_ts": checkpoint["ts"],
|
371
|
-
},
|
372
|
-
}
|
373
|
-
|
374
|
-
def list(self, config: RunnableConfig) -> Generator[CheckpointTuple, None, None]:
|
375
|
-
"""Get all the checkpoints for the given configuration."""
|
376
|
-
with self._get_sync_connection() as conn:
|
377
|
-
with conn.cursor() as cur:
|
378
|
-
thread_id = config["configurable"]["thread_id"]
|
379
|
-
cur.execute(
|
380
|
-
"SELECT checkpoint, thread_ts, parent_ts "
|
381
|
-
"FROM checkpoints "
|
382
|
-
"WHERE thread_id = %(thread_id)s "
|
383
|
-
"ORDER BY thread_ts DESC",
|
384
|
-
{
|
385
|
-
"thread_id": thread_id,
|
386
|
-
},
|
387
|
-
)
|
388
|
-
for value in cur:
|
389
|
-
yield CheckpointTuple(
|
390
|
-
{
|
391
|
-
"configurable": {
|
392
|
-
"thread_id": thread_id,
|
393
|
-
"thread_ts": value[1].isoformat(),
|
394
|
-
}
|
395
|
-
},
|
396
|
-
self.serializer.loads(value[0]),
|
397
|
-
{
|
398
|
-
"configurable": {
|
399
|
-
"thread_id": thread_id,
|
400
|
-
"thread_ts": value[2].isoformat(),
|
401
|
-
}
|
402
|
-
}
|
403
|
-
if value[2]
|
404
|
-
else None,
|
405
|
-
)
|
406
|
-
|
407
|
-
async def alist(self, config: RunnableConfig) -> AsyncIterator[CheckpointTuple]:
|
408
|
-
"""Get all the checkpoints for the given configuration."""
|
409
|
-
async with self._get_async_connection() as conn:
|
410
|
-
async with conn.cursor() as cur:
|
411
|
-
thread_id = config["configurable"]["thread_id"]
|
412
|
-
await cur.execute(
|
413
|
-
"SELECT checkpoint, thread_ts, parent_ts "
|
414
|
-
"FROM checkpoints "
|
415
|
-
"WHERE thread_id = %(thread_id)s "
|
416
|
-
"ORDER BY thread_ts DESC",
|
417
|
-
{
|
418
|
-
"thread_id": thread_id,
|
419
|
-
},
|
420
|
-
)
|
421
|
-
async for value in cur:
|
422
|
-
yield CheckpointTuple(
|
423
|
-
{
|
424
|
-
"configurable": {
|
425
|
-
"thread_id": thread_id,
|
426
|
-
"thread_ts": value[1].isoformat(),
|
427
|
-
}
|
428
|
-
},
|
429
|
-
self.serializer.loads(value[0]),
|
430
|
-
{
|
431
|
-
"configurable": {
|
432
|
-
"thread_id": thread_id,
|
433
|
-
"thread_ts": value[2].isoformat(),
|
434
|
-
}
|
435
|
-
}
|
436
|
-
if value[2]
|
437
|
-
else None,
|
438
|
-
)
|
439
|
-
|
440
|
-
def get_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
|
441
|
-
"""Get the checkpoint tuple for the given configuration.
|
442
|
-
|
443
|
-
Args:
|
444
|
-
config: The configuration for the checkpoint.
|
445
|
-
A dict with a `configurable` key which is a dict with
|
446
|
-
a `thread_id` key and an optional `thread_ts` key.
|
447
|
-
For example, { 'configurable': { 'thread_id': 'test_thread' } }
|
448
|
-
|
449
|
-
Returns:
|
450
|
-
The checkpoint tuple for the given configuration if it exists,
|
451
|
-
otherwise None.
|
452
|
-
|
453
|
-
If thread_ts is None, the latest checkpoint is returned if it exists.
|
454
|
-
"""
|
455
|
-
thread_id = config["configurable"]["thread_id"]
|
456
|
-
thread_ts = config["configurable"].get("thread_ts")
|
457
|
-
with self._get_sync_connection() as conn:
|
458
|
-
with conn.cursor() as cur:
|
459
|
-
if thread_ts:
|
460
|
-
cur.execute(
|
461
|
-
"SELECT checkpoint, parent_ts "
|
462
|
-
"FROM checkpoints "
|
463
|
-
"WHERE thread_id = %(thread_id)s AND thread_ts = %(thread_ts)s",
|
464
|
-
{
|
465
|
-
"thread_id": thread_id,
|
466
|
-
"thread_ts": thread_ts,
|
467
|
-
},
|
468
|
-
)
|
469
|
-
value = cur.fetchone()
|
470
|
-
if value:
|
471
|
-
return CheckpointTuple(
|
472
|
-
config,
|
473
|
-
self.serializer.loads(value[0]),
|
474
|
-
{
|
475
|
-
"configurable": {
|
476
|
-
"thread_id": thread_id,
|
477
|
-
"thread_ts": value[1].isoformat(),
|
478
|
-
}
|
479
|
-
}
|
480
|
-
if value[1]
|
481
|
-
else None,
|
482
|
-
)
|
483
|
-
else:
|
484
|
-
cur.execute(
|
485
|
-
"SELECT checkpoint, thread_ts, parent_ts "
|
486
|
-
"FROM checkpoints "
|
487
|
-
"WHERE thread_id = %(thread_id)s "
|
488
|
-
"ORDER BY thread_ts DESC LIMIT 1",
|
489
|
-
{
|
490
|
-
"thread_id": thread_id,
|
491
|
-
},
|
492
|
-
)
|
493
|
-
value = cur.fetchone()
|
494
|
-
if value:
|
495
|
-
return CheckpointTuple(
|
496
|
-
config={
|
497
|
-
"configurable": {
|
498
|
-
"thread_id": thread_id,
|
499
|
-
"thread_ts": value[1].isoformat(),
|
500
|
-
}
|
501
|
-
},
|
502
|
-
checkpoint=self.serializer.loads(value[0]),
|
503
|
-
parent_config={
|
504
|
-
"configurable": {
|
505
|
-
"thread_id": thread_id,
|
506
|
-
"thread_ts": value[2].isoformat(),
|
507
|
-
}
|
508
|
-
}
|
509
|
-
if value[2]
|
510
|
-
else None,
|
511
|
-
)
|
512
|
-
return None
|
513
|
-
|
514
|
-
async def aget_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
|
515
|
-
"""Get the checkpoint tuple for the given configuration.
|
516
|
-
|
517
|
-
Args:
|
518
|
-
config: The configuration for the checkpoint.
|
519
|
-
A dict with a `configurable` key which is a dict with
|
520
|
-
a `thread_id` key and an optional `thread_ts` key.
|
521
|
-
For example, { 'configurable': { 'thread_id': 'test_thread' } }
|
522
|
-
|
523
|
-
Returns:
|
524
|
-
The checkpoint tuple for the given configuration if it exists,
|
525
|
-
otherwise None.
|
526
|
-
|
527
|
-
If thread_ts is None, the latest checkpoint is returned if it exists.
|
528
|
-
"""
|
529
|
-
thread_id = config["configurable"]["thread_id"]
|
530
|
-
thread_ts = config["configurable"].get("thread_ts")
|
531
|
-
async with self._get_async_connection() as conn:
|
532
|
-
async with conn.cursor() as cur:
|
533
|
-
if thread_ts:
|
534
|
-
await cur.execute(
|
535
|
-
"SELECT checkpoint, parent_ts "
|
536
|
-
"FROM checkpoints "
|
537
|
-
"WHERE thread_id = %(thread_id)s AND thread_ts = %(thread_ts)s",
|
538
|
-
{
|
539
|
-
"thread_id": thread_id,
|
540
|
-
"thread_ts": thread_ts,
|
541
|
-
},
|
542
|
-
)
|
543
|
-
value = await cur.fetchone()
|
544
|
-
if value:
|
545
|
-
return CheckpointTuple(
|
546
|
-
config,
|
547
|
-
self.serializer.loads(value[0]),
|
548
|
-
{
|
549
|
-
"configurable": {
|
550
|
-
"thread_id": thread_id,
|
551
|
-
"thread_ts": value[1].isoformat(),
|
552
|
-
}
|
553
|
-
}
|
554
|
-
if value[1]
|
555
|
-
else None,
|
556
|
-
)
|
557
|
-
else:
|
558
|
-
await cur.execute(
|
559
|
-
"SELECT checkpoint, thread_ts, parent_ts "
|
560
|
-
"FROM checkpoints "
|
561
|
-
"WHERE thread_id = %(thread_id)s "
|
562
|
-
"ORDER BY thread_ts DESC LIMIT 1",
|
563
|
-
{
|
564
|
-
"thread_id": thread_id,
|
565
|
-
},
|
566
|
-
)
|
567
|
-
value = await cur.fetchone()
|
568
|
-
if value:
|
569
|
-
return CheckpointTuple(
|
570
|
-
config={
|
571
|
-
"configurable": {
|
572
|
-
"thread_id": thread_id,
|
573
|
-
"thread_ts": value[1].isoformat(),
|
574
|
-
}
|
575
|
-
},
|
576
|
-
checkpoint=self.serializer.loads(value[0]),
|
577
|
-
parent_config={
|
578
|
-
"configurable": {
|
579
|
-
"thread_id": thread_id,
|
580
|
-
"thread_ts": value[2].isoformat(),
|
581
|
-
}
|
582
|
-
}
|
583
|
-
if value[2]
|
584
|
-
else None,
|
585
|
-
)
|
586
|
-
|
587
|
-
return None
|
@@ -1,10 +0,0 @@
|
|
1
|
-
langchain_postgres/__init__.py,sha256=IMtNMHfY5cWhBuJ8M8diGlOD51L_4Dd741nYa_FeLsY,621
|
2
|
-
langchain_postgres/_utils.py,sha256=Johm50HEgA4qScLDaSDIfJfF3DygjA5KTBtNeVcD63I,2914
|
3
|
-
langchain_postgres/chat_message_histories.py,sha256=gh6hjBlrJ5GSo5kePQdh3VhiUYoWWdP37GXtZ1e25a4,14033
|
4
|
-
langchain_postgres/checkpoint.py,sha256=B0c03jyQcS0bAaNPljWEG3IuhlelIF2z3vSXWATi9-4,23519
|
5
|
-
langchain_postgres/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
langchain_postgres/vectorstores.py,sha256=-oMjtvd9FEANPDk3_97V5MPT__TMRvhibQUrP7q8DQE,50367
|
7
|
-
langchain_postgres-0.0.5.dist-info/LICENSE,sha256=2btS8uNUDWD_UNjw9ba6ZJt_00aUjEw9CGyK-xIHY8c,1072
|
8
|
-
langchain_postgres-0.0.5.dist-info/METADATA,sha256=Z33b8kDnE21iI-LqjsdhsT2OPZLRl_MhfME89xlFSAk,6014
|
9
|
-
langchain_postgres-0.0.5.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
10
|
-
langchain_postgres-0.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|