langgraph-api 0.0.14__tar.gz → 0.0.16__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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/PKG-INFO +3 -3
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/__init__.py +2 -1
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/assistants.py +4 -4
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/store.py +67 -15
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/asyncio.py +5 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/custom.py +20 -5
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/config.py +1 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/graph.py +6 -13
- langgraph_api-0.0.16/langgraph_api/js/base.py +9 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/build.mts +2 -0
- langgraph_api-0.0.16/langgraph_api/js/client.mts +830 -0
- langgraph_api-0.0.16/langgraph_api/js/client.new.mts +856 -0
- langgraph_api-0.0.16/langgraph_api/js/errors.py +11 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/package.json +3 -1
- langgraph_api-0.0.16/langgraph_api/js/remote.py +18 -0
- langgraph_api-0.0.16/langgraph_api/js/remote_new.py +693 -0
- langgraph_api-0.0.14/langgraph_api/js/remote.py → langgraph_api-0.0.16/langgraph_api/js/remote_old.py +188 -198
- langgraph_api-0.0.16/langgraph_api/js/schema.py +29 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/utils/serde.mts +7 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/api.test.mts +125 -8
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/compose-postgres.yml +2 -1
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/agent.mts +2 -0
- langgraph_api-0.0.16/langgraph_api/js/tests/graphs/delay.mts +30 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/langgraph.json +2 -1
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/yarn.lock +870 -18
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/models/run.py +1 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/queue.py +129 -31
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/route.py +8 -3
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/schema.py +1 -1
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/stream.py +12 -5
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/utils.py +11 -5
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/ops.py +9 -2
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/openapi.json +5 -5
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/pyproject.toml +4 -3
- langgraph_api-0.0.14/langgraph_api/js/client.mts +0 -856
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/LICENSE +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/README.md +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/cli.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/http.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/http_logger.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/server_sent_events.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/hooks.mjs +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/parser/parser.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/parser/parser.worker.mjs +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/schema/types.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/schema/types.template.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/.gitignore +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/error.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/nested.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/package.json +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/weather.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/graphs/yarn.lock +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/parser.test.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/js/tests/utils.mts +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/lifespan.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/server.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/state.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_license/middleware.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/__init__.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/checkpoint.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/database.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/queue.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/retry.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/store.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/langgraph_storage/ttl_dict.py +0 -0
- {langgraph_api-0.0.14 → langgraph_api-0.0.16}/logging.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.16
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -16,11 +16,11 @@ 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: langgraph-sdk (>=0.1.
|
|
19
|
+
Requires-Dist: langgraph-sdk (>=0.1.51,<0.2.0)
|
|
20
20
|
Requires-Dist: langsmith (>=0.1.63,<0.3.0)
|
|
21
21
|
Requires-Dist: orjson (>=3.10.1)
|
|
22
22
|
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
23
|
-
Requires-Dist: sse-starlette (>=2.1.0,<
|
|
23
|
+
Requires-Dist: sse-starlette (>=2.1.0,<2.2.0)
|
|
24
24
|
Requires-Dist: starlette (>=0.38.6)
|
|
25
25
|
Requires-Dist: structlog (>=24.4.0,<25.0.0)
|
|
26
26
|
Requires-Dist: tenacity (>=8.3.0,<9.0.0)
|
|
@@ -13,7 +13,6 @@ from langgraph_api.api.threads import threads_routes
|
|
|
13
13
|
from langgraph_api.auth.middleware import auth_middleware
|
|
14
14
|
from langgraph_api.config import MIGRATIONS_PATH
|
|
15
15
|
from langgraph_api.graph import js_bg_tasks
|
|
16
|
-
from langgraph_api.js.remote import js_healthcheck
|
|
17
16
|
from langgraph_api.validation import DOCS_HTML
|
|
18
17
|
from langgraph_storage.database import connect, healthcheck
|
|
19
18
|
|
|
@@ -23,6 +22,8 @@ async def ok(request: Request):
|
|
|
23
22
|
if check_db:
|
|
24
23
|
await healthcheck()
|
|
25
24
|
if js_bg_tasks:
|
|
25
|
+
from langgraph_api.js.remote import js_healthcheck
|
|
26
|
+
|
|
26
27
|
await js_healthcheck()
|
|
27
28
|
return JSONResponse({"ok": True})
|
|
28
29
|
|
|
@@ -8,7 +8,7 @@ from starlette.responses import Response
|
|
|
8
8
|
from starlette.routing import BaseRoute
|
|
9
9
|
|
|
10
10
|
from langgraph_api.graph import get_assistant_id, get_graph
|
|
11
|
-
from langgraph_api.js.
|
|
11
|
+
from langgraph_api.js.base import BaseRemotePregel
|
|
12
12
|
from langgraph_api.route import ApiRequest, ApiResponse, ApiRoute
|
|
13
13
|
from langgraph_api.serde import ajson_loads
|
|
14
14
|
from langgraph_api.utils import fetchone, validate_uuid
|
|
@@ -138,7 +138,7 @@ async def get_assistant_graph(
|
|
|
138
138
|
if xray <= 0:
|
|
139
139
|
raise HTTPException(422, detail="Invalid xray value") from None
|
|
140
140
|
|
|
141
|
-
if isinstance(graph,
|
|
141
|
+
if isinstance(graph, BaseRemotePregel):
|
|
142
142
|
drawable_graph = await graph.fetch_graph(xray=xray)
|
|
143
143
|
return ApiResponse(drawable_graph.to_json())
|
|
144
144
|
return ApiResponse(graph.get_graph(xray=xray).to_json())
|
|
@@ -158,7 +158,7 @@ async def get_assistant_subgraphs(
|
|
|
158
158
|
async with get_graph(assistant["graph_id"], config) as graph:
|
|
159
159
|
namespace = request.path_params.get("namespace")
|
|
160
160
|
|
|
161
|
-
if isinstance(graph,
|
|
161
|
+
if isinstance(graph, BaseRemotePregel):
|
|
162
162
|
return ApiResponse(
|
|
163
163
|
await graph.fetch_subgraphs(
|
|
164
164
|
namespace=namespace,
|
|
@@ -191,7 +191,7 @@ async def get_assistant_schemas(
|
|
|
191
191
|
assistant = await fetchone(assistant_)
|
|
192
192
|
config = await ajson_loads(assistant["config"])
|
|
193
193
|
async with get_graph(assistant["graph_id"], config) as graph:
|
|
194
|
-
if isinstance(graph,
|
|
194
|
+
if isinstance(graph, BaseRemotePregel):
|
|
195
195
|
schemas = await graph.fetch_state_schema()
|
|
196
196
|
return ApiResponse(
|
|
197
197
|
{
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from langgraph_sdk.auth import Auth
|
|
1
4
|
from starlette.responses import Response
|
|
2
5
|
from starlette.routing import BaseRoute
|
|
3
6
|
|
|
7
|
+
from langgraph_api.auth.custom import handle_event as _handle_event
|
|
4
8
|
from langgraph_api.route import ApiRequest, ApiResponse, ApiRoute
|
|
9
|
+
from langgraph_api.utils import get_auth_ctx
|
|
5
10
|
from langgraph_api.validation import (
|
|
6
11
|
StoreDeleteRequest,
|
|
7
12
|
StoreListNamespacesRequest,
|
|
@@ -21,6 +26,24 @@ def _validate_namespace(namespace: tuple[str, ...]) -> Response | None:
|
|
|
21
26
|
)
|
|
22
27
|
|
|
23
28
|
|
|
29
|
+
async def handle_event(
|
|
30
|
+
action: str,
|
|
31
|
+
value: Any,
|
|
32
|
+
) -> None:
|
|
33
|
+
ctx = get_auth_ctx()
|
|
34
|
+
if not ctx:
|
|
35
|
+
return
|
|
36
|
+
await _handle_event(
|
|
37
|
+
Auth.types.AuthContext(
|
|
38
|
+
user=ctx.user,
|
|
39
|
+
permissions=ctx.permissions,
|
|
40
|
+
resource="store",
|
|
41
|
+
action=action,
|
|
42
|
+
),
|
|
43
|
+
value,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
24
47
|
@retry_db
|
|
25
48
|
async def put_item(request: ApiRequest):
|
|
26
49
|
"""Store or update an item."""
|
|
@@ -28,9 +51,13 @@ async def put_item(request: ApiRequest):
|
|
|
28
51
|
namespace = tuple(payload["namespace"]) if payload.get("namespace") else ()
|
|
29
52
|
if err := _validate_namespace(namespace):
|
|
30
53
|
return err
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
handler_payload = {
|
|
55
|
+
"namespace": namespace,
|
|
56
|
+
"key": payload["key"],
|
|
57
|
+
"value": payload["value"],
|
|
58
|
+
}
|
|
59
|
+
await handle_event("put", handler_payload)
|
|
60
|
+
await Store().aput(namespace, handler_payload["key"], handler_payload["value"])
|
|
34
61
|
return Response(status_code=204)
|
|
35
62
|
|
|
36
63
|
|
|
@@ -43,6 +70,11 @@ async def get_item(request: ApiRequest):
|
|
|
43
70
|
key = request.query_params.get("key")
|
|
44
71
|
if not key:
|
|
45
72
|
return ApiResponse({"error": "Key is required"}, status_code=400)
|
|
73
|
+
handler_payload = {
|
|
74
|
+
"namespace": namespace,
|
|
75
|
+
"key": key,
|
|
76
|
+
}
|
|
77
|
+
await handle_event("get", handler_payload)
|
|
46
78
|
result = await Store().aget(namespace, key)
|
|
47
79
|
return ApiResponse(result.dict() if result is not None else None)
|
|
48
80
|
|
|
@@ -54,8 +86,12 @@ async def delete_item(request: ApiRequest):
|
|
|
54
86
|
namespace = tuple(payload["namespace"]) if payload.get("namespace") else ()
|
|
55
87
|
if err := _validate_namespace(namespace):
|
|
56
88
|
return err
|
|
57
|
-
|
|
58
|
-
|
|
89
|
+
handler_payload = {
|
|
90
|
+
"namespace": namespace,
|
|
91
|
+
"key": payload["key"],
|
|
92
|
+
}
|
|
93
|
+
await handle_event("delete", handler_payload)
|
|
94
|
+
await Store().adelete(handler_payload["namespace"], handler_payload["key"])
|
|
59
95
|
return Response(status_code=204)
|
|
60
96
|
|
|
61
97
|
|
|
@@ -70,12 +106,20 @@ async def search_items(request: ApiRequest):
|
|
|
70
106
|
limit = payload.get("limit") or 10
|
|
71
107
|
offset = payload.get("offset") or 0
|
|
72
108
|
query = payload.get("query")
|
|
109
|
+
handler_payload = {
|
|
110
|
+
"namespace": namespace_prefix,
|
|
111
|
+
"filter": filter,
|
|
112
|
+
"limit": limit,
|
|
113
|
+
"offset": offset,
|
|
114
|
+
"query": query,
|
|
115
|
+
}
|
|
116
|
+
await handle_event("search", handler_payload)
|
|
73
117
|
items = await Store().asearch(
|
|
74
|
-
|
|
75
|
-
filter=filter,
|
|
76
|
-
limit=limit,
|
|
77
|
-
offset=offset,
|
|
78
|
-
query=query,
|
|
118
|
+
handler_payload["namespace"],
|
|
119
|
+
filter=handler_payload["filter"],
|
|
120
|
+
limit=handler_payload["limit"],
|
|
121
|
+
offset=handler_payload["offset"],
|
|
122
|
+
query=handler_payload["query"],
|
|
79
123
|
)
|
|
80
124
|
return ApiResponse({"items": [item.dict() for item in items]})
|
|
81
125
|
|
|
@@ -93,12 +137,20 @@ async def list_namespaces(request: ApiRequest):
|
|
|
93
137
|
max_depth = payload.get("max_depth")
|
|
94
138
|
limit = payload.get("limit", 100)
|
|
95
139
|
offset = payload.get("offset", 0)
|
|
140
|
+
handler_payload = {
|
|
141
|
+
"namespace": prefix,
|
|
142
|
+
"suffix": suffix,
|
|
143
|
+
"max_depth": max_depth,
|
|
144
|
+
"limit": limit,
|
|
145
|
+
"offset": offset,
|
|
146
|
+
}
|
|
147
|
+
await handle_event("list_namespaces", handler_payload)
|
|
96
148
|
result = await Store().alist_namespaces(
|
|
97
|
-
prefix=
|
|
98
|
-
suffix=suffix,
|
|
99
|
-
max_depth=max_depth,
|
|
100
|
-
limit=limit,
|
|
101
|
-
offset=offset,
|
|
149
|
+
prefix=handler_payload["namespace"],
|
|
150
|
+
suffix=handler_payload["suffix"],
|
|
151
|
+
max_depth=handler_payload["max_depth"],
|
|
152
|
+
limit=handler_payload["limit"],
|
|
153
|
+
offset=handler_payload["offset"],
|
|
102
154
|
)
|
|
103
155
|
return ApiResponse({"namespaces": result})
|
|
104
156
|
|
|
@@ -60,6 +60,11 @@ async def wait_if_not_done(coro: Coroutine[Any, Any, T], done: ValueEvent) -> T:
|
|
|
60
60
|
try:
|
|
61
61
|
return await coro_task
|
|
62
62
|
except asyncio.CancelledError as e:
|
|
63
|
+
if e.args and asyncio.isfuture(e.args[-1]):
|
|
64
|
+
await logger.ainfo(
|
|
65
|
+
"Awaiting future upon cancellation", task=str(e.args[-1])
|
|
66
|
+
)
|
|
67
|
+
await e.args[-1]
|
|
63
68
|
if e.args and isinstance(e.args[0], Exception):
|
|
64
69
|
raise e.args[0] from None
|
|
65
70
|
raise
|
|
@@ -398,6 +398,16 @@ class DotDict:
|
|
|
398
398
|
raise AttributeError(f"'DotDict' object has no attribute '{name}'")
|
|
399
399
|
return self._dict[name]
|
|
400
400
|
|
|
401
|
+
def __getitem__(self, key):
|
|
402
|
+
return self._dict[key]
|
|
403
|
+
|
|
404
|
+
def __setitem__(self, key, value):
|
|
405
|
+
self._dict[key] = value
|
|
406
|
+
if isinstance(value, dict):
|
|
407
|
+
setattr(self, key, DotDict(value))
|
|
408
|
+
else:
|
|
409
|
+
setattr(self, key, value)
|
|
410
|
+
|
|
401
411
|
def __deepcopy__(self, memo):
|
|
402
412
|
return DotDict(copy.deepcopy(self._dict))
|
|
403
413
|
|
|
@@ -457,6 +467,12 @@ class ProxyUser(BaseUser):
|
|
|
457
467
|
**d,
|
|
458
468
|
}
|
|
459
469
|
|
|
470
|
+
def __getitem__(self, key):
|
|
471
|
+
return self._user[key]
|
|
472
|
+
|
|
473
|
+
def __setitem__(self, key, value):
|
|
474
|
+
self._user[key] = value
|
|
475
|
+
|
|
460
476
|
def __getattr__(self, name: str) -> Any:
|
|
461
477
|
"""Proxy any other attributes to the underlying user object."""
|
|
462
478
|
return getattr(self._user, name)
|
|
@@ -481,10 +497,10 @@ def _normalize_auth_response(
|
|
|
481
497
|
user = response
|
|
482
498
|
permissions = []
|
|
483
499
|
|
|
484
|
-
return AuthCredentials(permissions),
|
|
500
|
+
return AuthCredentials(permissions), normalize_user(user)
|
|
485
501
|
|
|
486
502
|
|
|
487
|
-
def
|
|
503
|
+
def normalize_user(user: Any) -> BaseUser:
|
|
488
504
|
"""Normalize user into a BaseUser instance."""
|
|
489
505
|
if isinstance(user, BaseUser):
|
|
490
506
|
return user
|
|
@@ -571,9 +587,8 @@ def _get_handler(auth: Auth, ctx: Auth.types.AuthContext) -> Auth.types.Handler
|
|
|
571
587
|
]
|
|
572
588
|
for key in keys:
|
|
573
589
|
if key in auth._handlers:
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
] # Get the last defined, most specific handler
|
|
590
|
+
# Get the last defined, most specific handler
|
|
591
|
+
result = auth._handlers[key][-1]
|
|
577
592
|
auth._handler_cache[key] = result
|
|
578
593
|
return result
|
|
579
594
|
if auth._global_handlers:
|
|
@@ -28,6 +28,7 @@ BG_JOB_NO_DELAY = env("BG_JOB_NO_DELAY", cast=bool, default=False)
|
|
|
28
28
|
N_JOBS_PER_WORKER = env("N_JOBS_PER_WORKER", cast=int, default=10)
|
|
29
29
|
BG_JOB_TIMEOUT_SECS = env("BG_JOB_TIMEOUT_SECS", cast=float, default=3600)
|
|
30
30
|
FF_CRONS_ENABLED = env("FF_CRONS_ENABLED", cast=bool, default=True)
|
|
31
|
+
FF_JS_ZEROMQ_ENABLED = env("FF_JS_ZEROMQ_ENABLED", cast=bool, default=False)
|
|
31
32
|
|
|
32
33
|
# auth
|
|
33
34
|
|
|
@@ -21,7 +21,7 @@ from langgraph.pregel import Pregel
|
|
|
21
21
|
from langgraph.store.base import BaseStore
|
|
22
22
|
from starlette.exceptions import HTTPException
|
|
23
23
|
|
|
24
|
-
from langgraph_api.js.
|
|
24
|
+
from langgraph_api.js.base import BaseRemotePregel
|
|
25
25
|
from langgraph_api.schema import Config
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
@@ -63,7 +63,7 @@ async def register_graph(graph_id: str, graph: GraphValue, config: dict | None)
|
|
|
63
63
|
@asynccontextmanager
|
|
64
64
|
async def _generate_graph(value: Any) -> AsyncIterator[Any]:
|
|
65
65
|
"""Yield a graph object regardless of its type."""
|
|
66
|
-
if isinstance(value, Pregel |
|
|
66
|
+
if isinstance(value, Pregel | BaseRemotePregel):
|
|
67
67
|
yield value
|
|
68
68
|
elif hasattr(value, "__aenter__") and hasattr(value, "__aexit__"):
|
|
69
69
|
async with value as ctx_value:
|
|
@@ -94,12 +94,12 @@ async def get_graph(
|
|
|
94
94
|
async with _generate_graph(value) as graph_obj:
|
|
95
95
|
if isinstance(graph_obj, Graph):
|
|
96
96
|
graph_obj = graph_obj.compile()
|
|
97
|
-
if not isinstance(graph_obj, Pregel |
|
|
97
|
+
if not isinstance(graph_obj, Pregel | BaseRemotePregel):
|
|
98
98
|
raise HTTPException(
|
|
99
99
|
status_code=424,
|
|
100
100
|
detail=f"Graph '{graph_id}' is not valid. Review graph registration.",
|
|
101
101
|
)
|
|
102
|
-
if isinstance(graph_obj,
|
|
102
|
+
if isinstance(graph_obj, BaseRemotePregel):
|
|
103
103
|
graph_obj.checkpointer = checkpointer
|
|
104
104
|
graph_obj.name = graph_id
|
|
105
105
|
yield graph_obj
|
|
@@ -228,20 +228,13 @@ async def collect_graphs_from_env(register: bool = False) -> None:
|
|
|
228
228
|
RemotePregel,
|
|
229
229
|
run_js_process,
|
|
230
230
|
run_remote_checkpointer,
|
|
231
|
-
run_remote_store,
|
|
232
231
|
wait_until_js_ready,
|
|
233
232
|
)
|
|
234
233
|
|
|
235
234
|
js_bg_tasks.add(
|
|
236
235
|
asyncio.create_task(
|
|
237
236
|
run_remote_checkpointer(),
|
|
238
|
-
name="remote-
|
|
239
|
-
)
|
|
240
|
-
)
|
|
241
|
-
js_bg_tasks.add(
|
|
242
|
-
asyncio.create_task(
|
|
243
|
-
run_remote_store(),
|
|
244
|
-
name="remote-store",
|
|
237
|
+
name="remote-socket-poller",
|
|
245
238
|
)
|
|
246
239
|
)
|
|
247
240
|
js_bg_tasks.add(
|
|
@@ -256,7 +249,7 @@ async def collect_graphs_from_env(register: bool = False) -> None:
|
|
|
256
249
|
await wait_until_js_ready()
|
|
257
250
|
|
|
258
251
|
for spec in js_specs:
|
|
259
|
-
graph =
|
|
252
|
+
graph = RemotePregel.load(graph_id=spec.id)
|
|
260
253
|
if register:
|
|
261
254
|
await register_graph(spec.id, graph, spec.config)
|
|
262
255
|
|