langgraph-sdk 0.2.8__tar.gz → 0.2.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/PKG-INFO +1 -1
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/__init__.py +1 -1
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/auth/__init__.py +1 -1
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/client.py +140 -14
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/.gitignore +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/LICENSE +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/Makefile +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/README.md +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/auth/exceptions.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/auth/types.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/py.typed +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/schema.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/langgraph_sdk/sse.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/pyproject.toml +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/tests/fixtures/response.txt +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/tests/test_api_parity.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/tests/test_client_stream.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/tests/test_select_fields_sync.py +0 -0
- {langgraph_sdk-0.2.8 → langgraph_sdk-0.2.9}/uv.lock +0 -0
|
@@ -437,6 +437,54 @@ class HttpClient:
|
|
|
437
437
|
logger.error(f"Error from langgraph-api: {body}", exc_info=e)
|
|
438
438
|
raise e
|
|
439
439
|
|
|
440
|
+
async def request_reconnect(
|
|
441
|
+
self,
|
|
442
|
+
path: str,
|
|
443
|
+
method: str,
|
|
444
|
+
*,
|
|
445
|
+
json: dict[str, Any] | None = None,
|
|
446
|
+
params: QueryParamTypes | None = None,
|
|
447
|
+
headers: Mapping[str, str] | None = None,
|
|
448
|
+
on_response: Callable[[httpx.Response], None] | None = None,
|
|
449
|
+
reconnect_limit: int = 5,
|
|
450
|
+
) -> Any:
|
|
451
|
+
"""Send a request that automatically reconnects to Location header."""
|
|
452
|
+
request_headers, content = await _aencode_json(json)
|
|
453
|
+
if headers:
|
|
454
|
+
request_headers.update(headers)
|
|
455
|
+
async with self.client.stream(
|
|
456
|
+
method, path, headers=request_headers, content=content, params=params
|
|
457
|
+
) as r:
|
|
458
|
+
if on_response:
|
|
459
|
+
on_response(r)
|
|
460
|
+
try:
|
|
461
|
+
r.raise_for_status()
|
|
462
|
+
except httpx.HTTPStatusError as e:
|
|
463
|
+
body = (await r.aread()).decode()
|
|
464
|
+
if sys.version_info >= (3, 11):
|
|
465
|
+
e.add_note(body)
|
|
466
|
+
else:
|
|
467
|
+
logger.error(f"Error from langgraph-api: {body}", exc_info=e)
|
|
468
|
+
raise e
|
|
469
|
+
loc = r.headers.get("location")
|
|
470
|
+
if reconnect_limit <= 0 or not loc:
|
|
471
|
+
return await _adecode_json(r)
|
|
472
|
+
try:
|
|
473
|
+
return await _adecode_json(r)
|
|
474
|
+
except httpx.HTTPError:
|
|
475
|
+
warnings.warn(
|
|
476
|
+
f"Request failed, attempting reconnect to Location: {loc}",
|
|
477
|
+
stacklevel=2,
|
|
478
|
+
)
|
|
479
|
+
await r.aclose()
|
|
480
|
+
return await self.request_reconnect(
|
|
481
|
+
loc,
|
|
482
|
+
"GET",
|
|
483
|
+
headers=request_headers,
|
|
484
|
+
# don't pass on_response so it's only called once
|
|
485
|
+
reconnect_limit=reconnect_limit - 1,
|
|
486
|
+
)
|
|
487
|
+
|
|
440
488
|
async def stream(
|
|
441
489
|
self,
|
|
442
490
|
path: str,
|
|
@@ -2533,8 +2581,9 @@ class RunsClient:
|
|
|
2533
2581
|
if on_run_created and (metadata := _get_run_metadata_from_response(res)):
|
|
2534
2582
|
on_run_created(metadata)
|
|
2535
2583
|
|
|
2536
|
-
response = await self.http.
|
|
2584
|
+
response = await self.http.request_reconnect(
|
|
2537
2585
|
endpoint,
|
|
2586
|
+
"POST",
|
|
2538
2587
|
json={k: v for k, v in payload.items() if v is not None},
|
|
2539
2588
|
params=params,
|
|
2540
2589
|
headers=headers,
|
|
@@ -2679,12 +2728,20 @@ class RunsClient:
|
|
|
2679
2728
|
}
|
|
2680
2729
|
if params:
|
|
2681
2730
|
query_params.update(params)
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2731
|
+
if wait:
|
|
2732
|
+
return await self.http.request_reconnect(
|
|
2733
|
+
f"/threads/{thread_id}/runs/{run_id}/cancel",
|
|
2734
|
+
"POST",
|
|
2735
|
+
params=query_params,
|
|
2736
|
+
headers=headers,
|
|
2737
|
+
)
|
|
2738
|
+
else:
|
|
2739
|
+
return await self.http.post(
|
|
2740
|
+
f"/threads/{thread_id}/runs/{run_id}/cancel",
|
|
2741
|
+
json=None,
|
|
2742
|
+
params=query_params,
|
|
2743
|
+
headers=headers,
|
|
2744
|
+
)
|
|
2688
2745
|
|
|
2689
2746
|
async def join(
|
|
2690
2747
|
self,
|
|
@@ -2716,8 +2773,11 @@ class RunsClient:
|
|
|
2716
2773
|
```
|
|
2717
2774
|
|
|
2718
2775
|
""" # noqa: E501
|
|
2719
|
-
return await self.http.
|
|
2720
|
-
f"/threads/{thread_id}/runs/{run_id}/join",
|
|
2776
|
+
return await self.http.request_reconnect(
|
|
2777
|
+
f"/threads/{thread_id}/runs/{run_id}/join",
|
|
2778
|
+
"GET",
|
|
2779
|
+
headers=headers,
|
|
2780
|
+
params=params,
|
|
2721
2781
|
)
|
|
2722
2782
|
|
|
2723
2783
|
def join_stream(
|
|
@@ -3689,6 +3749,54 @@ class SyncHttpClient:
|
|
|
3689
3749
|
logger.error(f"Error from langgraph-api: {body}", exc_info=e)
|
|
3690
3750
|
raise e
|
|
3691
3751
|
|
|
3752
|
+
def request_reconnect(
|
|
3753
|
+
self,
|
|
3754
|
+
path: str,
|
|
3755
|
+
method: str,
|
|
3756
|
+
*,
|
|
3757
|
+
json: dict[str, Any] | None = None,
|
|
3758
|
+
params: QueryParamTypes | None = None,
|
|
3759
|
+
headers: Mapping[str, str] | None = None,
|
|
3760
|
+
on_response: Callable[[httpx.Response], None] | None = None,
|
|
3761
|
+
reconnect_limit: int = 5,
|
|
3762
|
+
) -> Any:
|
|
3763
|
+
"""Send a request that automatically reconnects to Location header."""
|
|
3764
|
+
request_headers, content = _encode_json(json)
|
|
3765
|
+
if headers:
|
|
3766
|
+
request_headers.update(headers)
|
|
3767
|
+
with self.client.stream(
|
|
3768
|
+
method, path, headers=request_headers, content=content, params=params
|
|
3769
|
+
) as r:
|
|
3770
|
+
if on_response:
|
|
3771
|
+
on_response(r)
|
|
3772
|
+
try:
|
|
3773
|
+
r.raise_for_status()
|
|
3774
|
+
except httpx.HTTPStatusError as e:
|
|
3775
|
+
body = r.read().decode()
|
|
3776
|
+
if sys.version_info >= (3, 11):
|
|
3777
|
+
e.add_note(body)
|
|
3778
|
+
else:
|
|
3779
|
+
logger.error(f"Error from langgraph-api: {body}", exc_info=e)
|
|
3780
|
+
raise e
|
|
3781
|
+
loc = r.headers.get("location")
|
|
3782
|
+
if reconnect_limit <= 0 or not loc:
|
|
3783
|
+
return _decode_json(r)
|
|
3784
|
+
try:
|
|
3785
|
+
return _decode_json(r)
|
|
3786
|
+
except httpx.HTTPError:
|
|
3787
|
+
warnings.warn(
|
|
3788
|
+
f"Request failed, attempting reconnect to Location: {loc}",
|
|
3789
|
+
stacklevel=2,
|
|
3790
|
+
)
|
|
3791
|
+
r.close()
|
|
3792
|
+
return self.request_reconnect(
|
|
3793
|
+
loc,
|
|
3794
|
+
"GET",
|
|
3795
|
+
headers=request_headers,
|
|
3796
|
+
# don't pass on_response so it's only called once
|
|
3797
|
+
reconnect_limit=reconnect_limit - 1,
|
|
3798
|
+
)
|
|
3799
|
+
|
|
3692
3800
|
def stream(
|
|
3693
3801
|
self,
|
|
3694
3802
|
path: str,
|
|
@@ -5754,8 +5862,9 @@ class SyncRunsClient:
|
|
|
5754
5862
|
endpoint = (
|
|
5755
5863
|
f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait"
|
|
5756
5864
|
)
|
|
5757
|
-
return self.http.
|
|
5865
|
+
return self.http.request_reconnect(
|
|
5758
5866
|
endpoint,
|
|
5867
|
+
"POST",
|
|
5759
5868
|
json={k: v for k, v in payload.items() if v is not None},
|
|
5760
5869
|
params=params,
|
|
5761
5870
|
headers=headers,
|
|
@@ -5878,11 +5987,25 @@ class SyncRunsClient:
|
|
|
5878
5987
|
```
|
|
5879
5988
|
|
|
5880
5989
|
""" # noqa: E501
|
|
5990
|
+
query_params = {
|
|
5991
|
+
"wait": 1 if wait else 0,
|
|
5992
|
+
"action": action,
|
|
5993
|
+
}
|
|
5994
|
+
if params:
|
|
5995
|
+
query_params.update(params)
|
|
5996
|
+
if wait:
|
|
5997
|
+
return self.http.request_reconnect(
|
|
5998
|
+
f"/threads/{thread_id}/runs/{run_id}/cancel",
|
|
5999
|
+
"POST",
|
|
6000
|
+
json=None,
|
|
6001
|
+
params=query_params,
|
|
6002
|
+
headers=headers,
|
|
6003
|
+
)
|
|
5881
6004
|
return self.http.post(
|
|
5882
|
-
f"/threads/{thread_id}/runs/{run_id}/cancel
|
|
6005
|
+
f"/threads/{thread_id}/runs/{run_id}/cancel",
|
|
5883
6006
|
json=None,
|
|
6007
|
+
params=query_params,
|
|
5884
6008
|
headers=headers,
|
|
5885
|
-
params=params,
|
|
5886
6009
|
)
|
|
5887
6010
|
|
|
5888
6011
|
def join(
|
|
@@ -5915,8 +6038,11 @@ class SyncRunsClient:
|
|
|
5915
6038
|
```
|
|
5916
6039
|
|
|
5917
6040
|
""" # noqa: E501
|
|
5918
|
-
return self.http.
|
|
5919
|
-
f"/threads/{thread_id}/runs/{run_id}/join",
|
|
6041
|
+
return self.http.request_reconnect(
|
|
6042
|
+
f"/threads/{thread_id}/runs/{run_id}/join",
|
|
6043
|
+
"GET",
|
|
6044
|
+
headers=headers,
|
|
6045
|
+
params=params,
|
|
5920
6046
|
)
|
|
5921
6047
|
|
|
5922
6048
|
def join_stream(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|