langgraph-api 0.0.3__py3-none-any.whl → 0.0.4__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 +30 -0
- langgraph_api/stream.py +12 -8
- {langgraph_api-0.0.3.dist-info → langgraph_api-0.0.4.dist-info}/METADATA +2 -2
- {langgraph_api-0.0.3.dist-info → langgraph_api-0.0.4.dist-info}/RECORD +8 -8
- langgraph_storage/store.py +22 -6
- {langgraph_api-0.0.3.dist-info → langgraph_api-0.0.4.dist-info}/LICENSE +0 -0
- {langgraph_api-0.0.3.dist-info → langgraph_api-0.0.4.dist-info}/WHEEL +0 -0
- {langgraph_api-0.0.3.dist-info → langgraph_api-0.0.4.dist-info}/entry_points.txt +0 -0
langgraph_api/cli.py
CHANGED
|
@@ -10,6 +10,29 @@ logging.basicConfig(level=logging.INFO)
|
|
|
10
10
|
logger = logging.getLogger(__name__)
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
def _get_org_id() -> str | None:
|
|
14
|
+
from langsmith.client import Client
|
|
15
|
+
from langsmith.utils import tracing_is_enabled
|
|
16
|
+
|
|
17
|
+
# Yes, the organizationId is actually the workspace iD
|
|
18
|
+
# which is actually the tenantID which we actually get via
|
|
19
|
+
# the sessions endpoint
|
|
20
|
+
|
|
21
|
+
if not tracing_is_enabled():
|
|
22
|
+
return
|
|
23
|
+
client = Client()
|
|
24
|
+
try:
|
|
25
|
+
response = client.request_with_retries(
|
|
26
|
+
"GET", "/api/v1/sessions", params={"limit": 1}
|
|
27
|
+
)
|
|
28
|
+
result = response.json()
|
|
29
|
+
if result:
|
|
30
|
+
return result[0]["tenant_id"]
|
|
31
|
+
except Exception as e:
|
|
32
|
+
logger.debug("Failed to get organization ID: %s", str(e))
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
13
36
|
@contextlib.contextmanager
|
|
14
37
|
def patch_environment(**kwargs):
|
|
15
38
|
"""Temporarily patch environment variables.
|
|
@@ -92,14 +115,21 @@ def run_server(
|
|
|
92
115
|
studio_url = f"https://smith.langchain.com/studio/?baseUrl={local_url}"
|
|
93
116
|
|
|
94
117
|
def _open_browser():
|
|
118
|
+
nonlocal studio_url
|
|
95
119
|
import time
|
|
96
120
|
import urllib.request
|
|
97
121
|
import webbrowser
|
|
98
122
|
|
|
123
|
+
org_id = _get_org_id()
|
|
124
|
+
if org_id:
|
|
125
|
+
studio_url = f"https://smith.langchain.com/studio/?baseUrl={local_url}&organizationId={org_id}"
|
|
126
|
+
|
|
99
127
|
while True:
|
|
100
128
|
try:
|
|
101
129
|
with urllib.request.urlopen(f"{local_url}/ok") as response:
|
|
102
130
|
if response.status == 200:
|
|
131
|
+
logger.info("🎨 Opening Studio in your browser...")
|
|
132
|
+
logger.info("URL: " + studio_url)
|
|
103
133
|
webbrowser.open(studio_url)
|
|
104
134
|
return
|
|
105
135
|
except urllib.error.URLError:
|
langgraph_api/stream.py
CHANGED
|
@@ -94,7 +94,7 @@ async def astream_state(
|
|
|
94
94
|
) -> AnyStream:
|
|
95
95
|
"""Stream messages from the runnable."""
|
|
96
96
|
run_id = str(run["run_id"])
|
|
97
|
-
await stack.enter_async_context(conn.pipeline())
|
|
97
|
+
pipe = await stack.enter_async_context(conn.pipeline())
|
|
98
98
|
# extract args from run
|
|
99
99
|
kwargs = run["kwargs"].copy()
|
|
100
100
|
subgraphs = kwargs.get("subgraphs", False)
|
|
@@ -103,7 +103,7 @@ async def astream_state(
|
|
|
103
103
|
graph = get_graph(
|
|
104
104
|
config["configurable"]["graph_id"],
|
|
105
105
|
config,
|
|
106
|
-
store=None if not conn else Store(conn),
|
|
106
|
+
store=None if not conn else Store(conn, pipe=pipe),
|
|
107
107
|
checkpointer=None if temporary else Checkpointer(conn),
|
|
108
108
|
)
|
|
109
109
|
input = kwargs.pop("input")
|
|
@@ -188,9 +188,11 @@ async def astream_state(
|
|
|
188
188
|
messages[msg.id] = msg
|
|
189
189
|
yield "messages/metadata", {msg.id: {"metadata": meta}}
|
|
190
190
|
yield (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
(
|
|
192
|
+
"messages/partial"
|
|
193
|
+
if isinstance(msg, BaseMessageChunk)
|
|
194
|
+
else "messages/complete"
|
|
195
|
+
),
|
|
194
196
|
[message_chunk_to_message(messages[msg.id])],
|
|
195
197
|
)
|
|
196
198
|
elif mode in stream_mode:
|
|
@@ -237,9 +239,11 @@ async def astream_state(
|
|
|
237
239
|
messages[msg.id] = msg
|
|
238
240
|
yield "messages/metadata", {msg.id: {"metadata": meta}}
|
|
239
241
|
yield (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
(
|
|
243
|
+
"messages/partial"
|
|
244
|
+
if isinstance(msg, BaseMessageChunk)
|
|
245
|
+
else "messages/complete"
|
|
246
|
+
),
|
|
243
247
|
[message_chunk_to_message(messages[msg.id])],
|
|
244
248
|
)
|
|
245
249
|
elif mode in stream_mode:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langgraph-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary:
|
|
5
5
|
License: Elastic-2.0
|
|
6
6
|
Author: Nuno Campos
|
|
@@ -15,7 +15,7 @@ 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
17
|
Requires-Dist: langgraph (>=0.2.52,<0.3.0)
|
|
18
|
-
Requires-Dist: langgraph-checkpoint (>=2.0.
|
|
18
|
+
Requires-Dist: langgraph-checkpoint (>=2.0.6,<3.0)
|
|
19
19
|
Requires-Dist: langsmith (>=0.1.63,<0.2.0)
|
|
20
20
|
Requires-Dist: orjson (>=3.10.1)
|
|
21
21
|
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
@@ -14,7 +14,7 @@ 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=wNGL4wnuwJn-WffuNY1akjeNSYMiZasV_uftF5XPP3E,7667
|
|
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
|
|
@@ -63,7 +63,7 @@ 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=
|
|
66
|
+
langgraph_api/stream.py,sha256=yHnhODy5FRqxmiN3t0m9pBYQADws0YSHuBLet8pXBDs,11521
|
|
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
|
|
@@ -75,12 +75,12 @@ langgraph_storage/database.py,sha256=0bB4y2rWBYiT4Jsmvbbsams4Q8G0CgEwPVwclz6iQrM
|
|
|
75
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
|
-
langgraph_storage/store.py,sha256=
|
|
78
|
+
langgraph_storage/store.py,sha256=k5DdW_dA1VaYnXo7Cm2IoXBqxm1FtPFiqNXNsmNiDUo,1452
|
|
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.
|
|
83
|
-
langgraph_api-0.0.
|
|
84
|
-
langgraph_api-0.0.
|
|
85
|
-
langgraph_api-0.0.
|
|
86
|
-
langgraph_api-0.0.
|
|
82
|
+
langgraph_api-0.0.4.dist-info/LICENSE,sha256=ZPwVR73Biwm3sK6vR54djCrhaRiM4cAD2zvOQZV8Xis,3859
|
|
83
|
+
langgraph_api-0.0.4.dist-info/METADATA,sha256=yNGt2rJsJVk7b-kJJEjukG8PHtBO7WCdQMK-38KoWyc,3993
|
|
84
|
+
langgraph_api-0.0.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
85
|
+
langgraph_api-0.0.4.dist-info/entry_points.txt,sha256=3EYLgj89DfzqJHHYGxPH4A_fEtClvlRbWRUHaXO7hj4,77
|
|
86
|
+
langgraph_api-0.0.4.dist-info/RECORD,,
|
langgraph_storage/store.py
CHANGED
|
@@ -1,28 +1,44 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from langgraph.checkpoint.memory import PersistentDict
|
|
4
5
|
from langgraph.store.memory import InMemoryStore
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class DiskBackedInMemStore(InMemoryStore):
|
|
8
|
-
def __init__(self, *args, filename=None, **kwargs):
|
|
9
|
+
def __init__(self, *args: Any, filename: str | None = None, **kwargs: Any) -> None:
|
|
9
10
|
super().__init__(*args, **kwargs)
|
|
10
11
|
self.filename = filename
|
|
11
12
|
self._data = PersistentDict(dict, filename=self.filename)
|
|
13
|
+
self._load_data()
|
|
14
|
+
|
|
15
|
+
def _load_data(self) -> None:
|
|
16
|
+
if not self.filename:
|
|
17
|
+
return
|
|
12
18
|
try:
|
|
13
19
|
self._data.load()
|
|
14
20
|
except FileNotFoundError:
|
|
21
|
+
# It's okay if the file doesn't exist yet
|
|
15
22
|
pass
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
except (EOFError, ValueError) as e:
|
|
24
|
+
raise RuntimeError(
|
|
25
|
+
f"Failed to load store from {self.filename}. "
|
|
26
|
+
"This may be due to changes in the stored data structure. "
|
|
27
|
+
"Consider clearing the local store by running: rm -rf .langgraph_api"
|
|
28
|
+
) from e
|
|
29
|
+
except Exception as e:
|
|
30
|
+
raise RuntimeError(
|
|
31
|
+
f"Unexpected error loading store from {self.filename}: {str(e)}"
|
|
32
|
+
) from e
|
|
33
|
+
|
|
34
|
+
def close(self) -> None:
|
|
18
35
|
self._data.close()
|
|
19
36
|
|
|
20
37
|
|
|
21
38
|
_STORE_FILE = os.path.join(".langgraph_api", "store.pckl")
|
|
22
|
-
|
|
23
|
-
os.mkdir(".langgraph_api")
|
|
39
|
+
os.makedirs(".langgraph_api", exist_ok=True)
|
|
24
40
|
STORE = DiskBackedInMemStore(filename=_STORE_FILE)
|
|
25
41
|
|
|
26
42
|
|
|
27
|
-
def Store(*args, **kwargs):
|
|
43
|
+
def Store(*args: Any, **kwargs: Any) -> DiskBackedInMemStore:
|
|
28
44
|
return STORE
|
|
File without changes
|
|
File without changes
|
|
File without changes
|