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

import typing
from ..core.client_wrapper import SyncClientWrapper
from ..commons.types.entity_id_base import EntityIdBase
from .types.conversation_message_request import ConversationMessageRequest
from ..commons.types.response_config import ResponseConfig
import datetime as dt
from ..core.request_options import RequestOptions
from ..commons.types.conversation_response import ConversationResponse
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.pydantic_utilities import parse_obj_as
from ..commons.errors.not_found_error import NotFoundError
from ..commons.types.error_message import ErrorMessage
from ..commons.errors.bad_request_error import BadRequestError
from ..commons.errors.server_error import ServerError
from json.decoder import JSONDecodeError
from ..core.api_error import ApiError
from ..core.jsonable_encoder import jsonable_encoder
from .types.attachment import Attachment
from .types.stream_response import StreamResponse
import httpx_sse
import json
from .types.categorization_response import CategorizationResponse
from ..commons.types.feedback_type import FeedbackType
from ..commons.types.feedback import Feedback
from ..core.client_wrapper import AsyncClientWrapper

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


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

    def initialize(
        self,
        *,
        conversation_id: EntityIdBase,
        messages: typing.Sequence[ConversationMessageRequest],
        response_config: typing.Optional[ResponseConfig] = OMIT,
        subject: typing.Optional[str] = OMIT,
        url: typing.Optional[str] = OMIT,
        created_at: typing.Optional[dt.datetime] = OMIT,
        updated_at: typing.Optional[dt.datetime] = OMIT,
        tags: typing.Optional[typing.Set[str]] = OMIT,
        metadata: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Initialize a new conversation. Only required if the ask request wishes to supply conversation level data or when syncing to external systems.

        Parameters
        ----------
        conversation_id : EntityIdBase
            An externally supplied ID to uniquely identify this conversation

        messages : typing.Sequence[ConversationMessageRequest]
            The messages in the conversation

        response_config : typing.Optional[ResponseConfig]
            Optional configurations for responses to this conversation

        subject : typing.Optional[str]
            The subject of the conversation

        url : typing.Optional[str]
            The url of the conversation

        created_at : typing.Optional[dt.datetime]
            The date and time the conversation was created

        updated_at : typing.Optional[dt.datetime]
            The date and time the conversation was last updated

        tags : typing.Optional[typing.Set[str]]
            The tags of the conversation. Used for filtering in Agent Designer.

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

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

        Returns
        -------
        ConversationResponse
            Initialized conversation

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import ConversationMessageRequest

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.initialize(
            conversation_id=EntityIdBase(
                reference_id="referenceId",
            ),
            messages=[
                ConversationMessageRequest(
                    conversation_message_id=EntityIdBase(
                        reference_id="referenceId",
                    ),
                ),
                ConversationMessageRequest(
                    conversation_message_id=EntityIdBase(
                        reference_id="referenceId",
                    ),
                ),
            ],
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/conversations",
            method="POST",
            json={
                "conversationId": convert_and_respect_annotation_metadata(
                    object_=conversation_id, annotation=EntityIdBase, direction="write"
                ),
                "messages": convert_and_respect_annotation_metadata(
                    object_=messages, annotation=typing.Sequence[ConversationMessageRequest], direction="write"
                ),
                "responseConfig": convert_and_respect_annotation_metadata(
                    object_=response_config, annotation=ResponseConfig, direction="write"
                ),
                "subject": subject,
                "url": url,
                "createdAt": created_at,
                "updatedAt": updated_at,
                "tags": tags,
                "metadata": metadata,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def get(
        self,
        conversation_id: str,
        *,
        app_id: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Get a conversation

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to get

        app_id : typing.Optional[str]
            The App ID of the conversation to get. If not provided the ID of the calling app will be used.

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

        Returns
        -------
        ConversationResponse

        Examples
        --------
        from mavenagi import MavenAGI

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.get(
            conversation_id="conversationId",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}",
            method="GET",
            params={
                "appId": app_id,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def append_new_messages(
        self,
        conversation_id: str,
        *,
        request: typing.Sequence[ConversationMessageRequest],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Append messages to an existing conversation. The conversation must be initialized first. If a message with the same id already exists, it will be ignored.

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to append messages to

        request : typing.Sequence[ConversationMessageRequest]

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

        Returns
        -------
        ConversationResponse
            Updated Conversation

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import ConversationMessageRequest

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.append_new_messages(
            conversation_id="conversationId",
            request=[
                ConversationMessageRequest(
                    conversation_message_id=EntityIdBase(
                        reference_id="referenceId",
                    ),
                ),
                ConversationMessageRequest(
                    conversation_message_id=EntityIdBase(
                        reference_id="referenceId",
                    ),
                ),
            ],
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/messages",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=typing.Sequence[ConversationMessageRequest], direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def ask(
        self,
        conversation_id: str,
        *,
        conversation_message_id: EntityIdBase,
        user_id: EntityIdBase,
        text: str,
        attachments: typing.Optional[typing.Sequence[Attachment]] = OMIT,
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Ask a question

        Parameters
        ----------
        conversation_id : str
            The ID of a new or existing conversation to use as context for the question

        conversation_message_id : EntityIdBase
            Externally supplied ID to uniquely identify this message within the conversation

        user_id : EntityIdBase
            Externally supplied ID to uniquely identify the user that created this message

        text : str
            The text of the message

        attachments : typing.Optional[typing.Sequence[Attachment]]
            The attachments to the message.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken by this ask request. For example, one may put in user tokens as transient data.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with a user message of the question and a bot message with the response

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import Attachment

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.ask(
            conversation_id="conversation-0",
            conversation_message_id=EntityIdBase(
                reference_id="message-0",
            ),
            user_id=EntityIdBase(
                reference_id="user-0",
            ),
            text="How do I reset my password?",
            attachments=[
                Attachment(
                    type="image/png",
                    content="iVBORw0KGgo...",
                )
            ],
            transient_data={"userToken": "abcdef123", "queryApiKey": "foobar456"},
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/ask",
            method="POST",
            json={
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "text": text,
                "attachments": convert_and_respect_annotation_metadata(
                    object_=attachments, annotation=typing.Sequence[Attachment], direction="write"
                ),
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def ask_stream(
        self,
        conversation_id: str,
        *,
        conversation_message_id: EntityIdBase,
        user_id: EntityIdBase,
        text: str,
        attachments: typing.Optional[typing.Sequence[Attachment]] = OMIT,
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Iterator[StreamResponse]:
        """
        Ask a question with a streaming response. The response will be sent as a stream of events. The text portions of stream responses should be concatenated to form the full response text. Action and metadata events should overwrite past data and do not need concatenation.

        Parameters
        ----------
        conversation_id : str
            The ID of a new or existing conversation to use as context for the question

        conversation_message_id : EntityIdBase
            Externally supplied ID to uniquely identify this message within the conversation

        user_id : EntityIdBase
            Externally supplied ID to uniquely identify the user that created this message

        text : str
            The text of the message

        attachments : typing.Optional[typing.Sequence[Attachment]]
            The attachments to the message.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken by this ask request. For example, one may put in user tokens as transient data.

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

        Yields
        ------
        typing.Iterator[StreamResponse]

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import Attachment

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        response = client.conversation.ask_stream(
            conversation_id="conversation-0",
            conversation_message_id=EntityIdBase(
                reference_id="message-0",
            ),
            user_id=EntityIdBase(
                reference_id="user-0",
            ),
            text="How do I reset my password?",
            attachments=[
                Attachment(
                    type="image/png",
                    content="iVBORw0KGgo...",
                )
            ],
            transient_data={"userToken": "abcdef123", "queryApiKey": "foobar456"},
        )
        for chunk in response:
            yield chunk
        """
        with self._client_wrapper.httpx_client.stream(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/ask_stream",
            method="POST",
            json={
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "text": text,
                "attachments": convert_and_respect_annotation_metadata(
                    object_=attachments, annotation=typing.Sequence[Attachment], direction="write"
                ),
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:
            try:
                if 200 <= _response.status_code < 300:
                    _event_source = httpx_sse.EventSource(_response)
                    for _sse in _event_source.iter_sse():
                        try:
                            yield typing.cast(
                                StreamResponse,
                                parse_obj_as(
                                    type_=StreamResponse,  # type: ignore
                                    object_=json.loads(_sse.data),
                                ),
                            )
                        except:
                            pass
                    return
                _response.read()
                if _response.status_code == 404:
                    raise NotFoundError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                if _response.status_code == 400:
                    raise BadRequestError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                if _response.status_code == 500:
                    raise ServerError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                _response_json = _response.json()
            except JSONDecodeError:
                raise ApiError(status_code=_response.status_code, body=_response.text)
            raise ApiError(status_code=_response.status_code, body=_response_json)

    def generate_maven_suggestions(
        self,
        conversation_id: str,
        *,
        conversation_message_ids: typing.Sequence[EntityIdBase],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Generate a response suggestion for each requested message id in a conversation

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the messages belong to

        conversation_message_ids : typing.Sequence[EntityIdBase]
            The message ids to generate a suggested response for. One suggestion will be generated for each message id.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with new BOT_SUGGESTION messages as requested

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.generate_maven_suggestions(
            conversation_id="conversationId",
            conversation_message_ids=[
                EntityIdBase(
                    reference_id="referenceId",
                ),
                EntityIdBase(
                    reference_id="referenceId",
                ),
            ],
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/generate_maven_suggestions",
            method="POST",
            json={
                "conversationMessageIds": convert_and_respect_annotation_metadata(
                    object_=conversation_message_ids, annotation=typing.Sequence[EntityIdBase], direction="write"
                ),
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def categorize(
        self, conversation_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> CategorizationResponse:
        """
        Uses an LLM flow to categorize the conversation. Experimental.

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to categorize

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

        Returns
        -------
        CategorizationResponse
            The conversation categorization

        Examples
        --------
        from mavenagi import MavenAGI

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.categorize(
            conversation_id="conversationId",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/categorize",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    CategorizationResponse,
                    parse_obj_as(
                        type_=CategorizationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def create_feedback(
        self,
        *,
        feedback_id: EntityIdBase,
        conversation_id: EntityIdBase,
        conversation_message_id: EntityIdBase,
        type: FeedbackType,
        user_id: typing.Optional[EntityIdBase] = OMIT,
        text: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> Feedback:
        """
        Update feedback or create it if it doesn't exist

        Parameters
        ----------
        feedback_id : EntityIdBase
            The ID that uniquely identifies this feedback

        conversation_id : EntityIdBase
            The ID that uniquely identifies the the conversation the feedback is about

        conversation_message_id : EntityIdBase
            The ID that uniquely identifies the message within the conversation the feedback is about

        type : FeedbackType
            The type of feedback

        user_id : typing.Optional[EntityIdBase]
            The ID of the user who is creating the feedback

        text : typing.Optional[str]
            The feedback text

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

        Returns
        -------
        Feedback

        Examples
        --------
        from mavenagi import MavenAGI
        from mavenagi.commons import EntityIdBase

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.create_feedback(
            feedback_id=EntityIdBase(
                reference_id="feedback-0",
            ),
            user_id=EntityIdBase(
                reference_id="user-0",
            ),
            conversation_id=EntityIdBase(
                reference_id="conversation-0",
            ),
            conversation_message_id=EntityIdBase(
                reference_id="message-1",
            ),
            type="THUMBS_UP",
            text="Great answer!",
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            "v1/conversations/feedback",
            method="POST",
            json={
                "feedbackId": convert_and_respect_annotation_metadata(
                    object_=feedback_id, annotation=EntityIdBase, direction="write"
                ),
                "conversationId": convert_and_respect_annotation_metadata(
                    object_=conversation_id, annotation=EntityIdBase, direction="write"
                ),
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "type": type,
                "text": text,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    Feedback,
                    parse_obj_as(
                        type_=Feedback,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def submit_action_form(
        self,
        conversation_id: str,
        *,
        action_form_id: str,
        parameters: typing.Dict[str, typing.Optional[typing.Any]],
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Submit a filled out action form

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the form being submitted belongs to

        action_form_id : str

        parameters : typing.Dict[str, typing.Optional[typing.Any]]
            Map of parameter IDs to values provided by the user. All required action fields must be provided.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken. For example, one may put in user tokens as transient data.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with a new BOT_RESPONSE after taking the action

        Examples
        --------
        from mavenagi import MavenAGI

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.submit_action_form(
            conversation_id="conversationId",
            action_form_id="actionFormId",
            parameters={"parameters": {"key": "value"}},
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/submit-form",
            method="POST",
            json={
                "actionFormId": action_form_id,
                "parameters": parameters,
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    def add_conversation_metadata(
        self,
        conversation_id: str,
        *,
        request: typing.Dict[str, str],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Dict[str, str]:
        """
        Add metadata to an existing conversation. If a metadata field already exists, it will be overwritten.

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the metadata being added belongs to

        request : typing.Dict[str, str]

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

        Returns
        -------
        typing.Dict[str, str]
            The metadata of the conversation

        Examples
        --------
        from mavenagi import MavenAGI

        client = MavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )
        client.conversation.add_conversation_metadata(
            conversation_id="conversationId",
            request={"string": "string"},
        )
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/metadata",
            method="POST",
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.Dict[str, str],
                    parse_obj_as(
                        type_=typing.Dict[str, str],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def initialize(
        self,
        *,
        conversation_id: EntityIdBase,
        messages: typing.Sequence[ConversationMessageRequest],
        response_config: typing.Optional[ResponseConfig] = OMIT,
        subject: typing.Optional[str] = OMIT,
        url: typing.Optional[str] = OMIT,
        created_at: typing.Optional[dt.datetime] = OMIT,
        updated_at: typing.Optional[dt.datetime] = OMIT,
        tags: typing.Optional[typing.Set[str]] = OMIT,
        metadata: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Initialize a new conversation. Only required if the ask request wishes to supply conversation level data or when syncing to external systems.

        Parameters
        ----------
        conversation_id : EntityIdBase
            An externally supplied ID to uniquely identify this conversation

        messages : typing.Sequence[ConversationMessageRequest]
            The messages in the conversation

        response_config : typing.Optional[ResponseConfig]
            Optional configurations for responses to this conversation

        subject : typing.Optional[str]
            The subject of the conversation

        url : typing.Optional[str]
            The url of the conversation

        created_at : typing.Optional[dt.datetime]
            The date and time the conversation was created

        updated_at : typing.Optional[dt.datetime]
            The date and time the conversation was last updated

        tags : typing.Optional[typing.Set[str]]
            The tags of the conversation. Used for filtering in Agent Designer.

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

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

        Returns
        -------
        ConversationResponse
            Initialized conversation

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import ConversationMessageRequest

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.initialize(
                conversation_id=EntityIdBase(
                    reference_id="referenceId",
                ),
                messages=[
                    ConversationMessageRequest(
                        conversation_message_id=EntityIdBase(
                            reference_id="referenceId",
                        ),
                    ),
                    ConversationMessageRequest(
                        conversation_message_id=EntityIdBase(
                            reference_id="referenceId",
                        ),
                    ),
                ],
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/conversations",
            method="POST",
            json={
                "conversationId": convert_and_respect_annotation_metadata(
                    object_=conversation_id, annotation=EntityIdBase, direction="write"
                ),
                "messages": convert_and_respect_annotation_metadata(
                    object_=messages, annotation=typing.Sequence[ConversationMessageRequest], direction="write"
                ),
                "responseConfig": convert_and_respect_annotation_metadata(
                    object_=response_config, annotation=ResponseConfig, direction="write"
                ),
                "subject": subject,
                "url": url,
                "createdAt": created_at,
                "updatedAt": updated_at,
                "tags": tags,
                "metadata": metadata,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def get(
        self,
        conversation_id: str,
        *,
        app_id: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Get a conversation

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to get

        app_id : typing.Optional[str]
            The App ID of the conversation to get. If not provided the ID of the calling app will be used.

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

        Returns
        -------
        ConversationResponse

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.get(
                conversation_id="conversationId",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}",
            method="GET",
            params={
                "appId": app_id,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def append_new_messages(
        self,
        conversation_id: str,
        *,
        request: typing.Sequence[ConversationMessageRequest],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Append messages to an existing conversation. The conversation must be initialized first. If a message with the same id already exists, it will be ignored.

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to append messages to

        request : typing.Sequence[ConversationMessageRequest]

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

        Returns
        -------
        ConversationResponse
            Updated Conversation

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import ConversationMessageRequest

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.append_new_messages(
                conversation_id="conversationId",
                request=[
                    ConversationMessageRequest(
                        conversation_message_id=EntityIdBase(
                            reference_id="referenceId",
                        ),
                    ),
                    ConversationMessageRequest(
                        conversation_message_id=EntityIdBase(
                            reference_id="referenceId",
                        ),
                    ),
                ],
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/messages",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=typing.Sequence[ConversationMessageRequest], direction="write"
            ),
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def ask(
        self,
        conversation_id: str,
        *,
        conversation_message_id: EntityIdBase,
        user_id: EntityIdBase,
        text: str,
        attachments: typing.Optional[typing.Sequence[Attachment]] = OMIT,
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Ask a question

        Parameters
        ----------
        conversation_id : str
            The ID of a new or existing conversation to use as context for the question

        conversation_message_id : EntityIdBase
            Externally supplied ID to uniquely identify this message within the conversation

        user_id : EntityIdBase
            Externally supplied ID to uniquely identify the user that created this message

        text : str
            The text of the message

        attachments : typing.Optional[typing.Sequence[Attachment]]
            The attachments to the message.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken by this ask request. For example, one may put in user tokens as transient data.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with a user message of the question and a bot message with the response

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import Attachment

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.ask(
                conversation_id="conversation-0",
                conversation_message_id=EntityIdBase(
                    reference_id="message-0",
                ),
                user_id=EntityIdBase(
                    reference_id="user-0",
                ),
                text="How do I reset my password?",
                attachments=[
                    Attachment(
                        type="image/png",
                        content="iVBORw0KGgo...",
                    )
                ],
                transient_data={"userToken": "abcdef123", "queryApiKey": "foobar456"},
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/ask",
            method="POST",
            json={
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "text": text,
                "attachments": convert_and_respect_annotation_metadata(
                    object_=attachments, annotation=typing.Sequence[Attachment], direction="write"
                ),
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def ask_stream(
        self,
        conversation_id: str,
        *,
        conversation_message_id: EntityIdBase,
        user_id: EntityIdBase,
        text: str,
        attachments: typing.Optional[typing.Sequence[Attachment]] = OMIT,
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.AsyncIterator[StreamResponse]:
        """
        Ask a question with a streaming response. The response will be sent as a stream of events. The text portions of stream responses should be concatenated to form the full response text. Action and metadata events should overwrite past data and do not need concatenation.

        Parameters
        ----------
        conversation_id : str
            The ID of a new or existing conversation to use as context for the question

        conversation_message_id : EntityIdBase
            Externally supplied ID to uniquely identify this message within the conversation

        user_id : EntityIdBase
            Externally supplied ID to uniquely identify the user that created this message

        text : str
            The text of the message

        attachments : typing.Optional[typing.Sequence[Attachment]]
            The attachments to the message.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken by this ask request. For example, one may put in user tokens as transient data.

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

        Yields
        ------
        typing.AsyncIterator[StreamResponse]

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase
        from mavenagi.conversation import Attachment

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            response = await client.conversation.ask_stream(
                conversation_id="conversation-0",
                conversation_message_id=EntityIdBase(
                    reference_id="message-0",
                ),
                user_id=EntityIdBase(
                    reference_id="user-0",
                ),
                text="How do I reset my password?",
                attachments=[
                    Attachment(
                        type="image/png",
                        content="iVBORw0KGgo...",
                    )
                ],
                transient_data={"userToken": "abcdef123", "queryApiKey": "foobar456"},
            )
            async for chunk in response:
                yield chunk


        asyncio.run(main())
        """
        async with self._client_wrapper.httpx_client.stream(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/ask_stream",
            method="POST",
            json={
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "text": text,
                "attachments": convert_and_respect_annotation_metadata(
                    object_=attachments, annotation=typing.Sequence[Attachment], direction="write"
                ),
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        ) as _response:
            try:
                if 200 <= _response.status_code < 300:
                    _event_source = httpx_sse.EventSource(_response)
                    async for _sse in _event_source.aiter_sse():
                        try:
                            yield typing.cast(
                                StreamResponse,
                                parse_obj_as(
                                    type_=StreamResponse,  # type: ignore
                                    object_=json.loads(_sse.data),
                                ),
                            )
                        except:
                            pass
                    return
                await _response.aread()
                if _response.status_code == 404:
                    raise NotFoundError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                if _response.status_code == 400:
                    raise BadRequestError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                if _response.status_code == 500:
                    raise ServerError(
                        typing.cast(
                            ErrorMessage,
                            parse_obj_as(
                                type_=ErrorMessage,  # type: ignore
                                object_=_response.json(),
                            ),
                        )
                    )
                _response_json = _response.json()
            except JSONDecodeError:
                raise ApiError(status_code=_response.status_code, body=_response.text)
            raise ApiError(status_code=_response.status_code, body=_response_json)

    async def generate_maven_suggestions(
        self,
        conversation_id: str,
        *,
        conversation_message_ids: typing.Sequence[EntityIdBase],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Generate a response suggestion for each requested message id in a conversation

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the messages belong to

        conversation_message_ids : typing.Sequence[EntityIdBase]
            The message ids to generate a suggested response for. One suggestion will be generated for each message id.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with new BOT_SUGGESTION messages as requested

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.generate_maven_suggestions(
                conversation_id="conversationId",
                conversation_message_ids=[
                    EntityIdBase(
                        reference_id="referenceId",
                    ),
                    EntityIdBase(
                        reference_id="referenceId",
                    ),
                ],
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/generate_maven_suggestions",
            method="POST",
            json={
                "conversationMessageIds": convert_and_respect_annotation_metadata(
                    object_=conversation_message_ids, annotation=typing.Sequence[EntityIdBase], direction="write"
                ),
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def categorize(
        self, conversation_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> CategorizationResponse:
        """
        Uses an LLM flow to categorize the conversation. Experimental.

        Parameters
        ----------
        conversation_id : str
            The ID of the conversation to categorize

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

        Returns
        -------
        CategorizationResponse
            The conversation categorization

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.categorize(
                conversation_id="conversationId",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/categorize",
            method="POST",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    CategorizationResponse,
                    parse_obj_as(
                        type_=CategorizationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def create_feedback(
        self,
        *,
        feedback_id: EntityIdBase,
        conversation_id: EntityIdBase,
        conversation_message_id: EntityIdBase,
        type: FeedbackType,
        user_id: typing.Optional[EntityIdBase] = OMIT,
        text: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> Feedback:
        """
        Update feedback or create it if it doesn't exist

        Parameters
        ----------
        feedback_id : EntityIdBase
            The ID that uniquely identifies this feedback

        conversation_id : EntityIdBase
            The ID that uniquely identifies the the conversation the feedback is about

        conversation_message_id : EntityIdBase
            The ID that uniquely identifies the message within the conversation the feedback is about

        type : FeedbackType
            The type of feedback

        user_id : typing.Optional[EntityIdBase]
            The ID of the user who is creating the feedback

        text : typing.Optional[str]
            The feedback text

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

        Returns
        -------
        Feedback

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI
        from mavenagi.commons import EntityIdBase

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.create_feedback(
                feedback_id=EntityIdBase(
                    reference_id="feedback-0",
                ),
                user_id=EntityIdBase(
                    reference_id="user-0",
                ),
                conversation_id=EntityIdBase(
                    reference_id="conversation-0",
                ),
                conversation_message_id=EntityIdBase(
                    reference_id="message-1",
                ),
                type="THUMBS_UP",
                text="Great answer!",
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            "v1/conversations/feedback",
            method="POST",
            json={
                "feedbackId": convert_and_respect_annotation_metadata(
                    object_=feedback_id, annotation=EntityIdBase, direction="write"
                ),
                "conversationId": convert_and_respect_annotation_metadata(
                    object_=conversation_id, annotation=EntityIdBase, direction="write"
                ),
                "conversationMessageId": convert_and_respect_annotation_metadata(
                    object_=conversation_message_id, annotation=EntityIdBase, direction="write"
                ),
                "userId": convert_and_respect_annotation_metadata(
                    object_=user_id, annotation=EntityIdBase, direction="write"
                ),
                "type": type,
                "text": text,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    Feedback,
                    parse_obj_as(
                        type_=Feedback,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def submit_action_form(
        self,
        conversation_id: str,
        *,
        action_form_id: str,
        parameters: typing.Dict[str, typing.Optional[typing.Any]],
        transient_data: typing.Optional[typing.Dict[str, str]] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> ConversationResponse:
        """
        Submit a filled out action form

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the form being submitted belongs to

        action_form_id : str

        parameters : typing.Dict[str, typing.Optional[typing.Any]]
            Map of parameter IDs to values provided by the user. All required action fields must be provided.

        transient_data : typing.Optional[typing.Dict[str, str]]
            Transient data which the Maven platform will not persist. This data will only be forwarded to actions taken. For example, one may put in user tokens as transient data.

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

        Returns
        -------
        ConversationResponse
            Updated Conversation with a new BOT_RESPONSE after taking the action

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.submit_action_form(
                conversation_id="conversationId",
                action_form_id="actionFormId",
                parameters={"parameters": {"key": "value"}},
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/submit-form",
            method="POST",
            json={
                "actionFormId": action_form_id,
                "parameters": parameters,
                "transientData": transient_data,
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    ConversationResponse,
                    parse_obj_as(
                        type_=ConversationResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)

    async def add_conversation_metadata(
        self,
        conversation_id: str,
        *,
        request: typing.Dict[str, str],
        request_options: typing.Optional[RequestOptions] = None,
    ) -> typing.Dict[str, str]:
        """
        Add metadata to an existing conversation. If a metadata field already exists, it will be overwritten.

        Parameters
        ----------
        conversation_id : str
            The ID of a conversation the metadata being added belongs to

        request : typing.Dict[str, str]

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

        Returns
        -------
        typing.Dict[str, str]
            The metadata of the conversation

        Examples
        --------
        import asyncio

        from mavenagi import AsyncMavenAGI

        client = AsyncMavenAGI(
            organization_id="YOUR_ORGANIZATION_ID",
            agent_id="YOUR_AGENT_ID",
            app_id="YOUR_APP_ID",
            app_secret="YOUR_APP_SECRET",
        )


        async def main() -> None:
            await client.conversation.add_conversation_metadata(
                conversation_id="conversationId",
                request={"string": "string"},
            )


        asyncio.run(main())
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v1/conversations/{jsonable_encoder(conversation_id)}/metadata",
            method="POST",
            json=request,
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                return typing.cast(
                    typing.Dict[str, str],
                    parse_obj_as(
                        type_=typing.Dict[str, str],  # type: ignore
                        object_=_response.json(),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 400:
                raise BadRequestError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            if _response.status_code == 500:
                raise ServerError(
                    typing.cast(
                        ErrorMessage,
                        parse_obj_as(
                            type_=ErrorMessage,  # type: ignore
                            object_=_response.json(),
                        ),
                    )
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
