langgraph-api 0.12.0.dev13__py3-none-any.whl → 0.12.0.dev15__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/asyncio.py +2 -0
- langgraph_api/config/__init__.py +4 -0
- langgraph_api/grpc/ops/__init__.py +19 -4
- langgraph_api/metadata.py +19 -4
- langgraph_api/stream.py +20 -1
- {langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/METADATA +2 -2
- {langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/RECORD +18 -12
- langgraph_grpc_common/conversion/store.py +208 -0
- langgraph_grpc_common/proto/__init__.py +4 -0
- langgraph_grpc_common/proto/store_pb2.py +54 -0
- langgraph_grpc_common/proto/store_pb2.pyi +246 -0
- langgraph_grpc_common/proto/store_pb2_grpc.py +101 -0
- langgraph_grpc_common/proto/store_pb2_grpc.pyi +58 -0
- langgraph_grpc_common/store.py +109 -0
- {langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/WHEEL +0 -0
- {langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/entry_points.txt +0 -0
- {langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/licenses/LICENSE +0 -0
langgraph_api/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.12.0.
|
|
1
|
+
__version__ = "0.12.0.dev15"
|
langgraph_api/asyncio.py
CHANGED
|
@@ -103,6 +103,8 @@ async def wait_if_not_done(coro: Coroutine[Any, Any, T], done: ValueEvent) -> T:
|
|
|
103
103
|
await logger.ainfo("Done awaiting.", task=str(fut))
|
|
104
104
|
if e.args and isinstance(e.args[0], Exception):
|
|
105
105
|
raise e.args[0] from None
|
|
106
|
+
if isinstance(done._value, Exception):
|
|
107
|
+
raise done._value from None
|
|
106
108
|
raise
|
|
107
109
|
except ExceptionGroup as e:
|
|
108
110
|
raise e.exceptions[0] from None
|
langgraph_api/config/__init__.py
CHANGED
|
@@ -243,6 +243,8 @@ WEBHOOKS_ENABLED = HTTP_CONFIG and HTTP_CONFIG.get("disable_webhooks")
|
|
|
243
243
|
STORE_CONFIG = env(
|
|
244
244
|
"LANGGRAPH_STORE", cast=_parse.parse_schema(StoreConfig), default=None
|
|
245
245
|
)
|
|
246
|
+
LANGGRAPH_STORE_BACKEND = env("LANGGRAPH_STORE_BACKEND", cast=str, default="python")
|
|
247
|
+
USE_GRPC_STORE = LANGGRAPH_STORE_BACKEND == "grpc"
|
|
246
248
|
|
|
247
249
|
|
|
248
250
|
def _validate_mount_prefix(mount_prefix: str | None) -> str | None:
|
|
@@ -668,6 +670,7 @@ __all__ = [
|
|
|
668
670
|
"LANGGRAPH_METRICS_ENDPOINT",
|
|
669
671
|
"LANGGRAPH_METRICS_EXPORT_INTERVAL_MS",
|
|
670
672
|
"LANGGRAPH_POSTGRES_EXTENSIONS",
|
|
673
|
+
"LANGGRAPH_STORE_BACKEND",
|
|
671
674
|
"LANGSMITH_API_KEY",
|
|
672
675
|
"LANGSMITH_AUTH_ENDPOINT",
|
|
673
676
|
"LANGSMITH_AUTH_VERIFY_TENANT_ID",
|
|
@@ -715,6 +718,7 @@ __all__ = [
|
|
|
715
718
|
"USES_STORE_TTL",
|
|
716
719
|
"USES_THREAD_TTL",
|
|
717
720
|
"USE_CUSTOM_CHECKPOINTER",
|
|
721
|
+
"USE_GRPC_STORE",
|
|
718
722
|
"AuthConfig",
|
|
719
723
|
"CheckpointerConfig",
|
|
720
724
|
"CorsConfig",
|
|
@@ -39,6 +39,7 @@ GRPC_STATUS_TO_HTTP_STATUS = {
|
|
|
39
39
|
StatusCode.INVALID_ARGUMENT: HTTPStatus.UNPROCESSABLE_ENTITY,
|
|
40
40
|
StatusCode.PERMISSION_DENIED: HTTPStatus.FORBIDDEN,
|
|
41
41
|
StatusCode.UNAUTHENTICATED: HTTPStatus.UNAUTHORIZED,
|
|
42
|
+
StatusCode.RESOURCE_EXHAUSTED: HTTPStatus.TOO_MANY_REQUESTS,
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
|
|
@@ -187,19 +188,33 @@ def _handle_grpc_error(error: AioRpcError) -> None:
|
|
|
187
188
|
Always return detail as a string here.
|
|
188
189
|
"""
|
|
189
190
|
error_details = error.details()
|
|
191
|
+
retry_after_seconds = None
|
|
190
192
|
if error_details is not None:
|
|
191
193
|
try:
|
|
192
194
|
details = orjson.loads(error_details)
|
|
193
|
-
|
|
195
|
+
retry_after_seconds = details.get("retry_after_seconds")
|
|
196
|
+
message = details.get("message", "")
|
|
197
|
+
# A string message is the detail verbatim; only re-encode structured
|
|
198
|
+
# (non-string) messages as JSON.
|
|
199
|
+
error_details = (
|
|
200
|
+
message if isinstance(message, str) else orjson.dumps(message).decode()
|
|
201
|
+
)
|
|
194
202
|
except orjson.JSONDecodeError:
|
|
195
203
|
# error details is not json, so just retun it as is
|
|
196
204
|
pass
|
|
197
205
|
|
|
206
|
+
status_code = GRPC_STATUS_TO_HTTP_STATUS.get(
|
|
207
|
+
error.code(), HTTPStatus.INTERNAL_SERVER_ERROR
|
|
208
|
+
)
|
|
209
|
+
headers = None
|
|
210
|
+
if status_code == HTTPStatus.TOO_MANY_REQUESTS and retry_after_seconds:
|
|
211
|
+
# The Go core carries Retry-After as a structured integer (seconds).
|
|
212
|
+
headers = {"Retry-After": str(int(retry_after_seconds))}
|
|
213
|
+
|
|
198
214
|
raise HTTPException(
|
|
199
|
-
status_code=
|
|
200
|
-
error.code(), HTTPStatus.INTERNAL_SERVER_ERROR
|
|
201
|
-
),
|
|
215
|
+
status_code=status_code,
|
|
202
216
|
detail=error_details,
|
|
217
|
+
headers=headers,
|
|
203
218
|
)
|
|
204
219
|
|
|
205
220
|
|
langgraph_api/metadata.py
CHANGED
|
@@ -2,9 +2,9 @@ import asyncio
|
|
|
2
2
|
import os
|
|
3
3
|
import uuid
|
|
4
4
|
from datetime import UTC, datetime
|
|
5
|
+
from importlib import metadata as importlib_metadata
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
|
-
import langgraph.version
|
|
8
8
|
import orjson
|
|
9
9
|
import structlog
|
|
10
10
|
|
|
@@ -58,6 +58,10 @@ else:
|
|
|
58
58
|
HOST = "self-hosted"
|
|
59
59
|
PLAN = "enterprise" if plus_features_enabled() else "developer"
|
|
60
60
|
USER_API_URL = os.getenv("LANGGRAPH_API_URL", None)
|
|
61
|
+
DEPENDENCY_VERSION_DISTRIBUTIONS = {
|
|
62
|
+
"langgraph.python.version": "langgraph",
|
|
63
|
+
"starlette.version": "starlette",
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
RUN_COUNTER = 0
|
|
63
67
|
NODE_COUNTER = 0
|
|
@@ -80,6 +84,19 @@ if LANGSMITH_AUTH_ENDPOINT:
|
|
|
80
84
|
)
|
|
81
85
|
|
|
82
86
|
|
|
87
|
+
def _dependency_version_metadata() -> dict[str, str]:
|
|
88
|
+
tags = {}
|
|
89
|
+
for tag, distribution in DEPENDENCY_VERSION_DISTRIBUTIONS.items():
|
|
90
|
+
try:
|
|
91
|
+
tags[tag] = importlib_metadata.version(distribution)
|
|
92
|
+
except importlib_metadata.PackageNotFoundError:
|
|
93
|
+
logger.debug(
|
|
94
|
+
"Dependency package not found for metadata", package=distribution
|
|
95
|
+
)
|
|
96
|
+
tags[tag] = ""
|
|
97
|
+
return tags
|
|
98
|
+
|
|
99
|
+
|
|
83
100
|
def _lang_usage_metadata() -> tuple[dict[str, str], dict[str, int]]:
|
|
84
101
|
js_graph_count = sum(1 for graph_id in GRAPHS if is_js_graph(graph_id))
|
|
85
102
|
py_graph_count = len(GRAPHS) - js_graph_count
|
|
@@ -130,8 +147,6 @@ async def metadata_loop() -> None:
|
|
|
130
147
|
"No license key or control plane API key set, skipping metadata loop"
|
|
131
148
|
)
|
|
132
149
|
return
|
|
133
|
-
lg_version = langgraph.version.__version__
|
|
134
|
-
|
|
135
150
|
if (
|
|
136
151
|
LANGGRAPH_CLOUD_LICENSE_KEY
|
|
137
152
|
and not LANGGRAPH_CLOUD_LICENSE_KEY.startswith("lcl_")
|
|
@@ -160,7 +175,7 @@ async def metadata_loop() -> None:
|
|
|
160
175
|
base_tags = _ensure_strings(
|
|
161
176
|
# Tag values must be strings.
|
|
162
177
|
{
|
|
163
|
-
|
|
178
|
+
**_dependency_version_metadata(),
|
|
164
179
|
"langgraph_api.version": __version__ or "",
|
|
165
180
|
"langgraph.platform.revision": REVISION or "",
|
|
166
181
|
"langgraph.platform.variant": VARIANT or "",
|
langgraph_api/stream.py
CHANGED
|
@@ -339,7 +339,26 @@ async def astream_state(
|
|
|
339
339
|
):
|
|
340
340
|
yield event["name"], event["data"]
|
|
341
341
|
# TODO support messages-tuple for js graphs
|
|
342
|
-
|
|
342
|
+
# For JS (BaseRemotePregel) with subgraphs=True, subgraph events
|
|
343
|
+
# carry the subgraph's own run_id. Accept them if the chunk is a
|
|
344
|
+
# proper 3-tuple [ns, mode, chunk] — that's the sidecar's
|
|
345
|
+
# normalized format. Limit this bypass to remote graphs only;
|
|
346
|
+
# Python child events must fall through to the raw "events"
|
|
347
|
+
# fallback below when the client requests stream_mode="events".
|
|
348
|
+
_chunk_data = (
|
|
349
|
+
event["data"].get("chunk")
|
|
350
|
+
if event["event"] == "on_chain_stream"
|
|
351
|
+
else None
|
|
352
|
+
)
|
|
353
|
+
if event["event"] == "on_chain_stream" and (
|
|
354
|
+
event["run_id"] == run_id
|
|
355
|
+
or (
|
|
356
|
+
subgraphs
|
|
357
|
+
and is_remote_pregel
|
|
358
|
+
and isinstance(_chunk_data, (list, tuple))
|
|
359
|
+
and len(_chunk_data) == 3
|
|
360
|
+
)
|
|
361
|
+
):
|
|
343
362
|
if subgraphs:
|
|
344
363
|
ns, mode, chunk = event["data"]["chunk"]
|
|
345
364
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.12.0.
|
|
3
|
+
Version: 0.12.0.dev15
|
|
4
4
|
Author-email: Will Fu-Hinthorn <will@langchain.dev>, Josh Rogers <josh@langchain.dev>, Parker Rule <parker@langchain.dev>
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -29,7 +29,7 @@ Requires-Dist: prometheus-client>=0.0.1
|
|
|
29
29
|
Requires-Dist: protobuf<7.0.0,>=6.32.1
|
|
30
30
|
Requires-Dist: pyjwt>=2.13.0
|
|
31
31
|
Requires-Dist: sse-starlette<3.4.0,>=2.1.3
|
|
32
|
-
Requires-Dist: starlette>=
|
|
32
|
+
Requires-Dist: starlette>=1.3.1
|
|
33
33
|
Requires-Dist: structlog<26,>=24.1.0
|
|
34
34
|
Requires-Dist: tenacity>=8.0.0
|
|
35
35
|
Requires-Dist: truststore>=0.1
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
langgraph_api/__init__.py,sha256=
|
|
1
|
+
langgraph_api/__init__.py,sha256=3hHYNZlyWnoc9JVCLo-c7OAsrbQDPhSBvtrj8CKX1z4,29
|
|
2
2
|
langgraph_api/_factory_utils.py,sha256=5JsiJbg_YocVSryN2jwoZTg03-eyymlWMK6sKCmXwz0,5756
|
|
3
3
|
langgraph_api/asgi_transport.py,sha256=XApY3lIWBZTMbbsl8dDJzl0cLGirmAGE0SifqZUnXvs,11896
|
|
4
|
-
langgraph_api/asyncio.py,sha256=
|
|
4
|
+
langgraph_api/asyncio.py,sha256=smqyAoO9nIyPPQRw1IVSCh85fwoZP4PEo-5dDhxGruc,10676
|
|
5
5
|
langgraph_api/cache.py,sha256=LuB3Te0UdXC8a-uEJoRHoe5XsgXulXI59f_Q6DCJNKc,13005
|
|
6
6
|
langgraph_api/cli.py,sha256=ATtS9s9Cx7QNiGPJceKnMCko29A25ZA-xz39fdxmgfg,22389
|
|
7
7
|
langgraph_api/command.py,sha256=d-k8h6H4ix1n7fSZ-Zb01NbSkEyqrD6cMKfDFXEIYEw,821
|
|
@@ -13,7 +13,7 @@ langgraph_api/http.py,sha256=7hPxKbj-xoAKcm7iucBpT5nM_hXOgGVCPbBsCD693Cw,6977
|
|
|
13
13
|
langgraph_api/http_metrics.py,sha256=etxbZNmYxdb58DVLNkHP7S-N6njXPTiQh2OWKMaIZi8,5336
|
|
14
14
|
langgraph_api/http_metrics_utils.py,sha256=sjxF7SYGTzY0Wz_G0dzatsYNnWr31S6ujej4JmBG2yo,866
|
|
15
15
|
langgraph_api/logging.py,sha256=V1RCnqVLuMvJtrBiyMMLfaEdbS3k5A2M8Unhr4FUUdQ,6801
|
|
16
|
-
langgraph_api/metadata.py,sha256=
|
|
16
|
+
langgraph_api/metadata.py,sha256=hXkF55cWxxnjAJ0MB_PhU_4NfVzpLuwU4xwFDaAgi7I,10314
|
|
17
17
|
langgraph_api/metrics_collector.py,sha256=gMLHL18rJyYl985AOmu9eH7W1ttdRdkPHzeyczjCOBw,8280
|
|
18
18
|
langgraph_api/metrics_otlp.py,sha256=t9oJrxfxY2O5jY4JW2gONPKoBiBuklhzCrnZvn1qTxQ,28730
|
|
19
19
|
langgraph_api/otel_context.py,sha256=DWFwW4Yu88QY4W2J0IRcURR450Th9J2DupvDDkSkMBA,7166
|
|
@@ -29,7 +29,7 @@ langgraph_api/server.py,sha256=1eAZPim0Pkgh5oGS4EvW-_7Zh_82iGOZtR1rpX08FoA,11216
|
|
|
29
29
|
langgraph_api/sse.py,sha256=cChZ7raQUHp8p5BreE_5wMBR8lFO0n7746sV8_HQOrc,4822
|
|
30
30
|
langgraph_api/state.py,sha256=A6jx2OpcVmiFNBafjZ2tX1x6s_AhBk5EW2drd-vaqIc,4396
|
|
31
31
|
langgraph_api/store.py,sha256=i-jVfWzDEmPESVofh1tNWbo0HMLiLz_BSKKV4QjN-dE,5027
|
|
32
|
-
langgraph_api/stream.py,sha256=
|
|
32
|
+
langgraph_api/stream.py,sha256=rJIGe8rEeS6QxQfsDKomUBRED6ZPIF-ALtx4D8Gw0JQ,33348
|
|
33
33
|
langgraph_api/stream_v2.py,sha256=KCIsPf6gs_jrIdZ8D2VTEi5c5p5aRNpVNhMP4kzjp2g,10824
|
|
34
34
|
langgraph_api/traceblock.py,sha256=GhgAtLhAQ8Z8LHtRQq3par-rfPpRBQp2Q7WBACJq1NI,677
|
|
35
35
|
langgraph_api/validation.py,sha256=XyeKyt7jAICmIlT_b0J0mv2YbwIbNoe4m6zEmfk9gOA,14657
|
|
@@ -64,7 +64,7 @@ langgraph_api/auth/studio_user.py,sha256=gNCicIo6cYaHmFj2sEdsvDYkKW7NWfGXGS2tTAM
|
|
|
64
64
|
langgraph_api/auth/langsmith/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
65
|
langgraph_api/auth/langsmith/backend.py,sha256=Y6-VxD7zfV1jzGdjmQ66CgNa3SenLbo3d_375CcKZ9U,3770
|
|
66
66
|
langgraph_api/auth/langsmith/client.py,sha256=79kwCVeHU64nsHsxWipfZhf44lM6vfs2nlfTxlJF6LU,4142
|
|
67
|
-
langgraph_api/config/__init__.py,sha256=
|
|
67
|
+
langgraph_api/config/__init__.py,sha256=NYJWKJ-PbfeI6k5KnF3W_HWLE8EOS0rJKaQQqKTCAus,25717
|
|
68
68
|
langgraph_api/config/_parse.py,sha256=RpfZgFAPJlRMv13AzGr3kAYbIrqHcgjzO8IgeboTw4A,3922
|
|
69
69
|
langgraph_api/config/schemas.py,sha256=cHzVvepthpD7DDeWE2ytkOHah-iDNH7xRx9dSWUatQI,20864
|
|
70
70
|
langgraph_api/encryption/__init__.py,sha256=gaCZ00CocSbqSqrDn6XJHaSp2CZCnC8qnrD9G4fbzyI,363
|
|
@@ -86,7 +86,7 @@ langgraph_api/grpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
86
86
|
langgraph_api/grpc/client.py,sha256=ypSgZWclK7OCKLGW8gD_LZwwgsgQEahJqc8mBWF8Rug,15578
|
|
87
87
|
langgraph_api/grpc/server.py,sha256=Fknr6BJbdSK38wF7B1vPDplK25KB_UfMB9Fp1er6DPU,8366
|
|
88
88
|
langgraph_api/grpc/generated/core_api_pb2.pyi,sha256=0PEzVh8s6rqHq52ekhqPaMI_TOsP4_xuUUv9_XS7r1w,54758
|
|
89
|
-
langgraph_api/grpc/ops/__init__.py,sha256=
|
|
89
|
+
langgraph_api/grpc/ops/__init__.py,sha256=ACO-Cp7ygehNfOG1ucSH8iMw3hVXbLluxiqczG2PKTQ,18827
|
|
90
90
|
langgraph_api/grpc/ops/assistants.py,sha256=00vY7Dd7BcXaVp_6UrKZIb5b4tQ8Lm5MxJcEpyVPfo0,13902
|
|
91
91
|
langgraph_api/grpc/ops/cache.py,sha256=MoPAmSuOwbt2Cud1YZJm_YJeaDHPFy1IiV4m0PDImgg,1399
|
|
92
92
|
langgraph_api/grpc/ops/crons.py,sha256=oGPW9qW-J4H9baX7Jsee1opsFnXfThHLHh_N47mDf9s,19596
|
|
@@ -165,14 +165,16 @@ openapi.json,sha256=0N-D4j0_3ruH6nMF4k5lnqmpV-aoB5Se-WWheCQuQQs,219552
|
|
|
165
165
|
langgraph_grpc_common/__init__.py,sha256=sO7jFHekQxt6zZPhTPZAWLYLB_S8w7-VuJ7NyWFlFNo,97
|
|
166
166
|
langgraph_grpc_common/checkpointer.py,sha256=u3ERFgqnUCpCYpOSxKR_6Jvo_tR4yDvq7qU-EL61bSg,14022
|
|
167
167
|
langgraph_grpc_common/serde.py,sha256=pxIhgxtrXtwWVhAlLE2LAeSAuKk2ZHtnvAP3DRDT2Qw,6184
|
|
168
|
+
langgraph_grpc_common/store.py,sha256=BIHYT_BTw2ByFAIsomu9vwNVu1kZdUEOjkJChV7rjuA,3721
|
|
168
169
|
langgraph_grpc_common/conversion/__init__.py,sha256=pLsOrRtmF9YkgmCPhcfym6lYOB7PCJTRItyo1YK_AT8,208
|
|
169
170
|
langgraph_grpc_common/conversion/_compat.py,sha256=MIEo69I7tfaPskunPGwBCKheksLwxpw-z-4O3hvO9og,4010
|
|
170
171
|
langgraph_grpc_common/conversion/checkpoint.py,sha256=Ty81cijafeal7blzzXbYFjWpu9iXVb_spFLBZ2FvmgI,12045
|
|
171
172
|
langgraph_grpc_common/conversion/config.py,sha256=HjlHRX-_GpKa1m0RWVL1PEZQCvA3w_8wKVYrtaT06do,13015
|
|
172
173
|
langgraph_grpc_common/conversion/durability.py,sha256=FWhqjzVN4JrrsAL9AwsJkvIorQGNRl14w97Va-WZRk0,991
|
|
174
|
+
langgraph_grpc_common/conversion/store.py,sha256=NGGZp4FiMzJXByIqRRy2qYDxlWeXBGkEN9k1aNTsVUA,6253
|
|
173
175
|
langgraph_grpc_common/conversion/struct.py,sha256=yk4jpPdywzn8UosAohun21lU5D_IIglOY9rkBhiG-gA,2072
|
|
174
176
|
langgraph_grpc_common/conversion/value.py,sha256=eZ9fDqKje9tKsO8A_6f0BPSI7lt94Vzuu3NNEEYLFBM,8343
|
|
175
|
-
langgraph_grpc_common/proto/__init__.py,sha256=
|
|
177
|
+
langgraph_grpc_common/proto/__init__.py,sha256=eBejrrULiDdasi3_Hga_AJW8ZPMkjKyyAeW9Ey640Ks,1375
|
|
176
178
|
langgraph_grpc_common/proto/checkpointer_pb2.py,sha256=c-gaVwNHm7sUzThJDzumME2M_nP4B1RjEki4ZG7-kjM,7915
|
|
177
179
|
langgraph_grpc_common/proto/checkpointer_pb2.pyi,sha256=rGUxQyNFifmu8OPy0S418sCWSBQY_CVckobPXtFfZfs,20763
|
|
178
180
|
langgraph_grpc_common/proto/checkpointer_pb2_grpc.py,sha256=MLhZ7M4g9gjfXZqWenk93oO2uIZSybbFoaeU8bauFPA,20176
|
|
@@ -229,8 +231,12 @@ langgraph_grpc_common/proto/errors_pb2.py,sha256=JI6x-vBK1AE7DHZ5DQwN1mZWF6C4xTR
|
|
|
229
231
|
langgraph_grpc_common/proto/errors_pb2.pyi,sha256=rd3-BYUH8V-aO66taL7OOblaLgdrDtf1Vcd38GUoVVM,2181
|
|
230
232
|
langgraph_grpc_common/proto/errors_pb2_grpc.py,sha256=2-LwQ0OPGo-NtC0269q7Fw6GPBxnTLYWq3xP5Eq0_YA,886
|
|
231
233
|
langgraph_grpc_common/proto/errors_pb2_grpc.pyi,sha256=uC9Wnq6uyg488QiONpJ0ba1s_iouQCOYsjd_FDd1XUM,495
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
langgraph_api-0.12.0.
|
|
234
|
+
langgraph_grpc_common/proto/store_pb2.py,sha256=5px40nIUag8p0KlE6o5vpvgfenX71BDIr3VjFfFQP6E,3406
|
|
235
|
+
langgraph_grpc_common/proto/store_pb2.pyi,sha256=cZZGod9tBReUukPkjNzssEdz5OBoZ2pecXugbp-9Lmo,9755
|
|
236
|
+
langgraph_grpc_common/proto/store_pb2_grpc.py,sha256=wSD65QgFkYTkPTHcf7VhyI2FQ7UH_RgIf3vQW3VYlsM,3324
|
|
237
|
+
langgraph_grpc_common/proto/store_pb2_grpc.pyi,sha256=oS1h2cDoq2OjyM8xazcmc8LwRDC5oCAD0zto2QUmPQw,2027
|
|
238
|
+
langgraph_api-0.12.0.dev15.dist-info/METADATA,sha256=nc5DmJfxPOxGO2rAoxSIuNyd_s0yNxlCB-M8FZGlWL8,4631
|
|
239
|
+
langgraph_api-0.12.0.dev15.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
240
|
+
langgraph_api-0.12.0.dev15.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
|
|
241
|
+
langgraph_api-0.12.0.dev15.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
242
|
+
langgraph_api-0.12.0.dev15.dist-info/RECORD,,
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Marshal langgraph.store.base GetOp/PutOp/Item/Result to and from store.proto."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
7
|
+
|
|
8
|
+
import orjson
|
|
9
|
+
from google.protobuf import empty_pb2
|
|
10
|
+
from langgraph.store.base import (
|
|
11
|
+
GetOp,
|
|
12
|
+
IndexConfig,
|
|
13
|
+
Item,
|
|
14
|
+
Op,
|
|
15
|
+
PutOp,
|
|
16
|
+
Result,
|
|
17
|
+
ensure_embeddings,
|
|
18
|
+
get_text_at_path,
|
|
19
|
+
tokenize_path,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from langgraph_grpc_common.proto import store_pb2
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import Sequence
|
|
26
|
+
|
|
27
|
+
from langchain_core.embeddings import Embeddings
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _ensure_index_config(
|
|
31
|
+
index_config: IndexConfig,
|
|
32
|
+
) -> tuple[Embeddings | None, IndexConfig]:
|
|
33
|
+
# Vendored from langgraph.store.postgres.base so grpc_common_py stays
|
|
34
|
+
# backend-agnostic (no langgraph-checkpoint-postgres / psycopg dependency).
|
|
35
|
+
index_config = index_config.copy()
|
|
36
|
+
tokenized: list[tuple[str, str | list[str]]] = []
|
|
37
|
+
tot = 0
|
|
38
|
+
fields = index_config.get("fields") or ["$"]
|
|
39
|
+
if isinstance(fields, str):
|
|
40
|
+
fields = [fields]
|
|
41
|
+
if not isinstance(fields, list):
|
|
42
|
+
raise ValueError(f"Text fields must be a list or a string. Got {fields}")
|
|
43
|
+
for p in fields:
|
|
44
|
+
if p == "$":
|
|
45
|
+
tokenized.append((p, "$"))
|
|
46
|
+
tot += 1
|
|
47
|
+
else:
|
|
48
|
+
toks = tokenize_path(p)
|
|
49
|
+
tokenized.append((p, toks))
|
|
50
|
+
tot += len(toks)
|
|
51
|
+
index_config["__tokenized_fields"] = tokenized # ty: ignore[invalid-key]
|
|
52
|
+
index_config["__estimated_num_vectors"] = tot # ty: ignore[invalid-key]
|
|
53
|
+
embeddings = ensure_embeddings(index_config.get("embed"))
|
|
54
|
+
return embeddings, index_config
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _ttl_to_proto_minutes(ttl: float | None) -> int:
|
|
58
|
+
if ttl is None:
|
|
59
|
+
return 0
|
|
60
|
+
if ttl != int(ttl):
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f"gRPC store only supports integer-minute TTL; got fractional ttl={ttl}"
|
|
63
|
+
)
|
|
64
|
+
return int(ttl)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def op_to_proto(
|
|
68
|
+
op: Op,
|
|
69
|
+
*,
|
|
70
|
+
vectors: Sequence[store_pb2.VectorValue] | None = None,
|
|
71
|
+
) -> store_pb2.Op:
|
|
72
|
+
if isinstance(op, GetOp):
|
|
73
|
+
return store_pb2.Op(
|
|
74
|
+
get=store_pb2.GetOp(
|
|
75
|
+
namespace=list(op.namespace),
|
|
76
|
+
key=str(op.key),
|
|
77
|
+
refreshTTL=op.refresh_ttl,
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
if isinstance(op, PutOp):
|
|
81
|
+
if op.value is None:
|
|
82
|
+
raise TypeError(
|
|
83
|
+
"PutOp with value=None (delete) is not supported by gRPC store"
|
|
84
|
+
)
|
|
85
|
+
put_kwargs: dict[str, Any] = {
|
|
86
|
+
"namespace": list(op.namespace),
|
|
87
|
+
"key": str(op.key),
|
|
88
|
+
"value_json": orjson.dumps(op.value),
|
|
89
|
+
"ttlMinutes": _ttl_to_proto_minutes(op.ttl),
|
|
90
|
+
}
|
|
91
|
+
if vectors is not None:
|
|
92
|
+
put_kwargs["vectors"] = list(vectors)
|
|
93
|
+
return store_pb2.Op(put=store_pb2.PutOp(**put_kwargs))
|
|
94
|
+
raise TypeError(f"unsupported op: {type(op).__name__}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def op_from_proto(msg: store_pb2.Op) -> Op:
|
|
98
|
+
kind = msg.WhichOneof("op")
|
|
99
|
+
if kind == "get":
|
|
100
|
+
g = msg.get
|
|
101
|
+
return GetOp(
|
|
102
|
+
namespace=tuple(g.namespace),
|
|
103
|
+
key=g.key,
|
|
104
|
+
refresh_ttl=g.refreshTTL,
|
|
105
|
+
)
|
|
106
|
+
if kind == "put":
|
|
107
|
+
p = msg.put
|
|
108
|
+
ttl: float | None = None
|
|
109
|
+
if p.ttlMinutes:
|
|
110
|
+
ttl = float(p.ttlMinutes)
|
|
111
|
+
return PutOp(
|
|
112
|
+
namespace=tuple(p.namespace),
|
|
113
|
+
key=p.key,
|
|
114
|
+
value=orjson.loads(p.value_json),
|
|
115
|
+
ttl=ttl,
|
|
116
|
+
)
|
|
117
|
+
raise ValueError("empty Op message (no oneof set)")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def result_to_proto(result: Result, op: Op) -> store_pb2.OpResult:
|
|
121
|
+
if isinstance(op, GetOp):
|
|
122
|
+
if result is None:
|
|
123
|
+
return store_pb2.OpResult(none=empty_pb2.Empty())
|
|
124
|
+
if not isinstance(result, Item):
|
|
125
|
+
raise TypeError(
|
|
126
|
+
f"expected Item for GetOp result, got {type(result).__name__}"
|
|
127
|
+
)
|
|
128
|
+
return store_pb2.OpResult(item=_item_to_proto(result))
|
|
129
|
+
if isinstance(op, PutOp):
|
|
130
|
+
return store_pb2.OpResult(none=empty_pb2.Empty())
|
|
131
|
+
raise TypeError(f"unsupported op for result encoding: {type(op).__name__}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def result_from_proto(msg: store_pb2.OpResult) -> Result:
|
|
135
|
+
kind = msg.WhichOneof("result")
|
|
136
|
+
if kind == "none":
|
|
137
|
+
return None
|
|
138
|
+
if kind == "item":
|
|
139
|
+
return _item_from_proto(msg.item)
|
|
140
|
+
raise ValueError("empty OpResult message (no oneof set)")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _item_to_proto(item: Item) -> store_pb2.Item:
|
|
144
|
+
return store_pb2.Item(
|
|
145
|
+
namespace=list(item.namespace),
|
|
146
|
+
key=item.key,
|
|
147
|
+
value_json=orjson.dumps(item.value),
|
|
148
|
+
created_at=_format_dt(item.created_at),
|
|
149
|
+
updated_at=_format_dt(item.updated_at),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _item_from_proto(msg: store_pb2.Item) -> Item:
|
|
154
|
+
return Item(
|
|
155
|
+
namespace=tuple(msg.namespace),
|
|
156
|
+
key=msg.key,
|
|
157
|
+
value=orjson.loads(msg.value_json),
|
|
158
|
+
created_at=datetime.fromisoformat(msg.created_at),
|
|
159
|
+
updated_at=datetime.fromisoformat(msg.updated_at),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _format_dt(dt: datetime) -> str:
|
|
164
|
+
return dt.isoformat()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def vectors_for_put_op(
|
|
168
|
+
op: PutOp,
|
|
169
|
+
index_config: IndexConfig,
|
|
170
|
+
embeddings: Embeddings,
|
|
171
|
+
) -> list[store_pb2.VectorValue]:
|
|
172
|
+
if op.index is False or op.value is None:
|
|
173
|
+
return []
|
|
174
|
+
|
|
175
|
+
value = op.value
|
|
176
|
+
if op.index is None:
|
|
177
|
+
paths = cast(
|
|
178
|
+
"list[tuple[str, str | list[str]]]",
|
|
179
|
+
index_config["__tokenized_fields"], # ty: ignore[invalid-key]
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
paths = [(ix, tokenize_path(ix)) for ix in op.index]
|
|
183
|
+
|
|
184
|
+
texts: list[str] = []
|
|
185
|
+
pathnames: list[str] = []
|
|
186
|
+
for path, tokenized_path in paths:
|
|
187
|
+
extracted = get_text_at_path(value, tokenized_path)
|
|
188
|
+
for i, text in enumerate(extracted):
|
|
189
|
+
pathname = f"{path}.{i}" if len(extracted) > 1 else path
|
|
190
|
+
pathnames.append(pathname)
|
|
191
|
+
texts.append(text)
|
|
192
|
+
|
|
193
|
+
if not texts:
|
|
194
|
+
return []
|
|
195
|
+
|
|
196
|
+
vectors = await embeddings.aembed_documents(texts)
|
|
197
|
+
return [
|
|
198
|
+
store_pb2.VectorValue(valuePath=pathname, embedding=vector)
|
|
199
|
+
for pathname, vector in zip(pathnames, vectors, strict=False)
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def normalize_index_config(
|
|
204
|
+
index: IndexConfig | None,
|
|
205
|
+
) -> tuple[Embeddings | None, IndexConfig | None]:
|
|
206
|
+
if not index:
|
|
207
|
+
return None, None
|
|
208
|
+
return _ensure_index_config(index)
|
|
@@ -15,6 +15,8 @@ from . import engine_common_pb2
|
|
|
15
15
|
from . import engine_common_pb2_grpc
|
|
16
16
|
from . import checkpointer_pb2
|
|
17
17
|
from . import checkpointer_pb2_grpc
|
|
18
|
+
from . import store_pb2
|
|
19
|
+
from . import store_pb2_grpc
|
|
18
20
|
from . import encryption_pb2
|
|
19
21
|
from . import encryption_pb2_grpc
|
|
20
22
|
from . import errors_pb2
|
|
@@ -27,6 +29,8 @@ __all__ = [
|
|
|
27
29
|
"engine_common_pb2_grpc",
|
|
28
30
|
"checkpointer_pb2",
|
|
29
31
|
"checkpointer_pb2_grpc",
|
|
32
|
+
"store_pb2",
|
|
33
|
+
"store_pb2_grpc",
|
|
30
34
|
"encryption_pb2",
|
|
31
35
|
"encryption_pb2_grpc",
|
|
32
36
|
"errors_pb2",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: store.proto
|
|
5
|
+
# Protobuf Python Version: 6.31.1
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
+
from google.protobuf.internal import builder as _builder
|
|
12
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
+
_runtime_version.Domain.PUBLIC,
|
|
14
|
+
6,
|
|
15
|
+
31,
|
|
16
|
+
1,
|
|
17
|
+
'',
|
|
18
|
+
'store.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0bstore.proto\x12\x05store\x1a\x1bgoogle/protobuf/empty.proto\"&\n\x0c\x42\x61tchRequest\x12\x16\n\x03ops\x18\x01 \x03(\x0b\x32\t.store.Op\"1\n\rBatchResponse\x12 \n\x07results\x18\x01 \x03(\x0b\x32\x0f.store.OpResult\"D\n\x02Op\x12\x1b\n\x03get\x18\x01 \x01(\x0b\x32\x0c.store.GetOpH\x00\x12\x1b\n\x03put\x18\x02 \x01(\x0b\x32\x0c.store.PutOpH\x00\x42\x04\n\x02op\";\n\x05GetOp\x12\x11\n\tnamespace\x18\x01 \x03(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x12\n\nrefreshTTL\x18\x03 \x01(\x08\"3\n\x0bVectorValue\x12\x11\n\tvaluePath\x18\x01 \x01(\t\x12\x11\n\tembedding\x18\x02 \x03(\x02\"t\n\x05PutOp\x12\x11\n\tnamespace\x18\x01 \x03(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x12\n\nvalue_json\x18\x03 \x01(\x0c\x12\x12\n\nttlMinutes\x18\x04 \x01(\x05\x12#\n\x07vectors\x18\x05 \x03(\x0b\x32\x12.store.VectorValue\"Y\n\x08OpResult\x12\x1b\n\x04item\x18\x01 \x01(\x0b\x32\x0b.store.ItemH\x00\x12&\n\x04none\x18\x02 \x01(\x0b\x32\x16.google.protobuf.EmptyH\x00\x42\x08\n\x06result\"b\n\x04Item\x12\x11\n\tnamespace\x18\x01 \x03(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x12\n\nvalue_json\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\t\x12\x12\n\nupdated_at\x18\x05 \x01(\t2;\n\x05Store\x12\x32\n\x05\x42\x61tch\x12\x13.store.BatchRequest\x1a\x14.store.BatchResponseB?Z=github.com/langchain-ai/langgraph-api/core/internal/engine/pbb\x06proto3')
|
|
29
|
+
|
|
30
|
+
_globals = globals()
|
|
31
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
32
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'store_pb2', _globals)
|
|
33
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
34
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
35
|
+
_globals['DESCRIPTOR']._serialized_options = b'Z=github.com/langchain-ai/langgraph-api/core/internal/engine/pb'
|
|
36
|
+
_globals['_BATCHREQUEST']._serialized_start=51
|
|
37
|
+
_globals['_BATCHREQUEST']._serialized_end=89
|
|
38
|
+
_globals['_BATCHRESPONSE']._serialized_start=91
|
|
39
|
+
_globals['_BATCHRESPONSE']._serialized_end=140
|
|
40
|
+
_globals['_OP']._serialized_start=142
|
|
41
|
+
_globals['_OP']._serialized_end=210
|
|
42
|
+
_globals['_GETOP']._serialized_start=212
|
|
43
|
+
_globals['_GETOP']._serialized_end=271
|
|
44
|
+
_globals['_VECTORVALUE']._serialized_start=273
|
|
45
|
+
_globals['_VECTORVALUE']._serialized_end=324
|
|
46
|
+
_globals['_PUTOP']._serialized_start=326
|
|
47
|
+
_globals['_PUTOP']._serialized_end=442
|
|
48
|
+
_globals['_OPRESULT']._serialized_start=444
|
|
49
|
+
_globals['_OPRESULT']._serialized_end=533
|
|
50
|
+
_globals['_ITEM']._serialized_start=535
|
|
51
|
+
_globals['_ITEM']._serialized_end=633
|
|
52
|
+
_globals['_STORE']._serialized_start=635
|
|
53
|
+
_globals['_STORE']._serialized_end=694
|
|
54
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@generated by mypy-protobuf. Do not edit manually!
|
|
3
|
+
isort:skip_file
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections import abc as _abc
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import empty_pb2 as _empty_pb2
|
|
9
|
+
from google.protobuf import message as _message
|
|
10
|
+
from google.protobuf.internal import containers as _containers
|
|
11
|
+
import builtins as _builtins
|
|
12
|
+
import sys
|
|
13
|
+
import typing as _typing
|
|
14
|
+
|
|
15
|
+
if sys.version_info >= (3, 11):
|
|
16
|
+
from typing import TypeAlias as _TypeAlias, Never as _Never
|
|
17
|
+
else:
|
|
18
|
+
from typing_extensions import TypeAlias as _TypeAlias, Never as _Never
|
|
19
|
+
|
|
20
|
+
DESCRIPTOR: _descriptor.FileDescriptor
|
|
21
|
+
|
|
22
|
+
@_typing.final
|
|
23
|
+
class BatchRequest(_message.Message):
|
|
24
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
25
|
+
|
|
26
|
+
OPS_FIELD_NUMBER: _builtins.int
|
|
27
|
+
@_builtins.property
|
|
28
|
+
def ops(self) -> _containers.RepeatedCompositeFieldContainer[Global___Op]: ...
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
ops: _abc.Iterable[Global___Op] | None = ...,
|
|
33
|
+
) -> None: ...
|
|
34
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
35
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
36
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["ops", b"ops"] # noqa: Y015
|
|
37
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
38
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
39
|
+
|
|
40
|
+
Global___BatchRequest: _TypeAlias = BatchRequest # noqa: Y015
|
|
41
|
+
|
|
42
|
+
@_typing.final
|
|
43
|
+
class BatchResponse(_message.Message):
|
|
44
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
45
|
+
|
|
46
|
+
RESULTS_FIELD_NUMBER: _builtins.int
|
|
47
|
+
@_builtins.property
|
|
48
|
+
def results(self) -> _containers.RepeatedCompositeFieldContainer[Global___OpResult]:
|
|
49
|
+
"""Same length as BatchRequest.ops, same order."""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
*,
|
|
54
|
+
results: _abc.Iterable[Global___OpResult] | None = ...,
|
|
55
|
+
) -> None: ...
|
|
56
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
57
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
58
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["results", b"results"] # noqa: Y015
|
|
59
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
60
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
61
|
+
|
|
62
|
+
Global___BatchResponse: _TypeAlias = BatchResponse # noqa: Y015
|
|
63
|
+
|
|
64
|
+
@_typing.final
|
|
65
|
+
class Op(_message.Message):
|
|
66
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
67
|
+
|
|
68
|
+
GET_FIELD_NUMBER: _builtins.int
|
|
69
|
+
PUT_FIELD_NUMBER: _builtins.int
|
|
70
|
+
@_builtins.property
|
|
71
|
+
def get(self) -> Global___GetOp: ...
|
|
72
|
+
@_builtins.property
|
|
73
|
+
def put(self) -> Global___PutOp: ...
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
*,
|
|
77
|
+
get: Global___GetOp | None = ...,
|
|
78
|
+
put: Global___PutOp | None = ...,
|
|
79
|
+
) -> None: ...
|
|
80
|
+
_HasFieldArgType: _TypeAlias = _typing.Literal["get", b"get", "op", b"op", "put", b"put"] # noqa: Y015
|
|
81
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
82
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["get", b"get", "op", b"op", "put", b"put"] # noqa: Y015
|
|
83
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
84
|
+
_WhichOneofReturnType_op: _TypeAlias = _typing.Literal["get", "put"] # noqa: Y015
|
|
85
|
+
_WhichOneofArgType_op: _TypeAlias = _typing.Literal["op", b"op"] # noqa: Y015
|
|
86
|
+
def WhichOneof(self, oneof_group: _WhichOneofArgType_op) -> _WhichOneofReturnType_op | None: ...
|
|
87
|
+
|
|
88
|
+
Global___Op: _TypeAlias = Op # noqa: Y015
|
|
89
|
+
|
|
90
|
+
@_typing.final
|
|
91
|
+
class GetOp(_message.Message):
|
|
92
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
93
|
+
|
|
94
|
+
NAMESPACE_FIELD_NUMBER: _builtins.int
|
|
95
|
+
KEY_FIELD_NUMBER: _builtins.int
|
|
96
|
+
REFRESHTTL_FIELD_NUMBER: _builtins.int
|
|
97
|
+
key: _builtins.str
|
|
98
|
+
refreshTTL: _builtins.bool
|
|
99
|
+
@_builtins.property
|
|
100
|
+
def namespace(self) -> _containers.RepeatedScalarFieldContainer[_builtins.str]:
|
|
101
|
+
"""Hierarchical namespace path, e.g. ["users", "profiles"]."""
|
|
102
|
+
|
|
103
|
+
def __init__(
|
|
104
|
+
self,
|
|
105
|
+
*,
|
|
106
|
+
namespace: _abc.Iterable[_builtins.str] | None = ...,
|
|
107
|
+
key: _builtins.str = ...,
|
|
108
|
+
refreshTTL: _builtins.bool = ...,
|
|
109
|
+
) -> None: ...
|
|
110
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
111
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
112
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "namespace", b"namespace", "refreshTTL", b"refreshTTL"] # noqa: Y015
|
|
113
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
114
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
115
|
+
|
|
116
|
+
Global___GetOp: _TypeAlias = GetOp # noqa: Y015
|
|
117
|
+
|
|
118
|
+
@_typing.final
|
|
119
|
+
class VectorValue(_message.Message):
|
|
120
|
+
"""Vector value for embedding support"""
|
|
121
|
+
|
|
122
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
123
|
+
|
|
124
|
+
VALUEPATH_FIELD_NUMBER: _builtins.int
|
|
125
|
+
EMBEDDING_FIELD_NUMBER: _builtins.int
|
|
126
|
+
valuePath: _builtins.str
|
|
127
|
+
"""path to the value in the document"""
|
|
128
|
+
@_builtins.property
|
|
129
|
+
def embedding(self) -> _containers.RepeatedScalarFieldContainer[_builtins.float]:
|
|
130
|
+
"""embedding vector"""
|
|
131
|
+
|
|
132
|
+
def __init__(
|
|
133
|
+
self,
|
|
134
|
+
*,
|
|
135
|
+
valuePath: _builtins.str = ...,
|
|
136
|
+
embedding: _abc.Iterable[_builtins.float] | None = ...,
|
|
137
|
+
) -> None: ...
|
|
138
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
139
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
140
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["embedding", b"embedding", "valuePath", b"valuePath"] # noqa: Y015
|
|
141
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
142
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
143
|
+
|
|
144
|
+
Global___VectorValue: _TypeAlias = VectorValue # noqa: Y015
|
|
145
|
+
|
|
146
|
+
@_typing.final
|
|
147
|
+
class PutOp(_message.Message):
|
|
148
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
149
|
+
|
|
150
|
+
NAMESPACE_FIELD_NUMBER: _builtins.int
|
|
151
|
+
KEY_FIELD_NUMBER: _builtins.int
|
|
152
|
+
VALUE_JSON_FIELD_NUMBER: _builtins.int
|
|
153
|
+
TTLMINUTES_FIELD_NUMBER: _builtins.int
|
|
154
|
+
VECTORS_FIELD_NUMBER: _builtins.int
|
|
155
|
+
key: _builtins.str
|
|
156
|
+
value_json: _builtins.bytes
|
|
157
|
+
"""JSON-encoded value (orjson)."""
|
|
158
|
+
ttlMinutes: _builtins.int
|
|
159
|
+
@_builtins.property
|
|
160
|
+
def namespace(self) -> _containers.RepeatedScalarFieldContainer[_builtins.str]: ...
|
|
161
|
+
@_builtins.property
|
|
162
|
+
def vectors(self) -> _containers.RepeatedCompositeFieldContainer[Global___VectorValue]:
|
|
163
|
+
"""array of vector values for embedding support"""
|
|
164
|
+
|
|
165
|
+
def __init__(
|
|
166
|
+
self,
|
|
167
|
+
*,
|
|
168
|
+
namespace: _abc.Iterable[_builtins.str] | None = ...,
|
|
169
|
+
key: _builtins.str = ...,
|
|
170
|
+
value_json: _builtins.bytes = ...,
|
|
171
|
+
ttlMinutes: _builtins.int = ...,
|
|
172
|
+
vectors: _abc.Iterable[Global___VectorValue] | None = ...,
|
|
173
|
+
) -> None: ...
|
|
174
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
175
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
176
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["key", b"key", "namespace", b"namespace", "ttlMinutes", b"ttlMinutes", "value_json", b"value_json", "vectors", b"vectors"] # noqa: Y015
|
|
177
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
178
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
179
|
+
|
|
180
|
+
Global___PutOp: _TypeAlias = PutOp # noqa: Y015
|
|
181
|
+
|
|
182
|
+
@_typing.final
|
|
183
|
+
class OpResult(_message.Message):
|
|
184
|
+
"""Result corresponds to langgraph.store.base.Result.
|
|
185
|
+
Kind is derived from the originating op:
|
|
186
|
+
GetOp -> item (or none if missing)
|
|
187
|
+
PutOp -> none
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
191
|
+
|
|
192
|
+
ITEM_FIELD_NUMBER: _builtins.int
|
|
193
|
+
NONE_FIELD_NUMBER: _builtins.int
|
|
194
|
+
@_builtins.property
|
|
195
|
+
def item(self) -> Global___Item: ...
|
|
196
|
+
@_builtins.property
|
|
197
|
+
def none(self) -> _empty_pb2.Empty: ...
|
|
198
|
+
def __init__(
|
|
199
|
+
self,
|
|
200
|
+
*,
|
|
201
|
+
item: Global___Item | None = ...,
|
|
202
|
+
none: _empty_pb2.Empty | None = ...,
|
|
203
|
+
) -> None: ...
|
|
204
|
+
_HasFieldArgType: _TypeAlias = _typing.Literal["item", b"item", "none", b"none", "result", b"result"] # noqa: Y015
|
|
205
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
206
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["item", b"item", "none", b"none", "result", b"result"] # noqa: Y015
|
|
207
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
208
|
+
_WhichOneofReturnType_result: _TypeAlias = _typing.Literal["item", "none"] # noqa: Y015
|
|
209
|
+
_WhichOneofArgType_result: _TypeAlias = _typing.Literal["result", b"result"] # noqa: Y015
|
|
210
|
+
def WhichOneof(self, oneof_group: _WhichOneofArgType_result) -> _WhichOneofReturnType_result | None: ...
|
|
211
|
+
|
|
212
|
+
Global___OpResult: _TypeAlias = OpResult # noqa: Y015
|
|
213
|
+
|
|
214
|
+
@_typing.final
|
|
215
|
+
class Item(_message.Message):
|
|
216
|
+
DESCRIPTOR: _descriptor.Descriptor
|
|
217
|
+
|
|
218
|
+
NAMESPACE_FIELD_NUMBER: _builtins.int
|
|
219
|
+
KEY_FIELD_NUMBER: _builtins.int
|
|
220
|
+
VALUE_JSON_FIELD_NUMBER: _builtins.int
|
|
221
|
+
CREATED_AT_FIELD_NUMBER: _builtins.int
|
|
222
|
+
UPDATED_AT_FIELD_NUMBER: _builtins.int
|
|
223
|
+
key: _builtins.str
|
|
224
|
+
value_json: _builtins.bytes
|
|
225
|
+
"""JSON-encoded value (orjson)."""
|
|
226
|
+
created_at: _builtins.str
|
|
227
|
+
"""RFC 3339 / ISO 8601 strings, matching Item.dict()."""
|
|
228
|
+
updated_at: _builtins.str
|
|
229
|
+
@_builtins.property
|
|
230
|
+
def namespace(self) -> _containers.RepeatedScalarFieldContainer[_builtins.str]: ...
|
|
231
|
+
def __init__(
|
|
232
|
+
self,
|
|
233
|
+
*,
|
|
234
|
+
namespace: _abc.Iterable[_builtins.str] | None = ...,
|
|
235
|
+
key: _builtins.str = ...,
|
|
236
|
+
value_json: _builtins.bytes = ...,
|
|
237
|
+
created_at: _builtins.str = ...,
|
|
238
|
+
updated_at: _builtins.str = ...,
|
|
239
|
+
) -> None: ...
|
|
240
|
+
_HasFieldArgType: _TypeAlias = _Never # noqa: Y015
|
|
241
|
+
def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ...
|
|
242
|
+
_ClearFieldArgType: _TypeAlias = _typing.Literal["created_at", b"created_at", "key", b"key", "namespace", b"namespace", "updated_at", b"updated_at", "value_json", b"value_json"] # noqa: Y015
|
|
243
|
+
def ClearField(self, field_name: _ClearFieldArgType) -> None: ...
|
|
244
|
+
def WhichOneof(self, oneof_group: _Never) -> None: ...
|
|
245
|
+
|
|
246
|
+
Global___Item: _TypeAlias = Item # noqa: Y015
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
|
2
|
+
"""Client and server classes corresponding to protobuf-defined services."""
|
|
3
|
+
import grpc
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from . import store_pb2 as store__pb2
|
|
7
|
+
|
|
8
|
+
GRPC_GENERATED_VERSION = '1.80.0'
|
|
9
|
+
GRPC_VERSION = grpc.__version__
|
|
10
|
+
_version_not_supported = False
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from grpc._utilities import first_version_is_lower
|
|
14
|
+
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
|
15
|
+
except ImportError:
|
|
16
|
+
_version_not_supported = True
|
|
17
|
+
|
|
18
|
+
if _version_not_supported:
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
f'The grpc package installed is at version {GRPC_VERSION},'
|
|
21
|
+
+ ' but the generated code in store_pb2_grpc.py depends on'
|
|
22
|
+
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
|
23
|
+
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
|
24
|
+
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class StoreStub(object):
|
|
29
|
+
"""Store is the gRPC surface of langgraph's BaseStore.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, channel):
|
|
33
|
+
"""Constructor.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
channel: A grpc.Channel.
|
|
37
|
+
"""
|
|
38
|
+
self.Batch = channel.unary_unary(
|
|
39
|
+
'/store.Store/Batch',
|
|
40
|
+
request_serializer=store__pb2.BatchRequest.SerializeToString,
|
|
41
|
+
response_deserializer=store__pb2.BatchResponse.FromString,
|
|
42
|
+
_registered_method=True)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class StoreServicer(object):
|
|
46
|
+
"""Store is the gRPC surface of langgraph's BaseStore.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def Batch(self, request, context):
|
|
50
|
+
"""Batch executes a sequence of operations, returning results in input order.
|
|
51
|
+
"""
|
|
52
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
53
|
+
context.set_details('Method not implemented!')
|
|
54
|
+
raise NotImplementedError('Method not implemented!')
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def add_StoreServicer_to_server(servicer, server):
|
|
58
|
+
rpc_method_handlers = {
|
|
59
|
+
'Batch': grpc.unary_unary_rpc_method_handler(
|
|
60
|
+
servicer.Batch,
|
|
61
|
+
request_deserializer=store__pb2.BatchRequest.FromString,
|
|
62
|
+
response_serializer=store__pb2.BatchResponse.SerializeToString,
|
|
63
|
+
),
|
|
64
|
+
}
|
|
65
|
+
generic_handler = grpc.method_handlers_generic_handler(
|
|
66
|
+
'store.Store', rpc_method_handlers)
|
|
67
|
+
server.add_generic_rpc_handlers((generic_handler,))
|
|
68
|
+
server.add_registered_method_handlers('store.Store', rpc_method_handlers)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# This class is part of an EXPERIMENTAL API.
|
|
72
|
+
class Store(object):
|
|
73
|
+
"""Store is the gRPC surface of langgraph's BaseStore.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def Batch(request,
|
|
78
|
+
target,
|
|
79
|
+
options=(),
|
|
80
|
+
channel_credentials=None,
|
|
81
|
+
call_credentials=None,
|
|
82
|
+
insecure=False,
|
|
83
|
+
compression=None,
|
|
84
|
+
wait_for_ready=None,
|
|
85
|
+
timeout=None,
|
|
86
|
+
metadata=None):
|
|
87
|
+
return grpc.experimental.unary_unary(
|
|
88
|
+
request,
|
|
89
|
+
target,
|
|
90
|
+
'/store.Store/Batch',
|
|
91
|
+
store__pb2.BatchRequest.SerializeToString,
|
|
92
|
+
store__pb2.BatchResponse.FromString,
|
|
93
|
+
options,
|
|
94
|
+
channel_credentials,
|
|
95
|
+
insecure,
|
|
96
|
+
call_credentials,
|
|
97
|
+
compression,
|
|
98
|
+
wait_for_ready,
|
|
99
|
+
timeout,
|
|
100
|
+
metadata,
|
|
101
|
+
_registered_method=True)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
@generated by mypy-protobuf. Do not edit manually!
|
|
3
|
+
isort:skip_file
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections import abc as _abc
|
|
7
|
+
from grpc import aio as _aio
|
|
8
|
+
import abc as _abc_1
|
|
9
|
+
import grpc as _grpc
|
|
10
|
+
from . import store_pb2 as _store_pb2
|
|
11
|
+
import sys
|
|
12
|
+
import typing as _typing
|
|
13
|
+
|
|
14
|
+
if sys.version_info >= (3, 11):
|
|
15
|
+
from typing import Self as _Self
|
|
16
|
+
else:
|
|
17
|
+
from typing_extensions import Self as _Self
|
|
18
|
+
|
|
19
|
+
_T = _typing.TypeVar("_T")
|
|
20
|
+
|
|
21
|
+
class _MaybeAsyncIterator(_abc.AsyncIterator[_T], _abc.Iterator[_T], metaclass=_abc_1.ABCMeta): ...
|
|
22
|
+
|
|
23
|
+
class _ServicerContext(_grpc.ServicerContext, _aio.ServicerContext): # type: ignore[misc, type-arg]
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
GRPC_GENERATED_VERSION: str
|
|
27
|
+
GRPC_VERSION: str
|
|
28
|
+
|
|
29
|
+
class StoreStub:
|
|
30
|
+
"""Store is the gRPC surface of langgraph's BaseStore."""
|
|
31
|
+
|
|
32
|
+
@_typing.overload
|
|
33
|
+
def __new__(cls, channel: _grpc.Channel) -> _Self: ...
|
|
34
|
+
@_typing.overload
|
|
35
|
+
def __new__(cls, channel: _aio.Channel) -> StoreAsyncStub: ...
|
|
36
|
+
Batch: _grpc.UnaryUnaryMultiCallable[_store_pb2.BatchRequest, _store_pb2.BatchResponse]
|
|
37
|
+
"""Batch executes a sequence of operations, returning results in input order."""
|
|
38
|
+
|
|
39
|
+
@_typing.type_check_only
|
|
40
|
+
class StoreAsyncStub(StoreStub):
|
|
41
|
+
"""Store is the gRPC surface of langgraph's BaseStore."""
|
|
42
|
+
|
|
43
|
+
def __init__(self, channel: _aio.Channel) -> None: ...
|
|
44
|
+
Batch: _aio.UnaryUnaryMultiCallable[_store_pb2.BatchRequest, _store_pb2.BatchResponse] # type: ignore[assignment]
|
|
45
|
+
"""Batch executes a sequence of operations, returning results in input order."""
|
|
46
|
+
|
|
47
|
+
class StoreServicer(metaclass=_abc_1.ABCMeta):
|
|
48
|
+
"""Store is the gRPC surface of langgraph's BaseStore."""
|
|
49
|
+
|
|
50
|
+
@_abc_1.abstractmethod
|
|
51
|
+
def Batch(
|
|
52
|
+
self,
|
|
53
|
+
request: _store_pb2.BatchRequest,
|
|
54
|
+
context: _ServicerContext,
|
|
55
|
+
) -> _typing.Union[_store_pb2.BatchResponse, _abc.Awaitable[_store_pb2.BatchResponse]]:
|
|
56
|
+
"""Batch executes a sequence of operations, returning results in input order."""
|
|
57
|
+
|
|
58
|
+
def add_StoreServicer_to_server(servicer: StoreServicer, server: _typing.Union[_grpc.Server, _aio.Server]) -> None: ...
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""GrpcStore — BaseStore subclass that proxies to core-server Store."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import threading
|
|
7
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
8
|
+
|
|
9
|
+
import grpc.aio
|
|
10
|
+
from langgraph.store.base import IndexConfig, Op, PutOp, Result
|
|
11
|
+
from langgraph.store.base.batch import AsyncBatchedBaseStore
|
|
12
|
+
|
|
13
|
+
from langgraph_grpc_common.conversion.store import (
|
|
14
|
+
normalize_index_config,
|
|
15
|
+
op_to_proto,
|
|
16
|
+
result_from_proto,
|
|
17
|
+
vectors_for_put_op,
|
|
18
|
+
)
|
|
19
|
+
from langgraph_grpc_common.proto import store_pb2
|
|
20
|
+
from langgraph_grpc_common.proto.store_pb2_grpc import StoreStub
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Coroutine, Iterable
|
|
24
|
+
|
|
25
|
+
T = TypeVar("T")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GrpcStore(AsyncBatchedBaseStore):
|
|
29
|
+
"""BaseStore client that dispatches ``abatch`` over gRPC (get/put, TTL, vectors)."""
|
|
30
|
+
|
|
31
|
+
supports_ttl = True
|
|
32
|
+
_UNSUPPORTED = "delete, search, and list_namespaces are not implemented yet"
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
address: str,
|
|
37
|
+
*,
|
|
38
|
+
index: IndexConfig | None = None,
|
|
39
|
+
ttl: dict[str, Any] | None = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
super().__init__()
|
|
42
|
+
self.ttl_config = ttl
|
|
43
|
+
self._embeddings, self._index_config = normalize_index_config(index)
|
|
44
|
+
self._address = address
|
|
45
|
+
self._channel_lock = threading.Lock()
|
|
46
|
+
self._channel: grpc.aio.Channel | None = None
|
|
47
|
+
self._stub: StoreStub | None = None
|
|
48
|
+
|
|
49
|
+
def _get_stub(self) -> StoreStub:
|
|
50
|
+
if self._stub is None:
|
|
51
|
+
with self._channel_lock:
|
|
52
|
+
if self._stub is None:
|
|
53
|
+
# Internal loopback to core-server; matches langgraph_api.grpc.client.
|
|
54
|
+
self._channel = grpc.aio.insecure_channel(self._address)
|
|
55
|
+
self._stub = StoreStub(self._channel)
|
|
56
|
+
return self._stub
|
|
57
|
+
|
|
58
|
+
async def abatch(self, ops: Iterable[Op]) -> list[Result]:
|
|
59
|
+
op_list = list(ops)
|
|
60
|
+
if not op_list:
|
|
61
|
+
return []
|
|
62
|
+
|
|
63
|
+
proto_ops: list[store_pb2.Op] = []
|
|
64
|
+
for op in op_list:
|
|
65
|
+
if (
|
|
66
|
+
self._index_config is not None
|
|
67
|
+
and self._embeddings is not None
|
|
68
|
+
and isinstance(op, PutOp)
|
|
69
|
+
and op.index is not False
|
|
70
|
+
):
|
|
71
|
+
vectors = await vectors_for_put_op(
|
|
72
|
+
op, self._index_config, self._embeddings
|
|
73
|
+
)
|
|
74
|
+
proto_ops.append(op_to_proto(op, vectors=vectors))
|
|
75
|
+
else:
|
|
76
|
+
proto_ops.append(op_to_proto(op))
|
|
77
|
+
|
|
78
|
+
request = store_pb2.BatchRequest(ops=proto_ops)
|
|
79
|
+
stub = self._get_stub()
|
|
80
|
+
response = await stub.Batch(request)
|
|
81
|
+
if len(response.results) != len(op_list):
|
|
82
|
+
raise RuntimeError(
|
|
83
|
+
f"store-server returned {len(response.results)} results for "
|
|
84
|
+
f"{len(op_list)} ops"
|
|
85
|
+
)
|
|
86
|
+
return [result_from_proto(r) for r in response.results]
|
|
87
|
+
|
|
88
|
+
def batch(self, ops: Iterable[Op]) -> list[Result]:
|
|
89
|
+
return self._run_sync(self.abatch(ops))
|
|
90
|
+
|
|
91
|
+
def _run_sync(self, coro: Coroutine[Any, Any, T]) -> T:
|
|
92
|
+
return asyncio.run_coroutine_threadsafe(coro, self._loop).result()
|
|
93
|
+
|
|
94
|
+
async def aclose(self) -> None:
|
|
95
|
+
if self._channel is not None:
|
|
96
|
+
await self._channel.close()
|
|
97
|
+
self._channel = None
|
|
98
|
+
self._stub = None
|
|
99
|
+
|
|
100
|
+
async def adelete(self, namespace: tuple[str, ...], key: str) -> None:
|
|
101
|
+
raise NotImplementedError(self._UNSUPPORTED)
|
|
102
|
+
|
|
103
|
+
async def asearch(self, *args: Any, **kwargs: Any) -> list[Any]:
|
|
104
|
+
raise NotImplementedError(self._UNSUPPORTED)
|
|
105
|
+
|
|
106
|
+
async def alist_namespaces(
|
|
107
|
+
self, *args: Any, **kwargs: Any
|
|
108
|
+
) -> list[tuple[str, ...]]:
|
|
109
|
+
raise NotImplementedError(self._UNSUPPORTED)
|
|
File without changes
|
{langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{langgraph_api-0.12.0.dev13.dist-info → langgraph_api-0.12.0.dev15.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|