langgraph-api 0.0.2__py3-none-any.whl → 0.0.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/cli.py CHANGED
@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  import pathlib
6
6
  import threading
7
- from collections.abc import Mapping
7
+ from collections.abc import Mapping, Sequence
8
8
 
9
9
  logging.basicConfig(level=logging.INFO)
10
10
  logger = logging.getLogger(__name__)
@@ -47,6 +47,8 @@ def run_server(
47
47
  open_browser: bool = False,
48
48
  debug_port: int | None = None,
49
49
  env: str | pathlib.Path | Mapping[str, str] | None = None,
50
+ reload_includes: Sequence[str] | None = None,
51
+ reload_excludes: Sequence[str] | None = None,
50
52
  ):
51
53
  """Run the LangGraph API server."""
52
54
  import uvicorn
@@ -127,7 +129,7 @@ For production use, please use LangGraph Cloud.
127
129
  REDIS_URI="fake",
128
130
  N_JOBS_PER_WORKER=str(n_jobs_per_worker if n_jobs_per_worker else 1),
129
131
  LANGSERVE_GRAPHS=json.dumps(graphs) if graphs else None,
130
- LANGSMITH_LANGGRAPH_API_VARIANT="test",
132
+ LANGSMITH_LANGGRAPH_API_VARIANT="local_dev",
131
133
  **(env_vars or {}),
132
134
  ):
133
135
  if open_browser:
@@ -140,6 +142,8 @@ For production use, please use LangGraph Cloud.
140
142
  reload=reload,
141
143
  env_file=env_file,
142
144
  access_log=False,
145
+ reload_includes=reload_includes,
146
+ reload_excludes=reload_excludes,
143
147
  log_config={
144
148
  "version": 1,
145
149
  "incremental": False,
langgraph_api/graph.py CHANGED
@@ -157,18 +157,20 @@ async def collect_graphs_from_env(register: bool = False) -> None:
157
157
 
158
158
  if paths_str:
159
159
  specs = [
160
- GraphSpec(
161
- key,
162
- module=value.split(":")[0],
163
- variable=value.split(":")[1],
164
- config=config_per_graph.get(key),
165
- )
166
- if "/" not in value
167
- else GraphSpec(
168
- key,
169
- path=value.split(":")[0],
170
- variable=value.split(":")[1],
171
- config=config_per_graph.get(key),
160
+ (
161
+ GraphSpec(
162
+ key,
163
+ module=value.split(":")[0],
164
+ variable=value.split(":")[1],
165
+ config=config_per_graph.get(key),
166
+ )
167
+ if "/" not in value
168
+ else GraphSpec(
169
+ key,
170
+ path=value.split(":")[0],
171
+ variable=value.split(":")[1],
172
+ config=config_per_graph.get(key),
173
+ )
172
174
  )
173
175
  for key, value in json.loads(paths_str).items()
174
176
  ]
@@ -268,7 +270,15 @@ def _graph_from_spec(spec: GraphSpec) -> GraphValue:
268
270
  modspec.loader.exec_module(module)
269
271
  except ImportError as e:
270
272
  e.add_note(f"Could not import python module for graph: {spec}")
271
- raise e
273
+ if os.environ.get("LANGSMITH_LANGGRAPH_API_VARIANT") == "local_dev":
274
+ e.add_note(
275
+ "This error likely means you haven't installed your project and its dependencies yet. Before running the server, install your project:\n\n"
276
+ "If you are using requirements.txt:\n"
277
+ "python -m pip install -r requirements.txt\n\n"
278
+ "If you are using pyproject.toml or setuptools:\n"
279
+ "python -m pip install -e .\n\n"
280
+ "Make sure to run this command from your project's root directory (where your setup.py or pyproject.toml is located)"
281
+ )
272
282
  else:
273
283
  raise ValueError("Graph specification must have a path or module")
274
284
 
@@ -5,7 +5,11 @@ export async function resolve(specifier, context, nextResolve) {
5
5
  const parentURL = new URL("./graph.mts", import.meta.url).toString();
6
6
 
7
7
  if (specifier.startsWith("@langchain/langgraph")) {
8
- return nextResolve(specifier, { ...context, parentURL });
8
+ try {
9
+ return nextResolve(specifier, { ...context, parentURL });
10
+ } catch (error) {
11
+ return nextResolve(specifier, context);
12
+ }
9
13
  }
10
14
 
11
15
  return nextResolve(specifier, context);
langgraph_api/queue.py CHANGED
@@ -5,7 +5,7 @@ from random import random
5
5
  from typing import cast
6
6
 
7
7
  import structlog
8
- from langgraph.pregel.debug import CheckpointPayload
8
+ from langgraph.pregel.debug import CheckpointPayload, TaskResultPayload
9
9
 
10
10
  from langgraph_api.config import BG_JOB_NO_DELAY, STATS_INTERVAL_SECS
11
11
  from langgraph_api.errors import (
@@ -129,6 +129,13 @@ async def worker(
129
129
  nonlocal checkpoint
130
130
  checkpoint = checkpoint_arg
131
131
 
132
+ def on_task_result(task_result: TaskResultPayload):
133
+ if checkpoint is not None:
134
+ for task in checkpoint["tasks"]:
135
+ if task["id"] == task_result["id"]:
136
+ task.update(task_result)
137
+ break
138
+
132
139
  try:
133
140
  if attempt > MAX_RETRY_ATTEMPTS:
134
141
  raise RuntimeError(f"Run {run['run_id']} exceeded max attempts")
@@ -144,6 +151,7 @@ async def worker(
144
151
  attempt,
145
152
  done,
146
153
  on_checkpoint=on_checkpoint,
154
+ on_task_result=on_task_result,
147
155
  )
148
156
  await asyncio.wait_for(consume(stream, run_id), timeout)
149
157
  await logger.ainfo(
langgraph_api/schema.py CHANGED
@@ -98,6 +98,8 @@ class Thread(TypedDict):
98
98
  """The status of the thread. One of 'idle', 'busy', 'interrupted', "error"."""
99
99
  values: Fragment
100
100
  """The current state of the thread."""
101
+ interrupts: Fragment
102
+ """The current interrupts of the thread, a map of task_id to list of interrupts."""
101
103
 
102
104
 
103
105
  class ThreadTask(TypedDict):
langgraph_api/stream.py CHANGED
@@ -18,7 +18,7 @@ from langgraph.errors import (
18
18
  GraphRecursionError,
19
19
  InvalidUpdateError,
20
20
  )
21
- from langgraph.pregel.debug import CheckpointPayload
21
+ from langgraph.pregel.debug import CheckpointPayload, TaskResultPayload
22
22
  from langgraph.types import Command, Send
23
23
  from pydantic import ValidationError
24
24
  from pydantic.v1 import ValidationError as ValidationErrorLegacy
@@ -90,6 +90,7 @@ async def astream_state(
90
90
  done: ValueEvent,
91
91
  *,
92
92
  on_checkpoint: Callable[[CheckpointPayload], None] = lambda _: None,
93
+ on_task_result: Callable[[TaskResultPayload], None] = lambda _: None,
93
94
  ) -> AnyStream:
94
95
  """Stream messages from the runnable."""
95
96
  run_id = str(run["run_id"])
@@ -174,6 +175,8 @@ async def astream_state(
174
175
  if chunk["type"] == "checkpoint":
175
176
  checkpoint = _preprocess_debug_checkpoint(chunk["payload"])
176
177
  on_checkpoint(checkpoint)
178
+ elif chunk["type"] == "task_result":
179
+ on_task_result(chunk["payload"])
177
180
  if mode == "messages":
178
181
  if "messages-tuple" in stream_mode:
179
182
  yield "messages", chunk
@@ -221,6 +224,8 @@ async def astream_state(
221
224
  if chunk["type"] == "checkpoint":
222
225
  checkpoint = _preprocess_debug_checkpoint(chunk["payload"])
223
226
  on_checkpoint(checkpoint)
227
+ elif chunk["type"] == "task_result":
228
+ on_task_result(chunk["payload"])
224
229
  if mode == "messages":
225
230
  if "messages-tuple" in stream_mode:
226
231
  yield "messages", chunk
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langgraph-api
3
- Version: 0.0.2
3
+ Version: 0.0.3
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.52)
17
+ Requires-Dist: langgraph (>=0.2.52,<0.3.0)
18
18
  Requires-Dist: langgraph-checkpoint (>=2.0.5,<3.0)
19
19
  Requires-Dist: langsmith (>=0.1.63,<0.2.0)
20
20
  Requires-Dist: orjson (>=3.10.1)
@@ -14,11 +14,11 @@ 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=LTETSHr2j5pBwKJkidKxzXfCohEScMnXjjIpfANBJpY,6458
17
+ langgraph_api/cli.py,sha256=NNtETXM9meeGVT9nsArpuxE0Vumk1el1z3x804Esz0Q,6663
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=A9-l7cUvesyC3ymY_XFXxT02VG2kkoqbSYUDvjga5S0,9771
21
+ langgraph_api/graph.py,sha256=YM8XbgN8Q6FdqTO2LO_g_nV-cpbiJyOBMBtObnWXp18,10507
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
@@ -29,7 +29,7 @@ langgraph_api/js/package.json,sha256=glTUiod6sTKOXoGX7C7XcUXLeB_6Xa0hIw7MmJq2EY8
29
29
  langgraph_api/js/remote.py,sha256=n34B4X1sZW70vEF1hMQ4vn28BroZJt7_7BGaJ0TNeBU,23306
30
30
  langgraph_api/js/server_sent_events.py,sha256=DLgXOHauemt7706vnfDUCG1GI3TidKycSizccdz9KgA,3702
31
31
  langgraph_api/js/src/graph.mts,sha256=Gh2-TcCepeRhqMk8Bm1tWm5sv53y2FxgSclUTamnLNw,2636
32
- langgraph_api/js/src/hooks.mjs,sha256=IfPwixktR6W5FA8yNmmBVDVAaqBA549WZKuj1uQedVY,511
32
+ langgraph_api/js/src/hooks.mjs,sha256=rdAEcBmqtIwzTPzqxJ2e7TJq6FWnhh5Edpy6os8hmlk,597
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
@@ -56,31 +56,31 @@ langgraph_api/metadata.py,sha256=mih2G7ScQxiqyUlbksVXkqR3Oo-pM1b6lXtzOsgR1sw,304
56
56
  langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  langgraph_api/models/run.py,sha256=nNhlG-l2P-DThFWYmCaar0UuPctadB9sH3CCWJfLqVc,8178
58
58
  langgraph_api/patch.py,sha256=94ddcTSZJe22JcpjxiSNjFZdYVnmeoWjk4IX4iBSoyk,1249
59
- langgraph_api/queue.py,sha256=m_LcZ_KZO1PVROQxlHXZDud7CYBroZv9M3oLJ4n_qYA,9456
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=kEhwg9MUvlHKUDCvomRUts3ja53IlXHgz70H1_AXMvk,5138
61
+ langgraph_api/schema.py,sha256=yHHQS_4KQjiENF21JexzdJ_RF_HSxMEQX2aP6yPVTo4,5251
62
62
  langgraph_api/serde.py,sha256=VoJ7Z1IuqrQGXFzEP1qijAITtWCrmjtVqlCRuScjXJI,3533
63
63
  langgraph_api/server.py,sha256=cCD2lVv0SZdgf0o797UfxUyjFwmoazJVCjl_j-8Ae7A,1523
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=8VaGGUbh4BC_NJrAHeuPZgeLmRY0E8wNC0UkobLViqQ,11022
66
+ langgraph_api/stream.py,sha256=N3qneAy09Wftm8Mr-7vJCA-jGXBEp2TXFi2p-QLvVzQ,11351
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
70
70
  langgraph_license/middleware.py,sha256=_ODIYzQkymr6W9_Fp9wtf1kAQspnpsmr53xuzyF2GA0,612
71
- langgraph_license/validation.py,sha256=th7OP0JZ8R8uf7vKRpfl0K3LOI0dyCKBPBxwdmgcDOk,202
71
+ langgraph_license/validation.py,sha256=Uu_G8UGO_WTlLsBEY0gTVWjRR4czYGfw5YAD3HLZoj0,203
72
72
  langgraph_storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- langgraph_storage/checkpoint.py,sha256=9mJTKXo4LIatr0nD7AX2mU8p9q18XaRnSSi25kNQcGc,2691
73
+ langgraph_storage/checkpoint.py,sha256=55J7W0s5Z7svqqan9wphubSgCphWUItq98j-iWVwbH8,2774
74
74
  langgraph_storage/database.py,sha256=0bB4y2rWBYiT4Jsmvbbsams4Q8G0CgEwPVwclz6iQrM,4924
75
- langgraph_storage/ops.py,sha256=0btWlZnl7hl3KC7C9IIKzlsmUPilF-MQe4WwLVLymfs,51884
75
+ langgraph_storage/ops.py,sha256=mehNrHleaPAjZ2sFISNuD7iwi_ewyX_IMmSPwreHhR0,52186
76
76
  langgraph_storage/queue.py,sha256=6cTZ0ubHu3S1T43yxHMVOwsQsDaJupByiU0sTUFFls8,3261
77
77
  langgraph_storage/retry.py,sha256=uvYFuXJ-T6S1QY1ZwkZHyZQbsvS-Ab68LSbzbUUSI2E,696
78
78
  langgraph_storage/store.py,sha256=Z033CojJb6jMZbMu3VPtwR0bFdfyfdUS8dQSaXUASYU,731
79
79
  langgraph_storage/ttl_dict.py,sha256=FlpEY8EANeXWKo_G5nmIotPquABZGyIJyk6HD9u6vqY,1533
80
80
  logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
81
81
  openapi.json,sha256=JaieC_zSdQ9bzqJYdHUfCOnNt0ALBWcdj7uVjRLh9M8,122950
82
- langgraph_api-0.0.2.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
83
- langgraph_api-0.0.2.dist-info/METADATA,sha256=JlZkWP9lx3w6asP1m_U2NsCBkftoHp44PlEYWFmLezM,3986
84
- langgraph_api-0.0.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
85
- langgraph_api-0.0.2.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
86
- langgraph_api-0.0.2.dist-info/RECORD,,
82
+ langgraph_api-0.0.3.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
83
+ langgraph_api-0.0.3.dist-info/METADATA,sha256=h9q2RmDz5Z1hCr1Tqxbd390gZzyzfUEjoFhXXW9Xz3k,3993
84
+ langgraph_api-0.0.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
85
+ langgraph_api-0.0.3.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
86
+ langgraph_api-0.0.3.dist-info/RECORD,,
@@ -7,5 +7,5 @@ async def get_license_status() -> bool:
7
7
 
8
8
 
9
9
  def plus_features_enabled() -> bool:
10
- """Always return true"""
10
+ """Always return false"""
11
11
  return False
@@ -10,6 +10,8 @@ from langgraph.checkpoint.base import (
10
10
  )
11
11
  from langgraph.checkpoint.memory import MemorySaver, PersistentDict
12
12
 
13
+ from langgraph_api.serde import Serializer
14
+
13
15
  _EXCLUDED_KEYS = {"checkpoint_ns", "checkpoint_id", "run_id", "thread_id"}
14
16
 
15
17
 
@@ -37,7 +39,7 @@ class InMemorySaver(MemorySaver):
37
39
  return d
38
40
 
39
41
  super().__init__(
40
- serde=serde,
42
+ serde=serde if serde is not None else Serializer(),
41
43
  factory=factory,
42
44
  )
43
45
 
langgraph_storage/ops.py CHANGED
@@ -583,6 +583,15 @@ class Threads:
583
583
  "updated_at": datetime.now(UTC),
584
584
  "values": checkpoint["values"] if checkpoint else None,
585
585
  "status": status,
586
+ "interrupts": (
587
+ {
588
+ t["id"]: t["interrupts"]
589
+ for t in checkpoint["tasks"]
590
+ if t["interrupts"]
591
+ }
592
+ if checkpoint
593
+ else {}
594
+ ),
586
595
  }
587
596
  )
588
597