langgraph-api 0.5.1__py3-none-any.whl → 0.5.3__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/__init__.py +1 -1
- 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 +191 -0
- langgraph_api/grpc_ops/generated/engine_common_pb2.pyi +637 -0
- langgraph_api/grpc_ops/generated/engine_common_pb2_grpc.py +24 -0
- langgraph_api/grpc_ops/ops.py +26 -156
- langgraph_api/js/package.json +5 -5
- langgraph_api/js/yarn.lock +137 -187
- {langgraph_api-0.5.1.dist-info → langgraph_api-0.5.3.dist-info}/METADATA +2 -2
- {langgraph_api-0.5.1.dist-info → langgraph_api-0.5.3.dist-info}/RECORD +15 -11
- {langgraph_api-0.5.1.dist-info → langgraph_api-0.5.3.dist-info}/WHEEL +0 -0
- {langgraph_api-0.5.1.dist-info → langgraph_api-0.5.3.dist-info}/entry_points.txt +0 -0
- {langgraph_api-0.5.1.dist-info → langgraph_api-0.5.3.dist-info}/licenses/LICENSE +0 -0
langgraph_api/grpc_ops/ops.py
CHANGED
|
@@ -4,10 +4,10 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import functools
|
|
7
|
-
from collections.abc import AsyncIterator
|
|
7
|
+
from collections.abc import AsyncIterator
|
|
8
8
|
from datetime import UTC
|
|
9
9
|
from http import HTTPStatus
|
|
10
|
-
from typing import Any
|
|
10
|
+
from typing import Any, overload
|
|
11
11
|
from uuid import UUID
|
|
12
12
|
|
|
13
13
|
import orjson
|
|
@@ -16,10 +16,10 @@ from google.protobuf.json_format import MessageToDict
|
|
|
16
16
|
from google.protobuf.struct_pb2 import Struct # type: ignore[import]
|
|
17
17
|
from grpc import StatusCode
|
|
18
18
|
from grpc.aio import AioRpcError
|
|
19
|
-
from langgraph.pregel.debug import CheckpointPayload
|
|
20
19
|
from langgraph_sdk.schema import Config
|
|
21
20
|
from starlette.exceptions import HTTPException
|
|
22
21
|
|
|
22
|
+
from langgraph_api.grpc_ops import config_conversion
|
|
23
23
|
from langgraph_api.schema import (
|
|
24
24
|
Assistant,
|
|
25
25
|
AssistantSelectField,
|
|
@@ -50,30 +50,16 @@ def map_if_exists(if_exists: str) -> pb.OnConflictBehavior:
|
|
|
50
50
|
return pb.OnConflictBehavior.RAISE
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
@overload
|
|
54
|
+
def consolidate_config_and_context(
|
|
55
|
+
config: Config | None, context: None
|
|
56
|
+
) -> tuple[Config, None]: ...
|
|
55
57
|
|
|
56
|
-
The `extra` field mirrors any keys that are not first-class in
|
|
57
|
-
Config (e.g., "tags", "recursion_limit", "configurable").
|
|
58
|
-
It is JSON-encoded bytes to minimize serde overhead; the server will
|
|
59
|
-
unpack and persist them as top-level keys.
|
|
60
|
-
"""
|
|
61
|
-
base_keys = {"tags", "recursion_limit", "configurable"}
|
|
62
|
-
extra_dict = {k: v for k, v in (config or {}).items() if k not in base_keys}
|
|
63
|
-
|
|
64
|
-
kwargs: dict[str, Any] = dict(
|
|
65
|
-
tags=pb.Tags(values=config.get("tags")),
|
|
66
|
-
recursion_limit=config.get("recursion_limit"),
|
|
67
|
-
configurable=(
|
|
68
|
-
dict_to_struct(config.get("configurable", {}))
|
|
69
|
-
if config.get("configurable")
|
|
70
|
-
else None
|
|
71
|
-
),
|
|
72
|
-
)
|
|
73
|
-
if extra_dict:
|
|
74
|
-
kwargs["extra"] = orjson.dumps(extra_dict)
|
|
75
58
|
|
|
76
|
-
|
|
59
|
+
@overload
|
|
60
|
+
def consolidate_config_and_context(
|
|
61
|
+
config: Config | None, context: Context
|
|
62
|
+
) -> tuple[Config, Context]: ...
|
|
77
63
|
|
|
78
64
|
|
|
79
65
|
def consolidate_config_and_context(
|
|
@@ -84,17 +70,20 @@ def consolidate_config_and_context(
|
|
|
84
70
|
Does not mutate the passed-in objects. If both configurable and context
|
|
85
71
|
are provided, raises 400. If only one is provided, mirrors it to the other.
|
|
86
72
|
"""
|
|
87
|
-
cfg: Config =
|
|
73
|
+
cfg: Config = Config(config or {})
|
|
88
74
|
ctx: Context | None = dict(context) if context is not None else None
|
|
75
|
+
configurable = cfg.get("configurable")
|
|
89
76
|
|
|
90
|
-
if
|
|
77
|
+
if configurable and ctx:
|
|
91
78
|
raise HTTPException(
|
|
92
79
|
status_code=400,
|
|
93
|
-
detail="Cannot specify both configurable and context. Prefer setting context alone.
|
|
80
|
+
detail="Cannot specify both configurable and context. Prefer setting context alone."
|
|
81
|
+
" Context was introduced in LangGraph 0.6.0 and "
|
|
82
|
+
"is the long term planned replacement for configurable.",
|
|
94
83
|
)
|
|
95
84
|
|
|
96
|
-
if
|
|
97
|
-
ctx =
|
|
85
|
+
if configurable:
|
|
86
|
+
ctx = configurable
|
|
98
87
|
elif ctx is not None:
|
|
99
88
|
cfg["configurable"] = ctx
|
|
100
89
|
|
|
@@ -114,38 +103,6 @@ def struct_to_dict(struct: Struct) -> dict[str, Any]:
|
|
|
114
103
|
return MessageToDict(struct) if struct else {}
|
|
115
104
|
|
|
116
105
|
|
|
117
|
-
def _runnable_config_to_user_dict(cfg: pb.Config | None) -> dict[str, Any]:
|
|
118
|
-
"""Convert pb.Config to user-visible dict, unpacking `extra`.
|
|
119
|
-
|
|
120
|
-
- Keeps top-level known keys: tags, recursion_limit, configurable.
|
|
121
|
-
- Merges keys from `extra` into the top-level dict.
|
|
122
|
-
"""
|
|
123
|
-
if not cfg:
|
|
124
|
-
return {}
|
|
125
|
-
|
|
126
|
-
out: dict[str, Any] = {}
|
|
127
|
-
# tags
|
|
128
|
-
if cfg.tags and cfg.tags.values:
|
|
129
|
-
out["tags"] = list(cfg.tags.values)
|
|
130
|
-
# recursion_limit (preserve presence of 0 if set)
|
|
131
|
-
try:
|
|
132
|
-
if cfg.HasField("recursion_limit"):
|
|
133
|
-
out["recursion_limit"] = cfg.recursion_limit
|
|
134
|
-
except ValueError:
|
|
135
|
-
# Some runtimes may not support HasField on certain builds; fallback
|
|
136
|
-
if getattr(cfg, "recursion_limit", None) is not None:
|
|
137
|
-
out["recursion_limit"] = cfg.recursion_limit
|
|
138
|
-
# configurable
|
|
139
|
-
if cfg.HasField("configurable"):
|
|
140
|
-
out["configurable"] = struct_to_dict(cfg.configurable)
|
|
141
|
-
# extra (bytes: JSON-encoded object)
|
|
142
|
-
if cfg.HasField("extra") and cfg.extra:
|
|
143
|
-
extra = orjson.loads(cfg.extra)
|
|
144
|
-
if isinstance(extra, dict) and extra:
|
|
145
|
-
out.update(extra)
|
|
146
|
-
return out
|
|
147
|
-
|
|
148
|
-
|
|
149
106
|
def proto_to_assistant(proto_assistant: pb.Assistant) -> Assistant:
|
|
150
107
|
"""Convert protobuf Assistant to dictionary format."""
|
|
151
108
|
# Preserve None for optional scalar fields by checking presence via HasField
|
|
@@ -158,7 +115,7 @@ def proto_to_assistant(proto_assistant: pb.Assistant) -> Assistant:
|
|
|
158
115
|
"version": proto_assistant.version,
|
|
159
116
|
"created_at": proto_assistant.created_at.ToDatetime(tzinfo=UTC),
|
|
160
117
|
"updated_at": proto_assistant.updated_at.ToDatetime(tzinfo=UTC),
|
|
161
|
-
"config":
|
|
118
|
+
"config": config_conversion.config_from_proto(proto_assistant.config),
|
|
162
119
|
"context": struct_to_dict(proto_assistant.context),
|
|
163
120
|
"metadata": struct_to_dict(proto_assistant.metadata),
|
|
164
121
|
"name": proto_assistant.name,
|
|
@@ -299,93 +256,6 @@ def proto_to_thread(proto_thread: pb.Thread) -> Thread:
|
|
|
299
256
|
}
|
|
300
257
|
|
|
301
258
|
|
|
302
|
-
def _checkpoint_metadata_to_pb(
|
|
303
|
-
metadata: dict[str, Any] | None,
|
|
304
|
-
) -> pb.CheckpointMetadata | None:
|
|
305
|
-
if not metadata:
|
|
306
|
-
return None
|
|
307
|
-
|
|
308
|
-
message = pb.CheckpointMetadata()
|
|
309
|
-
source = metadata.get("source")
|
|
310
|
-
if source is not None:
|
|
311
|
-
if isinstance(source, str):
|
|
312
|
-
enum_key = f"CHECKPOINT_SOURCE_{source.upper()}"
|
|
313
|
-
try:
|
|
314
|
-
message.source = pb.CheckpointSource.Value(enum_key)
|
|
315
|
-
except ValueError:
|
|
316
|
-
logger.warning(
|
|
317
|
-
"Unknown checkpoint source enum, defaulting to unspecified",
|
|
318
|
-
source=source,
|
|
319
|
-
)
|
|
320
|
-
elif isinstance(source, int):
|
|
321
|
-
try:
|
|
322
|
-
message.source = pb.CheckpointSource(source)
|
|
323
|
-
except ValueError:
|
|
324
|
-
logger.warning(
|
|
325
|
-
"Unknown checkpoint source value, defaulting to unspecified",
|
|
326
|
-
source=source,
|
|
327
|
-
)
|
|
328
|
-
if step := metadata.get("step"):
|
|
329
|
-
message.step = int(step)
|
|
330
|
-
parents = metadata.get("parents")
|
|
331
|
-
if isinstance(parents, dict):
|
|
332
|
-
message.parents.update({str(k): str(v) for k, v in parents.items()})
|
|
333
|
-
return message
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def _checkpoint_tasks_to_pb(tasks: Sequence[dict[str, Any]]) -> list[pb.CheckpointTask]:
|
|
337
|
-
task_messages: list[pb.CheckpointTask] = []
|
|
338
|
-
for task in tasks:
|
|
339
|
-
message = pb.CheckpointTask(
|
|
340
|
-
id=task.get("id", ""),
|
|
341
|
-
name=task.get("name", ""),
|
|
342
|
-
)
|
|
343
|
-
if task.get("error"):
|
|
344
|
-
message.error = str(task["error"])
|
|
345
|
-
interrupts = task.get("interrupts") or []
|
|
346
|
-
for interrupt in interrupts:
|
|
347
|
-
message.interrupts.append(dict_to_struct(interrupt))
|
|
348
|
-
if task.get("state"):
|
|
349
|
-
message.state.CopyFrom(dict_to_struct(task["state"]))
|
|
350
|
-
task_messages.append(message)
|
|
351
|
-
return task_messages
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
def checkpoint_to_pb(
|
|
355
|
-
checkpoint: CheckpointPayload | None,
|
|
356
|
-
) -> pb.CheckpointPayload | None:
|
|
357
|
-
if checkpoint is None:
|
|
358
|
-
return None
|
|
359
|
-
|
|
360
|
-
message = pb.CheckpointPayload()
|
|
361
|
-
|
|
362
|
-
config = checkpoint.get("config")
|
|
363
|
-
if config:
|
|
364
|
-
message.config.CopyFrom(map_configurable(config))
|
|
365
|
-
|
|
366
|
-
metadata = _checkpoint_metadata_to_pb(checkpoint.get("metadata"))
|
|
367
|
-
if metadata:
|
|
368
|
-
message.metadata.CopyFrom(metadata)
|
|
369
|
-
|
|
370
|
-
values = checkpoint.get("values")
|
|
371
|
-
if values:
|
|
372
|
-
message.values.CopyFrom(dict_to_struct(values))
|
|
373
|
-
|
|
374
|
-
next_nodes = checkpoint.get("next")
|
|
375
|
-
if next_nodes:
|
|
376
|
-
message.next.extend([str(n) for n in next_nodes])
|
|
377
|
-
|
|
378
|
-
parent_config = checkpoint.get("parent_config")
|
|
379
|
-
if parent_config:
|
|
380
|
-
message.parent_config.CopyFrom(map_configurable(parent_config))
|
|
381
|
-
|
|
382
|
-
tasks = checkpoint.get("tasks")
|
|
383
|
-
if tasks:
|
|
384
|
-
message.tasks.extend(_checkpoint_tasks_to_pb(tasks))
|
|
385
|
-
|
|
386
|
-
return message
|
|
387
|
-
|
|
388
|
-
|
|
389
259
|
def exception_to_struct(exception: BaseException | None) -> Struct | None:
|
|
390
260
|
if exception is None:
|
|
391
261
|
return None
|
|
@@ -400,7 +270,7 @@ def _filter_thread_fields(
|
|
|
400
270
|
thread: Thread, select: list[ThreadSelectField] | None
|
|
401
271
|
) -> dict[str, Any]:
|
|
402
272
|
if not select:
|
|
403
|
-
return thread
|
|
273
|
+
return dict(thread)
|
|
404
274
|
return {field: thread[field] for field in select if field in thread}
|
|
405
275
|
|
|
406
276
|
|
|
@@ -628,7 +498,7 @@ class Assistants(Authenticated):
|
|
|
628
498
|
graph_id=graph_id,
|
|
629
499
|
filters=auth_filters or {},
|
|
630
500
|
if_exists=on_conflict,
|
|
631
|
-
config=
|
|
501
|
+
config=config_conversion.config_to_proto(config),
|
|
632
502
|
context=dict_to_struct(context or {}),
|
|
633
503
|
name=name,
|
|
634
504
|
description=description,
|
|
@@ -651,7 +521,7 @@ class Assistants(Authenticated):
|
|
|
651
521
|
conn, # Not used in gRPC implementation
|
|
652
522
|
assistant_id: UUID | str,
|
|
653
523
|
*,
|
|
654
|
-
config:
|
|
524
|
+
config: Config | None = None,
|
|
655
525
|
context: Context | None = None,
|
|
656
526
|
graph_id: str | None = None,
|
|
657
527
|
metadata: MetadataInput | None = None,
|
|
@@ -661,7 +531,7 @@ class Assistants(Authenticated):
|
|
|
661
531
|
) -> AsyncIterator[Assistant]: # type: ignore[return-value]
|
|
662
532
|
"""Update assistant via gRPC."""
|
|
663
533
|
metadata = metadata if metadata is not None else {}
|
|
664
|
-
config = config if config is not None else
|
|
534
|
+
config = config if config is not None else Config()
|
|
665
535
|
# Handle auth filters
|
|
666
536
|
auth_filters = await Assistants.handle_event(
|
|
667
537
|
ctx,
|
|
@@ -691,7 +561,7 @@ class Assistants(Authenticated):
|
|
|
691
561
|
|
|
692
562
|
# Add optional config if provided
|
|
693
563
|
if config:
|
|
694
|
-
request.config.CopyFrom(
|
|
564
|
+
request.config.CopyFrom(config_conversion.config_to_proto(config))
|
|
695
565
|
|
|
696
566
|
# Add optional context if provided
|
|
697
567
|
if context:
|
|
@@ -812,7 +682,7 @@ class Assistants(Authenticated):
|
|
|
812
682
|
"graph_id": version.graph_id,
|
|
813
683
|
"version": version.version,
|
|
814
684
|
"created_at": version.created_at.ToDatetime(tzinfo=UTC),
|
|
815
|
-
"config":
|
|
685
|
+
"config": config_conversion.config_from_proto(version.config),
|
|
816
686
|
"context": struct_to_dict(version.context),
|
|
817
687
|
"metadata": struct_to_dict(version.metadata),
|
|
818
688
|
"name": version.name,
|
langgraph_api/js/package.json
CHANGED
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"@langchain/langgraph-checkpoint": "^1.0.0",
|
|
17
17
|
"@types/json-schema": "^7.0.15",
|
|
18
18
|
"@typescript/vfs": "^1.6.0",
|
|
19
|
-
"dedent": "^1.
|
|
19
|
+
"dedent": "^1.7.0",
|
|
20
20
|
"exit-hook": "^4.0.0",
|
|
21
|
-
"hono": "^4.10.
|
|
21
|
+
"hono": "^4.10.4",
|
|
22
22
|
"p-queue": "^8.0.1",
|
|
23
23
|
"p-retry": "^6.2.0",
|
|
24
|
-
"tsx": "^4.
|
|
24
|
+
"tsx": "^4.20.6",
|
|
25
25
|
"typescript": "^5.5.4",
|
|
26
26
|
"undici": "^6.21.2",
|
|
27
27
|
"uuid": "^10.0.0",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@types/react-dom": "^19.0.3",
|
|
41
41
|
"jose": "^6.0.10",
|
|
42
42
|
"postgres": "^3.4.4",
|
|
43
|
-
"prettier": "^3.
|
|
44
|
-
"vitest": "^
|
|
43
|
+
"prettier": "^3.6.2",
|
|
44
|
+
"vitest": "^4.0.6"
|
|
45
45
|
},
|
|
46
46
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
47
47
|
}
|