langgraph-api 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- langgraph_api/api/runs.py +16 -2
- langgraph_api/api/store.py +17 -23
- langgraph_api/cli.py +12 -8
- langgraph_api/graph.py +6 -0
- langgraph_api/js/client.mts +9 -2
- langgraph_api/js/package.json +3 -3
- langgraph_api/js/remote.py +44 -42
- langgraph_api/js/src/graph.mts +14 -0
- langgraph_api/js/src/hooks.mjs +9 -8
- langgraph_api/js/tests/api.test.mts +86 -0
- langgraph_api/js/tests/graphs/agent.mts +9 -4
- langgraph_api/js/tests/graphs/package.json +2 -2
- langgraph_api/js/tests/graphs/yarn.lock +39 -24
- langgraph_api/js/yarn.lock +17 -17
- langgraph_api/schema.py +1 -1
- langgraph_api/stream.py +10 -6
- {langgraph_api-0.0.5.dist-info → langgraph_api-0.0.7.dist-info}/METADATA +2 -2
- {langgraph_api-0.0.5.dist-info → langgraph_api-0.0.7.dist-info}/RECORD +25 -25
- langgraph_storage/database.py +2 -3
- langgraph_storage/ops.py +10 -0
- langgraph_storage/store.py +20 -2
- openapi.json +34 -6
- {langgraph_api-0.0.5.dist-info → langgraph_api-0.0.7.dist-info}/LICENSE +0 -0
- {langgraph_api-0.0.5.dist-info → langgraph_api-0.0.7.dist-info}/WHEEL +0 -0
- {langgraph_api-0.0.5.dist-info → langgraph_api-0.0.7.dist-info}/entry_points.txt +0 -0
langgraph_api/api/runs.py
CHANGED
|
@@ -283,10 +283,18 @@ async def list_runs_http(
|
|
|
283
283
|
validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
284
284
|
limit = int(request.query_params.get("limit", 10))
|
|
285
285
|
offset = int(request.query_params.get("offset", 0))
|
|
286
|
+
status = request.query_params.get("status")
|
|
286
287
|
async with connect() as conn, conn.pipeline():
|
|
287
288
|
thread, runs = await asyncio.gather(
|
|
288
289
|
Threads.get(conn, thread_id),
|
|
289
|
-
Runs.search(
|
|
290
|
+
Runs.search(
|
|
291
|
+
conn,
|
|
292
|
+
thread_id,
|
|
293
|
+
limit=limit,
|
|
294
|
+
offset=offset,
|
|
295
|
+
status=status,
|
|
296
|
+
metadata=None,
|
|
297
|
+
),
|
|
290
298
|
)
|
|
291
299
|
await fetchone(thread)
|
|
292
300
|
return ApiResponse([run async for run in runs])
|
|
@@ -323,9 +331,15 @@ async def join_run_stream_endpoint(request: ApiRequest):
|
|
|
323
331
|
"""Wait for a run to finish."""
|
|
324
332
|
thread_id = request.path_params["thread_id"]
|
|
325
333
|
run_id = request.path_params["run_id"]
|
|
334
|
+
cancel_on_disconnect_str = request.query_params.get("cancel_on_disconnect", "false")
|
|
335
|
+
cancel_on_disconnect = cancel_on_disconnect_str.lower() in {"true", "yes", "1"}
|
|
326
336
|
validate_uuid(thread_id, "Invalid thread ID: must be a UUID")
|
|
327
337
|
validate_uuid(run_id, "Invalid run ID: must be a UUID")
|
|
328
|
-
return EventSourceResponse(
|
|
338
|
+
return EventSourceResponse(
|
|
339
|
+
Runs.Stream.join(
|
|
340
|
+
run_id, thread_id=thread_id, cancel_on_disconnect=cancel_on_disconnect
|
|
341
|
+
)
|
|
342
|
+
)
|
|
329
343
|
|
|
330
344
|
|
|
331
345
|
@retry_db
|
langgraph_api/api/store.py
CHANGED
|
@@ -8,7 +8,6 @@ from langgraph_api.validation import (
|
|
|
8
8
|
StorePutRequest,
|
|
9
9
|
StoreSearchRequest,
|
|
10
10
|
)
|
|
11
|
-
from langgraph_storage.database import connect
|
|
12
11
|
from langgraph_storage.retry import retry_db
|
|
13
12
|
from langgraph_storage.store import Store
|
|
14
13
|
|
|
@@ -31,8 +30,7 @@ async def put_item(request: ApiRequest):
|
|
|
31
30
|
return err
|
|
32
31
|
key = payload["key"]
|
|
33
32
|
value = payload["value"]
|
|
34
|
-
|
|
35
|
-
await Store(conn).aput(namespace, key, value)
|
|
33
|
+
await Store().aput(namespace, key, value)
|
|
36
34
|
return Response(status_code=204)
|
|
37
35
|
|
|
38
36
|
|
|
@@ -45,8 +43,7 @@ async def get_item(request: ApiRequest):
|
|
|
45
43
|
key = request.query_params.get("key")
|
|
46
44
|
if not key:
|
|
47
45
|
return ApiResponse({"error": "Key is required"}, status_code=400)
|
|
48
|
-
|
|
49
|
-
result = await Store(conn).aget(namespace, key)
|
|
46
|
+
result = await Store().aget(namespace, key)
|
|
50
47
|
return ApiResponse(result.dict() if result is not None else None)
|
|
51
48
|
|
|
52
49
|
|
|
@@ -58,8 +55,7 @@ async def delete_item(request: ApiRequest):
|
|
|
58
55
|
if err := _validate_namespace(namespace):
|
|
59
56
|
return err
|
|
60
57
|
key = payload["key"]
|
|
61
|
-
|
|
62
|
-
await Store(conn).adelete(namespace, key)
|
|
58
|
+
await Store().adelete(namespace, key)
|
|
63
59
|
return Response(status_code=204)
|
|
64
60
|
|
|
65
61
|
|
|
@@ -74,14 +70,13 @@ async def search_items(request: ApiRequest):
|
|
|
74
70
|
limit = payload.get("limit") or 10
|
|
75
71
|
offset = payload.get("offset") or 0
|
|
76
72
|
query = payload.get("query")
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
73
|
+
items = await Store().asearch(
|
|
74
|
+
namespace_prefix,
|
|
75
|
+
filter=filter,
|
|
76
|
+
limit=limit,
|
|
77
|
+
offset=offset,
|
|
78
|
+
query=query,
|
|
79
|
+
)
|
|
85
80
|
return ApiResponse({"items": [item.dict() for item in items]})
|
|
86
81
|
|
|
87
82
|
|
|
@@ -98,14 +93,13 @@ async def list_namespaces(request: ApiRequest):
|
|
|
98
93
|
max_depth = payload.get("max_depth")
|
|
99
94
|
limit = payload.get("limit", 100)
|
|
100
95
|
offset = payload.get("offset", 0)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
96
|
+
result = await Store().alist_namespaces(
|
|
97
|
+
prefix=prefix,
|
|
98
|
+
suffix=suffix,
|
|
99
|
+
max_depth=max_depth,
|
|
100
|
+
limit=limit,
|
|
101
|
+
offset=offset,
|
|
102
|
+
)
|
|
109
103
|
return ApiResponse({"namespaces": result})
|
|
110
104
|
|
|
111
105
|
|
langgraph_api/cli.py
CHANGED
|
@@ -94,10 +94,6 @@ class StoreConfig(TypedDict, total=False):
|
|
|
94
94
|
index: IndexConfig
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
class Config(TypedDict, total=False):
|
|
98
|
-
store: StoreConfig | None
|
|
99
|
-
|
|
100
|
-
|
|
101
97
|
def run_server(
|
|
102
98
|
host: str = "127.0.0.1",
|
|
103
99
|
port: int = 2024,
|
|
@@ -107,10 +103,11 @@ def run_server(
|
|
|
107
103
|
env_file: str | None = None,
|
|
108
104
|
open_browser: bool = False,
|
|
109
105
|
debug_port: int | None = None,
|
|
106
|
+
wait_for_client: bool = False,
|
|
110
107
|
env: str | pathlib.Path | Mapping[str, str] | None = None,
|
|
111
108
|
reload_includes: Sequence[str] | None = None,
|
|
112
109
|
reload_excludes: Sequence[str] | None = None,
|
|
113
|
-
|
|
110
|
+
store: StoreConfig | None = None,
|
|
114
111
|
**kwargs: Any,
|
|
115
112
|
):
|
|
116
113
|
"""Run the LangGraph API server."""
|
|
@@ -148,8 +145,9 @@ def run_server(
|
|
|
148
145
|
logger.info(" - Host: 0.0.0.0")
|
|
149
146
|
logger.info(f" - Port: {debug_port}")
|
|
150
147
|
logger.info("3. Start the debugger to connect to the server.")
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
if wait_for_client:
|
|
149
|
+
debugpy.wait_for_client()
|
|
150
|
+
logger.info("Debugger attached. Starting server...")
|
|
153
151
|
|
|
154
152
|
local_url = f"http://{host}:{port}"
|
|
155
153
|
studio_url = f"https://smith.langchain.com/studio/?baseUrl={local_url}"
|
|
@@ -213,7 +211,7 @@ For production use, please use LangGraph Cloud.
|
|
|
213
211
|
DATABASE_URI=":memory:",
|
|
214
212
|
REDIS_URI="fake",
|
|
215
213
|
N_JOBS_PER_WORKER=str(n_jobs_per_worker if n_jobs_per_worker else 1),
|
|
216
|
-
|
|
214
|
+
LANGGRAPH_STORE=json.dumps(store) if store else None,
|
|
217
215
|
LANGSERVE_GRAPHS=json.dumps(graphs) if graphs else None,
|
|
218
216
|
LANGSMITH_LANGGRAPH_API_VARIANT="local_dev",
|
|
219
217
|
**(env_vars or {}),
|
|
@@ -274,6 +272,11 @@ def main():
|
|
|
274
272
|
parser.add_argument(
|
|
275
273
|
"--debug-port", type=int, help="Port for debugger to listen on (default: none)"
|
|
276
274
|
)
|
|
275
|
+
parser.add_argument(
|
|
276
|
+
"--wait-for-client",
|
|
277
|
+
action="store_true",
|
|
278
|
+
help="Whether to break and wait for a debugger to attach",
|
|
279
|
+
)
|
|
277
280
|
|
|
278
281
|
args = parser.parse_args()
|
|
279
282
|
|
|
@@ -289,6 +292,7 @@ def main():
|
|
|
289
292
|
n_jobs_per_worker=args.n_jobs_per_worker,
|
|
290
293
|
open_browser=not args.no_browser,
|
|
291
294
|
debug_port=args.debug_port,
|
|
295
|
+
wait_for_client=args.wait_for_client,
|
|
292
296
|
env=config_data.get("env", None),
|
|
293
297
|
)
|
|
294
298
|
|
langgraph_api/graph.py
CHANGED
|
@@ -196,6 +196,12 @@ async def collect_graphs_from_env(register: bool = False) -> None:
|
|
|
196
196
|
py_specs = list(filterfalse(is_js_spec, specs))
|
|
197
197
|
|
|
198
198
|
if js_specs:
|
|
199
|
+
if os.environ.get("LANGSMITH_LANGGRAPH_API_VARIANT") == "local_dev":
|
|
200
|
+
raise NotImplementedError(
|
|
201
|
+
"LangGraph.JS graphs are not yet supported in local development mode. "
|
|
202
|
+
"To run your JS graphs, either use the LangGraph Studio application "
|
|
203
|
+
"or run `langgraph up` to start the server in a Docker container."
|
|
204
|
+
)
|
|
199
205
|
import sys
|
|
200
206
|
|
|
201
207
|
from langgraph_api.js.remote import (
|
langgraph_api/js/client.mts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
BaseStore,
|
|
10
10
|
Item,
|
|
11
11
|
Operation,
|
|
12
|
+
Command,
|
|
12
13
|
OperationResults,
|
|
13
14
|
type Checkpoint,
|
|
14
15
|
type CheckpointMetadata,
|
|
@@ -459,7 +460,7 @@ async function main() {
|
|
|
459
460
|
|
|
460
461
|
const specs = z
|
|
461
462
|
.record(z.string())
|
|
462
|
-
.parse(JSON.parse(process.env.LANGSERVE_GRAPHS));
|
|
463
|
+
.parse(JSON.parse(process.env.LANGSERVE_GRAPHS ?? "{}"));
|
|
463
464
|
|
|
464
465
|
if (!process.argv.includes("--skip-schema-cache")) {
|
|
465
466
|
try {
|
|
@@ -495,6 +496,7 @@ async function main() {
|
|
|
495
496
|
"json",
|
|
496
497
|
z.object({
|
|
497
498
|
input: z.unknown(),
|
|
499
|
+
command: z.object({ resume: z.unknown() }).nullish(),
|
|
498
500
|
stream_mode: z
|
|
499
501
|
.union([ExtraStreamModeSchema, z.array(ExtraStreamModeSchema)])
|
|
500
502
|
.optional(),
|
|
@@ -512,6 +514,11 @@ async function main() {
|
|
|
512
514
|
const graph = getGraph(c.req.param("graphId"));
|
|
513
515
|
const payload = c.req.valid("json");
|
|
514
516
|
|
|
517
|
+
const input = payload.command
|
|
518
|
+
? // @ts-expect-error Update LG.js to mark `resume as optional
|
|
519
|
+
new Command(payload.command)
|
|
520
|
+
: payload.input;
|
|
521
|
+
|
|
515
522
|
const userStreamMode =
|
|
516
523
|
payload.stream_mode == null
|
|
517
524
|
? []
|
|
@@ -551,7 +558,7 @@ async function main() {
|
|
|
551
558
|
const streamMode = [...graphStreamMode];
|
|
552
559
|
|
|
553
560
|
try {
|
|
554
|
-
for await (const data of graph.streamEvents(
|
|
561
|
+
for await (const data of graph.streamEvents(input, {
|
|
555
562
|
...config,
|
|
556
563
|
version: "v2",
|
|
557
564
|
streamMode,
|
langgraph_api/js/package.json
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@hono/node-server": "^1.12.0",
|
|
11
11
|
"@hono/zod-validator": "^0.2.2",
|
|
12
|
-
"@langchain/core": "^0.3.
|
|
13
|
-
"@langchain/langgraph": "^0.2.
|
|
12
|
+
"@langchain/core": "^0.3.22",
|
|
13
|
+
"@langchain/langgraph": "^0.2.26",
|
|
14
14
|
"@types/json-schema": "^7.0.15",
|
|
15
15
|
"@typescript/vfs": "^1.6.0",
|
|
16
16
|
"dedent": "^1.5.3",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"zod": "^3.23.8"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@langchain/langgraph-sdk": "^0.0.
|
|
27
|
+
"@langchain/langgraph-sdk": "^0.0.31",
|
|
28
28
|
"@types/node": "^22.2.0",
|
|
29
29
|
"postgres": "^3.4.4",
|
|
30
30
|
"prettier": "^3.3.3",
|
langgraph_api/js/remote.py
CHANGED
|
@@ -20,7 +20,7 @@ from langchain_core.runnables.schema import (
|
|
|
20
20
|
from langgraph.checkpoint.serde.base import SerializerProtocol
|
|
21
21
|
from langgraph.pregel.types import PregelTask, StateSnapshot
|
|
22
22
|
from langgraph.store.base import GetOp, Item, ListNamespacesOp, PutOp, SearchOp
|
|
23
|
-
from langgraph.types import Interrupt
|
|
23
|
+
from langgraph.types import Command, Interrupt
|
|
24
24
|
from pydantic import BaseModel
|
|
25
25
|
from starlette.applications import Starlette
|
|
26
26
|
from starlette.requests import Request
|
|
@@ -91,12 +91,18 @@ class RemotePregel(Runnable):
|
|
|
91
91
|
if version != "v2":
|
|
92
92
|
raise ValueError("Only v2 of astream_events is supported")
|
|
93
93
|
|
|
94
|
+
data = {
|
|
95
|
+
"command" if isinstance(input, Command) else "input": input,
|
|
96
|
+
"config": config,
|
|
97
|
+
**kwargs,
|
|
98
|
+
}
|
|
99
|
+
|
|
94
100
|
async with aconnect_sse(
|
|
95
101
|
self._async_client,
|
|
96
102
|
"POST",
|
|
97
103
|
f"/{self.graph_id}/streamEvents",
|
|
98
104
|
headers={"Content-Type": "application/json"},
|
|
99
|
-
data=orjson.dumps(
|
|
105
|
+
data=orjson.dumps(data),
|
|
100
106
|
) as event_source:
|
|
101
107
|
async for sse in event_source.aiter_sse():
|
|
102
108
|
event = orjson.loads(sse["data"])
|
|
@@ -173,15 +179,19 @@ class RemotePregel(Runnable):
|
|
|
173
179
|
tuple(task["path"]) if task.get("path") else tuple(),
|
|
174
180
|
# TODO: figure out how to properly deserialise errors
|
|
175
181
|
task.get("error"),
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
(
|
|
183
|
+
tuple(
|
|
184
|
+
Interrupt(
|
|
185
|
+
value=interrupt["value"],
|
|
186
|
+
when=interrupt["when"],
|
|
187
|
+
resumable=interrupt.get("resumable", True),
|
|
188
|
+
ns=interrupt.get("ns"),
|
|
189
|
+
)
|
|
190
|
+
for interrupt in task.get("interrupts")
|
|
180
191
|
)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
else [],
|
|
192
|
+
if task.get("interrupts")
|
|
193
|
+
else []
|
|
194
|
+
),
|
|
185
195
|
state,
|
|
186
196
|
)
|
|
187
197
|
)
|
|
@@ -413,17 +423,13 @@ async def run_remote_checkpointer():
|
|
|
413
423
|
await server.serve()
|
|
414
424
|
|
|
415
425
|
|
|
416
|
-
def _get_passthrough_store(
|
|
426
|
+
def _get_passthrough_store():
|
|
417
427
|
from langgraph_storage.store import Store
|
|
418
428
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return store
|
|
429
|
+
return Store()
|
|
422
430
|
|
|
423
431
|
|
|
424
432
|
async def run_remote_store():
|
|
425
|
-
from langgraph_storage.database import connect
|
|
426
|
-
|
|
427
433
|
async def abatch(request: Request):
|
|
428
434
|
payload = orjson.loads(await request.body())
|
|
429
435
|
operations = payload.get("operations", [])
|
|
@@ -470,9 +476,8 @@ async def run_remote_store():
|
|
|
470
476
|
{"error": f"Unknown operation type: {op}"}, status_code=400
|
|
471
477
|
)
|
|
472
478
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
results = await store.abatch(processed_operations)
|
|
479
|
+
store = _get_passthrough_store()
|
|
480
|
+
results = await store.abatch(processed_operations)
|
|
476
481
|
|
|
477
482
|
# Handle potentially undefined or non-dict results
|
|
478
483
|
processed_results = []
|
|
@@ -512,9 +517,8 @@ async def run_remote_store():
|
|
|
512
517
|
|
|
513
518
|
namespaces = namespaces_str.split(".")
|
|
514
519
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
result = await store.aget(namespaces, key)
|
|
520
|
+
store = _get_passthrough_store()
|
|
521
|
+
result = await store.aget(namespaces, key)
|
|
518
522
|
|
|
519
523
|
return ApiResponse(result)
|
|
520
524
|
|
|
@@ -524,10 +528,10 @@ async def run_remote_store():
|
|
|
524
528
|
namespace = tuple(payload["namespace"].split("."))
|
|
525
529
|
key = payload["key"]
|
|
526
530
|
value = payload["value"]
|
|
531
|
+
index = payload.get("index")
|
|
527
532
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
await store.aput(namespace, key, value)
|
|
533
|
+
store = _get_passthrough_store()
|
|
534
|
+
await store.aput(namespace, key, value, index=index)
|
|
531
535
|
|
|
532
536
|
return ApiResponse({"success": True})
|
|
533
537
|
|
|
@@ -538,12 +542,12 @@ async def run_remote_store():
|
|
|
538
542
|
filter = payload.get("filter")
|
|
539
543
|
limit = payload.get("limit", 10)
|
|
540
544
|
offset = payload.get("offset", 0)
|
|
545
|
+
query = payload.get("query")
|
|
541
546
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
)
|
|
547
|
+
store = _get_passthrough_store()
|
|
548
|
+
result = await store.asearch(
|
|
549
|
+
namespace_prefix, filter=filter, limit=limit, offset=offset, query=query
|
|
550
|
+
)
|
|
547
551
|
|
|
548
552
|
return ApiResponse([item.dict() for item in result])
|
|
549
553
|
|
|
@@ -553,9 +557,8 @@ async def run_remote_store():
|
|
|
553
557
|
namespace = tuple(payload["namespace"])
|
|
554
558
|
key = payload["key"]
|
|
555
559
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
await store.adelete(namespace, key)
|
|
560
|
+
store = _get_passthrough_store()
|
|
561
|
+
await store.adelete(namespace, key)
|
|
559
562
|
|
|
560
563
|
return ApiResponse({"success": True})
|
|
561
564
|
|
|
@@ -568,15 +571,14 @@ async def run_remote_store():
|
|
|
568
571
|
limit = payload.get("limit", 100)
|
|
569
572
|
offset = payload.get("offset", 0)
|
|
570
573
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
)
|
|
574
|
+
store = _get_passthrough_store()
|
|
575
|
+
result = await store.alist_namespaces(
|
|
576
|
+
prefix=prefix,
|
|
577
|
+
suffix=suffix,
|
|
578
|
+
max_depth=max_depth,
|
|
579
|
+
limit=limit,
|
|
580
|
+
offset=offset,
|
|
581
|
+
)
|
|
580
582
|
|
|
581
583
|
return ApiResponse([list(ns) for ns in result])
|
|
582
584
|
|
langgraph_api/js/src/graph.mts
CHANGED
|
@@ -20,6 +20,20 @@ export interface GraphSpec {
|
|
|
20
20
|
exportSymbol: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
export async function resolveGraph(
|
|
24
|
+
spec: string,
|
|
25
|
+
options?: { onlyFilePresence?: false }
|
|
26
|
+
): Promise<{
|
|
27
|
+
sourceFile: string;
|
|
28
|
+
exportSymbol: string;
|
|
29
|
+
resolved: CompiledGraph<string>;
|
|
30
|
+
}>;
|
|
31
|
+
|
|
32
|
+
export async function resolveGraph(
|
|
33
|
+
spec: string,
|
|
34
|
+
options: { onlyFilePresence: true }
|
|
35
|
+
): Promise<{ sourceFile: string; exportSymbol: string; resolved: undefined }>;
|
|
36
|
+
|
|
23
37
|
export async function resolveGraph(
|
|
24
38
|
spec: string,
|
|
25
39
|
options?: { onlyFilePresence?: boolean }
|
langgraph_api/js/src/hooks.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// This hook is to ensure that @langchain/langgraph package
|
|
2
2
|
// found in /api folder has precendence compared to user-provided package
|
|
3
3
|
// found in /deps. Does not attempt to semver check for too old packages.
|
|
4
|
-
|
|
4
|
+
const OVERRIDE_RESOLVE = [
|
|
5
|
+
"@langchain/langgraph",
|
|
6
|
+
"@langchain/langgraph-checkpoint",
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export const resolve = async (specifier, context, nextResolve) => {
|
|
5
10
|
const parentURL = new URL("./graph.mts", import.meta.url).toString();
|
|
6
11
|
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
return nextResolve(specifier, { ...context, parentURL });
|
|
10
|
-
} catch (error) {
|
|
11
|
-
return nextResolve(specifier, context);
|
|
12
|
-
}
|
|
12
|
+
if (OVERRIDE_RESOLVE.includes(specifier)) {
|
|
13
|
+
return nextResolve(specifier, { ...context, parentURL });
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
return nextResolve(specifier, context);
|
|
16
|
-
}
|
|
17
|
+
};
|
|
@@ -447,6 +447,35 @@ describe("runs", () => {
|
|
|
447
447
|
await sql`DELETE FROM store`;
|
|
448
448
|
});
|
|
449
449
|
|
|
450
|
+
it.skip.concurrent("list runs", async () => {
|
|
451
|
+
const assistant = await client.assistants.create({ graphId: "agent" });
|
|
452
|
+
const thread = await client.threads.create();
|
|
453
|
+
await client.runs.wait(thread.thread_id, assistant.assistant_id, {
|
|
454
|
+
input: { messages: [{ type: "human", content: "foo" }] },
|
|
455
|
+
config: globalConfig,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const pendingRun = await client.runs.create(
|
|
459
|
+
thread.thread_id,
|
|
460
|
+
assistant.assistant_id,
|
|
461
|
+
{
|
|
462
|
+
input: { messages: [{ type: "human", content: "bar" }] },
|
|
463
|
+
config: globalConfig,
|
|
464
|
+
}
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
let runs = await client.runs.list(thread.thread_id);
|
|
468
|
+
expect(runs.length).toBe(2);
|
|
469
|
+
|
|
470
|
+
runs = await client.runs.list(thread.thread_id, { status: "pending" });
|
|
471
|
+
expect(runs.length).toBe(1);
|
|
472
|
+
|
|
473
|
+
await client.runs.cancel(thread.thread_id, pendingRun.run_id);
|
|
474
|
+
|
|
475
|
+
runs = await client.runs.list(thread.thread_id, { status: "interrupted" });
|
|
476
|
+
expect(runs.length).toBe(1);
|
|
477
|
+
});
|
|
478
|
+
|
|
450
479
|
it.concurrent("stream values", async () => {
|
|
451
480
|
const assistant = await client.assistants.create({ graphId: "agent" });
|
|
452
481
|
const thread = await client.threads.create();
|
|
@@ -1500,6 +1529,63 @@ describe("subgraphs", () => {
|
|
|
1500
1529
|
expect(innerHistory[0].values.messages.length).toBe(2);
|
|
1501
1530
|
expect(innerHistory[innerHistory.length - 1].next).toEqual(["__start__"]);
|
|
1502
1531
|
});
|
|
1532
|
+
|
|
1533
|
+
it.concurrent("interrupt inside node", async () => {
|
|
1534
|
+
const assistant = await client.assistants.create({ graphId: "agent" });
|
|
1535
|
+
|
|
1536
|
+
let thread = await client.threads.create();
|
|
1537
|
+
await client.runs.wait(thread.thread_id, assistant.assistant_id, {
|
|
1538
|
+
input: {
|
|
1539
|
+
messages: [{ role: "human", content: "SF", id: "initial-message" }],
|
|
1540
|
+
interrupt: true,
|
|
1541
|
+
},
|
|
1542
|
+
config: globalConfig,
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
const state = await client.threads.getState(thread.thread_id);
|
|
1546
|
+
expect(state.next).toEqual(["agent"]);
|
|
1547
|
+
expect(state.tasks).toMatchObject([
|
|
1548
|
+
{
|
|
1549
|
+
id: expect.any(String),
|
|
1550
|
+
name: "agent",
|
|
1551
|
+
path: ["__pregel_pull", "agent"],
|
|
1552
|
+
error: null,
|
|
1553
|
+
interrupts: [
|
|
1554
|
+
{
|
|
1555
|
+
value: "i want to interrupt",
|
|
1556
|
+
when: "during",
|
|
1557
|
+
resumable: true,
|
|
1558
|
+
ns: [expect.stringMatching(/^agent:/)],
|
|
1559
|
+
},
|
|
1560
|
+
],
|
|
1561
|
+
checkpoint: null,
|
|
1562
|
+
state: null,
|
|
1563
|
+
result: null,
|
|
1564
|
+
},
|
|
1565
|
+
]);
|
|
1566
|
+
|
|
1567
|
+
thread = await client.threads.get(thread.thread_id);
|
|
1568
|
+
expect(thread.status).toBe("interrupted");
|
|
1569
|
+
expect(thread.interrupts).toMatchObject({
|
|
1570
|
+
[state.tasks[0].id]: [
|
|
1571
|
+
{
|
|
1572
|
+
value: "i want to interrupt",
|
|
1573
|
+
when: "during",
|
|
1574
|
+
resumable: true,
|
|
1575
|
+
ns: [expect.stringMatching(/^agent:/)],
|
|
1576
|
+
},
|
|
1577
|
+
],
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
const stream = await gatherIterator(
|
|
1581
|
+
client.runs.stream(thread.thread_id, assistant.assistant_id, {
|
|
1582
|
+
command: { resume: "i want to resume" },
|
|
1583
|
+
})
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
expect(stream.at(-1)?.event).toBe("values");
|
|
1587
|
+
expect(stream.at(-1)?.data.messages.length).toBe(4);
|
|
1588
|
+
});
|
|
1503
1589
|
});
|
|
1504
1590
|
|
|
1505
1591
|
describe("errors", () => {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
messagesStateReducer,
|
|
8
8
|
SharedValue,
|
|
9
9
|
LangGraphRunnableConfig,
|
|
10
|
+
interrupt,
|
|
10
11
|
} from "@langchain/langgraph";
|
|
11
12
|
import { FakeListChatModel } from "@langchain/core/utils/testing";
|
|
12
13
|
|
|
@@ -16,6 +17,7 @@ const GraphAnnotationOutput = Annotation.Root({
|
|
|
16
17
|
default: () => [],
|
|
17
18
|
}),
|
|
18
19
|
sharedStateValue: Annotation<string | null>(),
|
|
20
|
+
interrupt: Annotation<boolean>(),
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
const GraphAnnotationInput = Annotation.Root({
|
|
@@ -36,8 +38,10 @@ const getModel = (threadId: string) => {
|
|
|
36
38
|
|
|
37
39
|
const agentNode = async (
|
|
38
40
|
state: typeof GraphAnnotationInput.State,
|
|
39
|
-
config: LangGraphRunnableConfig
|
|
41
|
+
config: LangGraphRunnableConfig
|
|
40
42
|
) => {
|
|
43
|
+
if (state.interrupt) interrupt("i want to interrupt");
|
|
44
|
+
|
|
41
45
|
const model = getModel(config.configurable?.thread_id ?? "$");
|
|
42
46
|
const response = await model.invoke(state.messages);
|
|
43
47
|
const sharedStateValue = state.sharedState?.data?.user_id ?? null;
|
|
@@ -52,6 +56,7 @@ const agentNode = async (
|
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
return {
|
|
59
|
+
interrupt: false,
|
|
55
60
|
messages: [response],
|
|
56
61
|
sharedState: { data: { user_id: config?.configurable?.user_id } },
|
|
57
62
|
sharedStateValue,
|
|
@@ -60,7 +65,7 @@ const agentNode = async (
|
|
|
60
65
|
|
|
61
66
|
const toolNode = async (
|
|
62
67
|
state: typeof GraphAnnotationInput.State,
|
|
63
|
-
config: LangGraphRunnableConfig
|
|
68
|
+
config: LangGraphRunnableConfig
|
|
64
69
|
) => {
|
|
65
70
|
const store = config.store;
|
|
66
71
|
let sharedStateFromStoreConfig: Record<string, any> | null = null;
|
|
@@ -84,7 +89,7 @@ const toolNode = async (
|
|
|
84
89
|
|
|
85
90
|
const checkSharedStateNode = async (
|
|
86
91
|
_: typeof GraphAnnotationInput.State,
|
|
87
|
-
config: LangGraphRunnableConfig
|
|
92
|
+
config: LangGraphRunnableConfig
|
|
88
93
|
): Promise<Partial<typeof GraphAnnotationInput.State>> => {
|
|
89
94
|
const store = config.store;
|
|
90
95
|
const namespace = ["inputtedState", "data"];
|
|
@@ -114,7 +119,7 @@ const workflow = new StateGraph(
|
|
|
114
119
|
input: GraphAnnotationInput,
|
|
115
120
|
output: GraphAnnotationOutput,
|
|
116
121
|
},
|
|
117
|
-
Annotation.Root({ model_name: Annotation<string> })
|
|
122
|
+
Annotation.Root({ model_name: Annotation<string> })
|
|
118
123
|
)
|
|
119
124
|
.addNode("agent", agentNode)
|
|
120
125
|
.addNode("tool", toolNode)
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
# yarn lockfile v1
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
"@langchain/core@^0.3.
|
|
6
|
-
version "0.3.
|
|
7
|
-
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.
|
|
8
|
-
integrity sha512-
|
|
5
|
+
"@langchain/core@^0.3.22":
|
|
6
|
+
version "0.3.22"
|
|
7
|
+
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.22.tgz#22064eca45a1f506e554c30537de62dc742c67f8"
|
|
8
|
+
integrity sha512-9rwEbxJi3Fgs8XuealNYxB6s0FCOnvXLnpiV5/oKgmEJtCRS91IqgJCWA8d59s4YkaEply/EsZVc2azNPK6Wjw==
|
|
9
9
|
dependencies:
|
|
10
10
|
ansi-styles "^5.0.0"
|
|
11
11
|
camelcase "6"
|
|
12
12
|
decamelize "1.2.0"
|
|
13
13
|
js-tiktoken "^1.0.12"
|
|
14
|
-
langsmith "^0.
|
|
14
|
+
langsmith "^0.2.8"
|
|
15
15
|
mustache "^4.2.0"
|
|
16
16
|
p-queue "^6.6.2"
|
|
17
17
|
p-retry "4"
|
|
@@ -19,23 +19,38 @@
|
|
|
19
19
|
zod "^3.22.4"
|
|
20
20
|
zod-to-json-schema "^3.22.3"
|
|
21
21
|
|
|
22
|
-
"@langchain/langgraph-checkpoint@~0.0.
|
|
23
|
-
version "0.0.
|
|
24
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.
|
|
25
|
-
integrity sha512-
|
|
22
|
+
"@langchain/langgraph-checkpoint@~0.0.12":
|
|
23
|
+
version "0.0.12"
|
|
24
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-0.0.12.tgz#672f2dd5ea3a33054d9792ff5c151faebd75d852"
|
|
25
|
+
integrity sha512-XySxUqpt7X3k02UyncpKupZMOHqLbkjOpkGWFdwBTueT1+kVeS2+DTwZK80QT/BaWH6jEUkMk14oU9/D63R0tg==
|
|
26
26
|
dependencies:
|
|
27
27
|
uuid "^10.0.0"
|
|
28
28
|
|
|
29
|
-
"@langchain/langgraph
|
|
30
|
-
version "0.
|
|
31
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.
|
|
32
|
-
integrity sha512-
|
|
29
|
+
"@langchain/langgraph-sdk@~0.0.21":
|
|
30
|
+
version "0.0.31"
|
|
31
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.31.tgz#186cc2d31bb504d301e227dc7448dd22a8ee1933"
|
|
32
|
+
integrity sha512-oYZWoC3x7vH9bAL1Y30XjtuWnic1j3knXD4BbldsY0chFLxwIT5i6/GMThNy3Oiwb4SB+c6gvaSuxBNDkp7dkw==
|
|
33
33
|
dependencies:
|
|
34
|
-
"@
|
|
35
|
-
|
|
34
|
+
"@types/json-schema" "^7.0.15"
|
|
35
|
+
p-queue "^6.6.2"
|
|
36
|
+
p-retry "4"
|
|
37
|
+
uuid "^9.0.0"
|
|
38
|
+
|
|
39
|
+
"@langchain/langgraph@^0.2.26":
|
|
40
|
+
version "0.2.26"
|
|
41
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.26.tgz#8a9f771e4e356de616f7e4a90c61f566cd267a92"
|
|
42
|
+
integrity sha512-79nq4N5gUCW3RJQSTGdqRg28Rrdd6V493oxCW7dKST1qwS/CFf+Y/nU0nDzmwKYUekLZ3Fkh7WtyYrgonZhjjg==
|
|
43
|
+
dependencies:
|
|
44
|
+
"@langchain/langgraph-checkpoint" "~0.0.12"
|
|
45
|
+
"@langchain/langgraph-sdk" "~0.0.21"
|
|
36
46
|
uuid "^10.0.0"
|
|
37
47
|
zod "^3.23.8"
|
|
38
48
|
|
|
49
|
+
"@types/json-schema@^7.0.15":
|
|
50
|
+
version "7.0.15"
|
|
51
|
+
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
|
52
|
+
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
|
53
|
+
|
|
39
54
|
"@types/retry@0.12.0":
|
|
40
55
|
version "0.12.0"
|
|
41
56
|
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
|
|
@@ -71,11 +86,6 @@ decamelize@1.2.0:
|
|
|
71
86
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
|
72
87
|
integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
|
|
73
88
|
|
|
74
|
-
double-ended-queue@^2.1.0-0:
|
|
75
|
-
version "2.1.0-0"
|
|
76
|
-
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
|
|
77
|
-
integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ==
|
|
78
|
-
|
|
79
89
|
eventemitter3@^4.0.4:
|
|
80
90
|
version "4.0.7"
|
|
81
91
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
|
@@ -88,10 +98,10 @@ js-tiktoken@^1.0.12:
|
|
|
88
98
|
dependencies:
|
|
89
99
|
base64-js "^1.5.1"
|
|
90
100
|
|
|
91
|
-
langsmith@^0.
|
|
92
|
-
version "0.
|
|
93
|
-
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.
|
|
94
|
-
integrity sha512-
|
|
101
|
+
langsmith@^0.2.8:
|
|
102
|
+
version "0.2.9"
|
|
103
|
+
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.2.9.tgz#07366136832863b12e284ba0567bc836c1a73ead"
|
|
104
|
+
integrity sha512-bRAgdFgUeCU82eDcMTyTBuiadekDIv7oiNW1G5phxeuynTqXKjUII3mjpeak291bC00ow2q5kauWT0CTVEs+4Q==
|
|
95
105
|
dependencies:
|
|
96
106
|
"@types/uuid" "^10.0.0"
|
|
97
107
|
commander "^10.0.1"
|
|
@@ -148,6 +158,11 @@ uuid@^10.0.0:
|
|
|
148
158
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294"
|
|
149
159
|
integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==
|
|
150
160
|
|
|
161
|
+
uuid@^9.0.0:
|
|
162
|
+
version "9.0.1"
|
|
163
|
+
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
|
164
|
+
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
|
165
|
+
|
|
151
166
|
zod-to-json-schema@^3.22.3:
|
|
152
167
|
version "3.23.2"
|
|
153
168
|
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.23.2.tgz#bc7e379c8050462538383e382964c03d8fe008f9"
|
langgraph_api/js/yarn.lock
CHANGED
|
@@ -301,16 +301,16 @@
|
|
|
301
301
|
"@jridgewell/resolve-uri" "^3.1.0"
|
|
302
302
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
|
303
303
|
|
|
304
|
-
"@langchain/core@^0.3.
|
|
305
|
-
version "0.3.
|
|
306
|
-
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.
|
|
307
|
-
integrity sha512-
|
|
304
|
+
"@langchain/core@^0.3.22":
|
|
305
|
+
version "0.3.22"
|
|
306
|
+
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.22.tgz#22064eca45a1f506e554c30537de62dc742c67f8"
|
|
307
|
+
integrity sha512-9rwEbxJi3Fgs8XuealNYxB6s0FCOnvXLnpiV5/oKgmEJtCRS91IqgJCWA8d59s4YkaEply/EsZVc2azNPK6Wjw==
|
|
308
308
|
dependencies:
|
|
309
309
|
ansi-styles "^5.0.0"
|
|
310
310
|
camelcase "6"
|
|
311
311
|
decamelize "1.2.0"
|
|
312
312
|
js-tiktoken "^1.0.12"
|
|
313
|
-
langsmith "^0.2.
|
|
313
|
+
langsmith "^0.2.8"
|
|
314
314
|
mustache "^4.2.0"
|
|
315
315
|
p-queue "^6.6.2"
|
|
316
316
|
p-retry "4"
|
|
@@ -325,10 +325,10 @@
|
|
|
325
325
|
dependencies:
|
|
326
326
|
uuid "^10.0.0"
|
|
327
327
|
|
|
328
|
-
"@langchain/langgraph-sdk@^0.0.
|
|
329
|
-
version "0.0.
|
|
330
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.
|
|
331
|
-
integrity sha512-
|
|
328
|
+
"@langchain/langgraph-sdk@^0.0.31":
|
|
329
|
+
version "0.0.31"
|
|
330
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.31.tgz#186cc2d31bb504d301e227dc7448dd22a8ee1933"
|
|
331
|
+
integrity sha512-oYZWoC3x7vH9bAL1Y30XjtuWnic1j3knXD4BbldsY0chFLxwIT5i6/GMThNy3Oiwb4SB+c6gvaSuxBNDkp7dkw==
|
|
332
332
|
dependencies:
|
|
333
333
|
"@types/json-schema" "^7.0.15"
|
|
334
334
|
p-queue "^6.6.2"
|
|
@@ -345,10 +345,10 @@
|
|
|
345
345
|
p-retry "4"
|
|
346
346
|
uuid "^9.0.0"
|
|
347
347
|
|
|
348
|
-
"@langchain/langgraph@^0.2.
|
|
349
|
-
version "0.2.
|
|
350
|
-
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.
|
|
351
|
-
integrity sha512-
|
|
348
|
+
"@langchain/langgraph@^0.2.26":
|
|
349
|
+
version "0.2.26"
|
|
350
|
+
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-0.2.26.tgz#8a9f771e4e356de616f7e4a90c61f566cd267a92"
|
|
351
|
+
integrity sha512-79nq4N5gUCW3RJQSTGdqRg28Rrdd6V493oxCW7dKST1qwS/CFf+Y/nU0nDzmwKYUekLZ3Fkh7WtyYrgonZhjjg==
|
|
352
352
|
dependencies:
|
|
353
353
|
"@langchain/langgraph-checkpoint" "~0.0.12"
|
|
354
354
|
"@langchain/langgraph-sdk" "~0.0.21"
|
|
@@ -865,10 +865,10 @@ kuler@^2.0.0:
|
|
|
865
865
|
resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
|
|
866
866
|
integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
|
|
867
867
|
|
|
868
|
-
langsmith@^0.2.
|
|
869
|
-
version "0.2.
|
|
870
|
-
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.2.
|
|
871
|
-
integrity sha512-
|
|
868
|
+
langsmith@^0.2.8:
|
|
869
|
+
version "0.2.9"
|
|
870
|
+
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.2.9.tgz#07366136832863b12e284ba0567bc836c1a73ead"
|
|
871
|
+
integrity sha512-bRAgdFgUeCU82eDcMTyTBuiadekDIv7oiNW1G5phxeuynTqXKjUII3mjpeak291bC00ow2q5kauWT0CTVEs+4Q==
|
|
872
872
|
dependencies:
|
|
873
873
|
"@types/uuid" "^10.0.0"
|
|
874
874
|
commander "^10.0.1"
|
langgraph_api/schema.py
CHANGED
langgraph_api/stream.py
CHANGED
|
@@ -71,13 +71,17 @@ def _preprocess_debug_checkpoint(payload: CheckpointPayload | None) -> dict[str,
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
def _map_cmd(cmd: RunCommand) -> Command:
|
|
74
|
-
|
|
75
|
-
if
|
|
76
|
-
|
|
74
|
+
goto = cmd.get("goto")
|
|
75
|
+
if goto is not None and not isinstance(goto, list):
|
|
76
|
+
goto = [cmd.get("goto")]
|
|
77
77
|
|
|
78
78
|
return Command(
|
|
79
79
|
update=cmd.get("update"),
|
|
80
|
-
|
|
80
|
+
goto=[
|
|
81
|
+
it if isinstance(it, str) else Send(it["node"], it["input"]) for it in goto
|
|
82
|
+
]
|
|
83
|
+
if goto
|
|
84
|
+
else None,
|
|
81
85
|
resume=cmd.get("resume"),
|
|
82
86
|
)
|
|
83
87
|
|
|
@@ -94,7 +98,7 @@ async def astream_state(
|
|
|
94
98
|
) -> AnyStream:
|
|
95
99
|
"""Stream messages from the runnable."""
|
|
96
100
|
run_id = str(run["run_id"])
|
|
97
|
-
|
|
101
|
+
await stack.enter_async_context(conn.pipeline())
|
|
98
102
|
# extract args from run
|
|
99
103
|
kwargs = run["kwargs"].copy()
|
|
100
104
|
subgraphs = kwargs.get("subgraphs", False)
|
|
@@ -103,7 +107,7 @@ async def astream_state(
|
|
|
103
107
|
graph = await get_graph(
|
|
104
108
|
config["configurable"]["graph_id"],
|
|
105
109
|
config,
|
|
106
|
-
store=
|
|
110
|
+
store=Store(),
|
|
107
111
|
checkpointer=None if temporary else Checkpointer(conn),
|
|
108
112
|
)
|
|
109
113
|
input = kwargs.pop("input")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -14,7 +14,7 @@ Requires-Dist: cryptography (>=43.0.3,<44.0.0)
|
|
|
14
14
|
Requires-Dist: httpx (>=0.27.0)
|
|
15
15
|
Requires-Dist: jsonschema-rs (>=0.25.0,<0.26.0)
|
|
16
16
|
Requires-Dist: langchain-core (>=0.2.38,<0.4.0)
|
|
17
|
-
Requires-Dist: langgraph (>=0.2.
|
|
17
|
+
Requires-Dist: langgraph (>=0.2.56,<0.3.0)
|
|
18
18
|
Requires-Dist: langgraph-checkpoint (>=2.0.7,<3.0)
|
|
19
19
|
Requires-Dist: langsmith (>=0.1.63,<0.2.0)
|
|
20
20
|
Requires-Dist: orjson (>=3.10.1)
|
|
@@ -4,8 +4,8 @@ langgraph_api/api/__init__.py,sha256=tlMXuqnyJt99aSlUXwR-dS3w5X6sDDczJu4hbm2LP30
|
|
|
4
4
|
langgraph_api/api/assistants.py,sha256=3v4v7kLmlb2meSAnNt73toijnaSikbJgH9Jhb6IL04g,11270
|
|
5
5
|
langgraph_api/api/meta.py,sha256=hueasWpTDQ6xYLo9Bzt2jhNH8XQRzreH8FTeFfnRoxQ,2700
|
|
6
6
|
langgraph_api/api/openapi.py,sha256=zvKMMebBP28hLPMNt1kTtFK17aV9Tz-ok2okEM45XjA,906
|
|
7
|
-
langgraph_api/api/runs.py,sha256=
|
|
8
|
-
langgraph_api/api/store.py,sha256=
|
|
7
|
+
langgraph_api/api/runs.py,sha256=X3fPWVjj4IUGWMIkjVkddVSqBaNh2f9HqtXNVLol8-Q,15961
|
|
8
|
+
langgraph_api/api/store.py,sha256=y7VIejpsE7rpPF-tiMGBqqBwWPZ1wb3o48th6NUvb5I,3849
|
|
9
9
|
langgraph_api/api/threads.py,sha256=taU61XPcCEhBPCYPZcMDsgVDwwWUWJs8p-PrXFXWY48,8661
|
|
10
10
|
langgraph_api/asyncio.py,sha256=XiFEllu-Kg4zAO084npHPYOPnLQRire3V75XrVQYMxE,6023
|
|
11
11
|
langgraph_api/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -14,22 +14,22 @@ langgraph_api/auth/langsmith/backend.py,sha256=uHeb5-h13NIjrX_LDAvfWYr3zpbJvlvbd
|
|
|
14
14
|
langgraph_api/auth/langsmith/client.py,sha256=eKchvAom7hdkUXauD8vHNceBDDUijrFgdTV8bKd7x4Q,3998
|
|
15
15
|
langgraph_api/auth/middleware.py,sha256=_gJTOskEaln4RUT2rVYdQGPJVAyAiq-orsL_eQ3CynE,1369
|
|
16
16
|
langgraph_api/auth/noop.py,sha256=vDJmzG2vArJxVzdHePvrJWahEa0dvGnhc2LEMMeiFz0,391
|
|
17
|
-
langgraph_api/cli.py,sha256=
|
|
17
|
+
langgraph_api/cli.py,sha256=GjFMWQM4nXV6npc-A2AyLfEFuNIxj2EuQwy2LFrQVEw,10093
|
|
18
18
|
langgraph_api/config.py,sha256=cG6eO4P_SZ2pKedb2b4n4vnBHRQr0aiECvGvOA8ZlJA,2259
|
|
19
19
|
langgraph_api/cron_scheduler.py,sha256=DAzY2DsADzEpPVbG2BOSLTIufI93yeRswd71Aby_lV0,2257
|
|
20
20
|
langgraph_api/errors.py,sha256=Bu_i5drgNTyJcLiyrwVE_6-XrSU50BHf9TDpttki9wQ,1690
|
|
21
|
-
langgraph_api/graph.py,sha256=
|
|
21
|
+
langgraph_api/graph.py,sha256=uHAc5DP0aUN-ecgYjXGOYp0IJBC1k3JWlYhExL4jYaE,16505
|
|
22
22
|
langgraph_api/http.py,sha256=XrbyxpjtfSvnaWWh5ZLGpgZmY83WoDCrP_1GPguNiXI,4712
|
|
23
23
|
langgraph_api/http_logger.py,sha256=Sxo_q-65tElauRvkzVLt9lJojgNdgtcHGBYD0IRyX7M,3146
|
|
24
24
|
langgraph_api/js/.gitignore,sha256=qAah3Fq0HWAlfRj5ktZyC6QRQIsAolGLRGcRukA1XJI,33
|
|
25
25
|
langgraph_api/js/build.mts,sha256=v4ZJFnfBJBuLn8g0q-Uab9sgNtcssXcFEI-CmMoiOBc,1301
|
|
26
|
-
langgraph_api/js/client.mts,sha256=
|
|
26
|
+
langgraph_api/js/client.mts,sha256=GF34EYtjIKvl9u44PeWhWD_QCbTbrxFQ-BL-7v6P23c,24434
|
|
27
27
|
langgraph_api/js/global.d.ts,sha256=zR_zLYfpzyPfxpEFth5RgZoyfGulIXyZYPRf7cU0K0Y,106
|
|
28
|
-
langgraph_api/js/package.json,sha256
|
|
29
|
-
langgraph_api/js/remote.py,sha256=
|
|
28
|
+
langgraph_api/js/package.json,sha256=MuXjwh1Y-vLZFQnBAMgMABBJt2hDORvVLiS1xniyZnA,792
|
|
29
|
+
langgraph_api/js/remote.py,sha256=rudGN-8kHVuEbnGeDMEZbn__edtqkjxXlrxIuO1xOo0,23323
|
|
30
30
|
langgraph_api/js/server_sent_events.py,sha256=DLgXOHauemt7706vnfDUCG1GI3TidKycSizccdz9KgA,3702
|
|
31
|
-
langgraph_api/js/src/graph.mts,sha256=
|
|
32
|
-
langgraph_api/js/src/hooks.mjs,sha256=
|
|
31
|
+
langgraph_api/js/src/graph.mts,sha256=EO1ITYoKiUykzO_8V8mnQb6NYybooR1VXIovThZzywc,2998
|
|
32
|
+
langgraph_api/js/src/hooks.mjs,sha256=XtktgmIHlls_DsknAuwib-z7TqCm0haRoTXvnkgzMuo,601
|
|
33
33
|
langgraph_api/js/src/parser/parser.mts,sha256=wXre7teh8N8RYmGcyhZp4vMJd0kNnnFgoSGEyMVPzpQ,13007
|
|
34
34
|
langgraph_api/js/src/parser/parser.worker.mjs,sha256=2K6D0GlUmkk7LE39I8mryB8VZVE3-N9Cblji-ArPhFo,386
|
|
35
35
|
langgraph_api/js/src/schema/types.mts,sha256=SUj0vpvWVbID1mnGr2SUtumDBQkJ9zjfvJdoFP7DIzk,66536
|
|
@@ -37,19 +37,19 @@ langgraph_api/js/src/schema/types.template.mts,sha256=c-FA0Ykzp4KvPyYA6a-hDf60Kd
|
|
|
37
37
|
langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezOGe6Uklm2O5A,1644
|
|
38
38
|
langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
|
|
39
39
|
langgraph_api/js/src/utils/serde.mts,sha256=5SO-wYPnPa8f-D6HQX5Oy3NX3nuziZM8vQMqc2tuxbk,531
|
|
40
|
-
langgraph_api/js/tests/api.test.mts,sha256=
|
|
40
|
+
langgraph_api/js/tests/api.test.mts,sha256=ZfwWmu6RgxMBELwR5PUpGOdVFkeDWlONPx-f_huSRok,52248
|
|
41
41
|
langgraph_api/js/tests/compose-postgres.yml,sha256=7VCpWUgPjCzybf6Gu6pT788sZsxUnTjhbmji6c33cVc,1639
|
|
42
42
|
langgraph_api/js/tests/graphs/.gitignore,sha256=26J8MarZNXh7snXD5eTpV3CPFTht5Znv8dtHYCLNfkw,12
|
|
43
|
-
langgraph_api/js/tests/graphs/agent.mts,sha256=
|
|
43
|
+
langgraph_api/js/tests/graphs/agent.mts,sha256=i2s0GOnydW88laDGBatYkQnjUe9Q44RNHDhdEGIcT8w,3811
|
|
44
44
|
langgraph_api/js/tests/graphs/error.mts,sha256=l4tk89449dj1BnEF_0ZcfPt0Ikk1gl8L1RaSnRfr3xo,487
|
|
45
45
|
langgraph_api/js/tests/graphs/langgraph.json,sha256=-wSU_9H2fraq7Tijq_dTuK8SBDYLHsnfrYgi2zYUK2o,155
|
|
46
46
|
langgraph_api/js/tests/graphs/nested.mts,sha256=4G7jSOSaFVQAza-_ARbK-Iai1biLlF2DIPDZXf7PLIY,1245
|
|
47
|
-
langgraph_api/js/tests/graphs/package.json,sha256=
|
|
47
|
+
langgraph_api/js/tests/graphs/package.json,sha256=y8ZYXtFv3cl-qQHNmZtgsFXvsAlxKdlpvbyFqv8ReSY,119
|
|
48
48
|
langgraph_api/js/tests/graphs/weather.mts,sha256=A7mLK3xW8h5B-ZyJNAyX2M2fJJwzPJzXs4DYesJwreQ,1655
|
|
49
|
-
langgraph_api/js/tests/graphs/yarn.lock,sha256=
|
|
49
|
+
langgraph_api/js/tests/graphs/yarn.lock,sha256=H66dRY5yBM2zzKnszqeprc8eN58B0mEgXseX2_H4lRM,7903
|
|
50
50
|
langgraph_api/js/tests/parser.test.mts,sha256=3zAbboUNhI-cY3hj4Ssr7J-sQXCBTeeI1ItrkG0Ftuk,26257
|
|
51
51
|
langgraph_api/js/tests/utils.mts,sha256=2kTybJ3O7Yfe1q3ehDouqV54ibXkNzsPZ_wBZLJvY-4,421
|
|
52
|
-
langgraph_api/js/yarn.lock,sha256=
|
|
52
|
+
langgraph_api/js/yarn.lock,sha256=WAgI5IVsaZrATwEEs6uCvyB6P_iHJ6ghk39Cj1dyLtc,65156
|
|
53
53
|
langgraph_api/lifespan.py,sha256=Uj7NV-NqxxD1fgx_umM9pVqclcy-VlqrIxDljyj2he0,1820
|
|
54
54
|
langgraph_api/logging.py,sha256=tiDNrEFwqaIdL5ywZv908OXlzzfXsPCws9GXeoFtBV8,3367
|
|
55
55
|
langgraph_api/metadata.py,sha256=mih2G7ScQxiqyUlbksVXkqR3Oo-pM1b6lXtzOsgR1sw,3044
|
|
@@ -58,12 +58,12 @@ langgraph_api/models/run.py,sha256=nNhlG-l2P-DThFWYmCaar0UuPctadB9sH3CCWJfLqVc,8
|
|
|
58
58
|
langgraph_api/patch.py,sha256=94ddcTSZJe22JcpjxiSNjFZdYVnmeoWjk4IX4iBSoyk,1249
|
|
59
59
|
langgraph_api/queue.py,sha256=7tsbDgv4GlUYieJsrvIJDMQUEok4Eu-n_PIQ93rwKjk,9810
|
|
60
60
|
langgraph_api/route.py,sha256=Dzje_dSigJramglqkt4ERT9-cb2xFli7dx25ZV6B6mI,4147
|
|
61
|
-
langgraph_api/schema.py,sha256=
|
|
61
|
+
langgraph_api/schema.py,sha256=EiCWRR2GmGrBrOYcuK9SeVQS5b98SdaJlKaqOL7t-WQ,5263
|
|
62
62
|
langgraph_api/serde.py,sha256=VoJ7Z1IuqrQGXFzEP1qijAITtWCrmjtVqlCRuScjXJI,3533
|
|
63
63
|
langgraph_api/server.py,sha256=afHDnL6b_fAIu_q4icnK60a74lHTTZOMIe1egdhRXIk,1522
|
|
64
64
|
langgraph_api/sse.py,sha256=2wNodCOP2eg7a9mpSu0S3FQ0CHk2BBV_vv0UtIgJIcc,4034
|
|
65
65
|
langgraph_api/state.py,sha256=8jx4IoTCOjTJuwzuXJKKFwo1VseHjNnw_CCq4x1SW14,2284
|
|
66
|
-
langgraph_api/stream.py,sha256=
|
|
66
|
+
langgraph_api/stream.py,sha256=u0gjbCrmYvVw8Ux6DgsYTojLCHSwM4Pi-0LhSLGY4HM,11546
|
|
67
67
|
langgraph_api/utils.py,sha256=FI50tOFMVidV4-1TefouL1N-OJX41qD_fSEoWigTtf0,1575
|
|
68
68
|
langgraph_api/validation.py,sha256=McizHlz-Ez8Jhdbc79mbPSde7GIuf2Jlbjx2yv_l6dA,4475
|
|
69
69
|
langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -71,16 +71,16 @@ langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2G
|
|
|
71
71
|
langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
|
|
72
72
|
langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
73
|
langgraph_storage/checkpoint.py,sha256=55J7W0s5Z7svqqan9wphubSgCphWUItq98j-iWVwbH8,2774
|
|
74
|
-
langgraph_storage/database.py,sha256=
|
|
75
|
-
langgraph_storage/ops.py,sha256=
|
|
74
|
+
langgraph_storage/database.py,sha256=jYAC1tDijO7jTPABxAKB2GutTKLf3EkbMI9VAIM3dT8,5186
|
|
75
|
+
langgraph_storage/ops.py,sha256=Uev3bLTrEP53vX9POHIEo0eYEVH0pyZiLmliE04VCIM,52708
|
|
76
76
|
langgraph_storage/queue.py,sha256=6cTZ0ubHu3S1T43yxHMVOwsQsDaJupByiU0sTUFFls8,3261
|
|
77
77
|
langgraph_storage/retry.py,sha256=uvYFuXJ-T6S1QY1ZwkZHyZQbsvS-Ab68LSbzbUUSI2E,696
|
|
78
|
-
langgraph_storage/store.py,sha256=
|
|
78
|
+
langgraph_storage/store.py,sha256=D-p3cWc_umamkKp-6Cz3cAriSACpvM5nxUIvND6PuxE,2710
|
|
79
79
|
langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
|
|
80
80
|
logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
|
|
81
|
-
openapi.json,sha256=
|
|
82
|
-
langgraph_api-0.0.
|
|
83
|
-
langgraph_api-0.0.
|
|
84
|
-
langgraph_api-0.0.
|
|
85
|
-
langgraph_api-0.0.
|
|
86
|
-
langgraph_api-0.0.
|
|
81
|
+
openapi.json,sha256=UxAGHZYM4PgNd48TSZt7f2lVuyPUkDadxBBhRy5jcmk,124512
|
|
82
|
+
langgraph_api-0.0.7.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
83
|
+
langgraph_api-0.0.7.dist-info/METADATA,sha256=2-Fe-_N61HLzOGA8evWq8yOoMEV2mRoXhxJIdr5Nxa0,3993
|
|
84
|
+
langgraph_api-0.0.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
85
|
+
langgraph_api-0.0.7.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
86
|
+
langgraph_api-0.0.7.dist-info/RECORD,,
|
langgraph_storage/database.py
CHANGED
|
@@ -157,10 +157,9 @@ async def connect(*, __test__: bool = False) -> AsyncIterator[AsyncConnectionPro
|
|
|
157
157
|
|
|
158
158
|
async def start_pool() -> None:
|
|
159
159
|
if store._STORE_CONFIG is None:
|
|
160
|
-
if (config_val := os.getenv("
|
|
160
|
+
if (config_val := os.getenv("LANGGRAPH_STORE")) and config_val.strip():
|
|
161
161
|
config_ = json.loads(config_val.strip())
|
|
162
|
-
|
|
163
|
-
store.set_store_config(config_["store"])
|
|
162
|
+
store.set_store_config(config_)
|
|
164
163
|
|
|
165
164
|
if not os.path.exists(".langgraph_api"):
|
|
166
165
|
os.mkdir(".langgraph_api")
|
langgraph_storage/ops.py
CHANGED
|
@@ -1089,6 +1089,9 @@ class Runs:
|
|
|
1089
1089
|
# Create new run
|
|
1090
1090
|
configurable = Runs._merge_jsonb(
|
|
1091
1091
|
Runs._get_configurable(assistant["config"]),
|
|
1092
|
+
Runs._get_configurable(existing_thread["config"])
|
|
1093
|
+
if existing_thread
|
|
1094
|
+
else {},
|
|
1092
1095
|
Runs._get_configurable(config),
|
|
1093
1096
|
{
|
|
1094
1097
|
"run_id": str(run_id),
|
|
@@ -1097,6 +1100,11 @@ class Runs:
|
|
|
1097
1100
|
"assistant_id": str(assistant_id),
|
|
1098
1101
|
"user_id": (
|
|
1099
1102
|
config.get("configurable", {}).get("user_id")
|
|
1103
|
+
or (
|
|
1104
|
+
existing_thread["config"].get("configurable", {}).get("user_id")
|
|
1105
|
+
if existing_thread
|
|
1106
|
+
else None
|
|
1107
|
+
)
|
|
1100
1108
|
or assistant["config"].get("configurable", {}).get("user_id")
|
|
1101
1109
|
or user_id
|
|
1102
1110
|
),
|
|
@@ -1287,6 +1295,7 @@ class Runs:
|
|
|
1287
1295
|
limit: int = 10,
|
|
1288
1296
|
offset: int = 0,
|
|
1289
1297
|
metadata: MetadataInput,
|
|
1298
|
+
status: RunStatus | None = None,
|
|
1290
1299
|
) -> AsyncIterator[Run]:
|
|
1291
1300
|
"""List all runs by thread."""
|
|
1292
1301
|
runs = conn.store["runs"]
|
|
@@ -1297,6 +1306,7 @@ class Runs:
|
|
|
1297
1306
|
for run in runs
|
|
1298
1307
|
if run["thread_id"] == thread_id
|
|
1299
1308
|
and is_jsonb_contained(run["metadata"], metadata)
|
|
1309
|
+
and (status is None or run["status"] == status)
|
|
1300
1310
|
]
|
|
1301
1311
|
sorted_runs = sorted(filtered_runs, key=lambda x: x["created_at"], reverse=True)
|
|
1302
1312
|
sliced_runs = sorted_runs[offset : offset + limit]
|
langgraph_storage/store.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from collections import defaultdict
|
|
3
|
+
from collections.abc import Iterable
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
from langgraph.checkpoint.memory import PersistentDict
|
|
7
|
+
from langgraph.store.base import BaseStore, Op, Result
|
|
8
|
+
from langgraph.store.base.batch import AsyncBatchedBaseStore
|
|
6
9
|
from langgraph.store.memory import InMemoryStore
|
|
7
10
|
|
|
8
11
|
from langgraph_api.graph import resolve_embeddings
|
|
@@ -43,13 +46,28 @@ class DiskBackedInMemStore(InMemoryStore):
|
|
|
43
46
|
self._vectors.close()
|
|
44
47
|
|
|
45
48
|
|
|
49
|
+
class BatchedStore(AsyncBatchedBaseStore):
|
|
50
|
+
def __init__(self, store: BaseStore) -> None:
|
|
51
|
+
super().__init__()
|
|
52
|
+
self._store = store
|
|
53
|
+
|
|
54
|
+
def batch(self, ops: Iterable[Op]) -> list[Result]:
|
|
55
|
+
return self._store.batch(ops)
|
|
56
|
+
|
|
57
|
+
async def abatch(self, ops: Iterable[Op]) -> list[Result]:
|
|
58
|
+
return await self._store.abatch(ops)
|
|
59
|
+
|
|
60
|
+
def close(self) -> None:
|
|
61
|
+
self._store.close()
|
|
62
|
+
|
|
63
|
+
|
|
46
64
|
_STORE_FILE = os.path.join(".langgraph_api", "store.pckl")
|
|
47
65
|
_VECTOR_FILE = os.path.join(".langgraph_api", "store.vectors.pckl")
|
|
48
66
|
os.makedirs(".langgraph_api", exist_ok=True)
|
|
49
67
|
STORE = DiskBackedInMemStore()
|
|
50
68
|
|
|
51
69
|
|
|
52
|
-
def set_store_config(config) -> None:
|
|
70
|
+
def set_store_config(config: dict) -> None:
|
|
53
71
|
global _STORE_CONFIG, STORE
|
|
54
72
|
_STORE_CONFIG = config.copy()
|
|
55
73
|
_STORE_CONFIG["index"]["embed"] = resolve_embeddings(_STORE_CONFIG.get("index", {}))
|
|
@@ -59,4 +77,4 @@ def set_store_config(config) -> None:
|
|
|
59
77
|
|
|
60
78
|
|
|
61
79
|
def Store(*args: Any, **kwargs: Any) -> DiskBackedInMemStore:
|
|
62
|
-
return STORE
|
|
80
|
+
return BatchedStore(STORE)
|
openapi.json
CHANGED
|
@@ -1342,6 +1342,21 @@
|
|
|
1342
1342
|
},
|
|
1343
1343
|
"name": "offset",
|
|
1344
1344
|
"in": "query"
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"required": false,
|
|
1348
|
+
"schema": {
|
|
1349
|
+
"type": "string",
|
|
1350
|
+
"enum": [
|
|
1351
|
+
"pending",
|
|
1352
|
+
"error",
|
|
1353
|
+
"success",
|
|
1354
|
+
"timeout",
|
|
1355
|
+
"interrupted"
|
|
1356
|
+
]
|
|
1357
|
+
},
|
|
1358
|
+
"name": "status",
|
|
1359
|
+
"in": "query"
|
|
1345
1360
|
}
|
|
1346
1361
|
],
|
|
1347
1362
|
"responses": {
|
|
@@ -1836,6 +1851,17 @@
|
|
|
1836
1851
|
},
|
|
1837
1852
|
"name": "run_id",
|
|
1838
1853
|
"in": "path"
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
"required": false,
|
|
1857
|
+
"schema": {
|
|
1858
|
+
"type": "boolean",
|
|
1859
|
+
"title": "Cancel on Disconnect",
|
|
1860
|
+
"description": "If true, the run will be cancelled if the client disconnects.",
|
|
1861
|
+
"default": false
|
|
1862
|
+
},
|
|
1863
|
+
"name": "cancel_on_disconnect",
|
|
1864
|
+
"in": "query"
|
|
1839
1865
|
}
|
|
1840
1866
|
],
|
|
1841
1867
|
"responses": {
|
|
@@ -3231,7 +3257,7 @@
|
|
|
3231
3257
|
"title": "Resume",
|
|
3232
3258
|
"description": "A value to pass to an interrupted node."
|
|
3233
3259
|
},
|
|
3234
|
-
"
|
|
3260
|
+
"goto": {
|
|
3235
3261
|
"anyOf": [
|
|
3236
3262
|
{
|
|
3237
3263
|
"$ref": "#/components/schemas/Send"
|
|
@@ -3242,11 +3268,13 @@
|
|
|
3242
3268
|
"$ref": "#/components/schemas/Send"
|
|
3243
3269
|
}
|
|
3244
3270
|
},
|
|
3245
|
-
{
|
|
3246
|
-
|
|
3247
|
-
}
|
|
3248
|
-
]
|
|
3249
|
-
|
|
3271
|
+
{ "type": "string" },
|
|
3272
|
+
{ "type": "array", "items": { "type": "string" } },
|
|
3273
|
+
{ "type": "null" }
|
|
3274
|
+
],
|
|
3275
|
+
"title": "Goto",
|
|
3276
|
+
"description": "Name of the node(s) to navigate to next or node(s) to be executed with a provided input."
|
|
3277
|
+
}
|
|
3250
3278
|
}
|
|
3251
3279
|
},
|
|
3252
3280
|
"RunCreateStateful": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|