Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
assistants.py732 linesDownload Raw Back to _sync
1"""Synchronous client for managing assistants in LangGraph."""2 3from __future__ import annotations4 5from collections.abc import Mapping6from typing import Any, Literal, cast, overload7 8import httpx9 10from langgraph_sdk._sync.http import SyncHttpClient11from langgraph_sdk.schema import (12    Assistant,13    AssistantSelectField,14    AssistantSortBy,15    AssistantsSearchResponse,16    AssistantVersion,17    Config,18    Context,19    GraphSchema,20    Json,21    OnConflictBehavior,22    QueryParamTypes,23    SortOrder,24    Subgraphs,25)26 27 28class SyncAssistantsClient:29    """Client for managing assistants in LangGraph synchronously.30 31    This class provides methods to interact with assistants, which are versioned configurations of your graph.32 33    ???+ example "Example"34 35        ```python36        client = get_sync_client(url="http://localhost:2024")37        assistant = client.assistants.get("assistant_id_123")38        ```39    """40 41    def __init__(self, http: SyncHttpClient) -> None:42        self.http = http43 44    def get(45        self,46        assistant_id: str,47        *,48        headers: Mapping[str, str] | None = None,49        params: QueryParamTypes | None = None,50    ) -> Assistant:51        """Get an assistant by ID.52 53        Args:54            assistant_id: The ID of the assistant to get OR the name of the graph (to use the default assistant).55            headers: Optional custom headers to include with the request.56            params: Optional query parameters to include with the request.57 58        Returns:59            `Assistant` Object.60 61        ???+ example "Example Usage"62 63            ```python64            assistant = client.assistants.get(65                assistant_id="my_assistant_id"66            )67            print(assistant)68            ```69 70            ```shell71            ----------------------------------------------------72 73            {74                'assistant_id': 'my_assistant_id',75                'graph_id': 'agent',76                'created_at': '2024-06-25T17:10:33.109781+00:00',77                'updated_at': '2024-06-25T17:10:33.109781+00:00',78                'config': {},79                'context': {},80                'metadata': {'created_by': 'system'}81            }82            ```83 84        """85        return self.http.get(86            f"/assistants/{assistant_id}", headers=headers, params=params87        )88 89    def get_graph(90        self,91        assistant_id: str,92        *,93        xray: int | bool = False,94        headers: Mapping[str, str] | None = None,95        params: QueryParamTypes | None = None,96    ) -> dict[str, list[dict[str, Any]]]:97        """Get the graph of an assistant by ID.98 99        Args:100            assistant_id: The ID of the assistant to get the graph of.101            xray: Include graph representation of subgraphs. If an integer value is provided, only subgraphs with a depth less than or equal to the value will be included.102            headers: Optional custom headers to include with the request.103            params: Optional query parameters to include with the request.104 105        Returns:106            The graph information for the assistant in JSON format.107 108        ???+ example "Example Usage"109 110            ```python111            client = get_sync_client(url="http://localhost:2024")112            graph_info = client.assistants.get_graph(113                assistant_id="my_assistant_id"114            )115            print(graph_info)116 117            --------------------------------------------------------------------------------------------------------------------------118 119            {120                'nodes':121                    [122                        {'id': '__start__', 'type': 'schema', 'data': '__start__'},123                        {'id': '__end__', 'type': 'schema', 'data': '__end__'},124                        {'id': 'agent','type': 'runnable','data': {'id': ['langgraph', 'utils', 'RunnableCallable'],'name': 'agent'}},125                    ],126                'edges':127                    [128                        {'source': '__start__', 'target': 'agent'},129                        {'source': 'agent','target': '__end__'}130                    ]131            }132            ```133 134        """135        query_params = {"xray": xray}136        if params:137            query_params.update(params)138        return self.http.get(139            f"/assistants/{assistant_id}/graph", params=query_params, headers=headers140        )141 142    def get_schemas(143        self,144        assistant_id: str,145        *,146        headers: Mapping[str, str] | None = None,147        params: QueryParamTypes | None = None,148    ) -> GraphSchema:149        """Get the schemas of an assistant by ID.150 151        Args:152            assistant_id: The ID of the assistant to get the schema of.153            headers: Optional custom headers to include with the request.154            params: Optional query parameters to include with the request.155 156        Returns:157            GraphSchema: The graph schema for the assistant.158 159        ???+ example "Example Usage"160 161            ```python162            client = get_sync_client(url="http://localhost:2024")163            schema = client.assistants.get_schemas(164                assistant_id="my_assistant_id"165            )166            print(schema)167            ```168            ```shell169            ----------------------------------------------------------------------------------------------------------------------------170 171            {172                'graph_id': 'agent',173                'state_schema':174                    {175                        'title': 'LangGraphInput',176                        '$ref': '#/definitions/AgentState',177                        'definitions':178                            {179                                'BaseMessage':180                                    {181                                        'title': 'BaseMessage',182                                        'description': 'Base abstract Message class. Messages are the inputs and outputs of ChatModels.',183                                        'type': 'object',184                                        'properties':185                                            {186                                             'content':187                                                {188                                                    'title': 'Content',189                                                    'anyOf': [190                                                        {'type': 'string'},191                                                        {'type': 'array','items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}192                                                    ]193                                                },194                                            'additional_kwargs':195                                                {196                                                    'title': 'Additional Kwargs',197                                                    'type': 'object'198                                                },199                                            'response_metadata':200                                                {201                                                    'title': 'Response Metadata',202                                                    'type': 'object'203                                                },204                                            'type':205                                                {206                                                    'title': 'Type',207                                                    'type': 'string'208                                                },209                                            'name':210                                                {211                                                    'title': 'Name',212                                                    'type': 'string'213                                                },214                                            'id':215                                                {216                                                    'title': 'Id',217                                                    'type': 'string'218                                                }219                                            },220                                        'required': ['content', 'type']221                                    },222                                'AgentState':223                                    {224                                        'title': 'AgentState',225                                        'type': 'object',226                                        'properties':227                                            {228                                                'messages':229                                                    {230                                                        'title': 'Messages',231                                                        'type': 'array',232                                                        'items': {'$ref': '#/definitions/BaseMessage'}233                                                    }234                                            },235                                        'required': ['messages']236                                    }237                            }238                    },239                'config_schema':240                    {241                        'title': 'Configurable',242                        'type': 'object',243                        'properties':244                            {245                                'model_name':246                                    {247                                        'title': 'Model Name',248                                        'enum': ['anthropic', 'openai'],249                                        'type': 'string'250                                    }251                            }252                    },253                'context_schema':254                    {255                        'title': 'Context',256                        'type': 'object',257                        'properties':258                            {259                                'model_name':260                                    {261                                        'title': 'Model Name',262                                        'enum': ['anthropic', 'openai'],263                                        'type': 'string'264                                    }265                            }266                    }267            }268            ```269 270        """271        return self.http.get(272            f"/assistants/{assistant_id}/schemas", headers=headers, params=params273        )274 275    def get_subgraphs(276        self,277        assistant_id: str,278        namespace: str | None = None,279        recurse: bool = False,280        *,281        headers: Mapping[str, str] | None = None,282        params: QueryParamTypes | None = None,283    ) -> Subgraphs:284        """Get the schemas of an assistant by ID.285 286        Args:287            assistant_id: The ID of the assistant to get the schema of.288            headers: Optional custom headers to include with the request.289            params: Optional query parameters to include with the request.290 291        Returns:292            Subgraphs: The graph schema for the assistant.293 294        """295        get_params = {"recurse": recurse}296        if params:297            get_params = {**get_params, **dict(params)}298        if namespace is not None:299            return self.http.get(300                f"/assistants/{assistant_id}/subgraphs/{namespace}",301                params=get_params,302                headers=headers,303            )304        else:305            return self.http.get(306                f"/assistants/{assistant_id}/subgraphs",307                params=get_params,308                headers=headers,309            )310 311    def create(312        self,313        graph_id: str | None,314        config: Config | None = None,315        *,316        context: Context | None = None,317        metadata: Json = None,318        assistant_id: str | None = None,319        if_exists: OnConflictBehavior | None = None,320        name: str | None = None,321        headers: Mapping[str, str] | None = None,322        description: str | None = None,323        params: QueryParamTypes | None = None,324    ) -> Assistant:325        """Create a new assistant.326 327        Useful when graph is configurable and you want to create different assistants based on different configurations.328 329        Args:330            graph_id: The ID of the graph the assistant should use. The graph ID is normally set in your langgraph.json configuration.331            config: Configuration to use for the graph.332            context: Static context to add to the assistant.333                !!! version-added "Added in version 0.6.0"334            metadata: Metadata to add to assistant.335            assistant_id: Assistant ID to use, will default to a random UUID if not provided.336            if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood.337                Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing assistant).338            name: The name of the assistant. Defaults to 'Untitled' under the hood.339            headers: Optional custom headers to include with the request.340            description: Optional description of the assistant.341                The description field is available for langgraph-api server version>=0.0.45342            params: Optional query parameters to include with the request.343 344        Returns:345            The created assistant.346 347        ???+ example "Example Usage"348 349            ```python350            client = get_sync_client(url="http://localhost:2024")351            assistant = client.assistants.create(352                graph_id="agent",353                context={"model_name": "openai"},354                metadata={"number":1},355                assistant_id="my-assistant-id",356                if_exists="do_nothing",357                name="my_name"358            )359            ```360        """361        payload: dict[str, Any] = {362            "graph_id": graph_id,363        }364        if config:365            payload["config"] = config366        if context:367            payload["context"] = context368        if metadata:369            payload["metadata"] = metadata370        if assistant_id:371            payload["assistant_id"] = assistant_id372        if if_exists:373            payload["if_exists"] = if_exists374        if name:375            payload["name"] = name376        if description:377            payload["description"] = description378        return self.http.post(379            "/assistants", json=payload, headers=headers, params=params380        )381 382    def update(383        self,384        assistant_id: str,385        *,386        graph_id: str | None = None,387        config: Config | None = None,388        context: Context | None = None,389        metadata: Json = None,390        name: str | None = None,391        headers: Mapping[str, str] | None = None,392        description: str | None = None,393        params: QueryParamTypes | None = None,394    ) -> Assistant:395        """Update an assistant.396 397        Use this to point to a different graph, update the configuration, or change the metadata of an assistant.398 399        Args:400            assistant_id: Assistant to update.401            graph_id: The ID of the graph the assistant should use.402                The graph ID is normally set in your langgraph.json configuration. If `None`, assistant will keep pointing to same graph.403            config: Configuration to use for the graph.404            context: Static context to add to the assistant.405                !!! version-added "Added in version 0.6.0"406            metadata: Metadata to merge with existing assistant metadata.407            name: The new name for the assistant.408            headers: Optional custom headers to include with the request.409            description: Optional description of the assistant.410                The description field is available for langgraph-api server version>=0.0.45411 412        Returns:413            The updated assistant.414 415        ???+ example "Example Usage"416 417            ```python418            client = get_sync_client(url="http://localhost:2024")419            assistant = client.assistants.update(420                assistant_id='e280dad7-8618-443f-87f1-8e41841c180f',421                graph_id="other-graph",422                context={"model_name": "anthropic"},423                metadata={"number":2}424            )425            ```426        """427        payload: dict[str, Any] = {}428        if graph_id:429            payload["graph_id"] = graph_id430        if config is not None:431            payload["config"] = config432        if context is not None:433            payload["context"] = context434        if metadata:435            payload["metadata"] = metadata436        if name:437            payload["name"] = name438        if description:439            payload["description"] = description440        return self.http.patch(441            f"/assistants/{assistant_id}",442            json=payload,443            headers=headers,444            params=params,445        )446 447    def delete(448        self,449        assistant_id: str,450        *,451        delete_threads: bool = False,452        headers: Mapping[str, str] | None = None,453        params: QueryParamTypes | None = None,454    ) -> None:455        """Delete an assistant.456 457        Args:458            assistant_id: The assistant ID to delete.459            delete_threads: If true, delete all threads with `metadata.assistant_id`460                matching this assistant, along with runs and checkpoints belonging to461                those threads.462            headers: Optional custom headers to include with the request.463            params: Optional query parameters to include with the request.464 465        Returns:466            `None`467 468        ???+ example "Example Usage"469 470            ```python471            client = get_sync_client(url="http://localhost:2024")472            client.assistants.delete(473                assistant_id="my_assistant_id"474            )475            ```476 477        """478        query_params: dict[str, Any] = {}479        if delete_threads:480            query_params["delete_threads"] = True481        if params:482            query_params.update(params)483        self.http.delete(484            f"/assistants/{assistant_id}",485            headers=headers,486            params=query_params or None,487        )488 489    @overload490    def search(491        self,492        *,493        metadata: Json = None,494        graph_id: str | None = None,495        name: str | None = None,496        limit: int = 10,497        offset: int = 0,498        sort_by: AssistantSortBy | None = None,499        sort_order: SortOrder | None = None,500        select: list[AssistantSelectField] | None = None,501        response_format: Literal["object"],502        headers: Mapping[str, str] | None = None,503        params: QueryParamTypes | None = None,504    ) -> AssistantsSearchResponse: ...505 506    @overload507    def search(508        self,509        *,510        metadata: Json = None,511        graph_id: str | None = None,512        name: str | None = None,513        limit: int = 10,514        offset: int = 0,515        sort_by: AssistantSortBy | None = None,516        sort_order: SortOrder | None = None,517        select: list[AssistantSelectField] | None = None,518        response_format: Literal["array"] = "array",519        headers: Mapping[str, str] | None = None,520        params: QueryParamTypes | None = None,521    ) -> list[Assistant]: ...522 523    def search(524        self,525        *,526        metadata: Json = None,527        graph_id: str | None = None,528        name: str | None = None,529        limit: int = 10,530        offset: int = 0,531        sort_by: AssistantSortBy | None = None,532        sort_order: SortOrder | None = None,533        select: list[AssistantSelectField] | None = None,534        response_format: Literal["array", "object"] = "array",535        headers: Mapping[str, str] | None = None,536        params: QueryParamTypes | None = None,537    ) -> AssistantsSearchResponse | list[Assistant]:538        """Search for assistants.539 540        Args:541            metadata: Metadata to filter by. Exact match filter for each KV pair.542            graph_id: The ID of the graph to filter by.543                The graph ID is normally set in your langgraph.json configuration.544            name: The name of the assistant to filter by.545                The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name.546            limit: The maximum number of results to return.547            offset: The number of results to skip.548            sort_by: The field to sort by.549            sort_order: The order to sort by.550            select: Specific assistant fields to include in the response.551            response_format: Controls the response shape. Use `"array"` (default)552                to return a bare list of assistants, or `"object"` to return553                a mapping containing assistants plus pagination metadata.554                Defaults to "array", though this default will be changed to "object" in a future release.555            headers: Optional custom headers to include with the request.556 557        Returns:558            A list of assistants (when `response_format="array"`) or a mapping559            with the assistants and the next pagination cursor (when560            `response_format="object"`).561 562        ???+ example "Example Usage"563 564            ```python565            client = get_sync_client(url="http://localhost:2024")566            response = client.assistants.search(567                metadata = {"name":"my_name"},568                graph_id="my_graph_id",569                limit=5,570                offset=5,571                response_format="object",572            )573            assistants = response["assistants"]574            next_cursor = response["next"]575            ```576        """577        if response_format not in ("array", "object"):578            raise ValueError("response_format must be 'array' or 'object'")579        payload: dict[str, Any] = {580            "limit": limit,581            "offset": offset,582        }583        if metadata:584            payload["metadata"] = metadata585        if graph_id:586            payload["graph_id"] = graph_id587        if name:588            payload["name"] = name589        if sort_by:590            payload["sort_by"] = sort_by591        if sort_order:592            payload["sort_order"] = sort_order593        if select:594            payload["select"] = select595        next_cursor: str | None = None596 597        def capture_pagination(response: httpx.Response) -> None:598            nonlocal next_cursor599            next_cursor = response.headers.get("X-Pagination-Next")600 601        assistants = cast(602            list[Assistant],603            self.http.post(604                "/assistants/search",605                json=payload,606                headers=headers,607                params=params,608                on_response=capture_pagination if response_format == "object" else None,609            ),610        )611        if response_format == "object":612            return {"assistants": assistants, "next": next_cursor}613        return assistants614 615    def count(616        self,617        *,618        metadata: Json = None,619        graph_id: str | None = None,620        name: str | None = None,621        headers: Mapping[str, str] | None = None,622        params: QueryParamTypes | None = None,623    ) -> int:624        """Count assistants matching filters.625 626        Args:627            metadata: Metadata to filter by. Exact match for each key/value.628            graph_id: Optional graph id to filter by.629            name: Optional name to filter by.630                The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name.631            headers: Optional custom headers to include with the request.632            params: Optional query parameters to include with the request.633 634        Returns:635            int: Number of assistants matching the criteria.636        """637        payload: dict[str, Any] = {}638        if metadata:639            payload["metadata"] = metadata640        if graph_id:641            payload["graph_id"] = graph_id642        if name:643            payload["name"] = name644        return self.http.post(645            "/assistants/count", json=payload, headers=headers, params=params646        )647 648    def get_versions(649        self,650        assistant_id: str,651        metadata: Json = None,652        limit: int = 10,653        offset: int = 0,654        *,655        headers: Mapping[str, str] | None = None,656        params: QueryParamTypes | None = None,657    ) -> list[AssistantVersion]:658        """List all versions of an assistant.659 660        Args:661            assistant_id: The assistant ID to get versions for.662            metadata: Metadata to filter versions by. Exact match filter for each KV pair.663            limit: The maximum number of versions to return.664            offset: The number of versions to skip.665            headers: Optional custom headers to include with the request.666 667        Returns:668            A list of assistants.669 670        ???+ example "Example Usage"671 672            ```python673            client = get_sync_client(url="http://localhost:2024")674            assistant_versions = client.assistants.get_versions(675                assistant_id="my_assistant_id"676            )677            ```678 679        """680 681        payload: dict[str, Any] = {682            "limit": limit,683            "offset": offset,684        }685        if metadata:686            payload["metadata"] = metadata687        return self.http.post(688            f"/assistants/{assistant_id}/versions",689            json=payload,690            headers=headers,691            params=params,692        )693 694    def set_latest(695        self,696        assistant_id: str,697        version: int,698        *,699        headers: Mapping[str, str] | None = None,700        params: QueryParamTypes | None = None,701    ) -> Assistant:702        """Change the version of an assistant.703 704        Args:705            assistant_id: The assistant ID to delete.706            version: The version to change to.707            headers: Optional custom headers to include with the request.708 709        Returns:710            `Assistant` Object.711 712        ???+ example "Example Usage"713 714            ```python715            client = get_sync_client(url="http://localhost:2024")716            new_version_assistant = client.assistants.set_latest(717                assistant_id="my_assistant_id",718                version=3719            )720            ```721 722        """723 724        payload: dict[str, Any] = {"version": version}725 726        return self.http.post(727            f"/assistants/{assistant_id}/latest",728            json=payload,729            headers=headers,730            params=params,731        )732 
codekingpro/portable-devtools · Team Ai