langgraph-sdk 0.1.0__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.
@@ -0,0 +1,3 @@
1
+ from langgraph_sdk.client import get_client
2
+
3
+ __all__ = ["get_client"]
@@ -0,0 +1,267 @@
1
+ import sys
2
+ from typing import AsyncIterator, List, NamedTuple, Optional, Union
3
+
4
+ import httpx
5
+ import httpx_sse
6
+ from httpx._types import QueryParamTypes
7
+
8
+ from langgraph_sdk.schema import (
9
+ Assistant,
10
+ Config,
11
+ Metadata,
12
+ Run,
13
+ RunEvent,
14
+ StreamMode,
15
+ Thread,
16
+ )
17
+
18
+
19
+ def get_client(*, url: str = "http://localhost:8123") -> "LangServeClient":
20
+ client = httpx.AsyncClient(
21
+ base_url=url,
22
+ transport=httpx.AsyncHTTPTransport(retries=5),
23
+ timeout=httpx.Timeout(connect=5, read=60, write=60, pool=5),
24
+ )
25
+ return LangServeClient(client)
26
+
27
+
28
+ class StreamPart(NamedTuple):
29
+ event: str
30
+ data: dict
31
+
32
+
33
+ class LangServeClient:
34
+ def __init__(self, client: httpx.AsyncClient) -> None:
35
+ self.http = HttpClient(client)
36
+ self.assistants = AssistantsClient(self.http)
37
+ self.threads = ThreadsClient(self.http)
38
+ self.runs = RunsClient(self.http)
39
+
40
+
41
+ class HttpClient:
42
+ def __init__(self, client: httpx.AsyncClient) -> None:
43
+ self.client = client
44
+
45
+ async def get(self, path: str, *, params: QueryParamTypes = None) -> dict:
46
+ """Make a GET request."""
47
+ r = await self.client.get(path, params=params)
48
+ try:
49
+ r.raise_for_status()
50
+ except httpx.HTTPStatusError as e:
51
+ if sys.version_info >= (3, 11):
52
+ e.add_note((await r.aread()).decode())
53
+ raise e
54
+ return r.json()
55
+
56
+ async def post(self, path: str, *, json: dict) -> dict:
57
+ """Make a POST request."""
58
+ r = await self.client.post(path, json=json)
59
+ try:
60
+ r.raise_for_status()
61
+ except httpx.HTTPStatusError as e:
62
+ if sys.version_info >= (3, 11):
63
+ e.add_note((await r.aread()).decode())
64
+ raise e
65
+ return r.json()
66
+
67
+ async def put(self, path: str, *, json: dict) -> dict:
68
+ """Make a PUT request."""
69
+ r = await self.client.put(path, json=json)
70
+ try:
71
+ r.raise_for_status()
72
+ except httpx.HTTPStatusError as e:
73
+ if sys.version_info >= (3, 11):
74
+ e.add_note((await r.aread()).decode())
75
+ raise e
76
+ return r.json()
77
+
78
+ async def delete(self, path: str) -> None:
79
+ """Make a DELETE request."""
80
+ r = await self.client.delete(path)
81
+ try:
82
+ r.raise_for_status()
83
+ except httpx.HTTPStatusError as e:
84
+ if sys.version_info >= (3, 11):
85
+ e.add_note((await r.aread()).decode())
86
+ raise e
87
+
88
+ async def stream(
89
+ self, path: str, method: str, *, json: dict = None
90
+ ) -> AsyncIterator[StreamPart]:
91
+ """Stream the results of a request using SSE."""
92
+ async with httpx_sse.aconnect_sse(self.client, method, path, json=json) as sse:
93
+ try:
94
+ sse.response.raise_for_status()
95
+ except httpx.HTTPStatusError as e:
96
+ if sys.version_info >= (3, 11):
97
+ e.add_note((await sse.response.aread()).decode())
98
+ raise e
99
+ async for event in sse.aiter_sse():
100
+ yield StreamPart(event.event, event.json() if event.data else None)
101
+
102
+
103
+ class AssistantsClient:
104
+ def __init__(self, http: HttpClient) -> None:
105
+ self.http = http
106
+
107
+ async def get(self, assistant_id: str) -> Assistant:
108
+ """Get an assistant by ID."""
109
+ return await self.http.get(f"/assistants/{assistant_id}")
110
+
111
+ async def create(
112
+ self,
113
+ graph_id: Optional[str],
114
+ config: Optional[Config] = None,
115
+ *,
116
+ metadata: Metadata = None,
117
+ ) -> Assistant:
118
+ """Create a new assistant."""
119
+ return await self.http.post(
120
+ "/assistants",
121
+ json={"metadata": metadata, "graph_id": graph_id, "config": config or {}},
122
+ )
123
+
124
+ async def upsert(
125
+ self,
126
+ assistant_id: str,
127
+ graph_id: str,
128
+ config: Optional[Config] = None,
129
+ *,
130
+ metadata: Metadata = None,
131
+ ) -> Assistant:
132
+ """Create or update an assistant."""
133
+ return await self.http.put(
134
+ f"/assistants/{assistant_id}",
135
+ json={"metadata": metadata, "graph_id": graph_id, "config": config or {}},
136
+ )
137
+
138
+ async def search(
139
+ self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0
140
+ ) -> list[Assistant]:
141
+ """Search for assistants."""
142
+ return await self.http.post(
143
+ "/assistants/search",
144
+ json={"metadata": metadata, "limit": limit, "offset": offset},
145
+ )
146
+
147
+
148
+ class ThreadsClient:
149
+ def __init__(self, http: HttpClient) -> None:
150
+ self.http = http
151
+
152
+ async def get(self, thread_id: str) -> Thread:
153
+ """Get a thread by ID."""
154
+ return await self.http.get(f"/threads/{thread_id}")
155
+
156
+ async def create(self, *, metadata: Metadata = None) -> Thread:
157
+ """Create a new thread."""
158
+ return await self.http.post("/threads", json={"metadata": metadata})
159
+
160
+ async def upsert(self, thread_id: str, *, metadata: Metadata) -> Thread:
161
+ """Create or update a thread."""
162
+ return await self.http.put(f"/threads/{thread_id}", json={"metadata": metadata})
163
+
164
+ async def delete(self, thread_id: str) -> None:
165
+ """Delete a thread."""
166
+ await self.http.delete(f"/threads/{thread_id}")
167
+
168
+ async def search(
169
+ self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0
170
+ ) -> list[Thread]:
171
+ """Search for threads."""
172
+ return await self.http.post(
173
+ "/threads/search",
174
+ json={"metadata": metadata, "limit": limit, "offset": offset},
175
+ )
176
+
177
+ async def get_state(self, thread_id: str) -> dict:
178
+ """Get the state of a thread."""
179
+ return await self.http.get(f"/threads/{thread_id}/state")
180
+
181
+ async def update_state(self, thread_id: Union[str, Config], values: dict) -> None:
182
+ """Update the state of a thread."""
183
+ if isinstance(thread_id, dict):
184
+ config = thread_id
185
+ thread_id_: str = thread_id["configurable"]["thread_id"]
186
+ else:
187
+ thread_id_ = thread_id
188
+ config = None
189
+ return await self.http.post(
190
+ f"/threads/{thread_id_}/state", json={"values": values, "config": config}
191
+ )
192
+
193
+
194
+ class RunsClient:
195
+ def __init__(self, http: HttpClient) -> None:
196
+ self.http = http
197
+
198
+ def stream(
199
+ self,
200
+ thread_id: str,
201
+ assistant_id: str,
202
+ *,
203
+ input: Optional[dict] = None,
204
+ stream_mode: StreamMode = "values",
205
+ metadata: Optional[dict] = None,
206
+ config: Optional[Config] = None,
207
+ interrupt_before: Optional[list[str]] = None,
208
+ interrupt_after: Optional[list[str]] = None,
209
+ ) -> AsyncIterator[StreamPart]:
210
+ """Create a run and stream the results."""
211
+ return self.http.stream(
212
+ f"/threads/{thread_id}/runs/stream",
213
+ "POST",
214
+ json={
215
+ "input": input,
216
+ "config": config,
217
+ "metadata": metadata,
218
+ "stream_mode": stream_mode,
219
+ "assistant_id": assistant_id,
220
+ "interrupt_before": interrupt_before,
221
+ "interrupt_after": interrupt_after,
222
+ },
223
+ )
224
+
225
+ async def create(
226
+ self,
227
+ thread_id: str,
228
+ assistant_id: str,
229
+ *,
230
+ input: Optional[dict] = None,
231
+ stream_mode: StreamMode = "values",
232
+ metadata: Optional[dict] = None,
233
+ config: Optional[Config] = None,
234
+ interrupt_before: Optional[list[str]] = None,
235
+ interrupt_after: Optional[list[str]] = None,
236
+ webhook: Optional[str] = None,
237
+ ) -> Run:
238
+ """Create a background run."""
239
+ return await self.http.post(
240
+ f"/threads/{thread_id}/runs",
241
+ json={
242
+ "input": input,
243
+ "config": config,
244
+ "metadata": metadata,
245
+ "stream_mode": stream_mode,
246
+ "assistant_id": assistant_id,
247
+ "interrupt_before": interrupt_before,
248
+ "interrupt_after": interrupt_after,
249
+ "webhook": webhook,
250
+ },
251
+ )
252
+
253
+ async def list(
254
+ self, thread_id: str, *, limit: int = 10, offset: int = 0
255
+ ) -> List[Run]:
256
+ """List runs."""
257
+ return await self.http.get(f"/threads/{thread_id}/runs")
258
+
259
+ async def get(self, thread_id: str, run_id: str) -> Run:
260
+ """Get a run."""
261
+ return await self.http.get(f"/threads/{thread_id}/runs/{run_id}")
262
+
263
+ async def list_events(
264
+ self, thread_id: str, run_id: str, *, limit: int = 10, offset: int = 0
265
+ ) -> List[RunEvent]:
266
+ """List run events."""
267
+ return await self.http.get(f"/threads/{thread_id}/runs/{run_id}/events")
@@ -0,0 +1,110 @@
1
+ from datetime import datetime
2
+ from typing import Any, Literal, Optional, Sequence, Union, TypedDict
3
+
4
+
5
+ Metadata = Optional[dict[str, Any]]
6
+
7
+ RunStatus = Literal["pending", "running", "error", "success", "timeout", "interrupted"]
8
+
9
+ StreamMode = Literal["values", "messages", "updates", "events", "debug"]
10
+
11
+ All = Literal["*"]
12
+
13
+
14
+ class Config(TypedDict, total=False):
15
+ tags: list[str]
16
+ """
17
+ Tags for this call and any sub-calls (eg. a Chain calling an LLM).
18
+ You can use these to filter calls.
19
+ """
20
+
21
+ recursion_limit: int
22
+ """
23
+ Maximum number of times a call can recurse. If not provided, defaults to 25.
24
+ """
25
+
26
+ configurable: dict[str, Any]
27
+ """
28
+ Runtime values for attributes previously made configurable on this Runnable,
29
+ or sub-Runnables, through .configurable_fields() or .configurable_alternatives().
30
+ Check .output_schema() for a description of the attributes that have been made
31
+ configurable.
32
+ """
33
+
34
+
35
+ class Assistant(TypedDict):
36
+ """Assistant model."""
37
+
38
+ assistant_id: str
39
+ """The ID of the assistant."""
40
+ graph_id: str
41
+ """The ID of the graph."""
42
+ config: Config
43
+ """The assistant config."""
44
+ created_at: datetime
45
+ """The time the assistant was created."""
46
+ updated_at: datetime
47
+ """The last time the assistant was updated."""
48
+ metadata: Metadata
49
+ """The assistant metadata."""
50
+
51
+
52
+ class Thread(TypedDict):
53
+ thread_id: str
54
+ """The ID of the thread."""
55
+ created_at: datetime
56
+ """The time the thread was created."""
57
+ updated_at: datetime
58
+ """The last time the thread was updated."""
59
+ metadata: Metadata
60
+ """The thread metadata."""
61
+
62
+
63
+ class ThreadState(TypedDict):
64
+ values: Union[list[dict], dict[str, Any]]
65
+ """The state values."""
66
+ next: Sequence[str]
67
+ """The next nodes to execute. If empty, the thread is done until new input is
68
+ received."""
69
+ config: Config
70
+ """Config used to fetch/use this state"""
71
+ parent_config: Optional[Config] = None
72
+ """Config used to fetch the parent state, if any"""
73
+
74
+
75
+ class Run(TypedDict):
76
+ run_id: str
77
+ """The ID of the run."""
78
+ thread_id: str
79
+ """The ID of the thread."""
80
+ assistant_id: str
81
+ """The assistant that was used for this run."""
82
+ created_at: datetime
83
+ """The time the run was created."""
84
+ updated_at: datetime
85
+ """The last time the run was updated."""
86
+ status: RunStatus
87
+ """The status of the run. One of 'pending', 'running', 'error', 'success'."""
88
+ metadata: Metadata
89
+ """The run metadata."""
90
+
91
+
92
+ class RunEvent(TypedDict):
93
+ event_id: str
94
+ """The ID of the event."""
95
+ run_id: str
96
+ """The ID of the run."""
97
+ received_at: datetime
98
+ """The time the event was received."""
99
+ span_id: str
100
+ """The ID of the span."""
101
+ event: str
102
+ """The event type."""
103
+ name: str
104
+ """The event name."""
105
+ data: dict
106
+ """The event data."""
107
+ metadata: dict
108
+ """The event metadata."""
109
+ tags: list[str]
110
+ """The event tags."""
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.1
2
+ Name: langgraph-sdk
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: Nuno Campos
6
+ Author-email: nuno@langchain.dev
7
+ Requires-Python: >=3.9.0,<3.12
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: httpx (==0.25.2)
13
+ Requires-Dist: httpx-sse (>=0.4.0,<0.5.0)
14
+ Requires-Dist: orjson (>=3.10.1,<4.0.0)
15
+ Description-Content-Type: text/markdown
16
+
17
+ # langserve
18
+
@@ -0,0 +1,6 @@
1
+ langgraph_sdk/__init__.py,sha256=7kBFjarQJyTa_vUq69lkihKIVj5Psy1EWd5NZgyqRzU,70
2
+ langgraph_sdk/client.py,sha256=O_ZED5nMUCzjMSkM8w3dRmgsr1t2Z6EwJ1gEEVe7wYs,8772
3
+ langgraph_sdk/schema.py,sha256=ZbNbY3F-IkSpg0N3baiUFJdBIw8u31xw_FCxP2MS3EY,2975
4
+ langgraph_sdk-0.1.0.dist-info/METADATA,sha256=fF5TLp4HIGOTrr3UYu4C_6nqT1ufbRfX76RqEVeZ5xs,519
5
+ langgraph_sdk-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
6
+ langgraph_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any