# This file was auto-generated by Fern from our API Definition.

import typing
from ..core.client_wrapper import SyncClientWrapper
from .context.client import ContextClient
from .tools.client import ToolsClient
from .sources.client import SourcesClient
from .core_memory.client import CoreMemoryClient
from .archival_memory.client import ArchivalMemoryClient
from .messages.client import MessagesClient
from .templates.client import TemplatesClient
from .memory_variables.client import MemoryVariablesClient
from ..core.request_options import RequestOptions
from ..types.agent_state import AgentState
from ..core.unchecked_base_model import construct_type
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.http_validation_error import HttpValidationError
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from ..types.create_block import CreateBlock
from .types.create_agent_request_tool_rules_item import CreateAgentRequestToolRulesItem
from ..types.agent_type import AgentType
from ..types.llm_config import LlmConfig
from ..types.embedding_config import EmbeddingConfig
from ..types.message_create import MessageCreate
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.jsonable_encoder import jsonable_encoder
from .types.update_agent_tool_rules_item import UpdateAgentToolRulesItem
from .types.agents_search_request_search_item import AgentsSearchRequestSearchItem
from .types.agents_search_request_combinator import AgentsSearchRequestCombinator
from ..core.client_wrapper import AsyncClientWrapper
from .context.client import AsyncContextClient
from .tools.client import AsyncToolsClient
from .sources.client import AsyncSourcesClient
from .core_memory.client import AsyncCoreMemoryClient
from .archival_memory.client import AsyncArchivalMemoryClient
from .messages.client import AsyncMessagesClient
from .templates.client import AsyncTemplatesClient
from .memory_variables.client import AsyncMemoryVariablesClient

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class AgentsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper
        self.context = ContextClient(client_wrapper=self._client_wrapper)
        self.tools = ToolsClient(client_wrapper=self._client_wrapper)
        self.sources = SourcesClient(client_wrapper=self._client_wrapper)
        self.core_memory = CoreMemoryClient(client_wrapper=self._client_wrapper)
        self.archival_memory = ArchivalMemoryClient(client_wrapper=self._client_wrapper)
        self.messages = MessagesClient(client_wrapper=self._client_wrapper)
        self.templates = TemplatesClient(client_wrapper=self._client_wrapper)
        self.memory_variables = MemoryVariablesClient(client_wrapper=self._client_wrapper)

    def list(
        self,
        *,
        name: typing.Optional[str] = None,
        tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
        match_all_tags: typing.Optional[bool] = None,
        cursor: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        query_text: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.List[AgentState]:
        """
        List all agents associated with a given user.
        This endpoint retrieves a list of all agents and their configurations associated with the specified user ID.

        Parameters
        ----------
        name : typing.Optional[str]
            Name of the agent

        tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
            List of tags to filter agents by

        match_all_tags : typing.Optional[bool]
            If True, only returns agents that match ALL given tags. Otherwise, return agents that have ANY of the passed in tags.

        cursor : typing.Optional[str]
            Cursor for pagination

        limit : typing.Optional[int]
            Limit for pagination

        query_text : typing.Optional[str]
            Search agents by name

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        typing.List[AgentState]
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.list()
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/agents/",
            method="GET",
            params={
                "name": name,
                "tags": tags,
                "match_all_tags": match_all_tags,
                "cursor": cursor,
                "limit": limit,
                "query_text": query_text,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.List[AgentState],
                    construct_type(
                        type_=typing.List[AgentState],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def create(
        self,
        *,
        name: typing.Optional[str] = OMIT,
        memory_blocks: typing.Optional[typing.Sequence[CreateBlock]] = OMIT,
        tools: typing.Optional[typing.Sequence[str]] = OMIT,
        tool_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        source_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        block_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        tool_rules: typing.Optional[typing.Sequence[CreateAgentRequestToolRulesItem]] = OMIT,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        system: typing.Optional[str] = OMIT,
        agent_type: typing.Optional[AgentType] = OMIT,
        llm_config: typing.Optional[LlmConfig] = OMIT,
        embedding_config: typing.Optional[EmbeddingConfig] = OMIT,
        initial_message_sequence: typing.Optional[typing.Sequence[MessageCreate]] = OMIT,
        include_base_tools: typing.Optional[bool] = OMIT,
        include_multi_agent_tools: typing.Optional[bool] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        model: typing.Optional[str] = OMIT,
        embedding: typing.Optional[str] = OMIT,
        context_window_limit: typing.Optional[int] = OMIT,
        embedding_chunk_size: typing.Optional[int] = OMIT,
        from_template: typing.Optional[str] = OMIT,
        template: typing.Optional[bool] = OMIT,
        project: typing.Optional[str] = OMIT,
        tool_exec_environment_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Create a new agent with the specified configuration.

        Parameters
        ----------
        name : typing.Optional[str]
            The name of the agent.

        memory_blocks : typing.Optional[typing.Sequence[CreateBlock]]
            The blocks to create in the agent's in-context memory.

        tools : typing.Optional[typing.Sequence[str]]
            The tools used by the agent.

        tool_ids : typing.Optional[typing.Sequence[str]]
            The ids of the tools used by the agent.

        source_ids : typing.Optional[typing.Sequence[str]]
            The ids of the sources used by the agent.

        block_ids : typing.Optional[typing.Sequence[str]]
            The ids of the blocks used by the agent.

        tool_rules : typing.Optional[typing.Sequence[CreateAgentRequestToolRulesItem]]
            The tool rules governing the agent.

        tags : typing.Optional[typing.Sequence[str]]
            The tags associated with the agent.

        system : typing.Optional[str]
            The system prompt used by the agent.

        agent_type : typing.Optional[AgentType]
            The type of agent.

        llm_config : typing.Optional[LlmConfig]
            The LLM configuration used by the agent.

        embedding_config : typing.Optional[EmbeddingConfig]
            The embedding configuration used by the agent.

        initial_message_sequence : typing.Optional[typing.Sequence[MessageCreate]]
            The initial set of messages to put in the agent's in-context memory.

        include_base_tools : typing.Optional[bool]
            If true, attaches the Letta core tools (e.g. archival_memory and core_memory related functions).

        include_multi_agent_tools : typing.Optional[bool]
            If true, attaches the Letta multi-agent tools (e.g. sending a message to another agent).

        description : typing.Optional[str]
            The description of the agent.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            The metadata of the agent.

        model : typing.Optional[str]
            The LLM configuration handle used by the agent, specified in the format provider/model-name, as an alternative to specifying llm_config.

        embedding : typing.Optional[str]
            The embedding configuration handle used by the agent, specified in the format provider/model-name.

        context_window_limit : typing.Optional[int]
            The context window limit used by the agent.

        embedding_chunk_size : typing.Optional[int]
            The embedding chunk size used by the agent.

        from_template : typing.Optional[str]
            The template id used to configure the agent

        template : typing.Optional[bool]
            Whether the agent is a template

        project : typing.Optional[str]
            The project slug that the agent will be associated with.

        tool_exec_environment_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The environment variables for tool execution specific to this agent.

        memory_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The variables that should be set for the agent.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.create()
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/agents/",
            method="POST",
            json={
                "name": name,
                "memory_blocks": convert_and_respect_annotation_metadata(
                    object_=memory_blocks, annotation=typing.Sequence[CreateBlock], direction="write"
                ),
                "tools": tools,
                "tool_ids": tool_ids,
                "source_ids": source_ids,
                "block_ids": block_ids,
                "tool_rules": convert_and_respect_annotation_metadata(
                    object_=tool_rules, annotation=typing.Sequence[CreateAgentRequestToolRulesItem], direction="write"
                ),
                "tags": tags,
                "system": system,
                "agent_type": agent_type,
                "llm_config": convert_and_respect_annotation_metadata(
                    object_=llm_config, annotation=LlmConfig, direction="write"
                ),
                "embedding_config": convert_and_respect_annotation_metadata(
                    object_=embedding_config, annotation=EmbeddingConfig, direction="write"
                ),
                "initial_message_sequence": convert_and_respect_annotation_metadata(
                    object_=initial_message_sequence, annotation=typing.Sequence[MessageCreate], direction="write"
                ),
                "include_base_tools": include_base_tools,
                "include_multi_agent_tools": include_multi_agent_tools,
                "description": description,
                "metadata_": metadata,
                "model": model,
                "embedding": embedding,
                "context_window_limit": context_window_limit,
                "embedding_chunk_size": embedding_chunk_size,
                "from_template": from_template,
                "template": template,
                "project": project,
                "tool_exec_environment_variables": tool_exec_environment_variables,
                "memory_variables": memory_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get(self, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentState:
        """
        Get the state of the agent.

        Parameters
        ----------
        agent_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.get(
            agent_id="agent_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def delete(
        self, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> typing.Optional[typing.Any]:
        """
        Delete an agent.

        Parameters
        ----------
        agent_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        typing.Optional[typing.Any]
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.delete(
            agent_id="agent_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.Optional[typing.Any],
                    construct_type(
                        type_=typing.Optional[typing.Any],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def update(
        self,
        agent_id: str,
        *,
        name: typing.Optional[str] = OMIT,
        tool_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        source_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        block_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        system: typing.Optional[str] = OMIT,
        tool_rules: typing.Optional[typing.Sequence[UpdateAgentToolRulesItem]] = OMIT,
        llm_config: typing.Optional[LlmConfig] = OMIT,
        embedding_config: typing.Optional[EmbeddingConfig] = OMIT,
        message_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        tool_exec_environment_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Update an existing agent

        Parameters
        ----------
        agent_id : str

        name : typing.Optional[str]
            The name of the agent.

        tool_ids : typing.Optional[typing.Sequence[str]]
            The ids of the tools used by the agent.

        source_ids : typing.Optional[typing.Sequence[str]]
            The ids of the sources used by the agent.

        block_ids : typing.Optional[typing.Sequence[str]]
            The ids of the blocks used by the agent.

        tags : typing.Optional[typing.Sequence[str]]
            The tags associated with the agent.

        system : typing.Optional[str]
            The system prompt used by the agent.

        tool_rules : typing.Optional[typing.Sequence[UpdateAgentToolRulesItem]]
            The tool rules governing the agent.

        llm_config : typing.Optional[LlmConfig]
            The LLM configuration used by the agent.

        embedding_config : typing.Optional[EmbeddingConfig]
            The embedding configuration used by the agent.

        message_ids : typing.Optional[typing.Sequence[str]]
            The ids of the messages in the agent's in-context memory.

        description : typing.Optional[str]
            The description of the agent.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            The metadata of the agent.

        tool_exec_environment_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The environment variables for tool execution specific to this agent.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.update(
            agent_id="agent_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="PATCH",
            json={
                "name": name,
                "tool_ids": tool_ids,
                "source_ids": source_ids,
                "block_ids": block_ids,
                "tags": tags,
                "system": system,
                "tool_rules": convert_and_respect_annotation_metadata(
                    object_=tool_rules, annotation=typing.Sequence[UpdateAgentToolRulesItem], direction="write"
                ),
                "llm_config": convert_and_respect_annotation_metadata(
                    object_=llm_config, annotation=LlmConfig, direction="write"
                ),
                "embedding_config": convert_and_respect_annotation_metadata(
                    object_=embedding_config, annotation=EmbeddingConfig, direction="write"
                ),
                "message_ids": message_ids,
                "description": description,
                "metadata_": metadata,
                "tool_exec_environment_variables": tool_exec_environment_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def reset_messages(
        self,
        agent_id: str,
        *,
        add_default_initial_messages: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Resets the messages for an agent

        Parameters
        ----------
        agent_id : str

        add_default_initial_messages : typing.Optional[bool]
            If true, adds the default initial messages after resetting.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.reset_messages(
            agent_id="agent_id",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}/reset-messages",
            method="PATCH",
            params={
                "add_default_initial_messages": add_default_initial_messages,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def search(
        self,
        *,
        search: typing.Optional[typing.Sequence[AgentsSearchRequestSearchItem]] = OMIT,
        project_id: typing.Optional[str] = OMIT,
        combinator: typing.Optional[AgentsSearchRequestCombinator] = OMIT,
        limit: typing.Optional[float] = OMIT,
        offset: typing.Optional[float] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        <Note>This endpoint is only available on Letta Cloud.</Note>

        Search deployed agents.

        Parameters
        ----------
        search : typing.Optional[typing.Sequence[AgentsSearchRequestSearchItem]]

        project_id : typing.Optional[str]

        combinator : typing.Optional[AgentsSearchRequestCombinator]

        limit : typing.Optional[float]

        offset : typing.Optional[float]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        None

        Examples
        --------
        from letta_client import Letta

        client = Letta(
            token="YOUR_TOKEN",
        )
        client.agents.search()
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/agents/search",
            method="POST",
            json={
                "search": convert_and_respect_annotation_metadata(
                    object_=search, annotation=typing.Sequence[AgentsSearchRequestSearchItem], direction="write"
                ),
                "project_id": project_id,
                "combinator": combinator,
                "limit": limit,
                "offset": offset,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


class AsyncAgentsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper
        self.context = AsyncContextClient(client_wrapper=self._client_wrapper)
        self.tools = AsyncToolsClient(client_wrapper=self._client_wrapper)
        self.sources = AsyncSourcesClient(client_wrapper=self._client_wrapper)
        self.core_memory = AsyncCoreMemoryClient(client_wrapper=self._client_wrapper)
        self.archival_memory = AsyncArchivalMemoryClient(client_wrapper=self._client_wrapper)
        self.messages = AsyncMessagesClient(client_wrapper=self._client_wrapper)
        self.templates = AsyncTemplatesClient(client_wrapper=self._client_wrapper)
        self.memory_variables = AsyncMemoryVariablesClient(client_wrapper=self._client_wrapper)

    async def list(
        self,
        *,
        name: typing.Optional[str] = None,
        tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
        match_all_tags: typing.Optional[bool] = None,
        cursor: typing.Optional[str] = None,
        limit: typing.Optional[int] = None,
        query_text: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.List[AgentState]:
        """
        List all agents associated with a given user.
        This endpoint retrieves a list of all agents and their configurations associated with the specified user ID.

        Parameters
        ----------
        name : typing.Optional[str]
            Name of the agent

        tags : typing.Optional[typing.Union[str, typing.Sequence[str]]]
            List of tags to filter agents by

        match_all_tags : typing.Optional[bool]
            If True, only returns agents that match ALL given tags. Otherwise, return agents that have ANY of the passed in tags.

        cursor : typing.Optional[str]
            Cursor for pagination

        limit : typing.Optional[int]
            Limit for pagination

        query_text : typing.Optional[str]
            Search agents by name

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        typing.List[AgentState]
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.list()


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/agents/",
            method="GET",
            params={
                "name": name,
                "tags": tags,
                "match_all_tags": match_all_tags,
                "cursor": cursor,
                "limit": limit,
                "query_text": query_text,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.List[AgentState],
                    construct_type(
                        type_=typing.List[AgentState],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def create(
        self,
        *,
        name: typing.Optional[str] = OMIT,
        memory_blocks: typing.Optional[typing.Sequence[CreateBlock]] = OMIT,
        tools: typing.Optional[typing.Sequence[str]] = OMIT,
        tool_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        source_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        block_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        tool_rules: typing.Optional[typing.Sequence[CreateAgentRequestToolRulesItem]] = OMIT,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        system: typing.Optional[str] = OMIT,
        agent_type: typing.Optional[AgentType] = OMIT,
        llm_config: typing.Optional[LlmConfig] = OMIT,
        embedding_config: typing.Optional[EmbeddingConfig] = OMIT,
        initial_message_sequence: typing.Optional[typing.Sequence[MessageCreate]] = OMIT,
        include_base_tools: typing.Optional[bool] = OMIT,
        include_multi_agent_tools: typing.Optional[bool] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        model: typing.Optional[str] = OMIT,
        embedding: typing.Optional[str] = OMIT,
        context_window_limit: typing.Optional[int] = OMIT,
        embedding_chunk_size: typing.Optional[int] = OMIT,
        from_template: typing.Optional[str] = OMIT,
        template: typing.Optional[bool] = OMIT,
        project: typing.Optional[str] = OMIT,
        tool_exec_environment_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Create a new agent with the specified configuration.

        Parameters
        ----------
        name : typing.Optional[str]
            The name of the agent.

        memory_blocks : typing.Optional[typing.Sequence[CreateBlock]]
            The blocks to create in the agent's in-context memory.

        tools : typing.Optional[typing.Sequence[str]]
            The tools used by the agent.

        tool_ids : typing.Optional[typing.Sequence[str]]
            The ids of the tools used by the agent.

        source_ids : typing.Optional[typing.Sequence[str]]
            The ids of the sources used by the agent.

        block_ids : typing.Optional[typing.Sequence[str]]
            The ids of the blocks used by the agent.

        tool_rules : typing.Optional[typing.Sequence[CreateAgentRequestToolRulesItem]]
            The tool rules governing the agent.

        tags : typing.Optional[typing.Sequence[str]]
            The tags associated with the agent.

        system : typing.Optional[str]
            The system prompt used by the agent.

        agent_type : typing.Optional[AgentType]
            The type of agent.

        llm_config : typing.Optional[LlmConfig]
            The LLM configuration used by the agent.

        embedding_config : typing.Optional[EmbeddingConfig]
            The embedding configuration used by the agent.

        initial_message_sequence : typing.Optional[typing.Sequence[MessageCreate]]
            The initial set of messages to put in the agent's in-context memory.

        include_base_tools : typing.Optional[bool]
            If true, attaches the Letta core tools (e.g. archival_memory and core_memory related functions).

        include_multi_agent_tools : typing.Optional[bool]
            If true, attaches the Letta multi-agent tools (e.g. sending a message to another agent).

        description : typing.Optional[str]
            The description of the agent.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            The metadata of the agent.

        model : typing.Optional[str]
            The LLM configuration handle used by the agent, specified in the format provider/model-name, as an alternative to specifying llm_config.

        embedding : typing.Optional[str]
            The embedding configuration handle used by the agent, specified in the format provider/model-name.

        context_window_limit : typing.Optional[int]
            The context window limit used by the agent.

        embedding_chunk_size : typing.Optional[int]
            The embedding chunk size used by the agent.

        from_template : typing.Optional[str]
            The template id used to configure the agent

        template : typing.Optional[bool]
            Whether the agent is a template

        project : typing.Optional[str]
            The project slug that the agent will be associated with.

        tool_exec_environment_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The environment variables for tool execution specific to this agent.

        memory_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The variables that should be set for the agent.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.create()


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/agents/",
            method="POST",
            json={
                "name": name,
                "memory_blocks": convert_and_respect_annotation_metadata(
                    object_=memory_blocks, annotation=typing.Sequence[CreateBlock], direction="write"
                ),
                "tools": tools,
                "tool_ids": tool_ids,
                "source_ids": source_ids,
                "block_ids": block_ids,
                "tool_rules": convert_and_respect_annotation_metadata(
                    object_=tool_rules, annotation=typing.Sequence[CreateAgentRequestToolRulesItem], direction="write"
                ),
                "tags": tags,
                "system": system,
                "agent_type": agent_type,
                "llm_config": convert_and_respect_annotation_metadata(
                    object_=llm_config, annotation=LlmConfig, direction="write"
                ),
                "embedding_config": convert_and_respect_annotation_metadata(
                    object_=embedding_config, annotation=EmbeddingConfig, direction="write"
                ),
                "initial_message_sequence": convert_and_respect_annotation_metadata(
                    object_=initial_message_sequence, annotation=typing.Sequence[MessageCreate], direction="write"
                ),
                "include_base_tools": include_base_tools,
                "include_multi_agent_tools": include_multi_agent_tools,
                "description": description,
                "metadata_": metadata,
                "model": model,
                "embedding": embedding,
                "context_window_limit": context_window_limit,
                "embedding_chunk_size": embedding_chunk_size,
                "from_template": from_template,
                "template": template,
                "project": project,
                "tool_exec_environment_variables": tool_exec_environment_variables,
                "memory_variables": memory_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get(self, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None) -> AgentState:
        """
        Get the state of the agent.

        Parameters
        ----------
        agent_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.get(
                agent_id="agent_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def delete(
        self, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> typing.Optional[typing.Any]:
        """
        Delete an agent.

        Parameters
        ----------
        agent_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        typing.Optional[typing.Any]
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.delete(
                agent_id="agent_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.Optional[typing.Any],
                    construct_type(
                        type_=typing.Optional[typing.Any],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def update(
        self,
        agent_id: str,
        *,
        name: typing.Optional[str] = OMIT,
        tool_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        source_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        block_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        system: typing.Optional[str] = OMIT,
        tool_rules: typing.Optional[typing.Sequence[UpdateAgentToolRulesItem]] = OMIT,
        llm_config: typing.Optional[LlmConfig] = OMIT,
        embedding_config: typing.Optional[EmbeddingConfig] = OMIT,
        message_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        tool_exec_environment_variables: typing.Optional[typing.Dict[str, typing.Optional[str]]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Update an existing agent

        Parameters
        ----------
        agent_id : str

        name : typing.Optional[str]
            The name of the agent.

        tool_ids : typing.Optional[typing.Sequence[str]]
            The ids of the tools used by the agent.

        source_ids : typing.Optional[typing.Sequence[str]]
            The ids of the sources used by the agent.

        block_ids : typing.Optional[typing.Sequence[str]]
            The ids of the blocks used by the agent.

        tags : typing.Optional[typing.Sequence[str]]
            The tags associated with the agent.

        system : typing.Optional[str]
            The system prompt used by the agent.

        tool_rules : typing.Optional[typing.Sequence[UpdateAgentToolRulesItem]]
            The tool rules governing the agent.

        llm_config : typing.Optional[LlmConfig]
            The LLM configuration used by the agent.

        embedding_config : typing.Optional[EmbeddingConfig]
            The embedding configuration used by the agent.

        message_ids : typing.Optional[typing.Sequence[str]]
            The ids of the messages in the agent's in-context memory.

        description : typing.Optional[str]
            The description of the agent.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            The metadata of the agent.

        tool_exec_environment_variables : typing.Optional[typing.Dict[str, typing.Optional[str]]]
            The environment variables for tool execution specific to this agent.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.update(
                agent_id="agent_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}",
            method="PATCH",
            json={
                "name": name,
                "tool_ids": tool_ids,
                "source_ids": source_ids,
                "block_ids": block_ids,
                "tags": tags,
                "system": system,
                "tool_rules": convert_and_respect_annotation_metadata(
                    object_=tool_rules, annotation=typing.Sequence[UpdateAgentToolRulesItem], direction="write"
                ),
                "llm_config": convert_and_respect_annotation_metadata(
                    object_=llm_config, annotation=LlmConfig, direction="write"
                ),
                "embedding_config": convert_and_respect_annotation_metadata(
                    object_=embedding_config, annotation=EmbeddingConfig, direction="write"
                ),
                "message_ids": message_ids,
                "description": description,
                "metadata_": metadata,
                "tool_exec_environment_variables": tool_exec_environment_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def reset_messages(
        self,
        agent_id: str,
        *,
        add_default_initial_messages: typing.Optional[bool] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AgentState:
        """
        Resets the messages for an agent

        Parameters
        ----------
        agent_id : str

        add_default_initial_messages : typing.Optional[bool]
            If true, adds the default initial messages after resetting.

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AgentState
            Successful Response

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.reset_messages(
                agent_id="agent_id",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/agents/{jsonable_encoder(agent_id)}/reset-messages",
            method="PATCH",
            params={
                "add_default_initial_messages": add_default_initial_messages,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    AgentState,
                    construct_type(
                        type_=AgentState,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    typing.cast(
                        HttpValidationError,
                        construct_type(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def search(
        self,
        *,
        search: typing.Optional[typing.Sequence[AgentsSearchRequestSearchItem]] = OMIT,
        project_id: typing.Optional[str] = OMIT,
        combinator: typing.Optional[AgentsSearchRequestCombinator] = OMIT,
        limit: typing.Optional[float] = OMIT,
        offset: typing.Optional[float] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> None:
        """
        <Note>This endpoint is only available on Letta Cloud.</Note>

        Search deployed agents.

        Parameters
        ----------
        search : typing.Optional[typing.Sequence[AgentsSearchRequestSearchItem]]

        project_id : typing.Optional[str]

        combinator : typing.Optional[AgentsSearchRequestCombinator]

        limit : typing.Optional[float]

        offset : typing.Optional[float]

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        None

        Examples
        --------
        import asyncio

        from letta_client import AsyncLetta

        client = AsyncLetta(
            token="YOUR_TOKEN",
        )


        async def main() -> None:
            await client.agents.search()


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/agents/search",
            method="POST",
            json={
                "search": convert_and_respect_annotation_metadata(
                    object_=search, annotation=typing.Sequence[AgentsSearchRequestSearchItem], direction="write"
                ),
                "project_id": project_id,
                "combinator": combinator,
                "limit": limit,
                "offset": offset,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
