Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add SimpleAgentComponent and related pytests #4318

Merged
merged 31 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ade883e
simple ai agent
edwinjosechittilappilly Oct 29, 2024
019f3b3
Update simple_agent.py
edwinjosechittilappilly Oct 29, 2024
19f5047
Update simple_agent.py
edwinjosechittilappilly Oct 29, 2024
f685b77
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 29, 2024
32229b6
fix: INP001 ruff error
italojohnny Oct 30, 2024
1c2a482
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Oct 30, 2024
6e75f11
Update test_tool_calling_agent.py
edwinjosechittilappilly Oct 30, 2024
b475c2b
Update simple_agent.py
edwinjosechittilappilly Oct 30, 2024
3c43404
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 30, 2024
91d3c1c
updates in the input field orders
edwinjosechittilappilly Oct 30, 2024
ce911b4
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 30, 2024
29d5a84
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Oct 31, 2024
410ef12
Update simple_agent.py
edwinjosechittilappilly Oct 31, 2024
caea6b1
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 31, 2024
5f9a6d6
lint Errors Solved
edwinjosechittilappilly Oct 31, 2024
4c81f5b
Squashed commit of the following:
edwinjosechittilappilly Oct 31, 2024
894e627
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Oct 31, 2024
1573e3d
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
93ebd78
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
af24643
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
1768278
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
4b91266
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 1, 2024
b9ba913
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
4068681
Update worker.py
edwinjosechittilappilly Nov 1, 2024
fa4b473
[autofix.ci] apply automated fixes
autofix-ci[bot] Nov 1, 2024
574c813
Update worker.py
edwinjosechittilappilly Nov 1, 2024
ce0ac69
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 1, 2024
ae753b1
Merge branch 'main' into feat-simple-agents
edwinjosechittilappilly Nov 2, 2024
8518cbc
update in file names
edwinjosechittilappilly Nov 2, 2024
231d8fd
Update Agent Flow.json
edwinjosechittilappilly Nov 2, 2024
43d2179
fix: attempt to fix frontend integration test
italojohnny Nov 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions src/backend/base/langflow/components/agents/simple_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from langflow.base.models.model import LCModelComponent
from langflow.components.agents.tool_calling import ToolCallingAgentComponent
from langflow.components.models.azure_openai import AzureChatOpenAIComponent
from langflow.components.models.openai import OpenAIModelComponent
from langflow.io import (
DataInput,
DropdownInput,
HandleInput,
MessageTextInput,
Output,
)
from langflow.schema.dotdict import dotdict
from langflow.schema.message import Message


class SimpleAgentComponent(ToolCallingAgentComponent):
display_name: str = "Simple Agent"
description: str = "Agent that uses tools"
icon = "workflow"
beta = True
name = "SimpleAgent"

openai_inputs = [
component_input
for component_input in OpenAIModelComponent().inputs
if component_input.name not in [input_field.name for input_field in LCModelComponent._base_inputs]
]
azure_inputs = [
component_input
for component_input in AzureChatOpenAIComponent().inputs
if component_input.name not in [input_field.name for input_field in LCModelComponent._base_inputs]
]
inputs = [
HandleInput(
name="tools", display_name="Tools", input_types=["Tool", "BaseTool", "StructuredTool"], is_list=True
),
MessageTextInput(name="input_value", display_name="Input"),
DataInput(name="chat_history", display_name="Chat History", is_list=True, advanced=True),
DropdownInput(
name="agent_llm",
display_name="Language Model Type",
options=["Azure OpenAI", "OpenAI", "Custom"],
value="OpenAI",
real_time_refresh=True,
refresh_button=True,
input_types=[],
),
*openai_inputs,
]
outputs = [Output(name="response", display_name="Response", method="get_response")]

async def get_response(self) -> Message:
llm_model = self.get_llm()
if llm_model is None:
msg = "No language model selected"
raise ValueError(msg)

agent = ToolCallingAgentComponent().set(
llm=llm_model, tools=[self.tools], chat_history=self.chat_history, input_value=self.input_value
)

return await agent.message_response()

def get_llm(self):
try:
if self.agent_llm == "OpenAI":
return self._build_llm_model(OpenAIModelComponent(), self.openai_inputs)
if self.agent_llm == "Azure OpenAI":
return self._build_llm_model(AzureChatOpenAIComponent(), self.azure_inputs, prefix="azure_param_")
except Exception as e:
msg = f"Error building {self.agent_llm} language model"
raise ValueError(msg) from e
return self.agent_llm

def _build_llm_model(self, component, inputs, prefix=""):
return component.set(
**{component_input.name: getattr(self, f"{prefix}{component_input.name}") for component_input in inputs}
).build_model()

def delete_fields(self, build_config, fields):
for field in fields:
build_config.pop(field, None)

def update_build_config(self, build_config: dotdict, field_value: str, field_name: str | None = None):
if field_name == "agent_llm":
openai_fields = {component_input.name: component_input for component_input in self.openai_inputs}
azure_fields = {
f"azure_param_{component_input.name}": component_input for component_input in self.azure_inputs
}

if field_value == "OpenAI":
self.delete_fields(build_config, {**azure_fields})
if not any(field in build_config for field in openai_fields):
build_config.update(openai_fields)
build_config["agent_llm"]["input_types"] = []
build_config = self.update_input_types(build_config)

elif field_value == "Azure OpenAI":
self.delete_fields(build_config, {**openai_fields})
build_config.update(azure_fields)
build_config["agent_llm"]["input_types"] = []
build_config = self.update_input_types(build_config)
elif field_value == "Custom":
self.delete_fields(build_config, {**openai_fields})
self.delete_fields(build_config, {**azure_fields})
new_component = DropdownInput(
name="agent_llm",
display_name="Language Model",
options=["Azure OpenAI", "OpenAI", "Custom"],
value="Custom",
real_time_refresh=True,
input_types=["LanguageModel"],
)
build_config.update({"agent_llm": new_component.to_dict()})
build_config = self.update_input_types(build_config)
default_keys = ["code", "_type", "agent_llm", "tools", "input_value"]
missing_keys = [key for key in default_keys if key not in build_config]
if missing_keys:
msg = f"Missing required keys in build_config: {missing_keys}"
raise ValueError(msg)
return build_config

def update_input_types(self, build_config):
for key, value in build_config.items():
# Check if the value is a dictionary
if isinstance(value, dict):
if value.get("input_types") is None:
build_config[key]["input_types"] = []
# Check if the value has an attribute 'input_types' and it is None
elif hasattr(value, "input_types") and value.input_types is None:
value.input_types = []
return build_config
Empty file.
29 changes: 29 additions & 0 deletions src/backend/tests/unit/components/agents/test_simple_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os

import pytest
from langflow.components.agents.simple_agent import SimpleAgentComponent
from langflow.components.tools.calculator import CalculatorToolComponent


@pytest.mark.api_key_required
@pytest.mark.asyncio
async def test_simple_agent_with_calculator():
# Mock inputs
tools = [CalculatorToolComponent().build_tool()] # Use the Calculator component as a tool
input_value = "What is 2 + 2?"

api_key = os.environ["OPENAI_API_KEY"]
temperature = 0.1

# Initialize the SimpleAgentComponent with mocked inputs
agent = SimpleAgentComponent(
tools=tools,
input_value=input_value,
api_key=api_key,
model_name="gpt-4o",
llm_type="OpenAI",
temperature=temperature,
)

response = await agent.get_response()
assert "4" in response.data.get("text")
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os

from langflow.components.agents.tool_calling import ToolCallingAgentComponent
from langflow.components.models.openai import OpenAIModelComponent
from langflow.components.tools.calculator import CalculatorToolComponent


async def test_tool_calling_agent_component():
tools = [CalculatorToolComponent().build_tool()] # Use the Calculator component as a tool
input_value = "What is 2 + 2?"
chat_history = []
api_key = os.environ["OPENAI_API_KEY"]
temperature = 0.1

# Default OpenAI Model Component
llm_component = OpenAIModelComponent().set(
api_key=api_key,
temperature=temperature,
)
llm = llm_component.build_model()

agent = ToolCallingAgentComponent()
agent.set(llm=llm, tools=[tools], chat_history=chat_history, input_value=input_value)

# Chat output
response = await agent.message_response()
assert "4" in response.data.get("text")
Loading