langgraph-api 0.5.2__py3-none-any.whl → 0.5.4__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_api/__init__.py +1 -1
- langgraph_api/auth/custom.py +29 -24
- langgraph_api/grpc_ops/config_conversion.py +225 -0
- langgraph_api/grpc_ops/generated/core_api_pb2.py +194 -195
- langgraph_api/grpc_ops/generated/core_api_pb2.pyi +14 -25
- langgraph_api/grpc_ops/generated/engine_common_pb2.py +194 -0
- langgraph_api/grpc_ops/generated/engine_common_pb2.pyi +648 -0
- langgraph_api/grpc_ops/generated/engine_common_pb2_grpc.py +24 -0
- langgraph_api/grpc_ops/ops.py +26 -156
- langgraph_api/serde.py +3 -3
- {langgraph_api-0.5.2.dist-info → langgraph_api-0.5.4.dist-info}/METADATA +2 -2
- {langgraph_api-0.5.2.dist-info → langgraph_api-0.5.4.dist-info}/RECORD +15 -11
- {langgraph_api-0.5.2.dist-info → langgraph_api-0.5.4.dist-info}/WHEEL +0 -0
- {langgraph_api-0.5.2.dist-info → langgraph_api-0.5.4.dist-info}/entry_points.txt +0 -0
- {langgraph_api-0.5.2.dist-info → langgraph_api-0.5.4.dist-info}/licenses/LICENSE +0 -0
langgraph_api/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.5.
|
|
1
|
+
__version__ = "0.5.4"
|
langgraph_api/auth/custom.py
CHANGED
|
@@ -355,34 +355,39 @@ def _solve_fastapi_dependencies(
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
async def decorator(scope: dict, request: Request):
|
|
358
|
-
async with AsyncExitStack() as
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
358
|
+
async with AsyncExitStack() as request_stack:
|
|
359
|
+
scope["fastapi_inner_astack"] = request_stack
|
|
360
|
+
async with AsyncExitStack() as stack:
|
|
361
|
+
scope["fastapi_function_astack"] = stack
|
|
362
|
+
all_solved = await asyncio.gather(
|
|
363
|
+
*(
|
|
364
|
+
solve_dependencies(
|
|
365
|
+
request=request,
|
|
366
|
+
dependant=dependent,
|
|
367
|
+
async_exit_stack=stack,
|
|
368
|
+
embed_body_fields=False,
|
|
369
|
+
)
|
|
370
|
+
for dependent in dependents.values()
|
|
366
371
|
)
|
|
367
|
-
for dependent in dependents.values()
|
|
368
372
|
)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
373
|
+
all_injected = await asyncio.gather(
|
|
374
|
+
*(
|
|
375
|
+
_run_async(dependent.call, solved.values, is_async)
|
|
376
|
+
for dependent, solved in zip(
|
|
377
|
+
dependents.values(), all_solved, strict=False
|
|
378
|
+
)
|
|
375
379
|
)
|
|
376
380
|
)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
381
|
+
kwargs = {
|
|
382
|
+
name: value
|
|
383
|
+
for name, value in zip(
|
|
384
|
+
dependents.keys(), all_injected, strict=False
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
other_params = _extract_arguments_from_scope(
|
|
388
|
+
scope, _param_names, request=request
|
|
389
|
+
)
|
|
390
|
+
return await fn(**(kwargs | other_params))
|
|
386
391
|
|
|
387
392
|
return decorator
|
|
388
393
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Conversion utils for the RunnableConfig."""
|
|
2
|
+
|
|
3
|
+
# THIS IS DUPLICATED
|
|
4
|
+
# TODO: WFH - Deduplicate with the executor logic by moving into a separate package
|
|
5
|
+
# Sequencing in the next PR.
|
|
6
|
+
from typing import Any, cast
|
|
7
|
+
|
|
8
|
+
import orjson
|
|
9
|
+
from langchain_core.runnables.config import RunnableConfig
|
|
10
|
+
|
|
11
|
+
from langgraph_api.grpc_ops.generated import engine_common_pb2
|
|
12
|
+
|
|
13
|
+
CONFIG_KEY_SEND = "__pregel_send"
|
|
14
|
+
CONFIG_KEY_READ = "__pregel_read"
|
|
15
|
+
CONFIG_KEY_RESUMING = "__pregel_resuming"
|
|
16
|
+
CONFIG_KEY_TASK_ID = "__pregel_task_id"
|
|
17
|
+
CONFIG_KEY_THREAD_ID = "thread_id"
|
|
18
|
+
CONFIG_KEY_CHECKPOINT_MAP = "checkpoint_map"
|
|
19
|
+
CONFIG_KEY_CHECKPOINT_ID = "checkpoint_id"
|
|
20
|
+
CONFIG_KEY_CHECKPOINT_NS = "checkpoint_ns"
|
|
21
|
+
CONFIG_KEY_SCRATCHPAD = "__pregel_scratchpad"
|
|
22
|
+
CONFIG_KEY_DURABILITY = "__pregel_durability"
|
|
23
|
+
CONFIG_KEY_GRAPH_ID = "graph_id"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _durability_to_proto(
|
|
27
|
+
durability: str,
|
|
28
|
+
) -> engine_common_pb2.Durability:
|
|
29
|
+
match durability:
|
|
30
|
+
case "async":
|
|
31
|
+
return engine_common_pb2.Durability.ASYNC
|
|
32
|
+
case "sync":
|
|
33
|
+
return engine_common_pb2.Durability.SYNC
|
|
34
|
+
case "exit":
|
|
35
|
+
return engine_common_pb2.Durability.EXIT
|
|
36
|
+
case _:
|
|
37
|
+
raise ValueError(f"invalid durability: {durability}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _durability_from_proto(
|
|
41
|
+
durability: engine_common_pb2.Durability,
|
|
42
|
+
) -> str:
|
|
43
|
+
match durability:
|
|
44
|
+
case engine_common_pb2.Durability.ASYNC:
|
|
45
|
+
return "async"
|
|
46
|
+
case engine_common_pb2.Durability.SYNC:
|
|
47
|
+
return "sync"
|
|
48
|
+
case engine_common_pb2.Durability.EXIT:
|
|
49
|
+
return "exit"
|
|
50
|
+
case _:
|
|
51
|
+
raise ValueError(f"invalid durability: {durability}")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def config_to_proto(
|
|
55
|
+
config: RunnableConfig,
|
|
56
|
+
) -> engine_common_pb2.EngineRunnableConfig | None:
|
|
57
|
+
# Prepare kwargs for construction
|
|
58
|
+
if not config:
|
|
59
|
+
return None
|
|
60
|
+
cp = {**config}
|
|
61
|
+
pb_config = engine_common_pb2.EngineRunnableConfig()
|
|
62
|
+
for k, v in (cp.pop("metadata", None) or {}).items():
|
|
63
|
+
if k == "run_attempt":
|
|
64
|
+
pb_config.run_attempt = v
|
|
65
|
+
elif k == "run_id":
|
|
66
|
+
pb_config.server_run_id = str(v)
|
|
67
|
+
else:
|
|
68
|
+
pb_config.metadata_json[k] = orjson.dumps(v)
|
|
69
|
+
if run_name := cp.pop("run_name", None):
|
|
70
|
+
pb_config.run_name = run_name
|
|
71
|
+
|
|
72
|
+
if run_id := cp.pop("run_id", None):
|
|
73
|
+
pb_config.run_id = str(run_id)
|
|
74
|
+
|
|
75
|
+
if (max_concurrency := cp.pop("max_concurrency", None)) and isinstance(
|
|
76
|
+
max_concurrency, int
|
|
77
|
+
):
|
|
78
|
+
pb_config.max_concurrency = max_concurrency
|
|
79
|
+
|
|
80
|
+
if (recursion_limit := cp.pop("recursion_limit", None)) and isinstance(
|
|
81
|
+
recursion_limit, int
|
|
82
|
+
):
|
|
83
|
+
pb_config.recursion_limit = recursion_limit
|
|
84
|
+
|
|
85
|
+
# Handle collections after construction
|
|
86
|
+
if (tags := cp.pop("tags", None)) and isinstance(tags, list):
|
|
87
|
+
pb_config.tags.extend(tags)
|
|
88
|
+
|
|
89
|
+
if (configurable := cp.pop("configurable", None)) and isinstance(
|
|
90
|
+
configurable, dict
|
|
91
|
+
):
|
|
92
|
+
_inject_configurable_into_proto(configurable, pb_config)
|
|
93
|
+
if cp:
|
|
94
|
+
pb_config.extra_json.update({k: orjson.dumps(v) for k, v in cp.items()})
|
|
95
|
+
|
|
96
|
+
return pb_config
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
RESTRICTED_RESERVED_CONFIGURABLE_KEYS = {
|
|
100
|
+
CONFIG_KEY_SEND,
|
|
101
|
+
CONFIG_KEY_READ,
|
|
102
|
+
CONFIG_KEY_SCRATCHPAD,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _inject_configurable_into_proto(
|
|
107
|
+
configurable: dict[str, Any], proto: engine_common_pb2.EngineRunnableConfig
|
|
108
|
+
) -> None:
|
|
109
|
+
extra = {}
|
|
110
|
+
for key, value in configurable.items():
|
|
111
|
+
if key == CONFIG_KEY_RESUMING:
|
|
112
|
+
proto.resuming = bool(value)
|
|
113
|
+
elif key == CONFIG_KEY_TASK_ID:
|
|
114
|
+
proto.task_id = str(value)
|
|
115
|
+
elif key == CONFIG_KEY_THREAD_ID:
|
|
116
|
+
proto.thread_id = str(value)
|
|
117
|
+
elif key == CONFIG_KEY_CHECKPOINT_MAP:
|
|
118
|
+
proto.checkpoint_map.update(cast(dict[str, str], value))
|
|
119
|
+
elif key == CONFIG_KEY_CHECKPOINT_ID:
|
|
120
|
+
proto.checkpoint_id = str(value)
|
|
121
|
+
elif key == CONFIG_KEY_CHECKPOINT_NS:
|
|
122
|
+
proto.checkpoint_ns = str(value)
|
|
123
|
+
elif key == CONFIG_KEY_DURABILITY and value:
|
|
124
|
+
proto.durability = _durability_to_proto(value)
|
|
125
|
+
elif key not in RESTRICTED_RESERVED_CONFIGURABLE_KEYS:
|
|
126
|
+
extra[key] = value
|
|
127
|
+
if extra:
|
|
128
|
+
proto.extra_configurable_json.update(
|
|
129
|
+
{k: orjson.dumps(v) for k, v in extra.items()}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def context_to_json_bytes(context: dict[str, Any] | Any) -> bytes | None:
|
|
134
|
+
"""Convert context to JSON bytes for proto serialization."""
|
|
135
|
+
if context is None:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
# Convert dataclass or other objects to dict if needed
|
|
139
|
+
if hasattr(context, "__dict__") and not hasattr(context, "items"):
|
|
140
|
+
# Convert dataclass to dict
|
|
141
|
+
context_dict = context.__dict__
|
|
142
|
+
elif hasattr(context, "items"):
|
|
143
|
+
# Already a dict-like object
|
|
144
|
+
context_dict = dict(context)
|
|
145
|
+
else:
|
|
146
|
+
# Try to convert to dict using vars()
|
|
147
|
+
context_dict = vars(context) if hasattr(context, "__dict__") else {}
|
|
148
|
+
|
|
149
|
+
return orjson.dumps(context_dict)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def config_from_proto(
|
|
153
|
+
config_proto: engine_common_pb2.EngineRunnableConfig | None,
|
|
154
|
+
) -> RunnableConfig:
|
|
155
|
+
if not config_proto:
|
|
156
|
+
return RunnableConfig(tags=[], metadata={}, configurable={})
|
|
157
|
+
|
|
158
|
+
configurable = _configurable_from_proto(config_proto)
|
|
159
|
+
|
|
160
|
+
metadata = {}
|
|
161
|
+
for k, v in config_proto.metadata_json.items():
|
|
162
|
+
metadata[k] = orjson.loads(v)
|
|
163
|
+
if config_proto.HasField("run_attempt"):
|
|
164
|
+
metadata["run_attempt"] = config_proto.run_attempt
|
|
165
|
+
if config_proto.HasField("server_run_id"):
|
|
166
|
+
metadata["run_id"] = config_proto.server_run_id
|
|
167
|
+
|
|
168
|
+
config = RunnableConfig()
|
|
169
|
+
if config_proto.extra_json:
|
|
170
|
+
for k, v in config_proto.extra_json.items():
|
|
171
|
+
config[k] = orjson.loads(v) # type: ignore[invalid-key]
|
|
172
|
+
if config_proto.tags:
|
|
173
|
+
config["tags"] = list(config_proto.tags)
|
|
174
|
+
if metadata:
|
|
175
|
+
config["metadata"] = metadata
|
|
176
|
+
if configurable:
|
|
177
|
+
config["configurable"] = configurable
|
|
178
|
+
if config_proto.HasField("run_name"):
|
|
179
|
+
config["run_name"] = config_proto.run_name
|
|
180
|
+
|
|
181
|
+
if config_proto.HasField("max_concurrency"):
|
|
182
|
+
config["max_concurrency"] = config_proto.max_concurrency
|
|
183
|
+
|
|
184
|
+
if config_proto.HasField("recursion_limit"):
|
|
185
|
+
config["recursion_limit"] = config_proto.recursion_limit
|
|
186
|
+
|
|
187
|
+
return config
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _configurable_from_proto(
|
|
191
|
+
config_proto: engine_common_pb2.EngineRunnableConfig,
|
|
192
|
+
) -> dict[str, Any]:
|
|
193
|
+
configurable = {}
|
|
194
|
+
|
|
195
|
+
if config_proto.HasField("resuming"):
|
|
196
|
+
configurable[CONFIG_KEY_RESUMING] = config_proto.resuming
|
|
197
|
+
|
|
198
|
+
if config_proto.HasField("task_id"):
|
|
199
|
+
configurable[CONFIG_KEY_TASK_ID] = config_proto.task_id
|
|
200
|
+
|
|
201
|
+
if config_proto.HasField("thread_id"):
|
|
202
|
+
configurable[CONFIG_KEY_THREAD_ID] = config_proto.thread_id
|
|
203
|
+
|
|
204
|
+
if config_proto.HasField("checkpoint_id"):
|
|
205
|
+
configurable[CONFIG_KEY_CHECKPOINT_ID] = config_proto.checkpoint_id
|
|
206
|
+
|
|
207
|
+
if config_proto.HasField("checkpoint_ns"):
|
|
208
|
+
configurable[CONFIG_KEY_CHECKPOINT_NS] = config_proto.checkpoint_ns
|
|
209
|
+
|
|
210
|
+
if config_proto.HasField("durability"):
|
|
211
|
+
durability = _durability_from_proto(config_proto.durability)
|
|
212
|
+
if durability:
|
|
213
|
+
configurable[CONFIG_KEY_DURABILITY] = durability
|
|
214
|
+
|
|
215
|
+
if config_proto.HasField("graph_id"):
|
|
216
|
+
configurable[CONFIG_KEY_GRAPH_ID] = config_proto.graph_id
|
|
217
|
+
|
|
218
|
+
if len(config_proto.checkpoint_map) > 0:
|
|
219
|
+
configurable[CONFIG_KEY_CHECKPOINT_MAP] = dict(config_proto.checkpoint_map)
|
|
220
|
+
|
|
221
|
+
if len(config_proto.extra_configurable_json) > 0:
|
|
222
|
+
for k, v in config_proto.extra_configurable_json.items():
|
|
223
|
+
configurable[k] = orjson.loads(v)
|
|
224
|
+
|
|
225
|
+
return configurable
|