langgraph-runtime-inmem 0.14.0__py3-none-any.whl → 0.15.0__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.
- langgraph_runtime_inmem/__init__.py +1 -1
- langgraph_runtime_inmem/lifespan.py +39 -1
- langgraph_runtime_inmem/metrics.py +1 -1
- langgraph_runtime_inmem/ops.py +29 -9
- langgraph_runtime_inmem/queue.py +1 -0
- {langgraph_runtime_inmem-0.14.0.dist-info → langgraph_runtime_inmem-0.15.0.dist-info}/METADATA +3 -3
- langgraph_runtime_inmem-0.15.0.dist-info/RECORD +13 -0
- langgraph_runtime_inmem-0.14.0.dist-info/RECORD +0 -13
- {langgraph_runtime_inmem-0.14.0.dist-info → langgraph_runtime_inmem-0.15.0.dist-info}/WHEEL +0 -0
|
@@ -14,6 +14,13 @@ from langgraph_runtime_inmem.database import start_pool, stop_pool
|
|
|
14
14
|
logger = structlog.stdlib.get_logger(__name__)
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
_LAST_LIFESPAN_ERROR: BaseException | None = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_last_error() -> BaseException | None:
|
|
21
|
+
return _LAST_LIFESPAN_ERROR
|
|
22
|
+
|
|
23
|
+
|
|
17
24
|
@asynccontextmanager
|
|
18
25
|
async def lifespan(
|
|
19
26
|
app: Starlette | None = None,
|
|
@@ -42,9 +49,27 @@ async def lifespan(
|
|
|
42
49
|
except RuntimeError:
|
|
43
50
|
await logger.aerror("Failed to set loop")
|
|
44
51
|
|
|
52
|
+
global _LAST_LIFESPAN_ERROR
|
|
53
|
+
_LAST_LIFESPAN_ERROR = None
|
|
54
|
+
|
|
45
55
|
await start_http_client()
|
|
46
56
|
await start_pool()
|
|
47
57
|
await start_ui_bundler()
|
|
58
|
+
|
|
59
|
+
async def _log_graph_load_failure(err: graph.GraphLoadError) -> None:
|
|
60
|
+
cause = err.__cause__ or err.cause
|
|
61
|
+
log_fields = err.log_fields()
|
|
62
|
+
log_fields["action"] = "fix_user_graph"
|
|
63
|
+
await logger.aerror(
|
|
64
|
+
f"Graph '{err.spec.id}' failed to load: {err.cause_message}",
|
|
65
|
+
**log_fields,
|
|
66
|
+
)
|
|
67
|
+
await logger.adebug(
|
|
68
|
+
"Full graph load failure traceback (internal)",
|
|
69
|
+
**{k: v for k, v in log_fields.items() if k != "user_traceback"},
|
|
70
|
+
exc_info=cause,
|
|
71
|
+
)
|
|
72
|
+
|
|
48
73
|
try:
|
|
49
74
|
async with SimpleTaskGroup(
|
|
50
75
|
cancel=True,
|
|
@@ -77,11 +102,21 @@ async def lifespan(
|
|
|
77
102
|
var_child_runnable_config.set(langgraph_config)
|
|
78
103
|
|
|
79
104
|
# Keep after the setter above so users can access the store from within the factory function
|
|
80
|
-
|
|
105
|
+
try:
|
|
106
|
+
await graph.collect_graphs_from_env(True)
|
|
107
|
+
except graph.GraphLoadError as exc:
|
|
108
|
+
_LAST_LIFESPAN_ERROR = exc
|
|
109
|
+
await _log_graph_load_failure(exc)
|
|
110
|
+
raise
|
|
81
111
|
if config.N_JOBS_PER_WORKER > 0:
|
|
82
112
|
tg.create_task(queue_with_signal())
|
|
83
113
|
|
|
84
114
|
yield
|
|
115
|
+
except graph.GraphLoadError as exc:
|
|
116
|
+
_LAST_LIFESPAN_ERROR = exc
|
|
117
|
+
raise
|
|
118
|
+
except asyncio.CancelledError:
|
|
119
|
+
pass
|
|
85
120
|
finally:
|
|
86
121
|
await api_store.exit_store()
|
|
87
122
|
await stop_ui_bundler()
|
|
@@ -98,3 +133,6 @@ async def queue_with_signal():
|
|
|
98
133
|
except Exception as exc:
|
|
99
134
|
logger.exception("Queue failed. Signaling shutdown", exc_info=exc)
|
|
100
135
|
signal.raise_signal(signal.SIGINT)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
lifespan.get_last_error = get_last_error # type: ignore[attr-defined]
|
langgraph_runtime_inmem/ops.py
CHANGED
|
@@ -556,6 +556,8 @@ class Assistants(Authenticated):
|
|
|
556
556
|
"metadata": version_data["metadata"],
|
|
557
557
|
"version": version_data["version"],
|
|
558
558
|
"updated_at": datetime.now(UTC),
|
|
559
|
+
"name": version_data["name"],
|
|
560
|
+
"description": version_data["description"],
|
|
559
561
|
}
|
|
560
562
|
)
|
|
561
563
|
|
|
@@ -1230,13 +1232,23 @@ class Threads(Authenticated):
|
|
|
1230
1232
|
"""Create a copy of an existing thread."""
|
|
1231
1233
|
thread_id = _ensure_uuid(thread_id)
|
|
1232
1234
|
new_thread_id = uuid4()
|
|
1233
|
-
|
|
1235
|
+
read_filters = await Threads.handle_event(
|
|
1234
1236
|
ctx,
|
|
1235
1237
|
"read",
|
|
1236
1238
|
Auth.types.ThreadsRead(
|
|
1239
|
+
thread_id=thread_id,
|
|
1240
|
+
),
|
|
1241
|
+
)
|
|
1242
|
+
# Assert that the user has permissions to create a new thread.
|
|
1243
|
+
# (We don't actually need the filters.)
|
|
1244
|
+
await Threads.handle_event(
|
|
1245
|
+
ctx,
|
|
1246
|
+
"create",
|
|
1247
|
+
Auth.types.ThreadsCreate(
|
|
1237
1248
|
thread_id=new_thread_id,
|
|
1238
1249
|
),
|
|
1239
1250
|
)
|
|
1251
|
+
|
|
1240
1252
|
async with conn.pipeline():
|
|
1241
1253
|
# Find the original thread in our store
|
|
1242
1254
|
original_thread = next(
|
|
@@ -1245,8 +1257,8 @@ class Threads(Authenticated):
|
|
|
1245
1257
|
|
|
1246
1258
|
if not original_thread:
|
|
1247
1259
|
return _empty_generator()
|
|
1248
|
-
if
|
|
1249
|
-
original_thread["metadata"],
|
|
1260
|
+
if read_filters and not _check_filter_match(
|
|
1261
|
+
original_thread["metadata"], read_filters
|
|
1250
1262
|
):
|
|
1251
1263
|
return _empty_generator()
|
|
1252
1264
|
|
|
@@ -1399,6 +1411,7 @@ class Threads(Authenticated):
|
|
|
1399
1411
|
"""Add state to a thread."""
|
|
1400
1412
|
from langgraph_api.graph import get_graph
|
|
1401
1413
|
from langgraph_api.schema import ThreadUpdateResponse
|
|
1414
|
+
from langgraph_api.state import state_snapshot_to_thread_state
|
|
1402
1415
|
from langgraph_api.store import get_store
|
|
1403
1416
|
from langgraph_api.utils import fetchone
|
|
1404
1417
|
|
|
@@ -1487,7 +1500,7 @@ class Threads(Authenticated):
|
|
|
1487
1500
|
from langgraph_api.serde import json_dumpb
|
|
1488
1501
|
|
|
1489
1502
|
event_data = {
|
|
1490
|
-
"state": state,
|
|
1503
|
+
"state": state_snapshot_to_thread_state(state),
|
|
1491
1504
|
"thread_id": str(thread_id),
|
|
1492
1505
|
}
|
|
1493
1506
|
await Threads.Stream.publish(
|
|
@@ -2933,11 +2946,18 @@ def _check_filter_match(metadata: dict, filters: Auth.types.FilterType | None) -
|
|
|
2933
2946
|
if key not in metadata or metadata[key] != filter_value:
|
|
2934
2947
|
return False
|
|
2935
2948
|
elif op == "$contains":
|
|
2936
|
-
if (
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2949
|
+
if key not in metadata or not isinstance(metadata[key], list):
|
|
2950
|
+
return False
|
|
2951
|
+
|
|
2952
|
+
if isinstance(filter_value, list):
|
|
2953
|
+
# Mimick Postgres containment operator behavior.
|
|
2954
|
+
# It would be more efficient to use set operations here,
|
|
2955
|
+
# but we can't assume that elements are hashable.
|
|
2956
|
+
# The Postgres algorithm is also O(n^2).
|
|
2957
|
+
for filter_element in filter_value:
|
|
2958
|
+
if filter_element not in metadata[key]:
|
|
2959
|
+
return False
|
|
2960
|
+
elif filter_value not in metadata[key]:
|
|
2941
2961
|
return False
|
|
2942
2962
|
else:
|
|
2943
2963
|
# Direct equality
|
langgraph_runtime_inmem/queue.py
CHANGED
|
@@ -172,6 +172,7 @@ def _enable_blockbuster():
|
|
|
172
172
|
("memory/__init__.py", "sync"),
|
|
173
173
|
("memory/__init__.py", "load"),
|
|
174
174
|
("memory/__init__.py", "dump"),
|
|
175
|
+
("pydantic/main.py", "__init__"),
|
|
175
176
|
):
|
|
176
177
|
bb.functions["io.TextIOWrapper.read"].can_block_in(module, func)
|
|
177
178
|
bb.functions["io.TextIOWrapper.write"].can_block_in(module, func)
|
{langgraph_runtime_inmem-0.14.0.dist-info → langgraph_runtime_inmem-0.15.0.dist-info}/METADATA
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-runtime-inmem
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Inmem implementation for the LangGraph API server.
|
|
5
5
|
Author-email: Will Fu-Hinthorn <will@langchain.dev>
|
|
6
6
|
License: Elastic-2.0
|
|
7
7
|
Requires-Python: >=3.11.0
|
|
8
8
|
Requires-Dist: blockbuster<2.0.0,>=1.5.24
|
|
9
|
-
Requires-Dist: langgraph-checkpoint
|
|
10
|
-
Requires-Dist: langgraph
|
|
9
|
+
Requires-Dist: langgraph-checkpoint<4,>=3
|
|
10
|
+
Requires-Dist: langgraph<2,>=0.4.10
|
|
11
11
|
Requires-Dist: sse-starlette>=2
|
|
12
12
|
Requires-Dist: starlette>=0.37
|
|
13
13
|
Requires-Dist: structlog>23
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
langgraph_runtime_inmem/__init__.py,sha256=PQldy7XpkzOuPFy0MncSqMKD4D6bNmAChE5P1uwYzas,311
|
|
2
|
+
langgraph_runtime_inmem/checkpoint.py,sha256=nc1G8DqVdIu-ibjKTqXfbPfMbAsKjPObKqegrSzo6Po,4432
|
|
3
|
+
langgraph_runtime_inmem/database.py,sha256=QgaA_WQo1IY6QioYd8r-e6-0B0rnC5anS0muIEJWby0,6364
|
|
4
|
+
langgraph_runtime_inmem/inmem_stream.py,sha256=PFLWbsxU8RqbT5mYJgNk6v5q6TWJRIY1hkZWhJF8nkI,9094
|
|
5
|
+
langgraph_runtime_inmem/lifespan.py,sha256=fCoYcN_h0cxmj6-muC-f0csPdSpyepZuGRD1yBrq4XM,4755
|
|
6
|
+
langgraph_runtime_inmem/metrics.py,sha256=_YiSkLnhQvHpMktk38SZo0abyL-5GihfVAtBo0-lFIc,403
|
|
7
|
+
langgraph_runtime_inmem/ops.py,sha256=l27lXDzlx6bM--j-mKS_fXi2SEvKBbLrU3aMcQ-QwYc,108630
|
|
8
|
+
langgraph_runtime_inmem/queue.py,sha256=yV781CDjlsKNvkJ3puHyiHNnJpIIdB1G_gTY9dg6mys,9994
|
|
9
|
+
langgraph_runtime_inmem/retry.py,sha256=XmldOP4e_H5s264CagJRVnQMDFcEJR_dldVR1Hm5XvM,763
|
|
10
|
+
langgraph_runtime_inmem/store.py,sha256=rTfL1JJvd-j4xjTrL8qDcynaWF6gUJ9-GDVwH0NBD_I,3506
|
|
11
|
+
langgraph_runtime_inmem-0.15.0.dist-info/METADATA,sha256=ITNngpey-5LmTzIg1XcFrIp5vDmq8jzAVsmtkZrfjqY,570
|
|
12
|
+
langgraph_runtime_inmem-0.15.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
langgraph_runtime_inmem-0.15.0.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
langgraph_runtime_inmem/__init__.py,sha256=csu7K0Iyy69kpS21MCa9q3MkfeJLSBXmsT02eK_hGXc,311
|
|
2
|
-
langgraph_runtime_inmem/checkpoint.py,sha256=nc1G8DqVdIu-ibjKTqXfbPfMbAsKjPObKqegrSzo6Po,4432
|
|
3
|
-
langgraph_runtime_inmem/database.py,sha256=QgaA_WQo1IY6QioYd8r-e6-0B0rnC5anS0muIEJWby0,6364
|
|
4
|
-
langgraph_runtime_inmem/inmem_stream.py,sha256=PFLWbsxU8RqbT5mYJgNk6v5q6TWJRIY1hkZWhJF8nkI,9094
|
|
5
|
-
langgraph_runtime_inmem/lifespan.py,sha256=tngIYHMhDwTFd2zgpq9CZOxcBLONYYnkhwv2d2T5WWQ,3614
|
|
6
|
-
langgraph_runtime_inmem/metrics.py,sha256=HhO0RC2bMDTDyGBNvnd2ooLebLA8P1u5oq978Kp_nAA,392
|
|
7
|
-
langgraph_runtime_inmem/ops.py,sha256=63uV88PijGnNxzgWGL_SljeXIeHd8dAwowBrWi9X4Xo,107645
|
|
8
|
-
langgraph_runtime_inmem/queue.py,sha256=33qfFKPhQicZ1qiibllYb-bTFzUNSN2c4bffPACP5es,9952
|
|
9
|
-
langgraph_runtime_inmem/retry.py,sha256=XmldOP4e_H5s264CagJRVnQMDFcEJR_dldVR1Hm5XvM,763
|
|
10
|
-
langgraph_runtime_inmem/store.py,sha256=rTfL1JJvd-j4xjTrL8qDcynaWF6gUJ9-GDVwH0NBD_I,3506
|
|
11
|
-
langgraph_runtime_inmem-0.14.0.dist-info/METADATA,sha256=jegaYI5exlmydXtt4oxMbgFBCIrKaV7HawwHKNr2MrU,566
|
|
12
|
-
langgraph_runtime_inmem-0.14.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
-
langgraph_runtime_inmem-0.14.0.dist-info/RECORD,,
|
|
File without changes
|