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

import typing
from json.decoder import JSONDecodeError

from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pagination import AsyncPager, BaseHttpResponse, SyncPager
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
from ..errors.forbidden_error import ForbiddenError
from ..errors.not_found_error import NotFoundError
from ..types.agent import Agent
from ..types.agent_key import AgentKey
from ..types.agent_model import AgentModel
from ..types.agent_name import AgentName
from ..types.agent_tool_configuration import AgentToolConfiguration
from ..types.bad_request_error_body import BadRequestErrorBody
from ..types.components_schemas_conversational_agent_step import ComponentsSchemasConversationalAgentStep
from ..types.error import Error
from ..types.list_agents_response import ListAgentsResponse
from ..types.not_found_error_body import NotFoundErrorBody

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


class RawAgentsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def list(
        self,
        *,
        filter: typing.Optional[str] = None,
        enabled: typing.Optional[bool] = None,
        limit: typing.Optional[int] = None,
        page_key: typing.Optional[str] = None,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[Agent]:
        """
        List all agents available to the authenticated user, with optional filtering and pagination.

        Parameters
        ----------
        filter : typing.Optional[str]
            A regular expression against agent names and descriptions to filter the results.

        enabled : typing.Optional[bool]
            Filter agents by enabled status.

        limit : typing.Optional[int]
            The maximum number of agents to return in the list.

        page_key : typing.Optional[str]
            Used to retrieve the next page of agents after the limit has been reached.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        SyncPager[Agent]
            List of available agents.
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/agents",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            params={
                "filter": filter,
                "enabled": enabled,
                "limit": limit,
                "page_key": page_key,
            },
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListAgentsResponse,
                    parse_obj_as(
                        type_=ListAgentsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.agents
                _has_next = False
                _get_next = None
                if _parsed_response.metadata is not None:
                    _parsed_next = _parsed_response.metadata.page_key
                    _has_next = _parsed_next is not None and _parsed_next != ""
                    _get_next = lambda: self.list(
                        filter=filter,
                        enabled=enabled,
                        limit=limit,
                        page_key=_parsed_next,
                        request_timeout=request_timeout,
                        request_timeout_millis=request_timeout_millis,
                        request_options=request_options,
                    )
                return SyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def create(
        self,
        *,
        name: AgentName,
        tool_configurations: typing.Dict[str, AgentToolConfiguration],
        model: AgentModel,
        first_step: ComponentsSchemasConversationalAgentStep,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        key: typing.Optional[AgentKey] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Agent]:
        """
        Create a new agent. An agent is compromised as 3 main things of functionality:
          1. The instructions an agent follows. Known as a system in prompt in other platforms.
          2. The steps an agent follows when receiving an input.
          3. The tools an agent can use to resolve those steps and instructions.
        Instructions are tied to each step, and should be well crafted so that the agent can perform the desired actions when given an input.

        To use an agent, create a new session (called thread or chat in other platforms), and send new inputs to the agent to get responses.

        Note: Only a single step is supported with no follow up steps. So the `first_step` will be only the only step. We will add multiple steps and step types to execute complex workflows, but many agents can work well with a single step.

        Parameters
        ----------
        name : AgentName

        tool_configurations : typing.Dict[str, AgentToolConfiguration]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is the AgentToolConfiguration.

        model : AgentModel

        first_step : ComponentsSchemasConversationalAgentStep

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        key : typing.Optional[AgentKey]
            A user provided key that uniquely identifies this agent. If not provided, one will be auto-generated based on the agent name.

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent should be enabled upon creation.

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

        Returns
        -------
        HttpResponse[Agent]
            The agent has been created successfully.
        """
        _response = self._client_wrapper.httpx_client.request(
            "v2/agents",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json={
                "key": key,
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def get(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Agent]:
        """
        Retrieve the details of a specific agent by its ID, including its configuration, capabilities, and associated resources.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to retrieve.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        HttpResponse[Agent]
            The requested agent details.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def replace(
        self,
        agent_key: AgentKey,
        *,
        name: AgentName,
        tool_configurations: typing.Dict[str, AgentToolConfiguration],
        model: AgentModel,
        first_step: ComponentsSchemasConversationalAgentStep,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Agent]:
        """
        Completely replace an existing agent's configuration, including its corpora, tools, and generation presets.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to replace.

        name : AgentName

        tool_configurations : typing.Dict[str, AgentToolConfiguration]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is an agent tool configuration.

        model : AgentModel

        first_step : ComponentsSchemasConversationalAgentStep

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent is enabled.

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

        Returns
        -------
        HttpResponse[Agent]
            The agent has been replaced successfully.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="PUT",
            json={
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def delete(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[None]:
        """
        Permanently delete an agent and all its associated configuration. This action cannot be undone.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to delete.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        HttpResponse[None]
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="DELETE",
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return HttpResponse(response=_response, data=None)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def update(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        name: typing.Optional[AgentName] = OMIT,
        description: typing.Optional[str] = OMIT,
        tool_configurations: typing.Optional[typing.Dict[str, AgentToolConfiguration]] = OMIT,
        model: typing.Optional[AgentModel] = OMIT,
        first_step: typing.Optional[ComponentsSchemasConversationalAgentStep] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Agent]:
        """
        Update an existing agent's configuration, including its corpora, tools, and generation presets.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to update.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        name : typing.Optional[AgentName]

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        tool_configurations : typing.Optional[typing.Dict[str, AgentToolConfiguration]]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is an agent tool configuration.

        model : typing.Optional[AgentModel]

        first_step : typing.Optional[ComponentsSchemasConversationalAgentStep]

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent is enabled.

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

        Returns
        -------
        HttpResponse[Agent]
            The agent has been updated successfully.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="PATCH",
            json={
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


class AsyncRawAgentsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def list(
        self,
        *,
        filter: typing.Optional[str] = None,
        enabled: typing.Optional[bool] = None,
        limit: typing.Optional[int] = None,
        page_key: typing.Optional[str] = None,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[Agent]:
        """
        List all agents available to the authenticated user, with optional filtering and pagination.

        Parameters
        ----------
        filter : typing.Optional[str]
            A regular expression against agent names and descriptions to filter the results.

        enabled : typing.Optional[bool]
            Filter agents by enabled status.

        limit : typing.Optional[int]
            The maximum number of agents to return in the list.

        page_key : typing.Optional[str]
            Used to retrieve the next page of agents after the limit has been reached.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        AsyncPager[Agent]
            List of available agents.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/agents",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            params={
                "filter": filter,
                "enabled": enabled,
                "limit": limit,
                "page_key": page_key,
            },
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListAgentsResponse,
                    parse_obj_as(
                        type_=ListAgentsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.agents
                _has_next = False
                _get_next = None
                if _parsed_response.metadata is not None:
                    _parsed_next = _parsed_response.metadata.page_key
                    _has_next = _parsed_next is not None and _parsed_next != ""

                    async def _get_next():
                        return await self.list(
                            filter=filter,
                            enabled=enabled,
                            limit=limit,
                            page_key=_parsed_next,
                            request_timeout=request_timeout,
                            request_timeout_millis=request_timeout_millis,
                            request_options=request_options,
                        )

                return AsyncPager(
                    has_next=_has_next, items=_items, get_next=_get_next, response=BaseHttpResponse(response=_response)
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def create(
        self,
        *,
        name: AgentName,
        tool_configurations: typing.Dict[str, AgentToolConfiguration],
        model: AgentModel,
        first_step: ComponentsSchemasConversationalAgentStep,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        key: typing.Optional[AgentKey] = OMIT,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Agent]:
        """
        Create a new agent. An agent is compromised as 3 main things of functionality:
          1. The instructions an agent follows. Known as a system in prompt in other platforms.
          2. The steps an agent follows when receiving an input.
          3. The tools an agent can use to resolve those steps and instructions.
        Instructions are tied to each step, and should be well crafted so that the agent can perform the desired actions when given an input.

        To use an agent, create a new session (called thread or chat in other platforms), and send new inputs to the agent to get responses.

        Note: Only a single step is supported with no follow up steps. So the `first_step` will be only the only step. We will add multiple steps and step types to execute complex workflows, but many agents can work well with a single step.

        Parameters
        ----------
        name : AgentName

        tool_configurations : typing.Dict[str, AgentToolConfiguration]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is the AgentToolConfiguration.

        model : AgentModel

        first_step : ComponentsSchemasConversationalAgentStep

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        key : typing.Optional[AgentKey]
            A user provided key that uniquely identifies this agent. If not provided, one will be auto-generated based on the agent name.

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent should be enabled upon creation.

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

        Returns
        -------
        AsyncHttpResponse[Agent]
            The agent has been created successfully.
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v2/agents",
            base_url=self._client_wrapper.get_environment().default,
            method="POST",
            json={
                "key": key,
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def get(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Agent]:
        """
        Retrieve the details of a specific agent by its ID, including its configuration, capabilities, and associated resources.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to retrieve.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        AsyncHttpResponse[Agent]
            The requested agent details.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="GET",
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def replace(
        self,
        agent_key: AgentKey,
        *,
        name: AgentName,
        tool_configurations: typing.Dict[str, AgentToolConfiguration],
        model: AgentModel,
        first_step: ComponentsSchemasConversationalAgentStep,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        description: typing.Optional[str] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Agent]:
        """
        Completely replace an existing agent's configuration, including its corpora, tools, and generation presets.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to replace.

        name : AgentName

        tool_configurations : typing.Dict[str, AgentToolConfiguration]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is an agent tool configuration.

        model : AgentModel

        first_step : ComponentsSchemasConversationalAgentStep

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent is enabled.

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

        Returns
        -------
        AsyncHttpResponse[Agent]
            The agent has been replaced successfully.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="PUT",
            json={
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def delete(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[None]:
        """
        Permanently delete an agent and all its associated configuration. This action cannot be undone.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to delete.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

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

        Returns
        -------
        AsyncHttpResponse[None]
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="DELETE",
            headers={
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return AsyncHttpResponse(response=_response, data=None)
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def update(
        self,
        agent_key: AgentKey,
        *,
        request_timeout: typing.Optional[int] = None,
        request_timeout_millis: typing.Optional[int] = None,
        name: typing.Optional[AgentName] = OMIT,
        description: typing.Optional[str] = OMIT,
        tool_configurations: typing.Optional[typing.Dict[str, AgentToolConfiguration]] = OMIT,
        model: typing.Optional[AgentModel] = OMIT,
        first_step: typing.Optional[ComponentsSchemasConversationalAgentStep] = OMIT,
        metadata: typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]] = OMIT,
        enabled: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Agent]:
        """
        Update an existing agent's configuration, including its corpora, tools, and generation presets.

        Parameters
        ----------
        agent_key : AgentKey
            The unique key of the agent to update.

        request_timeout : typing.Optional[int]
            The API will make a best effort to complete the request in the specified seconds or time out.

        request_timeout_millis : typing.Optional[int]
            The API will make a best effort to complete the request in the specified milliseconds or time out.

        name : typing.Optional[AgentName]

        description : typing.Optional[str]
            A detailed description of the agent's purpose and capabilities.

        tool_configurations : typing.Optional[typing.Dict[str, AgentToolConfiguration]]
            A map of tool configurations available to the agent. The key is the name of the tool configuration and the value is an agent tool configuration.

        model : typing.Optional[AgentModel]

        first_step : typing.Optional[ComponentsSchemasConversationalAgentStep]

        metadata : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
            Arbitrary metadata associated with the agent for customization and configuration.

        enabled : typing.Optional[bool]
            Whether the agent is enabled.

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

        Returns
        -------
        AsyncHttpResponse[Agent]
            The agent has been updated successfully.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/agents/{jsonable_encoder(agent_key)}",
            base_url=self._client_wrapper.get_environment().default,
            method="PATCH",
            json={
                "name": name,
                "description": description,
                "tool_configurations": convert_and_respect_annotation_metadata(
                    object_=tool_configurations, annotation=typing.Dict[str, AgentToolConfiguration], direction="write"
                ),
                "model": convert_and_respect_annotation_metadata(
                    object_=model, annotation=AgentModel, direction="write"
                ),
                "first_step": convert_and_respect_annotation_metadata(
                    object_=first_step, annotation=ComponentsSchemasConversationalAgentStep, direction="write"
                ),
                "metadata": metadata,
                "enabled": enabled,
            },
            headers={
                "content-type": "application/json",
                "Request-Timeout": str(request_timeout) if request_timeout is not None else None,
                "Request-Timeout-Millis": str(request_timeout_millis) if request_timeout_millis is not None else None,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Agent,
                    parse_obj_as(
                        type_=Agent,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        BadRequestErrorBody,
                        parse_obj_as(
                            type_=BadRequestErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 403:
                raise ForbiddenError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        parse_obj_as(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        NotFoundErrorBody,
                        parse_obj_as(
                            type_=NotFoundErrorBody,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
