diff --git a/src/backend/langflow/base/agents/__init__.py b/src/backend/langflow/base/agents/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/base/agents/agent.py b/src/backend/langflow/base/agents/agent.py new file mode 100644 index 000000000..8dac73e61 --- /dev/null +++ b/src/backend/langflow/base/agents/agent.py @@ -0,0 +1,70 @@ +from typing import List, Union + +from langchain.agents import AgentExecutor, BaseMultiActionAgent, BaseSingleActionAgent + +from langflow import CustomComponent +from langflow.field_typing import BaseMemory, Text, Tool + + +class LCAgentComponent(CustomComponent): + def build_config(self): + return { + "lc": { + "display_name": "LangChain", + "info": "The LangChain to interact with.", + }, + "handle_parsing_errors": { + "display_name": "Handle Parsing Errors", + "info": "If True, the agent will handle parsing errors. If False, the agent will raise an error.", + "advanced": True, + }, + "output_key": { + "display_name": "Output Key", + "info": "The key to use to get the output from the agent.", + "advanced": True, + }, + "memory": { + "display_name": "Memory", + "info": "Memory to use for the agent.", + }, + "tools": { + "display_name": "Tools", + "info": "Tools the agent can use.", + }, + "input_value": { + "display_name": "Input", + "info": "Input text to pass to the agent.", + }, + } + + async def run_agent( + self, + agent: Union[BaseSingleActionAgent, BaseMultiActionAgent, AgentExecutor], + inputs: str, + input_variables: list[str], + tools: List[Tool], + memory: BaseMemory = None, + handle_parsing_errors: bool = True, + output_key: str = "output", + ) -> Text: + if isinstance(agent, AgentExecutor): + runnable = agent + else: + runnable = AgentExecutor.from_agent_and_tools( + agent=agent, tools=tools, verbose=True, memory=memory, handle_parsing_errors=handle_parsing_errors + ) + input_dict = {"input": inputs} + for var in input_variables: + if var not in ["agent_scratchpad", "input"]: + input_dict[var] = "" + result = await runnable.ainvoke(input_dict) + self.status = result + if output_key in result: + return result.get(output_key) + elif "output" not in result: + if output_key != "output": + raise ValueError(f"Output key not found in result. Tried '{output_key}' and 'output'.") + else: + raise ValueError("Output key not found in result. Tried 'output'.") + + return result.get("output") diff --git a/src/backend/langflow/components/agents/XMLAgent.py b/src/backend/langflow/components/agents/XMLAgent.py index 216c0e1f1..efd5cc010 100644 --- a/src/backend/langflow/components/agents/XMLAgent.py +++ b/src/backend/langflow/components/agents/XMLAgent.py @@ -1,13 +1,13 @@ from typing import List -from langchain.agents import AgentExecutor, create_xml_agent +from langchain.agents import create_xml_agent from langchain_core.prompts import PromptTemplate -from langflow import CustomComponent +from langflow.base.agents.agent import LCAgentComponent from langflow.field_typing import BaseLLM, BaseMemory, Text, Tool -class XMLAgentComponent(CustomComponent): +class XMLAgentComponent(LCAgentComponent): display_name = "XMLAgent" description = "Construct an XML agent from an LLM and tools." @@ -57,7 +57,7 @@ class XMLAgentComponent(CustomComponent): "display_name": "Memory", "info": "Memory to use for the agent.", }, - "inputs": { + "input_value": { "display_name": "Inputs", "info": "Input text to pass to the agent.", }, @@ -65,7 +65,7 @@ class XMLAgentComponent(CustomComponent): async def build( self, - inputs: str, + input_value: str, llm: BaseLLM, tools: List[Tool], prompt: str, @@ -84,13 +84,6 @@ class XMLAgentComponent(CustomComponent): prompt_template = PromptTemplate.from_template(prompt) input_variables = prompt_template.input_variables agent = create_xml_agent(llm, tools, prompt_template, tools_renderer=render_tool_description) - runnable = AgentExecutor.from_agent_and_tools( - agent=agent, tools=tools, verbose=True, memory=memory, handle_parsing_errors=handle_parsing_errors - ) - input_dict = {"input": inputs} - for var in input_variables: - if var not in ["agent_scratchpad", "input"]: - input_dict[var] = "" - result = await runnable.ainvoke(input_dict) + result = await self.run_agent(agent, input_value, input_variables, tools, memory, handle_parsing_errors) self.status = result - return result.get("output") + return result