langgraph-api 0.0.8__py3-none-any.whl → 0.0.9__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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- langgraph_api/api/openapi.py +38 -1
- langgraph_api/api/runs.py +70 -36
- langgraph_api/auth/custom.py +520 -0
- langgraph_api/auth/middleware.py +8 -3
- langgraph_api/cli.py +47 -1
- langgraph_api/config.py +24 -0
- langgraph_api/cron_scheduler.py +32 -27
- langgraph_api/graph.py +0 -11
- langgraph_api/models/run.py +77 -19
- langgraph_api/route.py +2 -0
- langgraph_api/utils.py +32 -0
- {langgraph_api-0.0.8.dist-info → langgraph_api-0.0.9.dist-info}/METADATA +2 -2
- {langgraph_api-0.0.8.dist-info → langgraph_api-0.0.9.dist-info}/RECORD +19 -18
- langgraph_storage/checkpoint.py +16 -0
- langgraph_storage/database.py +17 -1
- langgraph_storage/ops.py +495 -69
- {langgraph_api-0.0.8.dist-info → langgraph_api-0.0.9.dist-info}/LICENSE +0 -0
- {langgraph_api-0.0.8.dist-info → langgraph_api-0.0.9.dist-info}/WHEEL +0 -0
- {langgraph_api-0.0.8.dist-info → langgraph_api-0.0.9.dist-info}/entry_points.txt +0 -0
langgraph_api/cron_scheduler.py
CHANGED
|
@@ -3,9 +3,10 @@ from random import random
|
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
5
|
from langchain_core.runnables.config import run_in_executor
|
|
6
|
+
from starlette.authentication import SimpleUser
|
|
6
7
|
|
|
7
8
|
from langgraph_api.models.run import create_valid_run
|
|
8
|
-
from langgraph_api.utils import next_cron_date
|
|
9
|
+
from langgraph_api.utils import next_cron_date, with_user
|
|
9
10
|
from langgraph_storage.database import connect
|
|
10
11
|
from langgraph_storage.ops import Crons
|
|
11
12
|
from langgraph_storage.retry import retry_db
|
|
@@ -22,35 +23,39 @@ async def cron_scheduler():
|
|
|
22
23
|
try:
|
|
23
24
|
async with connect() as conn:
|
|
24
25
|
async for cron in Crons.next(conn):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
async with with_user(SimpleUser(str(cron["user_id"])), None):
|
|
27
|
+
logger.debug(f"Scheduling cron run {cron}")
|
|
28
|
+
try:
|
|
29
|
+
run_payload = cron["payload"]
|
|
30
|
+
run = await create_valid_run(
|
|
31
|
+
conn,
|
|
32
|
+
thread_id=(
|
|
33
|
+
str(cron.get("thread_id"))
|
|
34
|
+
if cron.get("thread_id")
|
|
35
|
+
else None
|
|
36
|
+
),
|
|
37
|
+
payload=run_payload,
|
|
38
|
+
headers={},
|
|
39
|
+
)
|
|
40
|
+
if not run:
|
|
41
|
+
logger.error(
|
|
42
|
+
"Run not created for cron_id={} payload".format(
|
|
43
|
+
cron["cron_id"],
|
|
44
|
+
)
|
|
41
45
|
)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.error(
|
|
48
|
+
"Error scheduling cron run cron_id={}".format(
|
|
49
|
+
cron["cron_id"]
|
|
50
|
+
),
|
|
51
|
+
exc_info=e,
|
|
42
52
|
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
exc_info=e,
|
|
53
|
+
next_run_date = await run_in_executor(
|
|
54
|
+
None, next_cron_date, cron["schedule"], cron["now"]
|
|
55
|
+
)
|
|
56
|
+
await Crons.set_next_run_date(
|
|
57
|
+
conn, cron["cron_id"], next_run_date
|
|
49
58
|
)
|
|
50
|
-
next_run_date = await run_in_executor(
|
|
51
|
-
None, next_cron_date, cron["schedule"], cron["now"]
|
|
52
|
-
)
|
|
53
|
-
await Crons.set_next_run_date(conn, cron["cron_id"], next_run_date)
|
|
54
59
|
|
|
55
60
|
await asyncio.sleep(SLEEP_TIME)
|
|
56
61
|
except asyncio.CancelledError:
|
langgraph_api/graph.py
CHANGED
|
@@ -366,17 +366,6 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
|
|
|
366
366
|
return graph
|
|
367
367
|
|
|
368
368
|
|
|
369
|
-
def _load(path: str, variable: str) -> None:
|
|
370
|
-
modname = "".join(choice("abcdefghijklmnopqrstuvwxyz") for _ in range(24))
|
|
371
|
-
modspec = importlib.util.spec_from_file_location(modname, path)
|
|
372
|
-
if modspec is None:
|
|
373
|
-
raise ValueError(f"Could not find python file for embeddings: {path}")
|
|
374
|
-
module = importlib.util.module_from_spec(modspec)
|
|
375
|
-
sys.modules[modname] = module
|
|
376
|
-
modspec.loader.exec_module(module)
|
|
377
|
-
return module.__dict__[variable]
|
|
378
|
-
|
|
379
|
-
|
|
380
369
|
@functools.lru_cache
|
|
381
370
|
def _get_init_embeddings() -> Callable[[str, ...], "Embeddings"] | None:
|
|
382
371
|
try:
|
langgraph_api/models/run.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import uuid
|
|
3
3
|
from collections.abc import Mapping, Sequence
|
|
4
|
-
from typing import Any, TypedDict
|
|
4
|
+
from typing import Any, NamedTuple, TypedDict
|
|
5
5
|
from uuid import UUID
|
|
6
6
|
|
|
7
7
|
from langgraph.checkpoint.base.id import uuid6
|
|
8
|
+
from starlette.authentication import BaseUser
|
|
8
9
|
from starlette.exceptions import HTTPException
|
|
9
10
|
|
|
10
11
|
from langgraph_api.graph import get_assistant_id
|
|
@@ -19,7 +20,7 @@ from langgraph_api.schema import (
|
|
|
19
20
|
RunCommand,
|
|
20
21
|
StreamMode,
|
|
21
22
|
)
|
|
22
|
-
from langgraph_api.utils import AsyncConnectionProto
|
|
23
|
+
from langgraph_api.utils import AsyncConnectionProto, get_auth_ctx
|
|
23
24
|
from langgraph_storage.ops import Runs, logger
|
|
24
25
|
|
|
25
26
|
|
|
@@ -82,24 +83,32 @@ class RunCreateDict(TypedDict):
|
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
def ensure_ids(
|
|
85
|
-
assistant_id: str,
|
|
86
|
-
thread_id: str | None,
|
|
86
|
+
assistant_id: str | UUID,
|
|
87
|
+
thread_id: str | UUID | None,
|
|
87
88
|
payload: RunCreateDict,
|
|
88
89
|
) -> tuple[uuid.UUID, uuid.UUID | None, uuid.UUID | None]:
|
|
89
90
|
try:
|
|
90
|
-
results = [
|
|
91
|
+
results = [
|
|
92
|
+
assistant_id if isinstance(assistant_id, UUID) else UUID(assistant_id)
|
|
93
|
+
]
|
|
91
94
|
except ValueError:
|
|
92
95
|
raise HTTPException(status_code=422, detail="Invalid assistant ID") from None
|
|
93
96
|
if thread_id:
|
|
94
97
|
try:
|
|
95
|
-
results.append(
|
|
98
|
+
results.append(
|
|
99
|
+
thread_id if isinstance(thread_id, UUID) else UUID(thread_id)
|
|
100
|
+
)
|
|
96
101
|
except ValueError:
|
|
97
102
|
raise HTTPException(status_code=422, detail="Invalid thread ID") from None
|
|
98
103
|
else:
|
|
99
104
|
results.append(None)
|
|
100
|
-
if payload.get("checkpoint_id"):
|
|
105
|
+
if checkpoint_id := payload.get("checkpoint_id"):
|
|
101
106
|
try:
|
|
102
|
-
results.append(
|
|
107
|
+
results.append(
|
|
108
|
+
checkpoint_id
|
|
109
|
+
if isinstance(checkpoint_id, UUID)
|
|
110
|
+
else UUID(checkpoint_id)
|
|
111
|
+
)
|
|
103
112
|
except ValueError:
|
|
104
113
|
raise HTTPException(
|
|
105
114
|
status_code=422, detail="Invalid checkpoint ID"
|
|
@@ -125,27 +134,40 @@ def assign_defaults(
|
|
|
125
134
|
return stream_mode, multitask_strategy, prevent_insert_if_inflight
|
|
126
135
|
|
|
127
136
|
|
|
137
|
+
def get_user_id(user: BaseUser | None) -> str | None:
|
|
138
|
+
if user is None:
|
|
139
|
+
return None
|
|
140
|
+
try:
|
|
141
|
+
return user.identity
|
|
142
|
+
except NotImplementedError:
|
|
143
|
+
try:
|
|
144
|
+
return user.display_name
|
|
145
|
+
except NotImplementedError:
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
|
|
128
149
|
async def create_valid_run(
|
|
129
150
|
conn: AsyncConnectionProto,
|
|
130
151
|
thread_id: str | None,
|
|
131
152
|
payload: RunCreateDict,
|
|
132
|
-
user_id: str | None,
|
|
133
153
|
headers: Mapping[str, str],
|
|
134
154
|
barrier: asyncio.Barrier | None = None,
|
|
135
155
|
run_id: UUID | None = None,
|
|
136
156
|
) -> Run:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
(
|
|
158
|
+
assistant_id,
|
|
159
|
+
thread_id,
|
|
160
|
+
checkpoint_id,
|
|
161
|
+
run_id,
|
|
162
|
+
) = _get_ids(
|
|
163
|
+
thread_id,
|
|
164
|
+
payload,
|
|
165
|
+
run_id=run_id,
|
|
143
166
|
)
|
|
167
|
+
temporary = thread_id is None and payload.get("on_completion", "delete") == "delete"
|
|
144
168
|
stream_mode, multitask_strategy, prevent_insert_if_inflight = assign_defaults(
|
|
145
169
|
payload
|
|
146
170
|
)
|
|
147
|
-
temporary = thread_id is None and payload.get("on_completion", "delete") == "delete"
|
|
148
|
-
run_id = run_id or uuid6()
|
|
149
171
|
|
|
150
172
|
# assign custom headers and checkpoint to config
|
|
151
173
|
config = payload.get("config") or {}
|
|
@@ -163,8 +185,14 @@ async def create_valid_run(
|
|
|
163
185
|
):
|
|
164
186
|
continue
|
|
165
187
|
config["configurable"][key] = value
|
|
166
|
-
|
|
167
|
-
|
|
188
|
+
ctx = get_auth_ctx()
|
|
189
|
+
if ctx:
|
|
190
|
+
user = ctx.user
|
|
191
|
+
user_id = get_user_id(user)
|
|
192
|
+
config["configurable"]["langgraph_auth_user"] = user
|
|
193
|
+
config["configurable"]["langgraph_auth_user_id"] = user_id
|
|
194
|
+
else:
|
|
195
|
+
user_id = None
|
|
168
196
|
run_coro = Runs.put(
|
|
169
197
|
conn,
|
|
170
198
|
assistant_id,
|
|
@@ -227,3 +255,33 @@ async def create_valid_run(
|
|
|
227
255
|
)
|
|
228
256
|
else:
|
|
229
257
|
raise NotImplementedError
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class _Ids(NamedTuple):
|
|
261
|
+
assistant_id: uuid.UUID
|
|
262
|
+
thread_id: uuid.UUID | None
|
|
263
|
+
checkpoint_id: uuid.UUID | None
|
|
264
|
+
run_id: uuid.UUID
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _get_ids(
|
|
268
|
+
thread_id: str | None,
|
|
269
|
+
payload: RunCreateDict,
|
|
270
|
+
run_id: UUID | None = None,
|
|
271
|
+
) -> _Ids:
|
|
272
|
+
# get assistant_id
|
|
273
|
+
assistant_id = get_assistant_id(payload["assistant_id"])
|
|
274
|
+
|
|
275
|
+
# ensure UUID validity defaults
|
|
276
|
+
assistant_id, thread_id, checkpoint_id = ensure_ids(
|
|
277
|
+
assistant_id, thread_id, payload
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
run_id = run_id or uuid6()
|
|
281
|
+
|
|
282
|
+
return _Ids(
|
|
283
|
+
assistant_id,
|
|
284
|
+
thread_id,
|
|
285
|
+
checkpoint_id,
|
|
286
|
+
run_id,
|
|
287
|
+
)
|
langgraph_api/route.py
CHANGED
|
@@ -14,6 +14,7 @@ from starlette.routing import Route, compile_path, get_name
|
|
|
14
14
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
15
15
|
|
|
16
16
|
from langgraph_api.serde import json_dumpb
|
|
17
|
+
from langgraph_api.utils import set_auth_ctx
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def api_request_response(
|
|
@@ -115,4 +116,5 @@ class ApiRoute(Route):
|
|
|
115
116
|
async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
116
117
|
# https://asgi.readthedocs.io/en/latest/specs/www.html#http-connection-scope
|
|
117
118
|
scope["route"] = self.path
|
|
119
|
+
set_auth_ctx(scope.get("user"), scope.get("auth"))
|
|
118
120
|
return await super().handle(scope, receive, send)
|
langgraph_api/utils.py
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
|
+
import contextvars
|
|
1
2
|
import uuid
|
|
2
3
|
from collections.abc import AsyncIterator
|
|
3
4
|
from contextlib import asynccontextmanager
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
from typing import Any, Protocol, TypeAlias, TypeVar
|
|
6
7
|
|
|
8
|
+
from langgraph_sdk import Auth
|
|
9
|
+
from starlette.authentication import AuthCredentials, BaseUser
|
|
7
10
|
from starlette.exceptions import HTTPException
|
|
8
11
|
|
|
9
12
|
T = TypeVar("T")
|
|
10
13
|
Row: TypeAlias = dict[str, Any]
|
|
14
|
+
AuthContext = contextvars.ContextVar[Auth.types.BaseAuthContext | None](
|
|
15
|
+
"AuthContext", default=None
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@asynccontextmanager
|
|
20
|
+
async def with_user(user: BaseUser | None = None, auth: AuthCredentials | None = None):
|
|
21
|
+
current = get_auth_ctx()
|
|
22
|
+
set_auth_ctx(user, auth)
|
|
23
|
+
yield
|
|
24
|
+
if current is None:
|
|
25
|
+
return
|
|
26
|
+
set_auth_ctx(current.user, AuthCredentials(scopes=current.scopes))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def set_auth_ctx(user: BaseUser | None, auth: AuthCredentials | None) -> None:
|
|
30
|
+
if not user or not auth:
|
|
31
|
+
AuthContext.set(None)
|
|
32
|
+
else:
|
|
33
|
+
AuthContext.set(
|
|
34
|
+
Auth.types.BaseAuthContext(
|
|
35
|
+
scopes=auth.scopes,
|
|
36
|
+
user=user,
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_auth_ctx() -> Auth.types.BaseAuthContext | None:
|
|
42
|
+
return AuthContext.get()
|
|
11
43
|
|
|
12
44
|
|
|
13
45
|
class AsyncCursorProto(Protocol):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -16,7 +16,7 @@ Requires-Dist: jsonschema-rs (>=0.25.0,<0.26.0)
|
|
|
16
16
|
Requires-Dist: langchain-core (>=0.2.38,<0.4.0)
|
|
17
17
|
Requires-Dist: langgraph (>=0.2.56,<0.3.0)
|
|
18
18
|
Requires-Dist: langgraph-checkpoint (>=2.0.7,<3.0)
|
|
19
|
-
Requires-Dist: langsmith (>=0.1.63,<0.
|
|
19
|
+
Requires-Dist: langsmith (>=0.1.63,<0.3.0)
|
|
20
20
|
Requires-Dist: orjson (>=3.10.1)
|
|
21
21
|
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
22
22
|
Requires-Dist: sse-starlette (>=2.1.0,<3.0.0)
|
|
@@ -3,22 +3,23 @@ langgraph_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
3
3
|
langgraph_api/api/__init__.py,sha256=tlMXuqnyJt99aSlUXwR-dS3w5X6sDDczJu4hbm2LP30,2057
|
|
4
4
|
langgraph_api/api/assistants.py,sha256=3v4v7kLmlb2meSAnNt73toijnaSikbJgH9Jhb6IL04g,11270
|
|
5
5
|
langgraph_api/api/meta.py,sha256=hueasWpTDQ6xYLo9Bzt2jhNH8XQRzreH8FTeFfnRoxQ,2700
|
|
6
|
-
langgraph_api/api/openapi.py,sha256=
|
|
7
|
-
langgraph_api/api/runs.py,sha256=
|
|
6
|
+
langgraph_api/api/openapi.py,sha256=3eRo3V6Pni8DjqHI_MNLn8F5CEOOGVBMXPEffft8Ubo,2781
|
|
7
|
+
langgraph_api/api/runs.py,sha256=wAzPXi_kcYB9BcLBL4FXgkBohWwCPIpe4XERnsnWnsA,16042
|
|
8
8
|
langgraph_api/api/store.py,sha256=y7VIejpsE7rpPF-tiMGBqqBwWPZ1wb3o48th6NUvb5I,3849
|
|
9
9
|
langgraph_api/api/threads.py,sha256=taU61XPcCEhBPCYPZcMDsgVDwwWUWJs8p-PrXFXWY48,8661
|
|
10
10
|
langgraph_api/asyncio.py,sha256=XiFEllu-Kg4zAO084npHPYOPnLQRire3V75XrVQYMxE,6023
|
|
11
11
|
langgraph_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
langgraph_api/auth/custom.py,sha256=zBJlCjHBr-yAP5Cw-9Q2wa2HVMSsm7BWCqYB8dni-R8,16785
|
|
12
13
|
langgraph_api/auth/langsmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
14
|
langgraph_api/auth/langsmith/backend.py,sha256=uHeb5-h13NIjrX_LDAvfWYr3zpbJvlvbdUffch48hbM,2571
|
|
14
15
|
langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdTV8bKd7x4Q,3998
|
|
15
|
-
langgraph_api/auth/middleware.py,sha256=
|
|
16
|
+
langgraph_api/auth/middleware.py,sha256=4RhtYv1eBA57irNUT3nXc5vpgBTKysaOKBnjyCMSuCY,1511
|
|
16
17
|
langgraph_api/auth/noop.py,sha256=vDJmzG2vArJxVzdHePvrJWahEa0dvGnhc2LEMMeiFz0,391
|
|
17
|
-
langgraph_api/cli.py,sha256=
|
|
18
|
-
langgraph_api/config.py,sha256=
|
|
19
|
-
langgraph_api/cron_scheduler.py,sha256=
|
|
18
|
+
langgraph_api/cli.py,sha256=7vQQiD3F50r-8KkbuFjwIz8LLbdKUTd4xZGUJPiO3yQ,11688
|
|
19
|
+
langgraph_api/config.py,sha256=m3cf13AS9HVF84deJ3-9mmNTJ5GSVqcukES-FNbDbvo,2794
|
|
20
|
+
langgraph_api/cron_scheduler.py,sha256=CybK-9Jwopi_scObTHRyB7gyb0KjC4gqaT2GLe-WOFg,2587
|
|
20
21
|
langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
|
|
21
|
-
langgraph_api/graph.py,sha256=
|
|
22
|
+
langgraph_api/graph.py,sha256=LXTo2lGnku3KPBiC9ssh4NcSvieT4Ks2vJuhPaqBCpY,15807
|
|
22
23
|
langgraph_api/http.py,sha256=XrbyxpjtfSvnaWWh5ZLGpgZmY83WoDCrP_1GPguNiXI,4712
|
|
23
24
|
langgraph_api/http_logger.py,sha256=Sxo_q-65tElauRvkzVLt9lJojgNdgtcHGBYD0IRyX7M,3146
|
|
24
25
|
langgraph_api/js/.gitignore,sha256=qAah3Fq0HWAlfRj5ktZyC6QRQIsAolGLRGcRukA1XJI,33
|
|
@@ -54,33 +55,33 @@ langgraph_api/lifespan.py,sha256=Uj7NV-NqxxD1fgx_umM9pVqclcy-VlqrIxDljyj2he0,182
|
|
|
54
55
|
langgraph_api/logging.py,sha256=tiDNrEFwqaIdL5ywZv908OXlzzfXsPCws9GXeoFtBV8,3367
|
|
55
56
|
langgraph_api/metadata.py,sha256=mih2G7ScQxiqyUlbksVXkqR3Oo-pM1b6lXtzOsgR1sw,3044
|
|
56
57
|
langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
-
langgraph_api/models/run.py,sha256=
|
|
58
|
+
langgraph_api/models/run.py,sha256=qGTcgQjnzmXrxer5VPaGHoGwifV1nyE4ZCXtBiZH1bc,9546
|
|
58
59
|
langgraph_api/patch.py,sha256=94ddcTSZJe22JcpjxiSNjFZdYVnmeoWjk4IX4iBSoyk,1249
|
|
59
60
|
langgraph_api/queue.py,sha256=7tsbDgv4GlUYieJsrvIJDMQUEok4Eu-n_PIQ93rwKjk,9810
|
|
60
|
-
langgraph_api/route.py,sha256=
|
|
61
|
+
langgraph_api/route.py,sha256=HnAcWeStCrWNe37YUXIqEsjsrCPCIPGijHG7pM9ga28,4251
|
|
61
62
|
langgraph_api/schema.py,sha256=EiCWRR2GmGrBrOYcuK9SeVQS5b98SdaJlKaqOL7t-WQ,5263
|
|
62
63
|
langgraph_api/serde.py,sha256=VoJ7Z1IuqrQGXFzEP1qijAITtWCrmjtVqlCRuScjXJI,3533
|
|
63
64
|
langgraph_api/server.py,sha256=afHDnL6b_fAIu_q4icnK60a74lHTTZOMIe1egdhRXIk,1522
|
|
64
65
|
langgraph_api/sse.py,sha256=2wNodCOP2eg7a9mpSu0S3FQ0CHk2BBV_vv0UtIgJIcc,4034
|
|
65
66
|
langgraph_api/state.py,sha256=8jx4IoTCOjTJuwzuXJKKFwo1VseHjNnw_CCq4x1SW14,2284
|
|
66
67
|
langgraph_api/stream.py,sha256=u0gjbCrmYvVw8Ux6DgsYTojLCHSwM4Pi-0LhSLGY4HM,11546
|
|
67
|
-
langgraph_api/utils.py,sha256=
|
|
68
|
+
langgraph_api/utils.py,sha256=17AZrdVzGHUQ7Y8b82Mknxe1LD5JMo4tZsb6TCcXEW0,2474
|
|
68
69
|
langgraph_api/validation.py,sha256=McizHlz-Ez8Jhdbc79mbPSde7GIuf2Jlbjx2yv_l6dA,4475
|
|
69
70
|
langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
71
|
langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
|
|
71
72
|
langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
|
|
72
73
|
langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
langgraph_storage/checkpoint.py,sha256=
|
|
74
|
-
langgraph_storage/database.py,sha256=
|
|
75
|
-
langgraph_storage/ops.py,sha256=
|
|
74
|
+
langgraph_storage/checkpoint.py,sha256=V4t2GwYEJdPCHbhq_4Udhlv0TWKDzlMu_rlNPdTDc50,3589
|
|
75
|
+
langgraph_storage/database.py,sha256=Nr5zE9Fur3-tESkqe7xNXMf2QlBuw3H0CUie7jVa6Q4,6003
|
|
76
|
+
langgraph_storage/ops.py,sha256=34zhzc1ISESlsfM-QlHaUlSNIvqSIgmN3aJHTQMb-xA,67670
|
|
76
77
|
langgraph_storage/queue.py,sha256=6cTZ0ubHu3S1T43yxHMVOwsQsDaJupByiU0sTUFFls8,3261
|
|
77
78
|
langgraph_storage/retry.py,sha256=uvYFuXJ-T6S1QY1ZwkZHyZQbsvS-Ab68LSbzbUUSI2E,696
|
|
78
79
|
langgraph_storage/store.py,sha256=D-p3cWc_umamkKp-6Cz3cAriSACpvM5nxUIvND6PuxE,2710
|
|
79
80
|
langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
|
|
80
81
|
logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
|
|
81
82
|
openapi.json,sha256=UxAGHZYM4PgNd48TSZt7f2lVuyPUkDadxBBhRy5jcmk,124512
|
|
82
|
-
langgraph_api-0.0.
|
|
83
|
-
langgraph_api-0.0.
|
|
84
|
-
langgraph_api-0.0.
|
|
85
|
-
langgraph_api-0.0.
|
|
86
|
-
langgraph_api-0.0.
|
|
83
|
+
langgraph_api-0.0.9.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
84
|
+
langgraph_api-0.0.9.dist-info/METADATA,sha256=dfqbTUQL54HjgW4XZThB8H-bJALao6b5Fhi01JXQwE4,3993
|
|
85
|
+
langgraph_api-0.0.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
86
|
+
langgraph_api-0.0.9.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
87
|
+
langgraph_api-0.0.9.dist-info/RECORD,,
|
langgraph_storage/checkpoint.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import uuid
|
|
3
4
|
|
|
@@ -12,6 +13,8 @@ from langgraph.checkpoint.memory import MemorySaver, PersistentDict
|
|
|
12
13
|
|
|
13
14
|
from langgraph_api.serde import Serializer
|
|
14
15
|
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
15
18
|
_EXCLUDED_KEYS = {"checkpoint_ns", "checkpoint_id", "run_id", "thread_id"}
|
|
16
19
|
|
|
17
20
|
|
|
@@ -36,6 +39,19 @@ class InMemorySaver(MemorySaver):
|
|
|
36
39
|
d.load()
|
|
37
40
|
except FileNotFoundError:
|
|
38
41
|
pass
|
|
42
|
+
except ModuleNotFoundError:
|
|
43
|
+
logger.error(
|
|
44
|
+
"Unable to load cached data - your code has changed in a way that's incompatible with the cache."
|
|
45
|
+
"\nThis usually happens when you've:"
|
|
46
|
+
"\n - Renamed or moved classes"
|
|
47
|
+
"\n - Changed class structures"
|
|
48
|
+
"\n - Pulled updates that modified class definitions in a way that's incompatible with the cache"
|
|
49
|
+
"\n\nRemoving invalid cache data stored at path: .langgraph_api"
|
|
50
|
+
)
|
|
51
|
+
os.remove(self.filename)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
logger.error("Failed to load cached data: %s", str(e))
|
|
54
|
+
os.remove(self.filename)
|
|
39
55
|
return d
|
|
40
56
|
|
|
41
57
|
super().__init__(
|
langgraph_storage/database.py
CHANGED
|
@@ -164,7 +164,23 @@ async def start_pool() -> None:
|
|
|
164
164
|
if not os.path.exists(".langgraph_api"):
|
|
165
165
|
os.mkdir(".langgraph_api")
|
|
166
166
|
if os.path.exists(OPS_FILENAME):
|
|
167
|
-
|
|
167
|
+
try:
|
|
168
|
+
GLOBAL_STORE.load()
|
|
169
|
+
except ModuleNotFoundError:
|
|
170
|
+
logger.error(
|
|
171
|
+
"Unable to load cached data - your code has changed in a way that's incompatible with the cache."
|
|
172
|
+
"\nThis usually happens when you've:"
|
|
173
|
+
"\n - Renamed or moved classes"
|
|
174
|
+
"\n - Changed class structures"
|
|
175
|
+
"\n - Pulled updates that modified class definitions in a way that's incompatible with the cache"
|
|
176
|
+
"\n\nRemoving invalid cache data stored at path: .langgraph_api"
|
|
177
|
+
)
|
|
178
|
+
os.remove(OPS_FILENAME)
|
|
179
|
+
os.remove(RETRY_COUNTER_FILENAME)
|
|
180
|
+
except Exception as e:
|
|
181
|
+
logger.error("Failed to load cached data: %s", str(e))
|
|
182
|
+
os.remove(OPS_FILENAME)
|
|
183
|
+
os.remove(RETRY_COUNTER_FILENAME)
|
|
168
184
|
for k in ["runs", "threads", "assistants", "assistant_versions"]:
|
|
169
185
|
if not GLOBAL_STORE.get(k):
|
|
170
186
|
GLOBAL_STORE[k] = []
|