diff --git a/docs/docs/cloud/reference/sdk/python_sdk_ref.md b/docs/docs/cloud/reference/sdk/python_sdk_ref.md index 9c362ddea..0492a08cd 100644 --- a/docs/docs/cloud/reference/sdk/python_sdk_ref.md +++ b/docs/docs/cloud/reference/sdk/python_sdk_ref.md @@ -1,79 +1,8 @@ # Python SDK Reference -The Python SDK provides four underlying clients (`AssistantsClient`, `ThreadsClient`, `RunsClient`, `CronClient`) that correspond to each of the core API models and one top-level client (`LangGraphClient`) to access them. - -## get_client() - -The `get_client()` function returns the top-level `LangGraphClient` client. - -```python -from langgraph_sdk import get_client - -# get top-level LangGraphClient -client = get_client(url="http://localhost:8123") - -# example usage: client..() -assistants = await client.assistants.get(assistant_id="some_uuid") -``` - -::: langgraph_sdk.client.get_client +::: langgraph_sdk.client handler: python -## LangGraphClient -`LangGraphClient` is the top-level client for accessing `AssistantsClient`, `ThreadsClient`, `RunsClient`, and `CronClient`. - -::: langgraph_sdk.client.LangGraphClient - handler: python - -## AssistantsClient - -Access the `AssistantsClient` via the `LangGraphClient.assistants` attribute. -```python -from langgraph_sdk import get_client - -client = get_client(url="http://localhost:8123") -await client.assistants.() -``` - -::: langgraph_sdk.client.AssistantsClient - handler: python - -## ThreadsClient - -Access the `ThreadsClient` via the `LangGraphClient.threads` attribute. -```python -from langgraph_sdk import get_client - -client = get_client(url="http://localhost:8123") -await client.threads.() -``` - -::: langgraph_sdk.client.ThreadsClient - handler: python - -## RunsClient - -Access the `RunsClient` via the `LangGraphClient.runs` attribute. -```python -from langgraph_sdk import get_client - -client = get_client(url="http://localhost:8123") -await client.runs.() -``` - -::: langgraph_sdk.client.RunsClient - handler: python - -## CronClient - -Access the `CronClient` via the `LangGraphClient.crons` attribute. -```python -from langgraph_sdk import get_client - -client = get_client(url="http://localhost:8123") -await client.crons.() -``` - -::: langgraph_sdk.client.CronClient +::: langgraph_sdk.schema handler: python diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index d352d4d88..8d7fccdc6 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -1,3 +1,11 @@ +"""The LangGraph client implementations connect to the LangGraph API. + +This module provides both asynchronous (LangGraphClient) and synchronous (SyncLanggraphClient) +clients to interacting with the LangGraph API's core resources such as +Assistants, Threads, Runs, and Cron jobs, as well as its persistent +document Store. +""" + from __future__ import annotations import asyncio @@ -117,6 +125,20 @@ def get_client( 3. LANGSMITH_API_KEY 4. LANGCHAIN_API_KEY headers: Optional custom headers + + Returns: + LangGraphClient: The top-level client for accessing AssistantsClient, + ThreadsClient, RunsClient, and CronClient. + + Example: + + from langgraph_sdk import get_client + + # get top-level LangGraphClient + client = get_client(url="http://localhost:8123") + + # example usage: client..() + assistants = await client.assistants.get(assistant_id="some_uuid") """ transport: Optional[httpx.AsyncBaseTransport] = None if url is None: @@ -141,6 +163,16 @@ def get_client( class LangGraphClient: + """Top-level client for LangGraph API. + + Attributes: + assistants: Manages versioned configuration for your graphs. + threads: Handles (potentially) multi-turn interactions, such as conversational threads. + runs: Controls individual invocations of the graph. + crons: Manages scheduled operations. + store: Interfaces with persistent, shared data storage. + """ + def __init__(self, client: httpx.AsyncClient) -> None: self.http = HttpClient(client) self.assistants = AssistantsClient(self.http) @@ -151,11 +183,20 @@ class LangGraphClient: class HttpClient: + """Hancle async requests to the LangGraph API. + + Adds additional error messaging & content handling above the + provided httpx client. + + Attributes: + client (httpx.AsyncClient): Underlying HTTPX async client. + """ + def __init__(self, client: httpx.AsyncClient) -> None: self.client = client async def get(self, path: str, *, params: Optional[QueryParamTypes] = None) -> Any: - """Make a GET request.""" + """Send a GET request.""" r = await self.client.get(path, params=params) try: r.raise_for_status() @@ -169,7 +210,7 @@ class HttpClient: return await adecode_json(r) async def post(self, path: str, *, json: Optional[dict]) -> Any: - """Make a POST request.""" + """Send a POST request.""" if json is not None: headers, content = await aencode_json(json) else: @@ -187,7 +228,7 @@ class HttpClient: return await adecode_json(r) async def put(self, path: str, *, json: dict) -> Any: - """Make a PUT request.""" + """Send a PUT request.""" headers, content = await aencode_json(json) r = await self.client.put(path, headers=headers, content=content) try: @@ -202,7 +243,7 @@ class HttpClient: return await adecode_json(r) async def patch(self, path: str, *, json: dict) -> Any: - """Make a PATCH request.""" + """Send a PATCH request.""" headers, content = await aencode_json(json) r = await self.client.patch(path, headers=headers, content=content) try: @@ -217,7 +258,7 @@ class HttpClient: return await adecode_json(r) async def delete(self, path: str, *, json: Optional[Any] = None) -> None: - """Make a DELETE request.""" + """Send a DELETE request.""" r = await self.client.request("DELETE", path, json=json) try: r.raise_for_status() @@ -232,7 +273,7 @@ class HttpClient: async def stream( self, path: str, method: str, *, json: Optional[dict] = None ) -> AsyncIterator[StreamPart]: - """Stream the results of a request using SSE.""" + """Stream results using SSE.""" headers, content = await aencode_json(json) async with httpx_sse.aconnect_sse( self.client, method, path, headers=headers, content=content @@ -276,6 +317,17 @@ async def adecode_json(r: httpx.Response) -> Any: class AssistantsClient: + """Client for managing assistants in LangGraph. + + This class provides methods to interact with assistants, + which are versioned configurations of your graph. + + Example: + + client = get_client() + assistant = await client.assistants.get("assistant_id_123") + """ + def __init__(self, http: HttpClient) -> None: self.http = http @@ -699,6 +751,18 @@ class AssistantsClient: class ThreadsClient: + """Client for managing threads in LangGraph. + + A thread maintains the state of a graph across multiple interactions/invocations (aka runs). + It accumulates and persists the graph's state, allowing for continuity between separate + invocations of the graph. + + Example: + + client = get_client() + new_thread = await client.threads.create(metadata={"user_id": "123"}) + """ + def __init__(self, http: HttpClient) -> None: self.http = http @@ -1070,6 +1134,17 @@ class ThreadsClient: class RunsClient: + """Client for managing runs in LangGraph. + + A run is a single assistant invocation with optional input, config, and metadata. + This client manages runs, which can be stateful (on threads) or stateless. + + Example: + + client = get_client() + run = await client.runs.create(assistant_id="asst_123", thread_id="thread_456", input={"query": "Hello"}) + """ + def __init__(self, http: HttpClient) -> None: self.http = http @@ -1677,6 +1752,22 @@ class RunsClient: class CronClient: + """Client for managing recurrent runs (cron jobs) in LangGraph. + + A run is a single invocation of an assistant with optional input and config. + This client allows scheduling recurring runs to occur automatically. + + Example: + + client = get_client() + cron_job = await client.crons.create_for_thread( + thread_id="thread_123", + assistant_id="asst_456", + schedule="0 9 * * *", + input={"message": "Daily update"} + ) + """ + def __init__(self, http_client: HttpClient) -> None: self.http = http_client @@ -1888,6 +1979,17 @@ class CronClient: class StoreClient: + """Client for interacting with the graph's shared storage. + + The Store provides a key-value storage system for persisting data across graph executions, + allowing for stateful operations and data sharing across threads. + + Example: + + client = get_client() + await client.store.put_item(["users", "user123"], "mem-123451342", {"name": "Alice", "score": 100}) + """ + def __init__(self, http: HttpClient) -> None: self.http = http @@ -2092,7 +2194,7 @@ def get_sync_client( api_key: Optional[str] = None, headers: Optional[dict[str, str]] = None, ) -> SyncLangGraphClient: - """Get a LangGraphClient instance. + """Get a synchronous LangGraphClient instance. Args: url: The URL of the LangGraph API. @@ -2103,6 +2205,19 @@ def get_sync_client( 3. LANGSMITH_API_KEY 4. LANGCHAIN_API_KEY headers: Optional custom headers + Returns: + SyncLangGraphClient: The top-level synchronous client for accessing AssistantsClient, + ThreadsClient, RunsClient, and CronClient. + + Example: + + from langgraph_sdk import get_sync_client + + # get top-level synchronous LangGraphClient + client = get_sync_client(url="http://localhost:8123") + + # example usage: client..() + assistant = client.assistants.get(assistant_id="some_uuid") """ if url is None: @@ -2119,6 +2234,17 @@ def get_sync_client( class SyncLangGraphClient: + """Synchronous client for interacting with the LangGraph API. + + This class provides synchronous access to LangGraph API endpoints for managing + assistants, threads, runs, cron jobs, and data storage. + + Example: + + client = get_sync_client() + assistant = client.assistants.get("asst_123") + """ + def __init__(self, client: httpx.Client) -> None: self.http = SyncHttpClient(client) self.assistants = SyncAssistantsClient(self.http) @@ -2133,7 +2259,7 @@ class SyncHttpClient: self.client = client def get(self, path: str, *, params: Optional[QueryParamTypes] = None) -> Any: - """Make a GET request.""" + """Send a GET request.""" r = self.client.get(path, params=params) try: r.raise_for_status() @@ -2147,7 +2273,7 @@ class SyncHttpClient: return decode_json(r) def post(self, path: str, *, json: Optional[dict]) -> Any: - """Make a POST request.""" + """Send a POST request.""" if json is not None: headers, content = encode_json(json) else: @@ -2165,7 +2291,7 @@ class SyncHttpClient: return decode_json(r) def put(self, path: str, *, json: dict) -> Any: - """Make a PUT request.""" + """Send a PUT request.""" headers, content = encode_json(json) r = self.client.put(path, headers=headers, content=content) try: @@ -2180,7 +2306,7 @@ class SyncHttpClient: return decode_json(r) def patch(self, path: str, *, json: dict) -> Any: - """Make a PATCH request.""" + """Send a PATCH request.""" headers, content = encode_json(json) r = self.client.patch(path, headers=headers, content=content) try: @@ -2195,7 +2321,7 @@ class SyncHttpClient: return decode_json(r) def delete(self, path: str, *, json: Optional[Any] = None) -> None: - """Make a DELETE request.""" + """Send a DELETE request.""" r = self.client.request("DELETE", path, json=json) try: r.raise_for_status() @@ -2248,6 +2374,16 @@ def decode_json(r: httpx.Response) -> Any: class SyncAssistantsClient: + """Client for managing assistants in LangGraph synchronously. + + This class provides methods to interact with assistants, which are versioned configurations of your graph. + + Example: + + client = get_client() + assistant = client.assistants.get("assistant_id_123") + """ + def __init__(self, http: SyncHttpClient) -> None: self.http = http @@ -2667,6 +2803,17 @@ class SyncAssistantsClient: class SyncThreadsClient: + """Synchronous client for managing threads in LangGraph. + + This class provides methods to create, retrieve, and manage threads, + which represent conversations or stateful interactions. + + Example: + + client = get_sync_client() + thread = client.threads.create(metadata={"user_id": "123"}) + """ + def __init__(self, http: SyncHttpClient) -> None: self.http = http @@ -3038,6 +3185,17 @@ class SyncThreadsClient: class SyncRunsClient: + """Synchronous client for managing runs in LangGraph. + + This class provides methods to create, retrieve, and manage runs, which represent + individual executions of graphs. + + Example: + + client = get_sync_client() + run = client.runs.create(thread_id="thread_123", assistant_id="asst_456") + """ + def __init__(self, http: SyncHttpClient) -> None: self.http = http @@ -3641,6 +3799,16 @@ class SyncRunsClient: class SyncCronClient: + """Synchronous client for managing cron jobs in LangGraph. + + This class provides methods to create and manage scheduled tasks (cron jobs) for automated graph executions. + + Example: + + client = get_sync_client() + cron_job = client.crons.create_for_thread(thread_id="thread_123", assistant_id="asst_456", schedule="0 * * * *") + """ + def __init__(self, http_client: SyncHttpClient) -> None: self.http = http_client @@ -3852,6 +4020,17 @@ class SyncCronClient: class SyncStoreClient: + """A client for synchronous operations on a key-value store. + + Provides methods to interact with a remote key-value store, allowing + storage and retrieval of items within namespaced hierarchies. + + Example: + + client = get_sync_client() + client.store.put_item(["users", "profiles"], "user123", {"name": "Alice", "age": 30}) + """ + def __init__(self, http: SyncHttpClient) -> None: self.http = http diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py index 2ea166aef..c6101bdce 100644 --- a/libs/sdk-py/langgraph_sdk/schema.py +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -1,26 +1,77 @@ +"""Data models for interacting with the LangGraph API.""" + from datetime import datetime from typing import Any, Literal, NamedTuple, Optional, Sequence, TypedDict, Union Json = Optional[dict[str, Any]] +"""Represents a JSON-like structure, which can be None or a dictionary with string keys and any values.""" RunStatus = Literal["pending", "running", "error", "success", "timeout", "interrupted"] +""" +Represents the status of a run: +- "pending": The run is waiting to start. +- "running": The run is currently in progress. +- "error": The run encountered an error and stopped. +- "success": The run completed successfully. +- "timeout": The run exceeded its time limit. +- "interrupted": The run was manually stopped or interrupted. +""" ThreadStatus = Literal["idle", "busy", "interrupted"] +""" +Represents the status of a thread: +- "idle": The thread is not currently processing any task. +- "busy": The thread is actively processing a task. +- "interrupted": The thread's execution was interrupted. +""" StreamMode = Literal["values", "messages", "updates", "events", "debug"] +""" +Defines the mode of streaming: +- "values": Stream only the values. +- "messages": Stream complete messages. +- "updates": Stream updates to the state. +- "events": Stream events occurring during execution. +- "debug": Stream detailed debug information. +""" DisconnectMode = Literal["cancel", "continue"] +""" +Specifies behavior on disconnection: +- "cancel": Cancel the operation on disconnection. +- "continue": Continue the operation even if disconnected. +""" MultitaskStrategy = Literal["reject", "interrupt", "rollback", "enqueue"] +""" +Defines how to handle multiple tasks: +- "reject": Reject new tasks when busy. +- "interrupt": Interrupt current task for new ones. +- "rollback": Roll back current task and start new one. +- "enqueue": Queue new tasks for later execution. +""" OnConflictBehavior = Literal["raise", "do_nothing"] +""" +Specifies behavior on conflict: +- "raise": Raise an exception when a conflict occurs. +- "do_nothing": Ignore conflicts and proceed. +""" OnCompletionBehavior = Literal["delete", "keep"] +""" +Defines action after completion: +- "delete": Delete resources after completion. +- "keep": Retain resources after completion. +""" All = Literal["*"] +"""Represents a wildcard or 'all' selector.""" class Config(TypedDict, total=False): + """Configuration options for a call.""" + tags: list[str] """ Tags for this call and any sub-calls (eg. a Chain calling an LLM). @@ -42,16 +93,20 @@ class Config(TypedDict, total=False): class Checkpoint(TypedDict): - """Checkpoint model.""" + """Represents a checkpoint in the execution process.""" thread_id: str + """Unique identifier for the thread associated with this checkpoint.""" checkpoint_ns: str + """Namespace for the checkpoint, used for organization and retrieval.""" checkpoint_id: Optional[str] + """Optional unique identifier for the checkpoint itself.""" checkpoint_map: Optional[dict[str, Any]] + """Optional dictionary containing checkpoint-specific data.""" class GraphSchema(TypedDict): - """Graph model.""" + """Defines the structure and properties of a graph.""" graph_id: str """The ID of the graph.""" @@ -73,7 +128,7 @@ Subgraphs = dict[str, GraphSchema] class AssistantBase(TypedDict): - """Assistant base model.""" + """Base model for an assistant.""" assistant_id: str """The ID of the assistant.""" @@ -90,13 +145,13 @@ class AssistantBase(TypedDict): class AssistantVersion(AssistantBase): - """Assistant version model.""" + """Represents a specific version of an assistant.""" pass class Assistant(AssistantBase): - """Assistant model.""" + """Represents an assistant with additional properties.""" updated_at: datetime """The last time the assistant was updated.""" @@ -105,6 +160,8 @@ class Assistant(AssistantBase): class Thread(TypedDict): + """Represents a conversation thread.""" + thread_id: str """The ID of the thread.""" created_at: datetime @@ -120,6 +177,8 @@ class Thread(TypedDict): class ThreadTask(TypedDict): + """Represents a task within a thread.""" + id: str name: str error: Optional[str] @@ -129,6 +188,8 @@ class ThreadTask(TypedDict): class ThreadState(TypedDict): + """Represents the state of a thread.""" + values: Union[list[dict], dict[str, Any]] """The state values.""" next: Sequence[str] @@ -147,6 +208,8 @@ class ThreadState(TypedDict): class Run(TypedDict): + """Represents a single execution run.""" + run_id: str """The ID of the run.""" thread_id: str @@ -166,6 +229,8 @@ class Run(TypedDict): class Cron(TypedDict): + """Represents a scheduled task.""" + cron_id: str """The ID of the cron.""" thread_id: Optional[str] @@ -183,27 +248,42 @@ class Cron(TypedDict): class RunCreate(TypedDict): - """Payload for creating a background run.""" + """Defines the parameters for initiating a background run.""" thread_id: Optional[str] + """The identifier of the thread to run. If not provided, the run is stateless.""" assistant_id: str + """The identifier of the assistant to use for this run.""" input: Optional[dict] + """Initial input data for the run.""" metadata: Optional[dict] + """Additional metadata to associate with the run.""" config: Optional[Config] + """Configuration options for the run.""" checkpoint_id: Optional[str] + """The identifier of a checkpoint to resume from.""" interrupt_before: Optional[list[str]] + """List of node names to interrupt execution before.""" interrupt_after: Optional[list[str]] + """List of node names to interrupt execution after.""" webhook: Optional[str] + """URL to send webhook notifications about the run's progress.""" multitask_strategy: Optional[MultitaskStrategy] + """Strategy for handling concurrent runs on the same thread.""" class Item(TypedDict): + """Represents a single document or data entry in the graph's Store. + + Items are used to store cross-thread memories. + """ + namespace: list[str] - """The namespace of the item.""" + """The namespace of the item. A namespace is analogous to a document's directory.""" key: str """The unique identifier of the item within its namespace. - In general, keys are not globally unique. + In general, keys needn't be globally unique. """ value: dict[str, Any] """The value stored in the item. This is the document itself.""" @@ -214,13 +294,23 @@ class Item(TypedDict): class ListNamespaceResponse(TypedDict): + """Response structure for listing namespaces.""" + namespaces: list[list[str]] + """A list of namespace paths, where each path is a list of strings.""" class SearchItemsResponse(TypedDict): + """Response structure for searching items.""" + items: list[Item] + """A list of items matching the search criteria.""" class StreamPart(NamedTuple): + """Represents a part of a stream response.""" + event: str + """The type of event for this stream part.""" data: dict + """The data payload associated with the event."""