langgraph-runtime-inmem 0.14.1__tar.gz → 0.16.0__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_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/.gitignore +1 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/PKG-INFO +3 -3
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/__init__.py +1 -1
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/database.py +3 -1
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/lifespan.py +39 -1
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/metrics.py +1 -1
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/ops.py +41 -43
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/pyproject.toml +3 -3
- langgraph_runtime_inmem-0.16.0/uv.lock +1166 -0
- langgraph_runtime_inmem-0.14.1/uv.lock +0 -1003
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/Makefile +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/README.md +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/checkpoint.py +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/inmem_stream.py +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/queue.py +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/retry.py +0 -0
- {langgraph_runtime_inmem-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/store.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-runtime-inmem
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.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
|
|
@@ -142,7 +142,9 @@ class InMemConnectionProto:
|
|
|
142
142
|
|
|
143
143
|
|
|
144
144
|
@asynccontextmanager
|
|
145
|
-
async def connect(
|
|
145
|
+
async def connect(
|
|
146
|
+
*, supports_core_api: bool = False, __test__: bool = False
|
|
147
|
+
) -> AsyncIterator["AsyncConnectionProto"]:
|
|
146
148
|
yield InMemConnectionProto()
|
|
147
149
|
|
|
148
150
|
|
|
@@ -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-0.14.1 → langgraph_runtime_inmem-0.16.0}/langgraph_runtime_inmem/ops.py
RENAMED
|
@@ -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(
|
|
@@ -2107,7 +2120,6 @@ class Runs(Authenticated):
|
|
|
2107
2120
|
ctx: Auth.types.BaseAuthContext | None = None,
|
|
2108
2121
|
) -> AsyncIterator[Run]:
|
|
2109
2122
|
"""Create a run."""
|
|
2110
|
-
from langgraph_api.config import FF_RICH_THREADS
|
|
2111
2123
|
from langgraph_api.schema import Run, Thread
|
|
2112
2124
|
|
|
2113
2125
|
assistant_id = _ensure_uuid(assistant_id)
|
|
@@ -2154,49 +2166,35 @@ class Runs(Authenticated):
|
|
|
2154
2166
|
# Create new thread
|
|
2155
2167
|
if thread_id is None:
|
|
2156
2168
|
thread_id = uuid4()
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
},
|
|
2175
|
-
),
|
|
2176
|
-
created_at=datetime.now(UTC),
|
|
2177
|
-
updated_at=datetime.now(UTC),
|
|
2178
|
-
values=b"",
|
|
2179
|
-
)
|
|
2180
|
-
else:
|
|
2181
|
-
thread = Thread(
|
|
2182
|
-
thread_id=thread_id,
|
|
2183
|
-
status="idle",
|
|
2184
|
-
metadata={
|
|
2185
|
-
"graph_id": assistant["graph_id"],
|
|
2186
|
-
"assistant_id": str(assistant_id),
|
|
2187
|
-
**(config.get("metadata") or {}),
|
|
2188
|
-
**metadata,
|
|
2169
|
+
|
|
2170
|
+
thread = Thread(
|
|
2171
|
+
thread_id=thread_id,
|
|
2172
|
+
status="busy",
|
|
2173
|
+
metadata={
|
|
2174
|
+
"graph_id": assistant["graph_id"],
|
|
2175
|
+
"assistant_id": str(assistant_id),
|
|
2176
|
+
**(config.get("metadata") or {}),
|
|
2177
|
+
**metadata,
|
|
2178
|
+
},
|
|
2179
|
+
config=Runs._merge_jsonb(
|
|
2180
|
+
assistant["config"],
|
|
2181
|
+
config,
|
|
2182
|
+
{
|
|
2183
|
+
"configurable": Runs._merge_jsonb(
|
|
2184
|
+
Runs._get_configurable(assistant["config"]),
|
|
2185
|
+
)
|
|
2189
2186
|
},
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2187
|
+
),
|
|
2188
|
+
created_at=datetime.now(UTC),
|
|
2189
|
+
updated_at=datetime.now(UTC),
|
|
2190
|
+
values=b"",
|
|
2191
|
+
)
|
|
2192
|
+
|
|
2195
2193
|
await logger.ainfo("Creating thread", thread_id=thread_id)
|
|
2196
2194
|
conn.store["threads"].append(thread)
|
|
2197
2195
|
elif existing_thread:
|
|
2198
2196
|
# Update existing thread
|
|
2199
|
-
if
|
|
2197
|
+
if existing_thread["status"] != "busy":
|
|
2200
2198
|
existing_thread["status"] = "busy"
|
|
2201
2199
|
existing_thread["metadata"] = Runs._merge_jsonb(
|
|
2202
2200
|
existing_thread["metadata"],
|
|
@@ -14,11 +14,11 @@ readme = "README.md"
|
|
|
14
14
|
requires-python = ">=3.11.0"
|
|
15
15
|
dependencies = [
|
|
16
16
|
"blockbuster>=1.5.24,<2.0.0",
|
|
17
|
-
"langgraph>=0.2",
|
|
17
|
+
"langgraph>=0.4.10,<2",
|
|
18
18
|
"structlog>23",
|
|
19
19
|
"sse-starlette>=2",
|
|
20
20
|
"starlette>=0.37",
|
|
21
|
-
"langgraph-checkpoint>=
|
|
21
|
+
"langgraph-checkpoint>=3,<4",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
[dependency-groups]
|
|
@@ -62,4 +62,4 @@ exclude = [
|
|
|
62
62
|
[tool.ruff]
|
|
63
63
|
lint.select = ["E", "F", "UP", "B", "I"]
|
|
64
64
|
lint.ignore = ["E501", "B008"]
|
|
65
|
-
target-version = "py311"
|
|
65
|
+
target-version = "py311"
|