langgraph-api 0.2.125__py3-none-any.whl → 0.2.128__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.125"
1
+ __version__ = "0.2.128"
langgraph_api/config.py CHANGED
@@ -180,6 +180,7 @@ REDIS_MAX_CONNECTIONS = env("REDIS_MAX_CONNECTIONS", cast=int, default=2000)
180
180
  REDIS_CONNECT_TIMEOUT = env("REDIS_CONNECT_TIMEOUT", cast=float, default=10.0)
181
181
  REDIS_MAX_IDLE_TIME = env("REDIS_MAX_IDLE_TIME", cast=float, default=120.0)
182
182
  REDIS_KEY_PREFIX = env("REDIS_KEY_PREFIX", cast=str, default="")
183
+ RUN_STATS_CACHE_SECONDS = env("RUN_STATS_CACHE_SECONDS", cast=int, default=60)
183
184
 
184
185
  # server
185
186
  ALLOW_PRIVATE_NETWORK = env("ALLOW_PRIVATE_NETWORK", cast=bool, default=False)
@@ -6,6 +6,7 @@ from starlette.requests import ClientDisconnect
6
6
  from starlette.types import Message, Receive, Scope, Send
7
7
 
8
8
  from langgraph_api.http_metrics import HTTP_METRICS_COLLECTOR
9
+ from langgraph_api.utils.headers import should_include_header
9
10
 
10
11
  asgi = structlog.stdlib.get_logger("asgi")
11
12
 
@@ -99,12 +100,24 @@ class AccessLoggerMiddleware:
99
100
  )
100
101
 
101
102
 
102
- HEADERS_IGNORE = {b"authorization", b"cookie", b"set-cookie", b"x-api-key"}
103
+ IGNORE_HEADERS = {
104
+ b"authorization",
105
+ b"cookie",
106
+ b"set-cookie",
107
+ b"x-api-key",
108
+ }
103
109
 
104
110
 
105
111
  def _headers_to_dict(headers: list[tuple[bytes, bytes]] | None) -> dict[str, str]:
106
112
  if headers is None:
107
113
  return {}
108
- return {
109
- k.decode(): v.decode() for k, v in headers if k.lower() not in HEADERS_IGNORE
110
- }
114
+
115
+ result = {}
116
+ for k, v in headers:
117
+ if k in IGNORE_HEADERS:
118
+ continue
119
+ key = k.decode()
120
+ if should_include_header(key):
121
+ result[key] = v.decode()
122
+
123
+ return result
@@ -1,6 +1,4 @@
1
1
  import asyncio
2
- import functools
3
- import re
4
2
  import time
5
3
  import urllib.parse
6
4
  import uuid
@@ -28,6 +26,7 @@ from langgraph_api.schema import (
28
26
  StreamMode,
29
27
  )
30
28
  from langgraph_api.utils import AsyncConnectionProto, get_auth_ctx
29
+ from langgraph_api.utils.headers import should_include_header
31
30
  from langgraph_runtime.ops import Runs, logger
32
31
 
33
32
 
@@ -180,82 +179,61 @@ LANGSMITH_TAGS = "langsmith-tags"
180
179
  LANGSMITH_PROJECT = "langsmith-project"
181
180
 
182
181
 
183
- def translate_pattern(pat: str) -> re.Pattern[str]:
184
- """Translate a pattern to regex, supporting only literals and * wildcards to avoid RE DoS."""
185
- res = []
186
- i = 0
187
- n = len(pat)
188
-
189
- while i < n:
190
- c = pat[i]
191
- i += 1
192
-
193
- if c == "*":
194
- res.append(".*")
195
- else:
196
- res.append(re.escape(c))
197
-
198
- pattern = "".join(res)
199
- return re.compile(rf"(?s:{pattern})\Z")
200
-
201
-
202
- @functools.lru_cache(maxsize=1)
203
- def get_header_patterns() -> tuple[
204
- list[re.Pattern[str] | None], list[re.Pattern[str] | None]
205
- ]:
206
- from langgraph_api import config
207
-
208
- if not config.HTTP_CONFIG:
209
- return None, None
210
- configurable = config.HTTP_CONFIG.get("configurable_headers")
211
- if not configurable:
212
- return None, None
213
- header_includes = configurable.get("includes") or configurable.get("include") or []
214
- include_patterns = []
215
- for include in header_includes:
216
- include_patterns.append(translate_pattern(include))
217
- header_excludes = configurable.get("excludes") or configurable.get("exclude") or []
218
- exclude_patterns = []
219
- for exclude in header_excludes:
220
- exclude_patterns.append(translate_pattern(exclude))
221
- return include_patterns, exclude_patterns
182
+ # Default headers to exclude from run configuration for security
183
+ DEFAULT_RUN_HEADERS_EXCLUDE = {"x-api-key", "x-tenant-id", "x-service-key"}
222
184
 
223
185
 
224
186
  def get_configurable_headers(headers: dict[str, str]) -> dict[str, str]:
187
+ """Extract headers that should be added to run configuration.
188
+
189
+ This function handles special cases like langsmith-trace and baggage headers,
190
+ while respecting the configurable header patterns.
191
+ """
225
192
  configurable = {}
226
- include_patterns, exclude_patterns = get_header_patterns()
193
+
227
194
  for key, value in headers.items():
228
- # First handle tracing stuff; not configurable
195
+ # First handle tracing stuff - always included regardless of patterns
229
196
  if key == "langsmith-trace":
230
197
  configurable[key] = value
231
198
  if baggage := headers.get("baggage"):
232
199
  for item in baggage.split(","):
233
- key, value = item.split("=")
234
- if key == LANGSMITH_METADATA and key not in configurable:
235
- configurable[key] = orjson.loads(urllib.parse.unquote(value))
236
- elif key == LANGSMITH_TAGS:
237
- configurable[key] = urllib.parse.unquote(value).split(",")
238
- elif key == LANGSMITH_PROJECT:
239
- configurable[key] = urllib.parse.unquote(value)
240
- # Then handle overridable behavior
241
- if exclude_patterns and any(pattern.match(key) for pattern in exclude_patterns):
242
- continue
243
- if include_patterns and any(pattern.match(key) for pattern in include_patterns):
244
- configurable[key] = value
200
+ baggage_key, baggage_value = item.split("=")
201
+ if (
202
+ baggage_key == LANGSMITH_METADATA
203
+ and baggage_key not in configurable
204
+ ):
205
+ configurable[baggage_key] = orjson.loads(
206
+ urllib.parse.unquote(baggage_value)
207
+ )
208
+ elif baggage_key == LANGSMITH_TAGS:
209
+ configurable[baggage_key] = urllib.parse.unquote(
210
+ baggage_value
211
+ ).split(",")
212
+ elif baggage_key == LANGSMITH_PROJECT:
213
+ configurable[baggage_key] = urllib.parse.unquote(baggage_value)
245
214
  continue
246
215
 
247
- # Then handle default behavior
216
+ # Check if header should be included based on patterns
217
+ # For run configuration, we have specific default behavior for x-* headers
248
218
  if key.startswith("x-"):
249
- if key in (
250
- "x-api-key",
251
- "x-tenant-id",
252
- "x-service-key",
253
- ):
219
+ # Check against default excludes for x-* headers
220
+ if key in DEFAULT_RUN_HEADERS_EXCLUDE:
221
+ # Check if explicitly included via patterns
222
+ if should_include_header(key):
223
+ configurable[key] = value
254
224
  continue
255
- configurable[key] = value
256
-
225
+ # Other x-* headers are included by default unless patterns exclude them
226
+ if should_include_header(key):
227
+ configurable[key] = value
257
228
  elif key == "user-agent":
258
- configurable[key] = value
229
+ # user-agent is included by default unless excluded by patterns
230
+ if should_include_header(key):
231
+ configurable[key] = value
232
+ else:
233
+ # All other headers only included if patterns allow
234
+ if should_include_header(key):
235
+ configurable[key] = value
236
+
259
237
  return configurable
260
238
 
261
239
 
@@ -297,6 +275,13 @@ async def create_valid_run(
297
275
  config = payload.get("config") or {}
298
276
  context = payload.get("context") or {}
299
277
  configurable = config.setdefault("configurable", {})
278
+
279
+ if configurable and context:
280
+ raise HTTPException(
281
+ status_code=400,
282
+ detail="Cannot specify both configurable and context. Prefer setting context alone. Context was introduced in LangGraph 0.6.0 and is the long term planned replacement for configurable.",
283
+ )
284
+
300
285
  if checkpoint_id:
301
286
  configurable["checkpoint_id"] = str(checkpoint_id)
302
287
  if checkpoint := payload.get("checkpoint"):
@@ -322,6 +307,12 @@ async def create_valid_run(
322
307
  configurable["__after_seconds__"] = after_seconds
323
308
  put_time_start = time.time()
324
309
  if_not_exists = payload.get("if_not_exists", "reject")
310
+
311
+ # Keep config and context in sync
312
+ # Configurable is either A) just internal config or B) internal config + user config (and context is empty). Either way, configurable is the default.
313
+ context = {**context, **configurable}
314
+ config["configurable"] = context
315
+
325
316
  run_coro = Runs.put(
326
317
  conn,
327
318
  assistant_id,
langgraph_api/stream.py CHANGED
@@ -348,7 +348,17 @@ async def astream_state(
348
348
  yield "feedback", feedback_urls
349
349
 
350
350
 
351
- async def consume(stream: AnyStream, run_id: str, resumable: bool = False) -> None:
351
+ async def consume(
352
+ stream: AnyStream,
353
+ run_id: str,
354
+ resumable: bool = False,
355
+ stream_modes: set[StreamMode] | None = None,
356
+ ) -> None:
357
+ stream_modes = stream_modes or set()
358
+ if "messages-tuple" in stream_modes:
359
+ stream_modes.add("messages")
360
+ stream_modes.add("metadata")
361
+
352
362
  async with aclosing(stream):
353
363
  try:
354
364
  async for mode, payload in stream:
@@ -356,7 +366,7 @@ async def consume(stream: AnyStream, run_id: str, resumable: bool = False) -> No
356
366
  run_id,
357
367
  mode,
358
368
  await run_in_executor(None, json_dumpb, payload),
359
- resumable=resumable,
369
+ resumable=resumable and mode.split("|")[0] in stream_modes,
360
370
  )
361
371
  except Exception as e:
362
372
  if isinstance(e, ExceptionGroup):
@@ -365,7 +375,6 @@ async def consume(stream: AnyStream, run_id: str, resumable: bool = False) -> No
365
375
  run_id,
366
376
  "error",
367
377
  await run_in_executor(None, json_dumpb, e),
368
- resumable=resumable,
369
378
  )
370
379
  raise e
371
380
 
@@ -0,0 +1,72 @@
1
+ """Shared utilities for configurable header filtering."""
2
+
3
+ import functools
4
+ import re
5
+
6
+
7
+ def translate_pattern(pat: str) -> re.Pattern[str]:
8
+ """Translate a pattern to regex, supporting only literals and * wildcards to avoid RE DoS."""
9
+ res = []
10
+ i = 0
11
+ n = len(pat)
12
+
13
+ while i < n:
14
+ c = pat[i]
15
+ i += 1
16
+
17
+ if c == "*":
18
+ res.append(".*")
19
+ else:
20
+ res.append(re.escape(c))
21
+
22
+ pattern = "".join(res)
23
+ return re.compile(rf"(?s:{pattern})\Z")
24
+
25
+
26
+ @functools.lru_cache(maxsize=1)
27
+ def get_header_patterns() -> tuple[
28
+ list[re.Pattern[str]] | None, list[re.Pattern[str]] | None
29
+ ]:
30
+ """Get the configured header include/exclude patterns."""
31
+ from langgraph_api import config
32
+
33
+ if not config.HTTP_CONFIG:
34
+ return None, None
35
+ configurable = config.HTTP_CONFIG.get("configurable_headers")
36
+ if not configurable:
37
+ return None, None
38
+ header_includes = configurable.get("includes") or configurable.get("include") or []
39
+ include_patterns = []
40
+ for include in header_includes:
41
+ include_patterns.append(translate_pattern(include))
42
+ header_excludes = configurable.get("excludes") or configurable.get("exclude") or []
43
+ exclude_patterns = []
44
+ for exclude in header_excludes:
45
+ exclude_patterns.append(translate_pattern(exclude))
46
+ return include_patterns or None, exclude_patterns or None
47
+
48
+
49
+ @functools.lru_cache(maxsize=512)
50
+ def should_include_header(key: str) -> bool:
51
+ """Check if a header should be included based on cached patterns.
52
+
53
+ This function uses cached patterns from get_header_patterns() and
54
+ provides efficient header filtering.
55
+
56
+ Args:
57
+ key: The header key to check
58
+
59
+ Returns:
60
+ True if the header should be included, False otherwise
61
+ """
62
+ include_patterns, exclude_patterns = get_header_patterns()
63
+
64
+ # Handle configurable behavior
65
+ if exclude_patterns and any(pattern.match(key) for pattern in exclude_patterns):
66
+ return False
67
+ if include_patterns:
68
+ # If include patterns are specified, only include headers matching them
69
+ return any(pattern.match(key) for pattern in include_patterns)
70
+
71
+ # Default behavior - include if not excluded
72
+ return True
langgraph_api/worker.py CHANGED
@@ -20,7 +20,7 @@ from langgraph_api.config import (
20
20
  from langgraph_api.errors import UserInterrupt, UserRollback, UserTimeout
21
21
  from langgraph_api.js.errors import RemoteException
22
22
  from langgraph_api.metadata import incr_runs
23
- from langgraph_api.schema import Run
23
+ from langgraph_api.schema import Run, StreamMode
24
24
  from langgraph_api.state import state_snapshot_to_thread_state
25
25
  from langgraph_api.stream import AnyStream, astream_state, consume
26
26
  from langgraph_api.utils import with_user
@@ -54,6 +54,7 @@ async def set_auth_ctx_for_run(
54
54
  user = normalize_user(user)
55
55
  # Reapply normalization to the kwargs
56
56
  run_kwargs["config"]["configurable"]["langgraph_auth_user"] = user
57
+ run_kwargs["context"]["langgraph_auth_user"] = user
57
58
  except Exception:
58
59
  user = SimpleUser(user_id) if user_id is not None else None
59
60
  permissions = None
@@ -130,9 +131,11 @@ async def worker(
130
131
  break
131
132
 
132
133
  # Wrap the graph execution to separate user errors from server errors
133
- async def wrap_user_errors(stream: AnyStream, run_id: str, resumable: bool):
134
+ async def wrap_user_errors(
135
+ stream: AnyStream, run_id: str, resumable: bool, stream_modes: set[StreamMode]
136
+ ):
134
137
  try:
135
- await consume(stream, run_id, resumable)
138
+ await consume(stream, run_id, resumable, stream_modes)
136
139
  except Exception as e:
137
140
  if not isinstance(e, UserRollback | UserInterrupt):
138
141
  logger.error(
@@ -184,8 +187,11 @@ async def worker(
184
187
  on_checkpoint=on_checkpoint,
185
188
  on_task_result=on_task_result,
186
189
  )
190
+ stream_modes: set[StreamMode] = set(
191
+ run["kwargs"].get("stream_mode", [])
192
+ )
187
193
  await asyncio.wait_for(
188
- wrap_user_errors(stream, run_id, resumable),
194
+ wrap_user_errors(stream, run_id, resumable, stream_modes),
189
195
  BG_JOB_TIMEOUT_SECS,
190
196
  )
191
197
  except (Exception, asyncio.CancelledError) as ee:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.2.125
3
+ Version: 0.2.128
4
4
  Author-email: Nuno Campos <nuno@langchain.dev>, Will Fu-Hinthorn <will@langchain.dev>
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
@@ -1,9 +1,9 @@
1
- langgraph_api/__init__.py,sha256=bcQUJPOGIDh7Iu1C7gCmymyGyrOInGOeeO_ttoZlkyA,24
1
+ langgraph_api/__init__.py,sha256=mxT2nps5QgA-B4fLdRmfWEWc4sx0YKxh3Dl4H6yEbUQ,24
2
2
  langgraph_api/asgi_transport.py,sha256=eqifhHxNnxvI7jJqrY1_8RjL4Fp9NdN4prEub2FWBt8,5091
3
3
  langgraph_api/asyncio.py,sha256=Wv4Rwm-a-Cf6JpfgJmVuVlXQ7SlwrjbTn0eq1ux8I2Q,9652
4
4
  langgraph_api/cli.py,sha256=xQojITwmmKSJw48Lr2regcnRPRq2FJqWlPpeyr5TgbU,16158
5
5
  langgraph_api/command.py,sha256=3O9v3i0OPa96ARyJ_oJbLXkfO8rPgDhLCswgO9koTFA,768
6
- langgraph_api/config.py,sha256=Nxhx6fOsxk_u-Aae54JAGn46JQ1wKXPjeu_KX_3d4wQ,11918
6
+ langgraph_api/config.py,sha256=P89uB2IOycXW0qD0bb3stiaN2xAv7ixw_vqBWHM94Bw,11997
7
7
  langgraph_api/cron_scheduler.py,sha256=CiwZ-U4gDOdG9zl9dlr7mH50USUgNB2Fvb8YTKVRBN4,2625
8
8
  langgraph_api/errors.py,sha256=zlnl3xXIwVG0oGNKKpXf1an9Rn_SBDHSyhe53hU6aLw,1858
9
9
  langgraph_api/feature_flags.py,sha256=GjwmNjfg0Jhs3OzR2VbK2WgrRy3o5l8ibIYiUtQkDPA,363
@@ -21,13 +21,13 @@ langgraph_api/server.py,sha256=KBnMFt3f9RVLVu_NqyeRc13D_Lq62Rk_2czZKEUMU5E,6994
21
21
  langgraph_api/sse.py,sha256=SLdtZmTdh5D8fbWrQjuY9HYLd2dg8Rmi6ZMmFMVc2iE,4204
22
22
  langgraph_api/state.py,sha256=P2mCo-0bqPu2v9FSFGJtUCjPPNvv6wLUKQh8SdxAtc8,4387
23
23
  langgraph_api/store.py,sha256=srRI0fQXNFo_RSUs4apucr4BEp_KrIseJksZXs32MlQ,4635
24
- langgraph_api/stream.py,sha256=RvO0mYEzU7XTSQz2PDvj3KzMO_T2Hpmsbwff0GoRDmI,15741
24
+ langgraph_api/stream.py,sha256=tZfwOvG-wQNURdfQ_chfUO93JGZYc8iShlkbgukrQhY,15960
25
25
  langgraph_api/thread_ttl.py,sha256=7H3gFlWcUiODPoaEzcwB0LR61uvcuyjD0ew_4BztB7k,1902
26
26
  langgraph_api/traceblock.py,sha256=2aWS6TKGTcQ0G1fOtnjVrzkpeGvDsR0spDbfddEqgRU,594
27
27
  langgraph_api/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  langgraph_api/validation.py,sha256=zMuKmwUEBjBgFMwAaeLZmatwGVijKv2sOYtYg7gfRtc,4950
29
29
  langgraph_api/webhook.py,sha256=VCJp4dI5E1oSJ15XP34cnPiOi8Ya8Q1BnBwVGadOpLI,1636
30
- langgraph_api/worker.py,sha256=LVvjvigurlDgpNjFcbAvRH7744fE01Lirrg2ZlHtORE,14245
30
+ langgraph_api/worker.py,sha256=psxipp6bFlJrN5erGKV7D1wm2olrfggPvMqKoWk7SE4,14518
31
31
  langgraph_api/api/__init__.py,sha256=WHy6oNLWtH1K7AxmmsU9RD-Vm6WP-Ov16xS8Ey9YCmQ,6090
32
32
  langgraph_api/api/assistants.py,sha256=ecHaID71ReTAZF4qsJzDe5L-2T5iOL2v8p6kQVHLKFk,16009
33
33
  langgraph_api/api/mcp.py,sha256=qe10ZRMN3f-Hli-9TI8nbQyWvMeBb72YB1PZVbyqBQw,14418
@@ -70,16 +70,17 @@ langgraph_api/js/src/utils/importMap.mts,sha256=pX4TGOyUpuuWF82kXcxcv3-8mgusRezO
70
70
  langgraph_api/js/src/utils/pythonSchemas.mts,sha256=98IW7Z_VP7L_CHNRMb3_MsiV3BgLE2JsWQY_PQcRR3o,685
71
71
  langgraph_api/js/src/utils/serde.mts,sha256=D9o6MwTgwPezC_DEmsWS5NnLPnjPMVWIb1I1D4QPEPo,743
72
72
  langgraph_api/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
- langgraph_api/middleware/http_logger.py,sha256=L7ZhypmQjlHBfm93GqZaqUXzu0r-ieaoO1lY7t1jGb0,3701
73
+ langgraph_api/middleware/http_logger.py,sha256=tUdWuIKtDa2EkFtG_kCjw1Wkgv7gbGH3hZSgWM5Pta4,3892
74
74
  langgraph_api/middleware/private_network.py,sha256=eYgdyU8AzU2XJu362i1L8aSFoQRiV7_aLBPw7_EgeqI,2111
75
75
  langgraph_api/middleware/request_id.py,sha256=SDj3Yi3WvTbFQ2ewrPQBjAV8sYReOJGeIiuoHeZpR9g,1242
76
76
  langgraph_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- langgraph_api/models/run.py,sha256=RX2LaE1kmTruX8o8HgvqeEt5YpPGHILWByChjMZVJ58,15035
77
+ langgraph_api/models/run.py,sha256=UmkZm9IL_ET3QNA8xVPFHTAcXXZ4htQDMQuPKzaWKPA,15383
78
78
  langgraph_api/tunneling/cloudflare.py,sha256=iKb6tj-VWPlDchHFjuQyep2Dpb-w2NGfJKt-WJG9LH0,3650
79
79
  langgraph_api/utils/__init__.py,sha256=EQu0PShwHhxUI_9mDFgqlAf5_y5bX8TEk723P5iby24,4161
80
80
  langgraph_api/utils/cache.py,sha256=SrtIWYibbrNeZzLXLUGBFhJPkMVNQnVxR5giiYGHEfI,1810
81
81
  langgraph_api/utils/config.py,sha256=gONI0UsoSpuR72D9lSGAmpr-_iSMDFdD4M_tiXXjmNk,3936
82
82
  langgraph_api/utils/future.py,sha256=CGhUb_Ht4_CnTuXc2kI8evEn1gnMKYN0ce9ZyUkW5G4,7251
83
+ langgraph_api/utils/headers.py,sha256=fRZWsR279KOlbfbdcoajguVDDgVdN7V2OYkWxnHeXCE,2239
83
84
  langgraph_license/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
85
  langgraph_license/validation.py,sha256=CU38RUZ5xhP1S8F_y8TNeV6OmtO-tIGjCXbXTwJjJO4,612
85
86
  langgraph_runtime/__init__.py,sha256=O4GgSmu33c-Pr8Xzxj_brcK5vkm70iNTcyxEjICFZxA,1075
@@ -94,8 +95,8 @@ langgraph_runtime/store.py,sha256=7mowndlsIroGHv3NpTSOZDJR0lCuaYMBoTnTrewjslw,11
94
95
  LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
95
96
  logging.json,sha256=3RNjSADZmDq38eHePMm1CbP6qZ71AmpBtLwCmKU9Zgo,379
96
97
  openapi.json,sha256=SPCrzYpta2xTl-WE2W6qwosYdQqLeB8qpzaYEbcK44k,150725
97
- langgraph_api-0.2.125.dist-info/METADATA,sha256=nf3cx_h7rAHCrc6PLmUvnzQk21W-B5ugdabVU9VoiDU,3890
98
- langgraph_api-0.2.125.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
99
- langgraph_api-0.2.125.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
100
- langgraph_api-0.2.125.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
101
- langgraph_api-0.2.125.dist-info/RECORD,,
98
+ langgraph_api-0.2.128.dist-info/METADATA,sha256=1gOWC24pl8KN1ymA6h8ONc4DhnTkFWH-fLf5ILi6Oo4,3890
99
+ langgraph_api-0.2.128.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
100
+ langgraph_api-0.2.128.dist-info/entry_points.txt,sha256=hGedv8n7cgi41PypMfinwS_HfCwA7xJIfS0jAp8htV8,78
101
+ langgraph_api-0.2.128.dist-info/licenses/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
102
+ langgraph_api-0.2.128.dist-info/RECORD,,