Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
30a2dfd
Adding an Agent component that uses components from ALTK.
kirankateNexplore Oct 10, 2025
637a355
Merge branch 'main' into altk_agent
kiran-kate Oct 10, 2025
009ce78
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 10, 2025
f428155
Changes as per coderabbitai review comments.
kirankateNexplore Oct 10, 2025
c9dc7a4
Minor change to invoke CI again.
kirankateNexplore Oct 12, 2025
ac3fb87
Deleting uv.lock so it can recreated with the latest ALTK.
kirankateNexplore Oct 13, 2025
bff6224
Marking the test with anthropic models as slow.
kirankateNexplore Oct 13, 2025
74789c6
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
1cb770e
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 13, 2025
7100c8f
Merge branch 'main' into altk_agent
kiran-kate Oct 13, 2025
13dc887
Minor changes to ALTK Agent UI labels.
kiran-kate Oct 20, 2025
c076ebf
Reusing parent agent inputs where possible.
kiran-kate Oct 21, 2025
fae566f
Refactored altk_agent.py as per the review comments.
kiran-kate Oct 21, 2025
c0904c8
Resolving conflicts with main.
kiran-kate Oct 21, 2025
e608d3a
Merge remote-tracking branch 'upstream/main' into altk_agent
kiran-kate Oct 21, 2025
d12111e
Fixing import order.
kiran-kate Oct 21, 2025
2a362d2
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 21, 2025
685a262
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 21, 2025
90bbeba
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Oct 21, 2025
6df7c46
Merge branch 'main' into altk_agent
ogabrielluiz Oct 22, 2025
6a5feec
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 22, 2025
1b1953a
Override check for _run.
kiran-kate Oct 22, 2025
d244b77
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 22, 2025
cd7a67d
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 22, 2025
d7d06ca
Merge branch 'main' into altk_agent
kiran-kate Oct 22, 2025
81a273b
Merge branch 'main' into altk_agent
kiran-kate Oct 22, 2025
0128cf7
Merge remote-tracking branch 'upstream/main' into altk_agent
kiran-kate Oct 24, 2025
70161c3
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 24, 2025
95957ed
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Oct 24, 2025
ac89144
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Oct 24, 2025
9e1f6f5
Adding a newline at the end of component_index.json
kiran-kate Oct 24, 2025
e630e24
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 24, 2025
87cc4d7
Merge branch 'main' into altk_agent
kerinin Oct 28, 2025
889a616
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 28, 2025
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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ dependencies = [
"fastparquet>=2024.11.0,<2025.0.0",
"traceloop-sdk>=0.43.1,<1.0.0",
"vlmrun[all]>=0.2.0",
"agent-lifecycle-toolkit",
]

[dependency-groups]
Expand Down
190 changes: 190 additions & 0 deletions src/backend/tests/unit/components/agents/test_altk_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import os
from typing import Any
from uuid import uuid4

import pytest
from langflow.custom import Component
from lfx.base.models.anthropic_constants import ANTHROPIC_MODELS
from lfx.components.agents.altk_agent import ALTKAgentComponent
from lfx.components.tools.calculator import CalculatorToolComponent

from tests.base import ComponentTestBaseWithClient, ComponentTestBaseWithoutClient
from tests.unit.mock_language_model import MockLanguageModel

# ALTKAgent supports the following model providers
MODEL_PROVIDERS = ["Anthropic", "OpenAI"]


class TestAgentComponent(ComponentTestBaseWithoutClient):
@pytest.fixture
def component_class(self):
return ALTKAgentComponent

@pytest.fixture
def file_names_mapping(self):
return []

async def component_setup(self, component_class: type[Any], default_kwargs: dict[str, Any]) -> Component:
component_instance = await super().component_setup(component_class, default_kwargs)
# Mock _should_process_output method
component_instance._should_process_output = lambda output: False # noqa: ARG005
return component_instance

@pytest.fixture
def default_kwargs(self):
return {
"_type": "Agent",
"add_current_date_tool": True,
"agent_description": "A helpful agent",
"agent_llm": MockLanguageModel(),
"handle_parsing_errors": True,
"input_value": "",
"max_iterations": 10,
"system_prompt": "You are a helpful assistant.",
"tools": [],
"verbose": True,
"n_messages": 100,
"format_instructions": "You are an AI that extracts structured JSON objects from unstructured text.",
"output_schema": [],
}

async def test_build_config_update(self, component_class, default_kwargs):
component = await self.component_setup(component_class, default_kwargs)
frontend_node = component.to_frontend_node()
build_config = frontend_node["data"]["node"]["template"]
# Test updating build config for OpenAI
component.set(agent_llm="OpenAI")
updated_config = await component.update_build_config(build_config, "OpenAI", "agent_llm")
assert "agent_llm" in updated_config
assert updated_config["agent_llm"]["value"] == "OpenAI"
assert isinstance(updated_config["agent_llm"]["options"], list)
assert len(updated_config["agent_llm"]["options"]) > 0
assert all(provider in updated_config["agent_llm"]["options"] for provider in MODEL_PROVIDERS)
assert (
updated_config["agent_llm"]["external_options"]["fields"]["data"]["node"]["name"] == "connect_other_models"
)

# Verify model_name field is populated for OpenAI

assert "model_name" in updated_config
model_name_dict = updated_config["model_name"]
assert isinstance(model_name_dict["options"], list)
assert len(model_name_dict["options"]) > 0 # OpenAI should have available models
assert "gpt-4o" in model_name_dict["options"]

# Test Anthropic
component.set(agent_llm="Anthropic")
updated_config = await component.update_build_config(build_config, "Anthropic", "agent_llm")
assert "agent_llm" in updated_config
assert updated_config["agent_llm"]["value"] == "Anthropic"
assert isinstance(updated_config["agent_llm"]["options"], list)
assert len(updated_config["agent_llm"]["options"]) > 0
assert all(provider in updated_config["agent_llm"]["options"] for provider in MODEL_PROVIDERS)
assert "Anthropic" in updated_config["agent_llm"]["options"]
assert updated_config["agent_llm"]["input_types"] == []
options = updated_config["model_name"]["options"]
assert any("sonnet" in option.lower() for option in options), f"Options: {options}"


class TestAgentComponentWithClient(ComponentTestBaseWithClient):
@pytest.fixture
def component_class(self):
return ALTKAgentComponent

@pytest.fixture
def file_names_mapping(self):
return []

@pytest.mark.api_key_required
@pytest.mark.no_blockbuster
async def test_agent_component_with_calculator(self):
# Now you can access the environment variables
api_key = os.getenv("OPENAI_API_KEY")
tools = [CalculatorToolComponent().build_tool()] # Use the Calculator component as a tool
input_value = "What is 2 + 2?"

temperature = 0.1

# Initialize the agent with mocked inputs
agent = ALTKAgentComponent(
tools=tools,
input_value=input_value,
api_key=api_key,
model_name="gpt-4o",
agent_llm="OpenAI",
temperature=temperature,
_session_id=str(uuid4()),
response_processing_size_threshold=1,
)

response = await agent.message_response()
response_text = str(response.data.get("text", ""))
assert "4" in response_text

@pytest.mark.api_key_required
@pytest.mark.no_blockbuster
@pytest.mark.slow
async def test_agent_component_with_all_openai_models(self):
# Mock inputs
api_key = os.getenv("OPENAI_API_KEY")
input_value = "What is 2 + 2?"

# Iterate over all OpenAI models
failed_models = []
openai_chat_model_names = ["gpt-4", "gpt-4o", "gpt-4o-mini"]
for model_name in openai_chat_model_names:
# Initialize the agent with mocked inputs
tools = [CalculatorToolComponent().build_tool()] # Use the Calculator component as a tool
agent = ALTKAgentComponent(
tools=tools,
input_value=input_value,
api_key=api_key,
model_name=model_name,
agent_llm="OpenAI",
_session_id=str(uuid4()),
response_processing_size_threshold=1,
verbose=True,
)

response = await agent.message_response()
response_text = str(response.data.get("text", ""))
if "4" not in response_text:
failed_models.append(model_name)
assert not failed_models, f"The following models failed the test: {failed_models}"

@pytest.mark.api_key_required
@pytest.mark.no_blockbuster
async def test_agent_component_with_all_anthropic_models(self):
# Mock inputs
api_key = os.getenv("ANTHROPIC_API_KEY")
input_value = "What is 2 + 2?"

# Iterate over all Anthropic models
failed_models = {}

for model_name in ANTHROPIC_MODELS:
try:
# Initialize the agent with mocked inputs
tools = [CalculatorToolComponent().build_tool()]
agent = ALTKAgentComponent(
tools=tools,
input_value=input_value,
api_key=api_key,
model_name=model_name,
agent_llm="Anthropic",
_session_id=str(uuid4()),
response_processing_size_threshold=1,
)

response = await agent.message_response()
response_text = response.data.get("text", "")

if "4" not in response_text:
failed_models[model_name] = f"Expected '4' in response but got: {response_text}"

except Exception as e:
failed_models[model_name] = f"Exception occurred: {e!s}"

assert not failed_models, "The following models failed the test:\n" + "\n".join(
f"{model}: {error}" for model, error in failed_models.items()
)
8 changes: 3 additions & 5 deletions src/lfx/src/lfx/components/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@

if TYPE_CHECKING:
from lfx.components.agents.agent import AgentComponent
from lfx.components.agents.altk_agent import ALTKAgentComponent
from lfx.components.agents.mcp_component import MCPToolsComponent

_dynamic_imports = {
"AgentComponent": "agent",
"MCPToolsComponent": "mcp_component",
}
_dynamic_imports = {"AgentComponent": "agent", "MCPToolsComponent": "mcp_component", "ALTKAgentComponent": "altk_agent"}

__all__ = ["AgentComponent", "MCPToolsComponent"]
__all__ = ["ALTKAgentComponent", "AgentComponent", "MCPToolsComponent"]


def __getattr__(attr_name: str) -> Any:
Expand Down
Loading
Loading