feat: run flow component with tool mode option to run a flow as a tool (#5518)
* Update calculator.py * Update json_cleaner.py * [autofix.ci] apply automated fixes * updated init * updated format format * update component sample component update * Update flow_orchestrator.py * test files tests * update in flow Orchestrator * Update flow_orchestrator.py solves issues with agents and session ids * Update flow_orchestrator.py * update to FlowOrchetstor update to FlowOrchetstor * draft Commit * updated to run_flow * updates * refactor code * [autofix.ci] apply automated fixes * default_name of tool to be the name of the flow * add tool_mode default activation * [autofix.ci] apply automated fixes * updates to build schema * [autofix.ci] apply automated fixes * update to schema and run flow * cleanup * Update run_flow.py * [autofix.ci] apply automated fixes * fix(run_flow.py): update condition to check if field_order exists in field_template for improved input validation * Update run_flow.py * [autofix.ci] apply automated fixes * debug updates * updates in flow tool outputs and tool mode * code cleanup * Update component_tool.py * Update run_flow.py * updated description added beta tag as per Simons Suggestion * [autofix.ci] apply automated fixes * Update component_tool.py * Update schema.py * [autofix.ci] apply automated fixes * feat: Add ToolModeMixin to CodeInput class * Update component.py * updated tests * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
parent
f4a7d9d797
commit
040a84ed52
20 changed files with 437 additions and 114 deletions
33
src/backend/tests/unit/base/tools/test_create_schema.py
Normal file
33
src/backend/tests/unit/base/tools/test_create_schema.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from langflow.io.schema import create_input_schema_from_dict
|
||||
from langflow.schema.dotdict import dotdict
|
||||
|
||||
|
||||
def test_create_schema():
|
||||
sample_input = [
|
||||
{
|
||||
"_input_type": "MultilineInput",
|
||||
"advanced": False,
|
||||
"display_name": "Chat Input - Text",
|
||||
"dynamic": False,
|
||||
"info": "Message to be passed as input.",
|
||||
"input_types": ["Message"],
|
||||
"list": False,
|
||||
"load_from_db": False,
|
||||
"multiline": True,
|
||||
"name": "ChatInput-xNZ0a|input_value",
|
||||
"placeholder": "",
|
||||
"required": False,
|
||||
"show": True,
|
||||
"title_case": False,
|
||||
"tool_mode": True,
|
||||
"trace_as_input": True,
|
||||
"trace_as_metadata": True,
|
||||
"type": "str",
|
||||
"value": "add 1+1",
|
||||
}
|
||||
]
|
||||
# convert to dotdict
|
||||
# change the key type
|
||||
sample_input = [dotdict(field) for field in sample_input]
|
||||
schema = create_input_schema_from_dict(sample_input)
|
||||
assert schema is not None
|
||||
|
|
@ -5,11 +5,11 @@ from langflow.components.agents.agent import AgentComponent
|
|||
from langflow.components.tools.calculator import CalculatorToolComponent
|
||||
|
||||
|
||||
def test_component_to_toolkit():
|
||||
async def test_component_to_toolkit():
|
||||
calculator_component = CalculatorToolComponent()
|
||||
agent_component = AgentComponent().set(tools=[calculator_component])
|
||||
|
||||
tools = agent_component.to_toolkit()
|
||||
tools = await agent_component.to_toolkit()
|
||||
assert len(tools) == 1
|
||||
tool = tools[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from langflow.custom.custom_component.component import Component
|
|||
|
||||
|
||||
class TestComponentOutputs:
|
||||
def test_run_and_validate_update_outputs_tool_mode(self):
|
||||
async def test_run_and_validate_update_outputs_tool_mode(self):
|
||||
"""Test run_and_validate_update_outputs with tool_mode field."""
|
||||
|
||||
class TestComponent(Component):
|
||||
|
|
@ -33,7 +33,7 @@ class TestComponentOutputs:
|
|||
}
|
||||
|
||||
# Test enabling tool mode
|
||||
updated_node = component.run_and_validate_update_outputs(
|
||||
updated_node = await component.run_and_validate_update_outputs(
|
||||
frontend_node=frontend_node.copy(), # Use a copy to avoid modifying original
|
||||
field_name="tool_mode",
|
||||
field_value=True,
|
||||
|
|
@ -45,7 +45,7 @@ class TestComponentOutputs:
|
|||
assert updated_node["outputs"][0]["display_name"] == TOOL_OUTPUT_DISPLAY_NAME
|
||||
|
||||
# Test disabling tool mode - use the original frontend node
|
||||
updated_node = component.run_and_validate_update_outputs(
|
||||
updated_node = await component.run_and_validate_update_outputs(
|
||||
frontend_node={"outputs": original_outputs.copy()}, # Use original outputs
|
||||
field_name="tool_mode",
|
||||
field_value=False,
|
||||
|
|
@ -60,7 +60,7 @@ class TestComponentOutputs:
|
|||
assert "types" in updated_node["outputs"][0]
|
||||
assert "selected" in updated_node["outputs"][0]
|
||||
|
||||
def test_run_and_validate_update_outputs_invalid_output(self):
|
||||
async def test_run_and_validate_update_outputs_invalid_output(self):
|
||||
"""Test run_and_validate_update_outputs with invalid output structure."""
|
||||
|
||||
class TestComponent(Component):
|
||||
|
|
@ -74,11 +74,11 @@ class TestComponentOutputs:
|
|||
|
||||
# Test validation fails for invalid output
|
||||
with pytest.raises(ValueError, match="Invalid output: 1 validation error for Output"):
|
||||
component.run_and_validate_update_outputs(
|
||||
await component.run_and_validate_update_outputs(
|
||||
frontend_node=frontend_node, field_name="some_field", field_value="some_value"
|
||||
)
|
||||
|
||||
def test_run_and_validate_update_outputs_custom_update(self):
|
||||
async def test_run_and_validate_update_outputs_custom_update(self):
|
||||
"""Test run_and_validate_update_outputs with custom update logic."""
|
||||
|
||||
class CustomComponent(Component):
|
||||
|
|
@ -111,7 +111,7 @@ class TestComponentOutputs:
|
|||
frontend_node = {"outputs": []}
|
||||
|
||||
# Test custom update logic
|
||||
updated_node = component.run_and_validate_update_outputs(
|
||||
updated_node = await component.run_and_validate_update_outputs(
|
||||
frontend_node=frontend_node, field_name="custom_field", field_value="custom_value"
|
||||
)
|
||||
|
||||
|
|
@ -122,14 +122,14 @@ class TestComponentOutputs:
|
|||
assert "types" in updated_node["outputs"][0]
|
||||
assert "selected" in updated_node["outputs"][0]
|
||||
|
||||
def test_run_and_validate_update_outputs_with_existing_tool_output(self):
|
||||
async def test_run_and_validate_update_outputs_with_existing_tool_output(self):
|
||||
"""Test run_and_validate_update_outputs when tool output already exists."""
|
||||
|
||||
class TestComponent(Component):
|
||||
def build(self) -> None:
|
||||
pass
|
||||
|
||||
def to_toolkit(self) -> list:
|
||||
async def to_toolkit(self) -> list:
|
||||
"""Method that returns a list of tools."""
|
||||
return []
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ class TestComponentOutputs:
|
|||
}
|
||||
|
||||
# Test enabling tool mode doesn't duplicate tool output
|
||||
updated_node = component.run_and_validate_update_outputs(
|
||||
updated_node = await component.run_and_validate_update_outputs(
|
||||
frontend_node=frontend_node, field_name="tool_mode", field_value=True
|
||||
)
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ class TestComponentOutputs:
|
|||
assert "types" in updated_node["outputs"][0]
|
||||
assert "selected" in updated_node["outputs"][0]
|
||||
|
||||
def test_run_and_validate_update_outputs_with_multiple_outputs(self):
|
||||
async def test_run_and_validate_update_outputs_with_multiple_outputs(self):
|
||||
"""Test run_and_validate_update_outputs with multiple outputs."""
|
||||
|
||||
class TestComponent(Component):
|
||||
|
|
@ -203,7 +203,7 @@ class TestComponentOutputs:
|
|||
frontend_node = {"outputs": []}
|
||||
|
||||
# Test adding multiple outputs
|
||||
updated_node = component.run_and_validate_update_outputs(
|
||||
updated_node = await component.run_and_validate_update_outputs(
|
||||
frontend_node=frontend_node, field_name="add_output", field_value=True
|
||||
)
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ class TestComponentOutputs:
|
|||
assert set(output["types"]) == {"Text"}
|
||||
assert output["selected"] == "Text"
|
||||
|
||||
def test_run_and_validate_update_outputs_output_validation(self):
|
||||
async def test_run_and_validate_update_outputs_output_validation(self):
|
||||
"""Test output validation in run_and_validate_update_outputs."""
|
||||
|
||||
class TestComponent(Component):
|
||||
|
|
@ -236,10 +236,14 @@ class TestComponentOutputs:
|
|||
}
|
||||
|
||||
with pytest.raises(AttributeError, match="nonexistent_method not found in TestComponent"):
|
||||
component.run_and_validate_update_outputs(frontend_node=invalid_node, field_name="test", field_value=True)
|
||||
await component.run_and_validate_update_outputs(
|
||||
frontend_node=invalid_node, field_name="test", field_value=True
|
||||
)
|
||||
|
||||
# Test missing method case
|
||||
invalid_node = {"outputs": [{"name": "test", "type": "str", "display_name": "Test"}]}
|
||||
|
||||
with pytest.raises(ValueError, match="Output test does not have a method"):
|
||||
component.run_and_validate_update_outputs(frontend_node=invalid_node, field_name="test", field_value=True)
|
||||
await component.run_and_validate_update_outputs(
|
||||
frontend_node=invalid_node, field_name="test", field_value=True
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue