        """Return the singular input key.

        :meta private:
        """
        return ["plan", "user_query", "previous_actions", "previous_thoughts", "page_info"]

    @property
    def output_keys(self) -> List[str]:
        """Return the singular output key.

        :meta private:
        """
        # success: boolean, message: string, action: string, thought: string
        # success is a boolean indicating whether the action was successful
        # message is the error message that will be displayed to the user if success == false
        # example: {'success': True, 'message' = 'success', 'thought': "I should first set the value in the search field to '...'", 'action': 'setValue(93, "...")', 'parsedAction': {'name': 'setValue', 'args': {'elementId': 93, 'value': '...'}}}
        return ["success", "message", "action", "thought", "parsedAction"]

    #example case: _format_error_output({"error": "This model's maximum context length is 8192 tokens. However, your messages resulted in 8243 tokens. Please reduce the length of the messages."})
    #you need to input like the example, i.e. stringfy the error thrown and put it in a dict with the key "error"
    def _format_error_output(self, error_output: Dict[str, str]) -> Dict[str, Any]:
        return {
            "success": False,
            "message": error_output["error"],
            "action": "error",
            "thought": error_output["error"],
            "parsedAction": {"name": "error", "args": {}},
        }

    def parse_response(self, text):
        if "finish" in text:
            thought_match = re.search("<Thought>(.*?)</Thought>", text)
            if thought_match is None:
                return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})
            thought = thought_match.group(1)
            action_string = "finish"
            parsed_action = "finish"
            return {"thought": thought, "action": action_string, "parsedAction": {"name": "finish", "args": {}}}

        class Argument:
            def __init__(self, name, arg_type):
                self.name = name
                self.type = arg_type

        class Action:
            def __init__(self, name, description, args):
                self.name = name
                self.description = description


        :meta private:
        """
        # success: boolean, message: string, action: string, thought: string
        # success is a boolean indicating whether the action was successful
        # message is the error message that will be displayed to the user if success == false
        # example: {'success': True, 'message' = 'success', 'thought': "I should first set the value in the search field to '...'", 'action': 'setValue(93, "...")', 'parsedAction': {'name': 'setValue', 'args': {'elementId': 93, 'value': '...'}}}
        return ["success", "message", "action", "thought", "parsedAction"]

    #example case: _format_error_output({"error": "This model's maximum context length is 8192 tokens. However, your messages resulted in 8243 tokens. Please reduce the length of the messages."})
    #you need to input like the example, i.e. stringfy the error thrown and put it in a dict with the key "error"
    def _format_error_output(self, error_output: Dict[str, str]) -> Dict[str, Any]:
        return {
            "success": False,
            "message": error_output["error"],
            "action": "error",
            "thought": error_output["error"],
            "parsedAction": {"name": "error", "args": {}},
        }

    def parse_response(self, text):
        if "finish" in text:
            thought_match = re.search("<Thought>(.*?)</Thought>", text)
            if thought_match is None:
                return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})
            thought = thought_match.group(1)
            action_string = "finish"
            parsed_action = "finish"
            return {"thought": thought, "action": action_string, "parsedAction": {"name": "finish", "args": {}}}

        class Argument:
            def __init__(self, name, arg_type):
                self.name = name
                self.type = arg_type

        class Action:
            def __init__(self, name, description, args):
                self.name = name
                self.description = description
                self.args = [Argument(arg["name"], arg["type"]) for arg in args]

        available_actions = [
            Action("click", "Clicks on an element", [{"name": "elementId", "type": "number"}]),
            Action(
                "setValue",
                "Focuses on and sets the value of an input element. Must set a proper value which aligns to the user's request and the function of the input box.",
                [{"name": "elementId", "type": "number"}, {"name": "value", "type": "string"}],
            ),
            Action("finish", "Indicates the task is finished(i.e. the info in the new page is enough for user's request or the task has been successfully completed).", []),
            Action("fail", "Indicates that you are unable to complete the task", []),
        ]
        thought_match = re.search("<Thought>\s*(.*?)\s*</Thought>", text)
        action_match = re.search("<Action>\s*(.*?)\s*</Action>", text)

        if thought_match is None:
            return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})

        if action_match is None:
            return self._format_error_output({"error": "Invalid response: Action not found in the model response."})

        thought = thought_match.group(1)
        action_string = action_match.group(1)
        action_pattern = re.compile("(\w+)\((.*?)\)")
        action_parts = action_pattern.match(action_string)

        if action_parts is None:
            return self._format_error_output({"error": "Invalid action format: Action should be in the format functionName(arg1, arg2, ...)."})

        action_name = action_parts.group(1)
        action_args_string = action_parts.group(2)

        available_action = next((action for action in available_actions if action.name == action_name), None)

        if available_action is None:
            return self._format_error_output({"error": f'Invalid action: "{action_name}" is not a valid action.'})

        # split by "," but only split in the first instance
        args_array = [arg.strip() for arg in action_args_string.split(",", 1) if arg.strip() != ""]
        parsed_args = {}

        if len(args_array) != len(available_action.args):
            return self._format_error_output({
                "error": f'Invalid number of arguments: Expected {len(available_action.args)} for action "{action_name}", but got {len(args_array)}.'
            })

        for i in range(len(args_array)):
            arg = args_array[i]
            expected_arg = available_action.args[i]

            if expected_arg.type == "number":
                try:
                    number_value = int(arg)
                    parsed_args[expected_arg.name] = number_value
                except ValueError:
                    return self._format_error_output({
                        "error": f'Invalid argument type: Expected a number for argument "{expected_arg.name}", but got "{arg}".'
                    })
            elif expected_arg.type == "string":
                match_single = re.match(r"^'((?:[^']|\\')*)'$", arg)
                match_double = re.match(r'^"((?:[^"]|\\")*)"$', arg)
                if match_single is not None:
                    parsed_args[expected_arg.name] = match_single.group(1)
                elif match_double is not None:
                    parsed_args[expected_arg.name] = match_double.group(1)
                else:
                    return self._format_error_output({
                        "error": f'Invalid argument type: Expected a string for argument "{expected_arg.name}", but got "{arg}".'
                    })
            else:
                return self._format_error_output({
                    "error": f'Invalid argument type: Unknown type "{expected_arg.type}" for argument "{expected_arg.name}".'
                })

        parsed_action = {"name": available_action.name, "args": parsed_args}

        return {"thought": thought, "action": action_string, "parsedAction": parsed_action}

    # check the validity of the action, if ok, return (True, ""), else return (False, error message)
    def _check_valid_action(self, html: str, parsed_return: dict) -> Tuple(bool, str):
        parsedAction = parsed_return["parsedAction"]
        action = parsed_return["action"]
        retry_message = ""

        # check if the element id exists in the html (fixme: maybe more validity checking methods can be applied)
        if parsedAction["name"] == "click":
            elementId = parsedAction["args"].get("elementId", None)
            if elementId != None and str(elementId) in html:
                return True, ""
            else:
                retry_message = "The elementId of your last action does not exist in the html, please try again."
                return False, retry_message
        elif parsedAction["name"] == "setValue":
            elementId = parsedAction["args"].get("elementId", None)
            value = parsedAction["args"].get("value", None)
            if elementId != None and value != None and str(elementId) in html:
                return True, ""


                match_single = re.match(r"^'((?:[^']|\\')*)'$", arg)
                match_double = re.match(r'^"((?:[^"]|\\")*)"$', arg)
                if match_single is not None:
                    parsed_args[expected_arg.name] = match_single.group(1)
                elif match_double is not None:
                    parsed_args[expected_arg.name] = match_double.group(1)
                else:
                    return self._format_error_output({
                        "error": f'Invalid argument type: Expected a string for argument "{expected_arg.name}", but got "{arg}".'
                    })
            else:
                return self._format_error_output({
                    "error": f'Invalid argument type: Unknown type "{expected_arg.type}" for argument "{expected_arg.name}".'
                })

        parsed_action = {"name": available_action.name, "args": parsed_args}

        return {"thought": thought, "action": action_string, "parsedAction": parsed_action}

    # check the validity of the action, if ok, return (True, ""), else return (False, error message)
    def _check_valid_action(self, html: str, parsed_return: dict) -> Tuple(bool, str):
        parsedAction = parsed_return["parsedAction"]
        action = parsed_return["action"]
        retry_message = ""

        # check if the element id exists in the html (fixme: maybe more validity checking methods can be applied)
        if parsedAction["name"] == "click":
            elementId = parsedAction["args"].get("elementId", None)
            if elementId != None and str(elementId) in html:
                return True, ""
            else:
                retry_message = "The elementId of your last action does not exist in the html, please try again."
                return False, retry_message
        elif parsedAction["name"] == "setValue":
            elementId = parsedAction["args"].get("elementId", None)
            value = parsedAction["args"].get("value", None)
            if elementId != None and value != None and str(elementId) in html:
                return True, ""
            else:
                retry_message = "The elementId of your last action does not exist in the html, please try again."
                return False, retry_message
        elif "finish" in parsedAction["name"]:
            return True, ""
        elif "fail" in parsedAction["name"]:
            return True, ""
        elif "interrupt" in parsedAction["name"]:
            return True, ""
        # parse error
        elif "error" in parsedAction["name"]:
            retry_message = "Action parse error, please follow the output format and try again."
            return False, retry_message
        else:
            retry_message = "Action not in available actions, please try again."
            return False, retry_message

    def _call(
        self,
        inputs: Dict[str, str],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        # logger.bind(msg_head="ReActWebotChain inputs").trace(inputs)

        _run_manager = run_manager or CallbackManagerForChainRun.get_noop_manager()

        # Get  ["user_query", "previous_actions", "previous_thoughts", "page_info"], and other raw data
        plan = inputs["plan"]
        previous_actions = inputs["previous_actions"]
        previous_thoughts = inputs["previous_thoughts"]
        user_query = inputs["user_query"]
        processed_html = inputs["page_info"]

        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        # Generate the prompt


            value = parsedAction["args"].get("value", None)
            if elementId != None and value != None and str(elementId) in html:
                return True, ""
            else:
                retry_message = "The elementId of your last action does not exist in the html, please try again."
                return False, retry_message
        elif "finish" in parsedAction["name"]:
            return True, ""
        elif "fail" in parsedAction["name"]:
            return True, ""
        elif "interrupt" in parsedAction["name"]:
            return True, ""
        # parse error
        elif "error" in parsedAction["name"]:
            retry_message = "Action parse error, please follow the output format and try again."
            return False, retry_message
        else:
            retry_message = "Action not in available actions, please try again."
            return False, retry_message

    def _call(
        self,
        inputs: Dict[str, str],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        # logger.bind(msg_head="ReActWebotChain inputs").trace(inputs)

        _run_manager = run_manager or CallbackManagerForChainRun.get_noop_manager()

        # Get  ["user_query", "previous_actions", "previous_thoughts", "page_info"], and other raw data
        plan = inputs["plan"]
        previous_actions = inputs["previous_actions"]
        previous_thoughts = inputs["previous_thoughts"]
        user_query = inputs["user_query"]
        processed_html = inputs["page_info"]

        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        # Generate the prompt
        previous_actions_string = "\n".join(
            [
                "<Thought>{}</Thought>\n<Action>{}</Action>".format(thought, action)
                for thought, action in zip(previous_thoughts, previous_actions)
            ]
        )
        if len(previous_actions_string) > 0:
            previous_actions_string  = "You have already taken the following thoughts and actions:\n"+previous_actions_string

        user_prompt = f"The user requests the following task:\n {user_query}\nyou have taken these{previous_actions_string}\nCurrent time: {current_time}\nCurrent page contents:\n{processed_html}"
        # print(user_prompt)

        valid_action = False
        count = 0
        retry_message = ""

        while not valid_action and count < self.max_retry_times:
            try:
                if count == 0:
                    action = self.llm_basic_chain.run(
                    **{
                        "formattedActions": self.formatted_actions,
                        "plan": plan,
                        "user_query": user_query,
                        "previous_actions_string": previous_actions_string,
                        "current_time": current_time,
                        "processed_html": processed_html,
                    }
                )
                else:
                    action = self.llm_retry_chain.run(
                    **{
                        "formattedActions": self.formatted_actions,
                        "plan": plan,
                        "user_query": user_query,
                        "previous_actions_string": previous_actions_string,
                        "current_time": current_time,
                        "processed_html": processed_html,
                        "retry_message": retry_message,
                    }
                )
            except Exception as e:
                print("*"*50)
                print("llm error:",e)
                print("*"*50)
                error_output = {"error": str(e)}
                return self._format_error_output(error_output)

            # print("llm output:",action)

            # Extract from "<Thought>{}</Thought>\n<Action>{}</Action>"
            action = action.split("</Action>")[0] + "</Action>"
            # action: <Thought>I should first set the value in the search field to '...'</Thought>
            #         <Action>setValue(93, "Tao Yu")</Action>
            # print("action:",action)

            # parsed return: {'thought': "I should first set the value in the search field to '...'", 'action': 'setValue(93, "...")', 'parsedAction': {'name': 'setValue', 'args': {'elementId': 93, 'value': '...'}}}
            parsed_return = self.parse_response(action)

            # If parse error, there will be  "success" and "message" key in parsed_return. If no problem, no "success" and "message" key. set its value by setdefault
            parsed_return.setdefault("success", True)
            parsed_return.setdefault("message", "success")

            valid_action, retry_message = self._check_valid_action(processed_html, parsed_return)

        # if "error" not in parsed_return:
            # logger.bind(msg_head="ReActWebotChain generated thought").trace(parsed_return["thought"])
            # logger.bind(msg_head="ReActWebotChain generated action").trace(parsed_return["parsedAction"])

        output = parsed_return

        return output

    @classmethod
    def from_llm(cls, llm: BaseLanguageModel, **kwargs: Any) -> WebotChain:
        """Load from the initial web page and user instruction"""
        llm_basic_chain = LLMChain(
            llm=llm,
            prompt=cls.create_basic_prompt(
                system_prompt=SYSTEM_PROMPT,
                user_prompt=USER_PROMPT,
            ),
        )

        llm_retry_chain = LLMChain(
            llm=llm,
            prompt=cls.create_retry_prompt(
                system_prompt=SYSTEM_PROMPT,
                retry_prompt=RETRY_PROMPT,
            ),
        )


            # print("action:",action)

            # parsed return: {'thought': "I should first set the value in the search field to '...'", 'action': 'setValue(93, "...")', 'parsedAction': {'name': 'setValue', 'args': {'elementId': 93, 'value': '...'}}}
            parsed_return = self.parse_response(action)

            # If parse error, there will be  "success" and "message" key in parsed_return. If no problem, no "success" and "message" key. set its value by setdefault
            parsed_return.setdefault("success", True)
            parsed_return.setdefault("message", "success")

            valid_action, retry_message = self._check_valid_action(processed_html, parsed_return)

        # if "error" not in parsed_return:
            # logger.bind(msg_head="ReActWebotChain generated thought").trace(parsed_return["thought"])
            # logger.bind(msg_head="ReActWebotChain generated action").trace(parsed_return["parsedAction"])

        output = parsed_return

        return output

    @classmethod
    def from_llm(cls, llm: BaseLanguageModel, **kwargs: Any) -> WebotChain:
        """Load from the initial web page and user instruction"""
        llm_basic_chain = LLMChain(
            llm=llm,
            prompt=cls.create_basic_prompt(
                system_prompt=SYSTEM_PROMPT,
                user_prompt=USER_PROMPT,
            ),
        )

        llm_retry_chain = LLMChain(
            llm=llm,
            prompt=cls.create_retry_prompt(
                system_prompt=SYSTEM_PROMPT,
                retry_prompt=RETRY_PROMPT,
            ),
        )

        return cls(
            llm_basic_chain=llm_basic_chain,
            llm_retry_chain=llm_retry_chain,
            **kwargs,
        )


Argument

    #you need to input like the example, i.e. stringfy the error thrown and put it in a dict with the key "error"
    def _format_error_output(self, error_output: Dict[str, str]) -> Dict[str, Any]:
        return {
            "success": False,
            "message": error_output["error"],
            "action": "error",
            "thought": error_output["error"],
            "parsedAction": {"name": "error", "args": {}},
        }

    def parse_response(self, text):
        if "finish" in text:
            thought_match = re.search("<Thought>(.*?)</Thought>", text)
            if thought_match is None:
                return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})
            thought = thought_match.group(1)
            action_string = "finish"
            parsed_action = "finish"
            return {"thought": thought, "action": action_string, "parsedAction": {"name": "finish", "args": {}}}

        class Argument:
            def __init__(self, name, arg_type):
                self.name = name
                self.type = arg_type

        class Action:
            def __init__(self, name, description, args):
                self.name = name
                self.description = description
                self.args = [Argument(arg["name"], arg["type"]) for arg in args]

        available_actions = [
            Action("click", "Clicks on an element", [{"name": "elementId", "type": "number"}]),
            Action(
                "setValue",
                "Focuses on and sets the value of an input element. Must set a proper value which aligns to the user's request and the function of the input box.",
                [{"name": "elementId", "type": "number"}, {"name": "value", "type": "string"}],
            ),
            Action("finish", "Indicates the task is finished(i.e. the info in the new page is enough for user's request or the task has been successfully completed).", []),
            Action("fail", "Indicates that you are unable to complete the task", []),
        ]
        thought_match = re.search("<Thought>\s*(.*?)\s*</Thought>", text)
        action_match = re.search("<Action>\s*(.*?)\s*</Action>", text)


Action

            "action": "error",
            "thought": error_output["error"],
            "parsedAction": {"name": "error", "args": {}},
        }

    def parse_response(self, text):
        if "finish" in text:
            thought_match = re.search("<Thought>(.*?)</Thought>", text)
            if thought_match is None:
                return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})
            thought = thought_match.group(1)
            action_string = "finish"
            parsed_action = "finish"
            return {"thought": thought, "action": action_string, "parsedAction": {"name": "finish", "args": {}}}

        class Argument:
            def __init__(self, name, arg_type):
                self.name = name
                self.type = arg_type

        class Action:
            def __init__(self, name, description, args):
                self.name = name
                self.description = description
                self.args = [Argument(arg["name"], arg["type"]) for arg in args]

        available_actions = [
            Action("click", "Clicks on an element", [{"name": "elementId", "type": "number"}]),
            Action(
                "setValue",
                "Focuses on and sets the value of an input element. Must set a proper value which aligns to the user's request and the function of the input box.",
                [{"name": "elementId", "type": "number"}, {"name": "value", "type": "string"}],
            ),
            Action("finish", "Indicates the task is finished(i.e. the info in the new page is enough for user's request or the task has been successfully completed).", []),
            Action("fail", "Indicates that you are unable to complete the task", []),
        ]
        thought_match = re.search("<Thought>\s*(.*?)\s*</Thought>", text)
        action_match = re.search("<Action>\s*(.*?)\s*</Action>", text)

        if thought_match is None:
            return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})

        if action_match is None:
            return self._format_error_output({"error": "Invalid response: Action not found in the model response."})


            "thought": error_output["error"],
            "parsedAction": {"name": "error", "args": {}},
        }

    def parse_response(self, text):
        if "finish" in text:
            thought_match = re.search("<Thought>(.*?)</Thought>", text)
            if thought_match is None:
                return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})
            thought = thought_match.group(1)
            action_string = "finish"
            parsed_action = "finish"
            return {"thought": thought, "action": action_string, "parsedAction": {"name": "finish", "args": {}}}

        class Argument:
            def __init__(self, name, arg_type):
                self.name = name
                self.type = arg_type

        class Action:
            def __init__(self, name, description, args):
                self.name = name
                self.description = description
                self.args = [Argument(arg["name"], arg["type"]) for arg in args]

        available_actions = [
            Action("click", "Clicks on an element", [{"name": "elementId", "type": "number"}]),
            Action(
                "setValue",
                "Focuses on and sets the value of an input element. Must set a proper value which aligns to the user's request and the function of the input box.",
                [{"name": "elementId", "type": "number"}, {"name": "value", "type": "string"}],
            ),
            Action("finish", "Indicates the task is finished(i.e. the info in the new page is enough for user's request or the task has been successfully completed).", []),
            Action("fail", "Indicates that you are unable to complete the task", []),
        ]
        thought_match = re.search("<Thought>\s*(.*?)\s*</Thought>", text)
        action_match = re.search("<Action>\s*(.*?)\s*</Action>", text)

        if thought_match is None:
            return self._format_error_output({"error": "Invalid response: Thought not found in the model response."})

        if action_match is None:
            return self._format_error_output({"error": "Invalid response: Action not found in the model response."})


SYSTEM_PROMPT = (
    """
You are a browser automation assistant.

You will be given a user request and DOM of current webpage at a time, you need to take one action at a time and finally finish the task.

The last page you visited will be further fed into another model who is responsible for chatting with the user.

You MUST take one of the following actions. NEVER EVER EVER make up actions that do not exist:

{formattedActions}

You will be be given a task to perform and the current state of the DOM. You will also be given previous actions that you have taken. You may retry a failed action up to one time.

This is an example of an action:

<Thought>I should click the add to cart button</Thought>
<Action>click(223)</Action>

You MUST always include the <Thought> and <Action> open/close tags or else your response will be marked as invalid.

Rules you MUST follow:
1. If you input something to a search box, YOU MUST FOLLOW:
    1.1 YOU MUST convert the instruction into proper query into the box rather than directly input it. e.g. YOU MUST input New York rather than New York apartments in the input box of zillow.com when user request about New York apartments.
    1.1 If there are some options pop out, you MUST NOT directly go to next action. You MUST click one of the options.
2. You must only take one step at a time. You cannot take multiple actions in a single response.
3. You should check whether your action last time was successful. If not, you should retry once. If it still fails, you should try another way.
    example 1: The box should be clicked and choose from the options and you just setValue and failed, you may consider to use click and then click the option.
    example 2: You click a button once but after checking the page you found that the button is not clicked, you should retry once.
4. You should not consider the action to present the result to the user. You only need to do available actions. If info in current page is enough for the user to solve the problem, you should finish.
5. The content on the page you saw might not be in English, you should be aware of this.

{plan}

Remember: you do not need to follow this plan exactly, but you MUST follow the rules above.
YOU MUST MUST check whether there are some options pop out if your last action is setValue. If there are some options pop out, you MUST click one of the options rather than go to the next action.
The id of the elements can be different each time. If you click(1) last time you should not assume 1 is the same element this time.
""".strip()
    + "\n"
)

USER_PROMPT = (
    """
The user requests the following task:

{user_query}

{previous_actions_string}

Current time: {current_time}

Current page contents:
{processed_html}
""".strip()
    + "\n"
)

RETRY_PROMPT = (
    """
The user requests the following task:

{user_query}

{previous_actions_string}

Current time: {current_time}

Current page contents:
{processed_html}

Your last answer has some problem:
{retry_message}
""".strip()
    + "\n"
)


from __future__ import annotations

from typing import Any, Optional, Sequence

from langchain.base_language import BaseLanguageModel
from langchain.tools.base import BaseTool

from real_agents.adapters.agent_helpers import AgentExecutor
from real_agents.data_agent.copilot import ConversationalChatAgent
from real_agents.plugins_agent.plugin import ConversationalPluginChatAgent
from real_agents.web_agent.webot import ConversationalWebotChatAgent

def initialize_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        callback_manager: CallbackManager to use. Global callback manager is used if
            not provided. Defaults to None.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_plugin_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalPluginChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_webot_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalWebotChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor


from __future__ import annotations

from typing import Any, Optional, Sequence

from langchain.base_language import BaseLanguageModel
from langchain.tools.base import BaseTool

from real_agents.adapters.agent_helpers import AgentExecutor
from real_agents.data_agent.copilot import ConversationalChatAgent
from real_agents.plugins_agent.plugin import ConversationalPluginChatAgent
from real_agents.web_agent.webot import ConversationalWebotChatAgent

def initialize_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        callback_manager: CallbackManager to use. Global callback manager is used if
            not provided. Defaults to None.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_plugin_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:


        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_plugin_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalPluginChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_webot_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:


        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalPluginChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor

def initialize_webot_agent(
    tools: Sequence[BaseTool],
    llm: BaseLanguageModel,
    continue_model: str = None,
    agent_kwargs: Optional[dict] = None,
    return_intermediate_steps: Optional[bool] = True,
    **kwargs: Any,
) -> AgentExecutor:
    """Load an agent executor given tools and LLM.

    Args:
        tools: List of tools this agent has access to.
        llm: Language model to use as the agent.
        agent_kwargs: Additional key word arguments to pass to the underlying agent_executor
        return_intermediate_steps: Whether to return intermediate steps in the agent
        **kwargs: Additional key word arguments passed to the agent executor

    Returns:
        An agent executor
    """

    agent_kwargs = agent_kwargs or {}
    agent_obj = ConversationalWebotChatAgent.from_llm_and_tools(
        llm=llm, tools=tools, continue_model=continue_model, **agent_kwargs
    )

    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent_obj,
        tools=tools,
        return_intermediate_steps=return_intermediate_steps,
        **kwargs,
    )
    return agent_executor


"""Chain that just formats a prompt and calls an LLM."""
from __future__ import annotations

from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
from pydantic import Extra

from langchain.base_language import BaseLanguageModel
from langchain.callbacks.manager import (
    AsyncCallbackManager,
    AsyncCallbackManagerForChainRun,
    CallbackManager,
    CallbackManagerForChainRun,
    Callbacks,
)
from langchain.chains.base import Chain
from langchain.input import get_colored_text
from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.schema import LLMResult, PromptValue

from real_agents.adapters.data_model import DataModel

class LLMChain(Chain):
    """Chain to run queries against LLMs.

    Example:
        .. code-block:: python

            from langchain import LLMChain, OpenAI, PromptTemplate
            prompt_template = "Tell me a {adjective} joke"
            prompt = PromptTemplate(
                input_variables=["adjective"], template=prompt_template
            )
            llm = LLMChain(llm=OpenAI(), prompt=prompt)
    """

    prompt: BasePromptTemplate
    """Prompt object to use."""
    llm: BaseLanguageModel
    output_key: str = "text"  #: :meta private:

    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = await self.aprep_prompts(input_list, run_manager=run_manager)
        return await self.llm.agenerate_prompt(
            prompts, stop, callbacks=run_manager.get_child() if run_manager else None
        )

    def prep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    async def aprep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                await run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    def apply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = CallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = self.generate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = await callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:
        """Create LLMChain from LLM and template."""
        prompt_template = PromptTemplate.from_template(template)
        return cls(llm=llm, prompt=prompt_template)


LLMChain

from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
from pydantic import Extra

from langchain.base_language import BaseLanguageModel
from langchain.callbacks.manager import (
    AsyncCallbackManager,
    AsyncCallbackManagerForChainRun,
    CallbackManager,
    CallbackManagerForChainRun,
    Callbacks,
)
from langchain.chains.base import Chain
from langchain.input import get_colored_text
from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.schema import LLMResult, PromptValue

from real_agents.adapters.data_model import DataModel

class LLMChain(Chain):
    """Chain to run queries against LLMs.

    Example:
        .. code-block:: python

            from langchain import LLMChain, OpenAI, PromptTemplate
            prompt_template = "Tell me a {adjective} joke"
            prompt = PromptTemplate(
                input_variables=["adjective"], template=prompt_template
            )
            llm = LLMChain(llm=OpenAI(), prompt=prompt)
    """

    prompt: BasePromptTemplate
    """Prompt object to use."""
    llm: BaseLanguageModel
    output_key: str = "text"  #: :meta private:

    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = await self.aprep_prompts(input_list, run_manager=run_manager)
        return await self.llm.agenerate_prompt(
            prompts, stop, callbacks=run_manager.get_child() if run_manager else None
        )

    def prep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    async def aprep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                await run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    def apply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = CallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = self.generate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = await callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:
        """Create LLMChain from LLM and template."""
        prompt_template = PromptTemplate.from_template(template)
        return cls(llm=llm, prompt=prompt_template)


Config

class LLMChain(Chain):
    """Chain to run queries against LLMs.

    Example:
        .. code-block:: python

            from langchain import LLMChain, OpenAI, PromptTemplate
            prompt_template = "Tell me a {adjective} joke"
            prompt = PromptTemplate(
                input_variables=["adjective"], template=prompt_template
            )
            llm = LLMChain(llm=OpenAI(), prompt=prompt)
    """

    prompt: BasePromptTemplate
    """Prompt object to use."""
    llm: BaseLanguageModel
    output_key: str = "text"  #: :meta private:

    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],


            from langchain import LLMChain, OpenAI, PromptTemplate
            prompt_template = "Tell me a {adjective} joke"
            prompt = PromptTemplate(
                input_variables=["adjective"], template=prompt_template
            )
            llm = LLMChain(llm=OpenAI(), prompt=prompt)
    """

    prompt: BasePromptTemplate
    """Prompt object to use."""
    llm: BaseLanguageModel
    output_key: str = "text"  #: :meta private:

    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]


    prompt: BasePromptTemplate
    """Prompt object to use."""
    llm: BaseLanguageModel
    output_key: str = "text"  #: :meta private:

    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger


        extra = Extra.forbid
        arbitrary_types_allowed = True

    @property
    def input_keys(self) -> List[str]:
        """Will be whatever keys the prompt expects.

        :meta private:
        """
        return self.prompt.input_variables

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],


generate

    @property
    def output_keys(self) -> List[str]:
        """Will always return text key.

        :meta private:
        """
        return [self.output_key]

    def _call(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        for k, v in inputs.items():
            if isinstance(v, DataModel):
                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = await self.aprep_prompts(input_list, run_manager=run_manager)
        return await self.llm.agenerate_prompt(
            prompts, stop, callbacks=run_manager.get_child() if run_manager else None
        )

    def prep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:


agenerate

                inputs[k] = v.get_llm_side_data()
        response = self.generate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def generate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = self.prep_prompts(input_list, run_manager=run_manager)
        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = await self.aprep_prompts(input_list, run_manager=run_manager)
        return await self.llm.agenerate_prompt(
            prompts, stop, callbacks=run_manager.get_child() if run_manager else None
        )

    def prep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")


        from loguru import logger

        logger.trace(
            "\n================<prompt>================\n"
            + prompts[0].to_string()
            + "\n================</prompt>================\n"
        )
        return self.llm.generate_prompt(prompts, stop, callbacks=run_manager.get_child() if run_manager else None)

    async def agenerate(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> LLMResult:
        """Generate LLM result from inputs."""
        prompts, stop = await self.aprep_prompts(input_list, run_manager=run_manager)
        return await self.llm.agenerate_prompt(
            prompts, stop, callbacks=run_manager.get_child() if run_manager else None
        )

    def prep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    async def aprep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                await run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")


        input_list: List[Dict[str, Any]],
        run_manager: Optional[CallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    async def aprep_prompts(
        self,
        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                await run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    def apply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = CallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = self.generate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)


apply

        input_list: List[Dict[str, Any]],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Tuple[List[PromptValue], Optional[List[str]]]:
        """Prepare prompts from inputs."""
        stop = None
        if "stop" in input_list[0]:
            stop = input_list[0]["stop"]
        prompts = []
        for inputs in input_list:
            selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
            prompt = self.prompt.format_prompt(**selected_inputs)
            _colored_text = get_colored_text(prompt.to_string(), "green")
            _text = "Prompt after formatting:\n" + _colored_text
            if run_manager:
                await run_manager.on_text(_text, end="\n", verbose=self.verbose)
            if "stop" in inputs and inputs["stop"] != stop:
                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    def apply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = CallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = self.generate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = await callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [


aapply

                raise ValueError("If `stop` is present in any inputs, should be present in all.")
            prompts.append(prompt)
        return prompts, stop

    def apply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = CallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = self.generate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = await callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.


        outputs = self.create_outputs(response)
        run_manager.on_chain_end({"outputs": outputs})
        return outputs

    async def aapply(self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None) -> List[Dict[str, str]]:
        """Utilize the LLM generate method for speed gains."""
        callback_manager = AsyncCallbackManager.configure(callbacks, self.callbacks, self.verbose)
        run_manager = await callback_manager.on_chain_start(
            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:


            {"name": self.__class__.__name__},
            {"input_list": input_list},
        )
        try:
            response = await self.agenerate(input_list, run_manager=run_manager)
        except (KeyboardInterrupt, Exception) as e:
            await run_manager.on_chain_error(e)
            raise e
        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.


predict

        outputs = self.create_outputs(response)
        await run_manager.on_chain_end({"outputs": outputs})
        return outputs

    def create_outputs(self, response: LLMResult) -> List[Dict[str, str]]:
        """Create outputs from response."""
        return [
            # Get the text of the top generated string.
            {self.output_key: generation[0].text}
            for generation in response.generations
        ]

    async def _acall(
        self,
        inputs: Dict[str, Any],
        run_manager: Optional[AsyncCallbackManagerForChainRun] = None,
    ) -> Dict[str, str]:
        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""


apredict

        response = await self.agenerate([inputs], run_manager=run_manager)
        return self.create_outputs(response)[0]

    def predict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(


        """
        return self(kwargs, callbacks=callbacks)[self.output_key]

    async def apredict(self, callbacks: Callbacks = None, **kwargs: Any) -> str:
        """Format prompt with kwargs and pass to LLM.

        Args:
            callbacks: Callbacks to pass to LLMChain
            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:


            **kwargs: Keys to pass to prompt template.

        Returns:
            Completion from LLM.

        Example:
            .. code-block:: python

                completion = llm.predict(adjective="funny")
        """
        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)


        return (await self.acall(kwargs, callbacks=callbacks))[self.output_key]

    def predict_and_parse(self, callbacks: Callbacks = None, **kwargs: Any) -> Union[str, List[str], Dict[str, Any]]:
        """Call predict and then parse the results."""
        result = self.predict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:


        else:
            return result

    async def apredict_and_parse(
        self, callbacks: Callbacks = None, **kwargs: Any
    ) -> Union[str, List[str], Dict[str, str]]:
        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:
        """Create LLMChain from LLM and template."""
        prompt_template = PromptTemplate.from_template(template)
        return cls(llm=llm, prompt=prompt_template)


        """Call apredict and then parse the results."""
        result = await self.apredict(callbacks=callbacks, **kwargs)
        if self.prompt.output_parser is not None:
            return self.prompt.output_parser.parse(result)
        else:
            return result

    def apply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:
        """Create LLMChain from LLM and template."""
        prompt_template = PromptTemplate.from_template(template)
        return cls(llm=llm, prompt=prompt_template)


        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = self.apply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    def _parse_result(self, result: List[Dict[str, str]]) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        if self.prompt.output_parser is not None:
            return [self.prompt.output_parser.parse(res[self.output_key]) for res in result]
        else:
            return result

    async def aapply_and_parse(
        self, input_list: List[Dict[str, Any]], callbacks: Callbacks = None
    ) -> Sequence[Union[str, List[str], Dict[str, str]]]:
        """Call apply and then parse the results."""
        result = await self.aapply(input_list, callbacks=callbacks)
        return self._parse_result(result)

    @property
    def _chain_type(self) -> str:
        return "llm_chain"

    @classmethod
    def from_string(cls, llm: BaseLanguageModel, template: str) -> Chain:
        """Create LLMChain from LLM and template."""
        prompt_template = PromptTemplate.from_template(template)
        return cls(llm=llm, prompt=prompt_template)