diff --git a/src/backend/base/langflow/components/agents/__init__.py b/src/backend/base/langflow/components/agents/__init__.py index ec446dae9ef..245c38a9760 100644 --- a/src/backend/base/langflow/components/agents/__init__.py +++ b/src/backend/base/langflow/components/agents/__init__.py @@ -1,12 +1,5 @@ -from .agent import Agent -from .agent_action_router import AgentActionRouter -from .agent_context import AgentContextBuilder -from .check_termination import CheckTerminationComponent from .crewai import CrewAIAgentComponent from .csv import CSVAgentComponent -from .decide_action import DecideActionComponent -from .execute_action import ExecuteActionComponent -from .generate_thought import GenerateThoughtComponent from .hierarchical_crew import HierarchicalCrewComponent from .json import JsonAgentComponent from .openai_tools import OpenAIToolsAgentComponent @@ -17,14 +10,9 @@ from .tool_calling import ToolCallingAgentComponent from .vector_store import VectorStoreAgentComponent from .vector_store_router import VectorStoreRouterAgentComponent -from .write_final_answer import ProvideFinalAnswerComponent -from .write_observation import ObserveResultComponent from .xml import XMLAgentComponent __all__ = [ - "AgentActionRouter", - "AgentContextBuilder", - "CheckTerminationComponent", "CSVAgentComponent", "CrewAIAgentComponent", "HierarchicalCrewComponent", @@ -35,17 +23,7 @@ "SequentialCrewComponent", "SequentialTaskAgentComponent", "ToolCallingAgentComponent", - "DecideActionComponent", - "ExecuteActionComponent", - "GenerateThoughtComponent", - "JsonAgentComponent", - "ObserveResultComponent", - "ProvideFinalAnswerComponent", - "SQLAgentComponent", - "UpdateContextComponent", - "UserInputComponent", "VectorStoreAgentComponent", "VectorStoreRouterAgentComponent", "XMLAgentComponent", - "Agent", ] diff --git a/src/backend/base/langflow/components/agents/agent.py b/src/backend/base/langflow/components/agents/agent.py deleted file mode 100644 index 08eab4b28a9..00000000000 --- a/src/backend/base/langflow/components/agents/agent.py +++ /dev/null @@ -1,105 +0,0 @@ -from loguru import logger - -from langflow.components.agents.agent_action_router import AgentActionRouter -from langflow.components.agents.agent_context import AgentContextBuilder -from langflow.components.agents.decide_action import DecideActionComponent -from langflow.components.agents.execute_action import ExecuteActionComponent -from langflow.components.agents.generate_thought import GenerateThoughtComponent -from langflow.components.agents.write_final_answer import ProvideFinalAnswerComponent -from langflow.components.inputs.chat import ChatInput -from langflow.components.outputs import ChatOutput -from langflow.components.prompts import PromptComponent -from langflow.custom import Component -from langflow.graph.graph.base import Graph -from langflow.graph.state.model import create_state_model -from langflow.io import BoolInput, HandleInput, IntInput, MessageTextInput, MultilineInput, Output -from langflow.schema.message import Message - - -class Agent(Component): - display_name = "Agent" - description = "Customizable Agent component" - - inputs = [ - HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True), - HandleInput(name="tools", display_name="Tools", input_types=["Tool"], is_list=True, required=True), - IntInput(name="max_iterations", display_name="Max Iterations", value=5), - BoolInput(name="verbose", display_name="Verbose", value=False), - MultilineInput(name="system_prompt", display_name="System Prompt", value="You are a helpful assistant."), - MultilineInput(name="user_prompt", display_name="User Prompt", value="{input}"), - MultilineInput( - name="loop_prompt", - display_name="Loop Prompt", - value="Last Action Result: {last_action_result}\nBased on the actions taken, here's the final answer:", - ), - MessageTextInput( - name="decide_action_prompt", - display_name="Decide Action Prompt", - value="Based on your thought, decide the best action to take next.", - advanced=True, - ), - MessageTextInput( - name="final_answer_prompt", - display_name="Final Answer Prompt", - value="Considering all observations, provide the final answer to the user's query.", - advanced=True, - ), - ] - outputs = [Output(name="response", display_name="Response", method="get_response")] - - async def get_response(self) -> Message: - # Chat input initialization - chat_input = ChatInput().set(input_value=self.user_prompt) - - # Agent Context Builder - agent_context = AgentContextBuilder().set( - initial_context=chat_input.message_response, - tools=self.tools, - llm=self.llm, - max_iterations=self.max_iterations, - ) - - # Generate Thought - generate_thought = GenerateThoughtComponent().set( - agent_context=agent_context.build_context, - ) - - # Decide Action - decide_action = DecideActionComponent().set( - agent_context=generate_thought.generate_thought, - prompt=self.decide_action_prompt, - ) - - # Agent Action Router - action_router = AgentActionRouter().set( - agent_context=decide_action.decide_action, - max_iterations=self.max_iterations, - ) - - # Execute Action - execute_action = ExecuteActionComponent().set(agent_context=action_router.route_to_execute_tool) - # Loop Prompt - loop_prompt = PromptComponent().set( - template=self.loop_prompt, - answer=execute_action.execute_action, - ) - - generate_thought.set(prompt=loop_prompt.build_prompt) - - # Final Answer - final_answer = ProvideFinalAnswerComponent().set( - agent_context=action_router.route_to_final_answer, - prompt=self.final_answer_prompt, - ) - - # Chat output - chat_output = ChatOutput().set(input_value=final_answer.get_final_answer) - output_model = create_state_model("AgentOutput", output=chat_output.message_response) - - # Build the graph - graph = Graph(chat_input, chat_output) - async for result in graph.async_start(max_iterations=self.max_iterations): - if self.verbose: - logger.info(result) - - return output_model.output diff --git a/src/backend/base/langflow/components/agents/agent_action_router.py b/src/backend/base/langflow/components/agents/agent_action_router.py deleted file mode 100644 index b0e5ccd8f60..00000000000 --- a/src/backend/base/langflow/components/agents/agent_action_router.py +++ /dev/null @@ -1,55 +0,0 @@ -from langchain.schema.agent import AgentFinish - -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, IntInput, Output - - -class AgentActionRouter(Component): - display_name = "Agent Action Router" - description = "Routes the agent's flow based on the last action type." - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.__iteration_updated = False - - inputs = [ - HandleInput(name="agent_context", display_name="Agent Context", input_types=["AgentContext"], required=True), - IntInput(name="max_iterations", display_name="Max Interations", required=True, value=5), - ] - - outputs = [ - Output(name="execute_tool", display_name="Execute Tool", method="route_to_execute_tool", cache=False), - Output(name="final_answer", display_name="Final Answer", method="route_to_final_answer", cache=False), - ] - - def _pre_run_setup(self): - self.__iteration_updated = False - - def _get_context_message_and_route_to_stop(self) -> tuple[str, str]: - if ( - isinstance(self.agent_context.last_action, AgentFinish) - or self.agent_context.iteration >= self.agent_context.max_iterations - ): - return "Provide Final Answer", "execute_tool" - return "Execute Tool", "final_answer" - - def iterate_and_stop_once(self, route_to_stop: str): - if not self.__iteration_updated: - self.agent_context.iteration += 1 - self.__iteration_updated = True - self.stop(route_to_stop) - - def route_to_execute_tool(self) -> AgentContext: - context_message, route_to_stop = self._get_context_message_and_route_to_stop() - self.agent_context.update_context("Router Decision", context_message) - self.iterate_and_stop_once(route_to_stop) - self.status = self.agent_context.to_data_repr() - return self.agent_context - - def route_to_final_answer(self) -> AgentContext: - context_message, route_to_stop = self._get_context_message_and_route_to_stop() - self.agent_context.update_context("Router Decision", context_message) - self.iterate_and_stop_once(route_to_stop) - self.status = self.agent_context.to_data_repr() - return self.agent_context diff --git a/src/backend/base/langflow/components/agents/agent_context.py b/src/backend/base/langflow/components/agents/agent_context.py deleted file mode 100644 index 0ec44fe27a8..00000000000 --- a/src/backend/base/langflow/components/agents/agent_context.py +++ /dev/null @@ -1,27 +0,0 @@ -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, IntInput, MessageTextInput, Output - - -class AgentContextBuilder(Component): - display_name = "Agent Context Builder" - description = "Builds the AgentContext instance for the agent execution loop." - - inputs = [ - HandleInput(name="tools", display_name="Tools", input_types=["Tool"], is_list=True, required=True), - HandleInput(name="llm", display_name="Language Model", input_types=["LanguageModel"], required=True), - MessageTextInput(name="initial_context", display_name="Initial Context", required=False), - IntInput(name="max_iterations", display_name="Max Iterations", value=5, required=False), - ] - - outputs = [Output(name="agent_context", display_name="Agent Context", method="build_context")] - - def build_context(self) -> AgentContext: - tools = [self.tools] if self.tools and not isinstance(self.tools, list) else self.tools - - tools_dict = {tool.name: tool for tool in tools} - context = AgentContext(tools=tools_dict, llm=self.llm, context=self.initial_context or "", iteration=0) - if self.max_iterations is not None: - context.max_iterations = self.max_iterations - self.status = context.to_data_repr() - return context diff --git a/src/backend/base/langflow/components/agents/check_termination.py b/src/backend/base/langflow/components/agents/check_termination.py deleted file mode 100644 index 3013114e547..00000000000 --- a/src/backend/base/langflow/components/agents/check_termination.py +++ /dev/null @@ -1,23 +0,0 @@ -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, Output - - -class CheckTerminationComponent(Component): - display_name = "Check Termination" - description = "Checks if the agent should terminate or continue the loop." - - inputs = [ - HandleInput(name="agent_context", input_types=["AgentContext"], required=True), - ] - - outputs = [ - Output(name="agent_context", method="check_termination"), - ] - - def check_termination(self) -> AgentContext: - should_continue = ( - self.agent_context.iteration < self.agent_context.max_iterations - and not self.agent_context.llm.should_terminate(self.agent_context.context) - ) - return should_continue, self.agent_context diff --git a/src/backend/base/langflow/components/agents/decide_action.py b/src/backend/base/langflow/components/agents/decide_action.py deleted file mode 100644 index a51c8a9380a..00000000000 --- a/src/backend/base/langflow/components/agents/decide_action.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import TYPE_CHECKING - -from langchain.agents.output_parsers.tools import parse_ai_message_to_tool_action - -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, MessageTextInput, Output - -if TYPE_CHECKING: - from langchain_core.messages import AIMessage - - -class DecideActionComponent(Component): - display_name = "Decide Action" - description = "Decides on an action based on the current thought and context." - - inputs = [ - HandleInput(name="agent_context", display_name="Agent Context", input_types=["AgentContext"], required=True), - MessageTextInput( - name="prompt", - display_name="Prompt", - required=True, - value="Based on your thought, decide the best action to take next.", - ), - ] - - outputs = [Output(name="processed_agent_context", display_name="Agent Context", method="decide_action")] - - def decide_action(self) -> AgentContext: - # Append the prompt after the accumulated context following ReAct format - full_prompt = f"{self.agent_context.get_full_context()}\n{self.prompt}\nAction:" - response: AIMessage = self.agent_context.llm.invoke(full_prompt) - action = parse_ai_message_to_tool_action(response) - if isinstance(action, list): - self.agent_context.last_action = action[0] - else: - self.agent_context.last_action = action - self.agent_context.update_context("Action", action) - self.status = self.agent_context.to_data_repr() - return self.agent_context diff --git a/src/backend/base/langflow/components/agents/execute_action.py b/src/backend/base/langflow/components/agents/execute_action.py deleted file mode 100644 index be0bf0deadc..00000000000 --- a/src/backend/base/langflow/components/agents/execute_action.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import TYPE_CHECKING - -from langflow.custom import Component -from langflow.io import HandleInput, Output -from langflow.schema.message import Message - -if TYPE_CHECKING: - from langchain_core.agents import AgentAction - - -class ExecuteActionComponent(Component): - display_name = "Execute Action" - description = "Executes the decided action using available tools." - - inputs = [ - HandleInput(name="agent_context", display_name="Agent Context", input_types=["AgentContext"], required=True), - ] - - outputs = [Output(name="action_execution", display_name="Agent Context", method="execute_action")] - - def execute_action(self) -> Message: - action: AgentAction = self.agent_context.last_action - - tools = self.agent_context.tools - if action.tool in tools: - data = tools[action.tool](action.tool_input) - self.agent_context.last_action_result = data - self.agent_context.update_context("Action Result", data) - else: - error_msg = f"Error: Action '{action}' not found in available tools." - self.agent_context.last_action_result = error_msg - self.agent_context.update_context("Action Result", error_msg) - tool_call_result = f"Tool: {action.tool} called with input: {action.tool_input} and returned: {data}" - self.status = self.agent_context.to_data_repr() - return Message(text=tool_call_result) diff --git a/src/backend/base/langflow/components/agents/generate_thought.py b/src/backend/base/langflow/components/agents/generate_thought.py deleted file mode 100644 index 47b7428ac30..00000000000 --- a/src/backend/base/langflow/components/agents/generate_thought.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import TYPE_CHECKING - -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, MessageTextInput, Output - -if TYPE_CHECKING: - from langchain_core.messages import AIMessage - - -class GenerateThoughtComponent(Component): - display_name = "Generate Thought" - description = "Generates a thought based on the current context." - - inputs = [ - HandleInput( - name="agent_context", - display_name="Agent Context", - input_types=["AgentContext"], - required=True, - ), - MessageTextInput( - name="prompt", - display_name="Prompt", - required=True, - value="Based on the provided context, generate your next thought.", - ), - ] - - outputs = [Output(name="processed_agent_context", display_name="Agent Context", method="generate_thought")] - - def generate_thought(self) -> AgentContext: - # Append the prompt after the accumulated context following ReAct format - full_prompt = f"{self.agent_context.get_full_context()}\n{self.prompt}\nThought:" - thought: AIMessage = self.agent_context.llm.invoke(full_prompt) - self.agent_context.thought = thought - self.agent_context.update_context("Thought", thought) - self.status = self.agent_context.to_data_repr() - return self.agent_context diff --git a/src/backend/base/langflow/components/agents/observe_result.py b/src/backend/base/langflow/components/agents/observe_result.py deleted file mode 100644 index bd06d1cc994..00000000000 --- a/src/backend/base/langflow/components/agents/observe_result.py +++ /dev/null @@ -1,27 +0,0 @@ -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, MessageTextInput, Output - - -class ObserveResultComponent(Component): - display_name = "Observe Result" - description = "Observes and processes the result of the executed action." - - inputs = [ - HandleInput(name="agent_context", input_types=["AgentContext"], required=True), - MessageTextInput( - name="prompt", - display_name="Prompt", - required=True, - value="Analyze the result of the action and provide an observation.", - ), - ] - - outputs = [Output(name="agent_context", method="observe_result")] - - def observe_result(self) -> AgentContext: - # Append the prompt after the accumulated context following ReAct format - full_prompt = f"{self.agent_context.get_full_context()}\n{self.prompt}\nObservation:" - observation = self.agent_context.llm.invoke(full_prompt).strip() - self.agent_context.update_context("Observation", observation) - return self.agent_context diff --git a/src/backend/base/langflow/components/agents/write_final_answer.py b/src/backend/base/langflow/components/agents/write_final_answer.py deleted file mode 100644 index 2c7b9d33c66..00000000000 --- a/src/backend/base/langflow/components/agents/write_final_answer.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import TYPE_CHECKING - -from langflow.custom import Component -from langflow.io import HandleInput, MessageTextInput, Output -from langflow.schema.message import Message - -if TYPE_CHECKING: - from langchain_core.messages import AIMessage - - -class ProvideFinalAnswerComponent(Component): - display_name = "Provide Final Answer" - description = "Generates the final answer based on the agent's context." - - inputs = [ - HandleInput(name="agent_context", display_name="Agent Context", input_types=["AgentContext"], required=True), - MessageTextInput( - name="prompt", - display_name="Prompt", - required=True, - value="Considering all observations, provide the final answer to the user's query.", - ), - ] - - outputs = [Output(name="final_answer", method="get_final_answer")] - - def get_final_answer(self) -> Message: - # Append the prompt after the accumulated context following ReAct format - full_prompt = f"{self.agent_context.get_full_context()}\n{self.prompt}\nFinal Answer:" - final_answer: AIMessage = self.agent_context.llm.invoke(full_prompt) - self.agent_context.final_answer = final_answer - self.agent_context.update_context("Final Answer", final_answer) - self.status = self.agent_context.to_data_repr() - return Message(text=final_answer.content) diff --git a/src/backend/base/langflow/components/agents/write_observation.py b/src/backend/base/langflow/components/agents/write_observation.py deleted file mode 100644 index ebac1fb04fe..00000000000 --- a/src/backend/base/langflow/components/agents/write_observation.py +++ /dev/null @@ -1,22 +0,0 @@ -from langflow.base.agents.context import AgentContext -from langflow.custom import Component -from langflow.io import HandleInput, MessageTextInput, Output - - -class ObserveResultComponent(Component): - display_name = "Observe Result" - description = "Observes and processes the result of the executed action." - - inputs = [ - HandleInput(name="agent_context", display_name="Agent Context", input_types=["AgentContext"], required=True), - MessageTextInput(name="prompt", display_name="Prompt", required=True), - ] - - outputs = [Output(name="observation", display_name="Observation", method="observe_result")] - - def observe_result(self) -> AgentContext: - # Move the prompt to the end of the context - full_prompt = f"{self.agent_context.get_full_context()}\n{self.prompt}" - observation = self.agent_context.llm.invoke(full_prompt) - self.agent_context.update_context(f"Observation: {observation}") - return self.agent_context