Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
runtime.py239 linesDownload Raw Back to langgraph_sdk
1from __future__ import annotations2 3import sys4from dataclasses import dataclass, field5from typing import TYPE_CHECKING, Generic, Literal, TypeVar6 7if sys.version_info >= (3, 13):8    ContextT = TypeVar("ContextT", default=None)9else:10    ContextT = TypeVar("ContextT")11 12if sys.version_info >= (3, 12):13    from typing import TypeAliasType14else:15    from typing_extensions import TypeAliasType16 17from langgraph_sdk.auth.types import BaseUser18 19if TYPE_CHECKING:20    from langgraph.store.base import BaseStore21 22__all__ = [23    "AccessContext",24    "ServerRuntime",25]26 27 28AccessContext = Literal[29    "threads.create_run",30    "threads.update",31    "threads.read",32    "assistants.read",33]34 35 36@dataclass(kw_only=True, slots=True, frozen=True)37class _ServerRuntimeBase(Generic[ContextT]):38    """Base for server runtime variants.39 40    !!! warning "Beta"41        This API is in beta and may change in future releases.42    """43 44    access_context: AccessContext45    """Why the graph factory is being called.46 47    The server accesses graphs in several contexts beyond just executing runs.48    For example, it calls the graph factory to retrieve schemas, render the49    graph structure, or read state history. This field tells you which50    operation triggered the current call.51 52    In all contexts, the returned graph must have the same topology (nodes,53    edges, state schema) as the graph used for execution. Use54    `.execution_runtime` to conditionally set up expensive *resources*55    (MCP servers, DB connections) without changing the graph structure.56 57    Write contexts (graph is used to write state):58 59    - `threads.create_run` (`graph.astream`) — full graph execution60      (nodes + edges). `context` is available (use `.execution_runtime`61      to narrow).62    - `threads.update` (`graph.aupdate_state`) — does NOT execute node63      functions or evaluate edges. Only runs the node's channel writers64      to apply the provided values to state channels as if the specified65      node had returned them. Reducers are applied and channel triggers66      are set, so the next `invoke`/`stream` call will evaluate edges67      from that node to determine the next step. Does not need access to68      external resources, but a different graph topology will apply69      writes to the wrong channels.70 71    Read state contexts (graph used to format the returned72    `StateSnapshot`). A different topology may cause `get_state` to73    report incorrect pending tasks. Note that `useStream` uses the state74    history endpoint to render interrupts and support branching:75 76    - `threads.read` (`graph.aget_state`, `graph.aget_state_history`) —77      the graph structure informs which tasks to include in the prepared78      view of the latest checkpoint and how to process subgraphs.79 80    Introspection contexts (graph structure only, no execution).81    A different topology may cause schemas and visualizations to not82    match actual execution:83 84    - `assistants.read` (`graph.aget_graph`, `graph.aget_subgraphs`,85      `graph.aget_schemas`) — return the graph definition, subgraph86      definitions, and input/output/config schemas. Used for87      visualization in the studio UI and to populate schemas for MCP,88      A2A, and other protocol integrations.89    """90 91    user: BaseUser | None = field(default=None)92    """The authenticated user, or `None` if no custom auth is configured."""93 94    store: BaseStore95    """Store for the graph run, enabling persistence and memory."""96 97    @property98    def execution_runtime(self) -> _ExecutionRuntime[ContextT] | None:99        """Narrow to the execution runtime, or `None` if not in an execution context.100 101        When the server calls the graph factory for `threads.create_run`, the returned102        object provides access to `context` (typed by the graph's103        `context_schema`). For all other access contexts (introspection, state104        reads, state updates), this returns `None`.105 106        Use this to conditionally set up expensive resources (MCP tool servers,107        database connections, etc.) that are only needed during execution:108 109        ```python110        import contextlib111        from langgraph_sdk.runtime import ServerRuntime112 113        @contextlib.asynccontextmanager114        async def my_factory(runtime: ServerRuntime[MyCtx]):115            if ert := runtime.execution_runtime:116                # Only connect to MCP servers when actually executing a run.117                # Introspection calls (get_schema, get_graph, ...) skip this.118                mcp_tools = await connect_mcp(ert.context.mcp_endpoint)119                yield create_agent(model, tools=mcp_tools)120                await disconnect_mcp()121            else:122                yield create_agent(model, tools=[])123        ```124        """125        if isinstance(self, _ExecutionRuntime):126            return self127        return None128 129    def ensure_user(self) -> BaseUser:130        """Return the authenticated user, or raise if not available.131 132        When custom auth is configured, `user` is set for all access contexts133        (the factory is only called from HTTP handlers where the auth134        middleware has already run). This method raises only when no custom135        auth is configured.136 137        Raises:138            PermissionError: If no user is authenticated.139        """140        if self.user is None:141            raise PermissionError(142                f"No authenticated user available in access_context='{self.access_context}'. "143                "Ensure custom auth is configured for the server."144            )145        return self.user146 147 148@dataclass(kw_only=True, slots=True, frozen=True)149class _ExecutionRuntime(_ServerRuntimeBase[ContextT], Generic[ContextT]):150    """Runtime for `threads.create_run` — the graph will be fully executed.151 152    Access this via `.execution_runtime` on `ServerRuntime`. Do not153    construct directly.154 155    !!! warning "Beta"156        This API is in beta and may change in future releases.157    """158 159    context: ContextT = field(default=None)  # type: ignore[assignment]160    """The graph run context, typed by the graph's `context_schema`.161 162    Only available during `threads.create_run`.163    """164 165 166@dataclass(kw_only=True, slots=True, frozen=True)167class _ReadRuntime(_ServerRuntimeBase[ContextT], Generic[ContextT]):168    """Runtime for non-execution access contexts.169 170    Used for introspection (`assistants.read`), state operations171    (`threads.read`), and state updates (`threads.update`).172    No `context` is available.173 174    !!! warning "Beta"175        This API is in beta and may change in future releases.176    """177 178 179ServerRuntime = TypeAliasType(180    "ServerRuntime",181    _ExecutionRuntime[ContextT] | _ReadRuntime[ContextT],182    type_params=(ContextT,),183)184"""Runtime context passed to graph builder factories within the Agent Server.185 186Requires version 0.7.30 or later of the agent server.187 188The server calls your graph factory in multiple contexts: executing runs,189reading state, fetching schemas, and more. `ServerRuntime` provides190the authenticated user, store, and access context for every call. Use191`.execution_runtime` to narrow to the execution variant and access192`context`.193 194Example — conditionally initialize MCP tools only during execution:195 196```python197import contextlib198from dataclasses import dataclass199 200from langchain.agents import create_agent201from langgraph_sdk.runtime import ServerRuntime202from my_agent import connect_mcp, disconnect_mcp203 204@dataclass205class MyCtx:206    mcp_endpoint: str207 208_readonly_agent = create_agent("anthropic:claude-3-5-haiku", tools=[])209 210@contextlib.asynccontextmanager211async def my_factory(runtime: ServerRuntime[MyCtx]):212    if ert := runtime.execution_runtime:213        # Only connect to MCP servers for actual runs.214        # Schema / graph introspection calls skip this.215        user_id = runtime.ensure_user().identity216        mcp_tools = await connect_mcp(ert.context.mcp_endpoint, user_id)217        yield create_agent("anthropic:claude-3-5-haiku", tools=mcp_tools)218        await disconnect_mcp()219    else:220        yield _readonly_agent221```222 223Example — simple factory that ignores context:224 225```python226from langgraph_sdk.runtime import ServerRuntime227 228def build_graph(user: BaseUser) -> CompiledGraph:229    ...230 231async def my_factory(runtime: ServerRuntime) -> CompiledGraph:232    # No generic needed if you don't use context.233    return build_graph(runtime.ensure_user())234```235 236!!! warning "Beta"237    This API is in beta and may change in future releases.238"""239 
codekingpro/portable-devtools · Team Ai