langgraph-checkpoint-sqlite 1.0.0__tar.gz → 1.0.1__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_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/PKG-INFO +2 -3
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/README.md +1 -3
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/langgraph/checkpoint/sqlite/__init__.py +22 -12
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/langgraph/checkpoint/sqlite/aio.py +34 -25
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/langgraph/checkpoint/sqlite/utils.py +8 -3
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/pyproject.toml +2 -2
- {langgraph_checkpoint_sqlite-1.0.0 → langgraph_checkpoint_sqlite-1.0.1}/langgraph/checkpoint/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-checkpoint-sqlite
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Library with a SQLite implementation of LangGraph checkpoint saver.
|
|
5
5
|
Home-page: https://www.github.com/langchain-ai/langgraph
|
|
6
6
|
License: MIT
|
|
@@ -53,7 +53,6 @@ with SqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"pending_sends": [],
|
|
56
|
-
"current_tasks": {}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
# store checkpoint
|
|
@@ -96,7 +95,6 @@ async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
96
95
|
}
|
|
97
96
|
},
|
|
98
97
|
"pending_sends": [],
|
|
99
|
-
"current_tasks": {}
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
# store checkpoint
|
|
@@ -108,3 +106,4 @@ async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
108
106
|
# list checkpoints
|
|
109
107
|
[c async for c in checkpointer.alist(read_config)]
|
|
110
108
|
```
|
|
109
|
+
|
|
@@ -35,7 +35,6 @@ with SqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"pending_sends": [],
|
|
38
|
-
"current_tasks": {}
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
# store checkpoint
|
|
@@ -78,7 +77,6 @@ async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
78
77
|
}
|
|
79
78
|
},
|
|
80
79
|
"pending_sends": [],
|
|
81
|
-
"current_tasks": {}
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
# store checkpoint
|
|
@@ -89,4 +87,4 @@ async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
|
89
87
|
|
|
90
88
|
# list checkpoints
|
|
91
89
|
[c async for c in checkpointer.alist(read_config)]
|
|
92
|
-
```
|
|
90
|
+
```
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import sqlite3
|
|
2
2
|
import threading
|
|
3
|
-
from contextlib import contextmanager
|
|
3
|
+
from contextlib import closing, contextmanager
|
|
4
4
|
from hashlib import md5
|
|
5
5
|
from typing import Any, AsyncIterator, Dict, Iterator, Optional, Sequence, Tuple
|
|
6
6
|
|
|
7
7
|
from langchain_core.runnables import RunnableConfig
|
|
8
8
|
|
|
9
9
|
from langgraph.checkpoint.base import (
|
|
10
|
+
WRITES_IDX_MAP,
|
|
10
11
|
BaseCheckpointSaver,
|
|
11
12
|
ChannelVersions,
|
|
12
13
|
Checkpoint,
|
|
@@ -176,7 +177,7 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
176
177
|
|
|
177
178
|
This method retrieves a checkpoint tuple from the SQLite database based on the
|
|
178
179
|
provided config. If the config contains a "checkpoint_id" key, the checkpoint with
|
|
179
|
-
the matching thread ID and
|
|
180
|
+
the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint
|
|
180
181
|
for the given thread ID is retrieved.
|
|
181
182
|
|
|
182
183
|
Args:
|
|
@@ -193,12 +194,12 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
193
194
|
>>> print(checkpoint_tuple)
|
|
194
195
|
CheckpointTuple(...)
|
|
195
196
|
|
|
196
|
-
With
|
|
197
|
+
With checkpoint ID:
|
|
197
198
|
|
|
198
199
|
>>> config = {
|
|
199
200
|
... "configurable": {
|
|
200
201
|
... "thread_id": "1",
|
|
201
|
-
|
|
202
|
+
... "checkpoint_ns": "",
|
|
202
203
|
... "checkpoint_id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
203
204
|
... }
|
|
204
205
|
... }
|
|
@@ -243,7 +244,7 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
243
244
|
}
|
|
244
245
|
# find any pending writes
|
|
245
246
|
cur.execute(
|
|
246
|
-
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ?",
|
|
247
|
+
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ? ORDER BY task_id, idx",
|
|
247
248
|
(
|
|
248
249
|
str(config["configurable"]["thread_id"]),
|
|
249
250
|
checkpoint_ns,
|
|
@@ -283,12 +284,12 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
283
284
|
"""List checkpoints from the database.
|
|
284
285
|
|
|
285
286
|
This method retrieves a list of checkpoint tuples from the SQLite database based
|
|
286
|
-
on the provided config. The checkpoints are ordered by
|
|
287
|
+
on the provided config. The checkpoints are ordered by checkpoint ID in descending order (newest first).
|
|
287
288
|
|
|
288
289
|
Args:
|
|
289
290
|
config (RunnableConfig): The config to use for listing the checkpoints.
|
|
290
291
|
filter (Optional[Dict[str, Any]]): Additional filtering criteria for metadata. Defaults to None.
|
|
291
|
-
before (Optional[RunnableConfig]): If provided, only checkpoints before the specified
|
|
292
|
+
before (Optional[RunnableConfig]): If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
|
|
292
293
|
limit (Optional[int]): The maximum number of checkpoints to return. Defaults to None.
|
|
293
294
|
|
|
294
295
|
Yields:
|
|
@@ -318,7 +319,7 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
318
319
|
ORDER BY checkpoint_id DESC"""
|
|
319
320
|
if limit:
|
|
320
321
|
query += f" LIMIT {limit}"
|
|
321
|
-
with self.cursor(transaction=False) as cur:
|
|
322
|
+
with self.cursor(transaction=False) as cur, closing(self.conn.cursor()) as wcur:
|
|
322
323
|
cur.execute(query, param_values)
|
|
323
324
|
for (
|
|
324
325
|
thread_id,
|
|
@@ -329,6 +330,10 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
329
330
|
checkpoint,
|
|
330
331
|
metadata,
|
|
331
332
|
) in cur:
|
|
333
|
+
wcur.execute(
|
|
334
|
+
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ? ORDER BY task_id, idx",
|
|
335
|
+
(thread_id, checkpoint_ns, checkpoint_id),
|
|
336
|
+
)
|
|
332
337
|
yield CheckpointTuple(
|
|
333
338
|
{
|
|
334
339
|
"configurable": {
|
|
@@ -350,6 +355,10 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
350
355
|
if parent_checkpoint_id
|
|
351
356
|
else None
|
|
352
357
|
),
|
|
358
|
+
[
|
|
359
|
+
(task_id, channel, self.serde.loads_typed((type, value)))
|
|
360
|
+
for task_id, channel, type, value in wcur
|
|
361
|
+
],
|
|
353
362
|
)
|
|
354
363
|
|
|
355
364
|
def put(
|
|
@@ -367,10 +376,11 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
367
376
|
Args:
|
|
368
377
|
config (RunnableConfig): The config to associate with the checkpoint.
|
|
369
378
|
checkpoint (Checkpoint): The checkpoint to save.
|
|
370
|
-
metadata (
|
|
379
|
+
metadata (CheckpointMetadata): Additional metadata to save with the checkpoint.
|
|
380
|
+
new_versions (ChannelVersions): New channel versions as of this write.
|
|
371
381
|
|
|
372
382
|
Returns:
|
|
373
|
-
RunnableConfig:
|
|
383
|
+
RunnableConfig: Updated configuration after storing the checkpoint.
|
|
374
384
|
|
|
375
385
|
Examples:
|
|
376
386
|
|
|
@@ -424,14 +434,14 @@ class SqliteSaver(BaseCheckpointSaver):
|
|
|
424
434
|
"""
|
|
425
435
|
with self.lock, self.cursor() as cur:
|
|
426
436
|
cur.executemany(
|
|
427
|
-
"INSERT OR
|
|
437
|
+
"INSERT OR IGNORE INTO writes (thread_id, checkpoint_ns, checkpoint_id, task_id, idx, channel, type, value) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
|
428
438
|
[
|
|
429
439
|
(
|
|
430
440
|
str(config["configurable"]["thread_id"]),
|
|
431
441
|
str(config["configurable"]["checkpoint_ns"]),
|
|
432
442
|
str(config["configurable"]["checkpoint_id"]),
|
|
433
443
|
task_id,
|
|
434
|
-
idx,
|
|
444
|
+
WRITES_IDX_MAP.get(channel, idx),
|
|
435
445
|
channel,
|
|
436
446
|
*self.serde.dumps_typed(value),
|
|
437
447
|
)
|
|
@@ -16,6 +16,7 @@ import aiosqlite
|
|
|
16
16
|
from langchain_core.runnables import RunnableConfig
|
|
17
17
|
|
|
18
18
|
from langgraph.checkpoint.base import (
|
|
19
|
+
WRITES_IDX_MAP,
|
|
19
20
|
BaseCheckpointSaver,
|
|
20
21
|
ChannelVersions,
|
|
21
22
|
Checkpoint,
|
|
@@ -230,7 +231,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
230
231
|
|
|
231
232
|
This method retrieves a checkpoint tuple from the SQLite database based on the
|
|
232
233
|
provided config. If the config contains a "checkpoint_id" key, the checkpoint with
|
|
233
|
-
the matching thread ID and
|
|
234
|
+
the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint
|
|
234
235
|
for the given thread ID is retrieved.
|
|
235
236
|
|
|
236
237
|
Args:
|
|
@@ -277,7 +278,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
277
278
|
}
|
|
278
279
|
# find any pending writes
|
|
279
280
|
await cur.execute(
|
|
280
|
-
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ?",
|
|
281
|
+
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ? ORDER BY task_id, idx",
|
|
281
282
|
(
|
|
282
283
|
str(config["configurable"]["thread_id"]),
|
|
283
284
|
checkpoint_ns,
|
|
@@ -317,26 +318,26 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
317
318
|
"""List checkpoints from the database asynchronously.
|
|
318
319
|
|
|
319
320
|
This method retrieves a list of checkpoint tuples from the SQLite database based
|
|
320
|
-
on the provided config. The checkpoints are ordered by
|
|
321
|
+
on the provided config. The checkpoints are ordered by checkpoint ID in descending order (newest first).
|
|
321
322
|
|
|
322
323
|
Args:
|
|
323
324
|
config (Optional[RunnableConfig]): Base configuration for filtering checkpoints.
|
|
324
325
|
filter (Optional[Dict[str, Any]]): Additional filtering criteria for metadata.
|
|
325
|
-
before (Optional[RunnableConfig]):
|
|
326
|
+
before (Optional[RunnableConfig]): If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
|
|
326
327
|
limit (Optional[int]): Maximum number of checkpoints to return.
|
|
327
328
|
|
|
328
329
|
Yields:
|
|
329
330
|
AsyncIterator[CheckpointTuple]: An asynchronous iterator of matching checkpoint tuples.
|
|
330
331
|
"""
|
|
331
332
|
await self.setup()
|
|
332
|
-
where,
|
|
333
|
+
where, params = search_where(config, filter, before)
|
|
333
334
|
query = f"""SELECT thread_id, checkpoint_ns, checkpoint_id, parent_checkpoint_id, type, checkpoint, metadata
|
|
334
335
|
FROM checkpoints
|
|
335
336
|
{where}
|
|
336
337
|
ORDER BY checkpoint_id DESC"""
|
|
337
338
|
if limit:
|
|
338
339
|
query += f" LIMIT {limit}"
|
|
339
|
-
async with self.conn.execute(query,
|
|
340
|
+
async with self.conn.execute(query, params) as cur, self.conn.cursor() as wcur:
|
|
340
341
|
async for (
|
|
341
342
|
thread_id,
|
|
342
343
|
checkpoint_ns,
|
|
@@ -345,7 +346,11 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
345
346
|
type,
|
|
346
347
|
checkpoint,
|
|
347
348
|
metadata,
|
|
348
|
-
) in
|
|
349
|
+
) in cur:
|
|
350
|
+
await wcur.execute(
|
|
351
|
+
"SELECT task_id, channel, type, value FROM writes WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id = ? ORDER BY task_id, idx",
|
|
352
|
+
(thread_id, checkpoint_ns, checkpoint_id),
|
|
353
|
+
)
|
|
349
354
|
yield CheckpointTuple(
|
|
350
355
|
{
|
|
351
356
|
"configurable": {
|
|
@@ -367,6 +372,10 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
367
372
|
if parent_checkpoint_id
|
|
368
373
|
else None
|
|
369
374
|
),
|
|
375
|
+
[
|
|
376
|
+
(task_id, channel, self.serde.loads_typed((type, value)))
|
|
377
|
+
async for task_id, channel, type, value in wcur
|
|
378
|
+
],
|
|
370
379
|
)
|
|
371
380
|
|
|
372
381
|
async def aput(
|
|
@@ -385,10 +394,10 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
385
394
|
config (RunnableConfig): The config to associate with the checkpoint.
|
|
386
395
|
checkpoint (Checkpoint): The checkpoint to save.
|
|
387
396
|
metadata (CheckpointMetadata): Additional metadata to save with the checkpoint.
|
|
388
|
-
new_versions (
|
|
397
|
+
new_versions (ChannelVersions): New channel versions as of this write.
|
|
389
398
|
|
|
390
399
|
Returns:
|
|
391
|
-
RunnableConfig:
|
|
400
|
+
RunnableConfig: Updated configuration after storing the checkpoint.
|
|
392
401
|
"""
|
|
393
402
|
await self.setup()
|
|
394
403
|
thread_id = config["configurable"]["thread_id"]
|
|
@@ -432,19 +441,19 @@ class AsyncSqliteSaver(BaseCheckpointSaver):
|
|
|
432
441
|
task_id (str): Identifier for the task creating the writes.
|
|
433
442
|
"""
|
|
434
443
|
await self.setup()
|
|
435
|
-
async with self.conn.
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
444
|
+
async with self.conn.cursor() as cur:
|
|
445
|
+
await cur.executemany(
|
|
446
|
+
"INSERT OR IGNORE INTO writes (thread_id, checkpoint_ns, checkpoint_id, task_id, idx, channel, type, value) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
|
447
|
+
[
|
|
448
|
+
(
|
|
449
|
+
str(config["configurable"]["thread_id"]),
|
|
450
|
+
str(config["configurable"]["checkpoint_ns"]),
|
|
451
|
+
str(config["configurable"]["checkpoint_id"]),
|
|
452
|
+
task_id,
|
|
453
|
+
WRITES_IDX_MAP.get(channel, idx),
|
|
454
|
+
channel,
|
|
455
|
+
*self.serde.dumps_typed(value),
|
|
456
|
+
)
|
|
457
|
+
for idx, (channel, value) in enumerate(writes)
|
|
458
|
+
],
|
|
459
|
+
)
|
|
@@ -70,9 +70,14 @@ def search_where(
|
|
|
70
70
|
if config is not None:
|
|
71
71
|
wheres.append("thread_id = ?")
|
|
72
72
|
param_values.append(config["configurable"]["thread_id"])
|
|
73
|
-
checkpoint_ns = config["configurable"].get("checkpoint_ns"
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
checkpoint_ns = config["configurable"].get("checkpoint_ns")
|
|
74
|
+
if checkpoint_ns is not None:
|
|
75
|
+
wheres.append("checkpoint_ns = ?")
|
|
76
|
+
param_values.append(checkpoint_ns)
|
|
77
|
+
|
|
78
|
+
if checkpoint_id := get_checkpoint_id(config):
|
|
79
|
+
wheres.append("checkpoint_id = ?")
|
|
80
|
+
param_values.append(checkpoint_id)
|
|
76
81
|
|
|
77
82
|
# construct predicate for metadata filter
|
|
78
83
|
if filter:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "langgraph-checkpoint-sqlite"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.1"
|
|
4
4
|
description = "Library with a SQLite implementation of LangGraph checkpoint saver."
|
|
5
5
|
authors = []
|
|
6
6
|
license = "MIT"
|
|
@@ -14,7 +14,7 @@ langgraph-checkpoint = "^1.0.1"
|
|
|
14
14
|
aiosqlite = "^0.20.0"
|
|
15
15
|
|
|
16
16
|
[tool.poetry.group.dev.dependencies]
|
|
17
|
-
ruff = "^0.
|
|
17
|
+
ruff = "^0.6.2"
|
|
18
18
|
codespell = "^2.2.0"
|
|
19
19
|
pytest = "^7.2.1"
|
|
20
20
|
pytest-asyncio = "^0.21.1"
|
|
File without changes
|