# 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.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.unchecked_base_model import construct_type
from ..errors.bad_request_error import BadRequestError
from ..errors.conflict_error import ConflictError
from ..errors.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..errors.payment_required_error import PaymentRequiredError
from ..types.conflict_error_body import ConflictErrorBody
from ..types.payment_required_error_body import PaymentRequiredErrorBody
from .types.templates_create_agents_from_template_request_initial_message_sequence_item import (
    TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem,
)
from .types.templates_create_agents_from_template_response import TemplatesCreateAgentsFromTemplateResponse
from .types.templates_create_template_request import TemplatesCreateTemplateRequest
from .types.templates_create_template_response import TemplatesCreateTemplateResponse
from .types.templates_delete_template_response import TemplatesDeleteTemplateResponse
from .types.templates_fork_template_response import TemplatesForkTemplateResponse
from .types.templates_get_template_snapshot_response import TemplatesGetTemplateSnapshotResponse
from .types.templates_list_request_sort_by import TemplatesListRequestSortBy
from .types.templates_list_response import TemplatesListResponse
from .types.templates_list_template_versions_response import TemplatesListTemplateVersionsResponse
from .types.templates_migrate_deployment_response import TemplatesMigrateDeploymentResponse
from .types.templates_rename_template_response import TemplatesRenameTemplateResponse
from .types.templates_save_template_version_response import TemplatesSaveTemplateVersionResponse
from .types.templates_set_current_template_from_snapshot_response import TemplatesSetCurrentTemplateFromSnapshotResponse
from .types.templates_update_current_template_from_agent_file_response import (
    TemplatesUpdateCurrentTemplateFromAgentFileResponse,
)
from .types.templates_update_template_description_response import TemplatesUpdateTemplateDescriptionResponse

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


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

    def createagentsfromtemplate(
        self,
        project_id: str,
        template_version: str,
        *,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        agent_name: typing.Optional[str] = OMIT,
        initial_message_sequence: typing.Optional[
            typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem]
        ] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        tool_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        identity_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesCreateAgentsFromTemplateResponse]:
        """
        Creates an Agent or multiple Agents from a template

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

        tags : typing.Optional[typing.Sequence[str]]
            The tags to assign to the agent

        agent_name : typing.Optional[str]
            The name of the agent, optional otherwise a random one will be assigned

        initial_message_sequence : typing.Optional[typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem]]
            Set an initial sequence of messages, if not provided, the agent will start with the default message sequence, if an empty array is provided, the agent will start with no messages

        memory_variables : typing.Optional[typing.Dict[str, str]]
            The memory variables to assign to the agent

        tool_variables : typing.Optional[typing.Dict[str, str]]
            The tool variables to assign to the agent

        identity_ids : typing.Optional[typing.Sequence[str]]
            The identity ids to assign to the agent

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

        Returns
        -------
        HttpResponse[TemplatesCreateAgentsFromTemplateResponse]
            201
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/agents",
            method="POST",
            json={
                "tags": tags,
                "agent_name": agent_name,
                "initial_message_sequence": convert_and_respect_annotation_metadata(
                    object_=initial_message_sequence,
                    annotation=typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem],
                    direction="write",
                ),
                "memory_variables": memory_variables,
                "tool_variables": tool_variables,
                "identity_ids": identity_ids,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesCreateAgentsFromTemplateResponse,
                    construct_type(
                        type_=TemplatesCreateAgentsFromTemplateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 402:
                raise PaymentRequiredError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        PaymentRequiredErrorBody,
                        construct_type(
                            type_=PaymentRequiredErrorBody,  # 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 list(
        self,
        *,
        offset: typing.Optional[str] = None,
        exact: typing.Optional[str] = None,
        limit: typing.Optional[str] = None,
        version: typing.Optional[str] = None,
        template_id: typing.Optional[str] = None,
        name: typing.Optional[str] = None,
        search: typing.Optional[str] = None,
        project_slug: typing.Optional[str] = None,
        project_id: typing.Optional[str] = None,
        sort_by: typing.Optional[TemplatesListRequestSortBy] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesListResponse]:
        """
        List all templates

        Parameters
        ----------
        offset : typing.Optional[str]

        exact : typing.Optional[str]
            Whether to search for an exact name match

        limit : typing.Optional[str]

        version : typing.Optional[str]
            Specify the version you want to return, otherwise will return the latest version

        template_id : typing.Optional[str]

        name : typing.Optional[str]

        search : typing.Optional[str]

        project_slug : typing.Optional[str]

        project_id : typing.Optional[str]

        sort_by : typing.Optional[TemplatesListRequestSortBy]

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

        Returns
        -------
        HttpResponse[TemplatesListResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/templates",
            method="GET",
            params={
                "offset": offset,
                "exact": exact,
                "limit": limit,
                "version": version,
                "template_id": template_id,
                "name": name,
                "search": search,
                "project_slug": project_slug,
                "project_id": project_id,
                "sort_by": sort_by,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesListResponse,
                    construct_type(
                        type_=TemplatesListResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 savetemplateversion(
        self,
        project_id: str,
        template_name: str,
        *,
        preserve_environment_variables_on_migration: typing.Optional[bool] = OMIT,
        preserve_core_memories_on_migration: typing.Optional[bool] = OMIT,
        migrate_agents: typing.Optional[bool] = OMIT,
        message: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesSaveTemplateVersionResponse]:
        """
        Saves the current version of the template as a new version

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template version, formatted as {template-name}, any version appended will be ignored

        preserve_environment_variables_on_migration : typing.Optional[bool]
            If true, the environment variables will be preserved in the template version when migrating agents

        preserve_core_memories_on_migration : typing.Optional[bool]
            If true, the core memories will be preserved in the template version when migrating agents

        migrate_agents : typing.Optional[bool]
            If true, existing agents attached to this template will be migrated to the new template version

        message : typing.Optional[str]
            A message to describe the changes made in this template version

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

        Returns
        -------
        HttpResponse[TemplatesSaveTemplateVersionResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}",
            method="POST",
            json={
                "preserve_environment_variables_on_migration": preserve_environment_variables_on_migration,
                "preserve_core_memories_on_migration": preserve_core_memories_on_migration,
                "migrate_agents": migrate_agents,
                "message": message,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesSaveTemplateVersionResponse,
                    construct_type(
                        type_=TemplatesSaveTemplateVersionResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 deletetemplate(
        self, project_id: str, template_name: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[TemplatesDeleteTemplateResponse]:
        """
        Deletes all versions of a template with the specified name

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

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

        Returns
        -------
        HttpResponse[TemplatesDeleteTemplateResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}",
            method="DELETE",
            json={},
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesDeleteTemplateResponse,
                    construct_type(
                        type_=TemplatesDeleteTemplateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 gettemplatesnapshot(
        self, project_id: str, template_version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[TemplatesGetTemplateSnapshotResponse]:
        """
        Get a snapshot of the template version, this will return the template state at a specific version

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

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

        Returns
        -------
        HttpResponse[TemplatesGetTemplateSnapshotResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/snapshot",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesGetTemplateSnapshotResponse,
                    construct_type(
                        type_=TemplatesGetTemplateSnapshotResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 setcurrenttemplatefromsnapshot(
        self,
        project_id: str,
        template_version: str,
        *,
        request: typing.Optional[typing.Any] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesSetCurrentTemplateFromSnapshotResponse]:
        """
        Updates the current working version of a template from a snapshot

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template name with :dev version (e.g., my-template:dev)

        request : typing.Optional[typing.Any]

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

        Returns
        -------
        HttpResponse[TemplatesSetCurrentTemplateFromSnapshotResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/snapshot",
            method="PUT",
            json=request,
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesSetCurrentTemplateFromSnapshotResponse,
                    construct_type(
                        type_=TemplatesSetCurrentTemplateFromSnapshotResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 forktemplate(
        self,
        project_id: str,
        template_version: str,
        *,
        name: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesForkTemplateResponse]:
        """
        Forks a template version into a new template

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

        name : typing.Optional[str]
            Optional custom name for the forked template. If not provided, a random name will be generated.

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

        Returns
        -------
        HttpResponse[TemplatesForkTemplateResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/fork",
            method="POST",
            json={
                "name": name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesForkTemplateResponse,
                    construct_type(
                        type_=TemplatesForkTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 createtemplate(
        self,
        project_id: str,
        *,
        request: TemplatesCreateTemplateRequest,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesCreateTemplateResponse]:
        """
        Creates a new template from an existing agent or agent file

        Parameters
        ----------
        project_id : str
            The project id

        request : TemplatesCreateTemplateRequest

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

        Returns
        -------
        HttpResponse[TemplatesCreateTemplateResponse]
            201
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=TemplatesCreateTemplateRequest, direction="write"
            ),
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesCreateTemplateResponse,
                    construct_type(
                        type_=TemplatesCreateTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 renametemplate(
        self,
        project_id: str,
        template_name: str,
        *,
        new_name: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesRenameTemplateResponse]:
        """
        Renames all versions of a template with the specified name. Versions are automatically stripped from the current template name if accidentally included.

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The current template name (version will be automatically stripped if included)

        new_name : str
            The new name for the template

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

        Returns
        -------
        HttpResponse[TemplatesRenameTemplateResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/name",
            method="PATCH",
            json={
                "new_name": new_name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesRenameTemplateResponse,
                    construct_type(
                        type_=TemplatesRenameTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 409:
                raise ConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ConflictErrorBody,
                        construct_type(
                            type_=ConflictErrorBody,  # 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 updatetemplatedescription(
        self,
        project_id: str,
        template_name: str,
        *,
        description: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesUpdateTemplateDescriptionResponse]:
        """
        Updates the description for all versions of a template with the specified name. Versions are automatically stripped from the current template name if accidentally included.

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (version will be automatically stripped if included)

        description : typing.Optional[str]
            The new description for the template

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

        Returns
        -------
        HttpResponse[TemplatesUpdateTemplateDescriptionResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/description",
            method="PATCH",
            json={
                "description": description,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesUpdateTemplateDescriptionResponse,
                    construct_type(
                        type_=TemplatesUpdateTemplateDescriptionResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 listtemplateversions(
        self,
        project_id: str,
        name: str,
        *,
        offset: typing.Optional[str] = None,
        limit: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesListTemplateVersionsResponse]:
        """
        List all versions of a specific template

        Parameters
        ----------
        project_id : str
            The project id

        name : str
            The template name (without version)

        offset : typing.Optional[str]

        limit : typing.Optional[str]

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

        Returns
        -------
        HttpResponse[TemplatesListTemplateVersionsResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(name)}/versions",
            method="GET",
            params={
                "offset": offset,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesListTemplateVersionsResponse,
                    construct_type(
                        type_=TemplatesListTemplateVersionsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 migratedeployment(
        self,
        project_id: str,
        template_name: str,
        deployment_id: str,
        *,
        version: str,
        preserve_tool_variables: typing.Optional[bool] = OMIT,
        preserve_core_memories: typing.Optional[bool] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesMigrateDeploymentResponse]:
        """
        Migrates a deployment to a specific template version

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

        deployment_id : str
            The deployment ID to migrate

        version : str
            The target template version to migrate to

        preserve_tool_variables : typing.Optional[bool]
            Whether to preserve existing tool variables during migration

        preserve_core_memories : typing.Optional[bool]
            Whether to preserve existing core memories during migration

        memory_variables : typing.Optional[typing.Dict[str, str]]
            Additional memory variables to apply during migration

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

        Returns
        -------
        HttpResponse[TemplatesMigrateDeploymentResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/deployments/{jsonable_encoder(deployment_id)}/migrate",
            method="POST",
            json={
                "version": version,
                "preserve_tool_variables": preserve_tool_variables,
                "preserve_core_memories": preserve_core_memories,
                "memory_variables": memory_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesMigrateDeploymentResponse,
                    construct_type(
                        type_=TemplatesMigrateDeploymentResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 updatecurrenttemplatefromagentfile(
        self,
        project_id: str,
        template_name: str,
        *,
        agent_file_json: typing.Dict[str, typing.Optional[typing.Any]],
        update_existing_tools: typing.Optional[bool] = OMIT,
        save_existing_changes: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TemplatesUpdateCurrentTemplateFromAgentFileResponse]:
        """
        Updates the current working version of a template from an agent file

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

        agent_file_json : typing.Dict[str, typing.Optional[typing.Any]]
            The agent file to update the current template version from

        update_existing_tools : typing.Optional[bool]
            If true, update existing custom tools source_code and json_schema (source_type cannot be changed)

        save_existing_changes : typing.Optional[bool]
            If true, Letta will automatically save any changes as a version before updating the template

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

        Returns
        -------
        HttpResponse[TemplatesUpdateCurrentTemplateFromAgentFileResponse]
            200
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/agent-file",
            method="PUT",
            json={
                "agent_file_json": agent_file_json,
                "update_existing_tools": update_existing_tools,
                "save_existing_changes": save_existing_changes,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesUpdateCurrentTemplateFromAgentFileResponse,
                    construct_type(
                        type_=TemplatesUpdateCurrentTemplateFromAgentFileResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 AsyncRawTemplatesClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def createagentsfromtemplate(
        self,
        project_id: str,
        template_version: str,
        *,
        tags: typing.Optional[typing.Sequence[str]] = OMIT,
        agent_name: typing.Optional[str] = OMIT,
        initial_message_sequence: typing.Optional[
            typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem]
        ] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        tool_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        identity_ids: typing.Optional[typing.Sequence[str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesCreateAgentsFromTemplateResponse]:
        """
        Creates an Agent or multiple Agents from a template

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

        tags : typing.Optional[typing.Sequence[str]]
            The tags to assign to the agent

        agent_name : typing.Optional[str]
            The name of the agent, optional otherwise a random one will be assigned

        initial_message_sequence : typing.Optional[typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem]]
            Set an initial sequence of messages, if not provided, the agent will start with the default message sequence, if an empty array is provided, the agent will start with no messages

        memory_variables : typing.Optional[typing.Dict[str, str]]
            The memory variables to assign to the agent

        tool_variables : typing.Optional[typing.Dict[str, str]]
            The tool variables to assign to the agent

        identity_ids : typing.Optional[typing.Sequence[str]]
            The identity ids to assign to the agent

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

        Returns
        -------
        AsyncHttpResponse[TemplatesCreateAgentsFromTemplateResponse]
            201
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/agents",
            method="POST",
            json={
                "tags": tags,
                "agent_name": agent_name,
                "initial_message_sequence": convert_and_respect_annotation_metadata(
                    object_=initial_message_sequence,
                    annotation=typing.Sequence[TemplatesCreateAgentsFromTemplateRequestInitialMessageSequenceItem],
                    direction="write",
                ),
                "memory_variables": memory_variables,
                "tool_variables": tool_variables,
                "identity_ids": identity_ids,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesCreateAgentsFromTemplateResponse,
                    construct_type(
                        type_=TemplatesCreateAgentsFromTemplateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 402:
                raise PaymentRequiredError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        PaymentRequiredErrorBody,
                        construct_type(
                            type_=PaymentRequiredErrorBody,  # 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 list(
        self,
        *,
        offset: typing.Optional[str] = None,
        exact: typing.Optional[str] = None,
        limit: typing.Optional[str] = None,
        version: typing.Optional[str] = None,
        template_id: typing.Optional[str] = None,
        name: typing.Optional[str] = None,
        search: typing.Optional[str] = None,
        project_slug: typing.Optional[str] = None,
        project_id: typing.Optional[str] = None,
        sort_by: typing.Optional[TemplatesListRequestSortBy] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesListResponse]:
        """
        List all templates

        Parameters
        ----------
        offset : typing.Optional[str]

        exact : typing.Optional[str]
            Whether to search for an exact name match

        limit : typing.Optional[str]

        version : typing.Optional[str]
            Specify the version you want to return, otherwise will return the latest version

        template_id : typing.Optional[str]

        name : typing.Optional[str]

        search : typing.Optional[str]

        project_slug : typing.Optional[str]

        project_id : typing.Optional[str]

        sort_by : typing.Optional[TemplatesListRequestSortBy]

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

        Returns
        -------
        AsyncHttpResponse[TemplatesListResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/templates",
            method="GET",
            params={
                "offset": offset,
                "exact": exact,
                "limit": limit,
                "version": version,
                "template_id": template_id,
                "name": name,
                "search": search,
                "project_slug": project_slug,
                "project_id": project_id,
                "sort_by": sort_by,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesListResponse,
                    construct_type(
                        type_=TemplatesListResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 savetemplateversion(
        self,
        project_id: str,
        template_name: str,
        *,
        preserve_environment_variables_on_migration: typing.Optional[bool] = OMIT,
        preserve_core_memories_on_migration: typing.Optional[bool] = OMIT,
        migrate_agents: typing.Optional[bool] = OMIT,
        message: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesSaveTemplateVersionResponse]:
        """
        Saves the current version of the template as a new version

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template version, formatted as {template-name}, any version appended will be ignored

        preserve_environment_variables_on_migration : typing.Optional[bool]
            If true, the environment variables will be preserved in the template version when migrating agents

        preserve_core_memories_on_migration : typing.Optional[bool]
            If true, the core memories will be preserved in the template version when migrating agents

        migrate_agents : typing.Optional[bool]
            If true, existing agents attached to this template will be migrated to the new template version

        message : typing.Optional[str]
            A message to describe the changes made in this template version

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

        Returns
        -------
        AsyncHttpResponse[TemplatesSaveTemplateVersionResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}",
            method="POST",
            json={
                "preserve_environment_variables_on_migration": preserve_environment_variables_on_migration,
                "preserve_core_memories_on_migration": preserve_core_memories_on_migration,
                "migrate_agents": migrate_agents,
                "message": message,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesSaveTemplateVersionResponse,
                    construct_type(
                        type_=TemplatesSaveTemplateVersionResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 deletetemplate(
        self, project_id: str, template_name: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[TemplatesDeleteTemplateResponse]:
        """
        Deletes all versions of a template with the specified name

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

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

        Returns
        -------
        AsyncHttpResponse[TemplatesDeleteTemplateResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}",
            method="DELETE",
            json={},
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesDeleteTemplateResponse,
                    construct_type(
                        type_=TemplatesDeleteTemplateResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 gettemplatesnapshot(
        self, project_id: str, template_version: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[TemplatesGetTemplateSnapshotResponse]:
        """
        Get a snapshot of the template version, this will return the template state at a specific version

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

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

        Returns
        -------
        AsyncHttpResponse[TemplatesGetTemplateSnapshotResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/snapshot",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesGetTemplateSnapshotResponse,
                    construct_type(
                        type_=TemplatesGetTemplateSnapshotResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 setcurrenttemplatefromsnapshot(
        self,
        project_id: str,
        template_version: str,
        *,
        request: typing.Optional[typing.Any] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesSetCurrentTemplateFromSnapshotResponse]:
        """
        Updates the current working version of a template from a snapshot

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template name with :dev version (e.g., my-template:dev)

        request : typing.Optional[typing.Any]

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

        Returns
        -------
        AsyncHttpResponse[TemplatesSetCurrentTemplateFromSnapshotResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/snapshot",
            method="PUT",
            json=request,
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesSetCurrentTemplateFromSnapshotResponse,
                    construct_type(
                        type_=TemplatesSetCurrentTemplateFromSnapshotResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 forktemplate(
        self,
        project_id: str,
        template_version: str,
        *,
        name: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesForkTemplateResponse]:
        """
        Forks a template version into a new template

        Parameters
        ----------
        project_id : str
            The project id

        template_version : str
            The template version, formatted as {template-name}:{version-number} or {template-name}:latest

        name : typing.Optional[str]
            Optional custom name for the forked template. If not provided, a random name will be generated.

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

        Returns
        -------
        AsyncHttpResponse[TemplatesForkTemplateResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_version)}/fork",
            method="POST",
            json={
                "name": name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesForkTemplateResponse,
                    construct_type(
                        type_=TemplatesForkTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 createtemplate(
        self,
        project_id: str,
        *,
        request: TemplatesCreateTemplateRequest,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesCreateTemplateResponse]:
        """
        Creates a new template from an existing agent or agent file

        Parameters
        ----------
        project_id : str
            The project id

        request : TemplatesCreateTemplateRequest

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

        Returns
        -------
        AsyncHttpResponse[TemplatesCreateTemplateResponse]
            201
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=TemplatesCreateTemplateRequest, direction="write"
            ),
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesCreateTemplateResponse,
                    construct_type(
                        type_=TemplatesCreateTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 renametemplate(
        self,
        project_id: str,
        template_name: str,
        *,
        new_name: str,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesRenameTemplateResponse]:
        """
        Renames all versions of a template with the specified name. Versions are automatically stripped from the current template name if accidentally included.

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The current template name (version will be automatically stripped if included)

        new_name : str
            The new name for the template

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

        Returns
        -------
        AsyncHttpResponse[TemplatesRenameTemplateResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/name",
            method="PATCH",
            json={
                "new_name": new_name,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesRenameTemplateResponse,
                    construct_type(
                        type_=TemplatesRenameTemplateResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 409:
                raise ConflictError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        ConflictErrorBody,
                        construct_type(
                            type_=ConflictErrorBody,  # 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 updatetemplatedescription(
        self,
        project_id: str,
        template_name: str,
        *,
        description: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesUpdateTemplateDescriptionResponse]:
        """
        Updates the description for all versions of a template with the specified name. Versions are automatically stripped from the current template name if accidentally included.

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (version will be automatically stripped if included)

        description : typing.Optional[str]
            The new description for the template

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

        Returns
        -------
        AsyncHttpResponse[TemplatesUpdateTemplateDescriptionResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/description",
            method="PATCH",
            json={
                "description": description,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesUpdateTemplateDescriptionResponse,
                    construct_type(
                        type_=TemplatesUpdateTemplateDescriptionResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 listtemplateversions(
        self,
        project_id: str,
        name: str,
        *,
        offset: typing.Optional[str] = None,
        limit: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesListTemplateVersionsResponse]:
        """
        List all versions of a specific template

        Parameters
        ----------
        project_id : str
            The project id

        name : str
            The template name (without version)

        offset : typing.Optional[str]

        limit : typing.Optional[str]

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

        Returns
        -------
        AsyncHttpResponse[TemplatesListTemplateVersionsResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(name)}/versions",
            method="GET",
            params={
                "offset": offset,
                "limit": limit,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesListTemplateVersionsResponse,
                    construct_type(
                        type_=TemplatesListTemplateVersionsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 migratedeployment(
        self,
        project_id: str,
        template_name: str,
        deployment_id: str,
        *,
        version: str,
        preserve_tool_variables: typing.Optional[bool] = OMIT,
        preserve_core_memories: typing.Optional[bool] = OMIT,
        memory_variables: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesMigrateDeploymentResponse]:
        """
        Migrates a deployment to a specific template version

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

        deployment_id : str
            The deployment ID to migrate

        version : str
            The target template version to migrate to

        preserve_tool_variables : typing.Optional[bool]
            Whether to preserve existing tool variables during migration

        preserve_core_memories : typing.Optional[bool]
            Whether to preserve existing core memories during migration

        memory_variables : typing.Optional[typing.Dict[str, str]]
            Additional memory variables to apply during migration

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

        Returns
        -------
        AsyncHttpResponse[TemplatesMigrateDeploymentResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/deployments/{jsonable_encoder(deployment_id)}/migrate",
            method="POST",
            json={
                "version": version,
                "preserve_tool_variables": preserve_tool_variables,
                "preserve_core_memories": preserve_core_memories,
                "memory_variables": memory_variables,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesMigrateDeploymentResponse,
                    construct_type(
                        type_=TemplatesMigrateDeploymentResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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 updatecurrenttemplatefromagentfile(
        self,
        project_id: str,
        template_name: str,
        *,
        agent_file_json: typing.Dict[str, typing.Optional[typing.Any]],
        update_existing_tools: typing.Optional[bool] = OMIT,
        save_existing_changes: typing.Optional[bool] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TemplatesUpdateCurrentTemplateFromAgentFileResponse]:
        """
        Updates the current working version of a template from an agent file

        Parameters
        ----------
        project_id : str
            The project id

        template_name : str
            The template name (without version)

        agent_file_json : typing.Dict[str, typing.Optional[typing.Any]]
            The agent file to update the current template version from

        update_existing_tools : typing.Optional[bool]
            If true, update existing custom tools source_code and json_schema (source_type cannot be changed)

        save_existing_changes : typing.Optional[bool]
            If true, Letta will automatically save any changes as a version before updating the template

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

        Returns
        -------
        AsyncHttpResponse[TemplatesUpdateCurrentTemplateFromAgentFileResponse]
            200
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/templates/{jsonable_encoder(project_id)}/{jsonable_encoder(template_name)}/agent-file",
            method="PUT",
            json={
                "agent_file_json": agent_file_json,
                "update_existing_tools": update_existing_tools,
                "save_existing_changes": save_existing_changes,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TemplatesUpdateCurrentTemplateFromAgentFileResponse,
                    construct_type(
                        type_=TemplatesUpdateCurrentTemplateFromAgentFileResponse,  # 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(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 500:
                raise InternalServerError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Optional[typing.Any],
                        construct_type(
                            type_=typing.Optional[typing.Any],  # 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)
