Custom Workflow Configuration
When a linear_workflow
isn't enough to capture your logic, you can implement a Custom Workflow directly in Python. This gives you complete control over the execution flow, allowing for conditional logic, branching, looping, and complex data manipulation between steps.
A custom workflow configuration is a JSON or YAML object with a type
field set to "custom_workflow"
. Its purpose is to link a component name to your Python code.
How It Works
- Configuration: You create a config file that gives your workflow a
name
and points to themodule_path
andclass_name
of your Python code. - Implementation: You write a Python class that inherits from
aurite.BaseCustomWorkflow
and implements therun
method. - Execution: When you run the workflow by its
name
, the framework dynamically loads your Python class, instantiates it, and calls itsrun
method, passing in the initial input and an execution engine.
Schema and Implementation
Configuring a custom workflow involves two parts: the configuration file and the Python implementation.
The configuration file tells the framework where to find your Python code.
Field | Type | Required | Description |
---|---|---|---|
name |
string |
Yes | A unique identifier for the custom workflow. |
description |
string |
No | A brief, human-readable description of what the workflow does. |
module_path |
string |
Yes | The path to the Python file containing your workflow class, relative to your project's root directory. |
class_name |
string |
Yes | The name of the class within the module that implements the workflow. |
Your Python class must inherit from BaseCustomWorkflow
and implement the run
method.
from typing import Any, Optional
from aurite import AuriteEngine, BaseCustomWorkflow, AgentRunResult
class MyWorkflow(BaseCustomWorkflow):
async def run(
self,
initial_input: Any,
executor: "AuriteEngine",
session_id: Optional[str] = None
) -> Any:
# Your custom logic goes here
print(f"Workflow started with input: {initial_input}")
# You can run agents using the executor instance passed to this method
result: AgentRunResult = await executor.run_agent(
agent_name="my-agent",
user_message="What is the weather in SF?",
session_id=session_id # Pass the session_id for history
)
return {"final_output": result.message_content}
def get_input_type(self) -> Any:
"""(Optional) Returns the expected type of `initial_input`."""
return str
def get_output_type(self) -> Any:
"""(Optional) Returns the expected type of the workflow's final output."""
return dict
Key Components:
BaseCustomWorkflow
: The required base class fromaurite
.run(self, initial_input, executor, session_id)
: The main entry point for your workflow's logic. This method must be implemented.initial_input
: The data passed to the workflow when it's executed.executor
: An instance ofAuriteEngine
, which allows you to run other components like agents (executor.run_agent(...)
).session_id
: An optional session ID for maintaining conversation history.
get_input_type()
(Optional): A method that returns the expected Python type forinitial_input
. This can be used for documentation or validation.get_output_type()
(Optional): A method that returns the expected Python type for the value yourrun
method returns.
End-to-End Example
This example shows how to create a custom workflow that intelligently routes a task to one of two agents based on the input. The file structure illustrates how the module_path
is relative to the directory containing the .aurite
file.
my_project/config/workflows/routing_workflow.json
my_project/custom_workflows/my_routing_logic.py
from typing import Any, Dict, Optional
from aurite import AuriteEngine, BaseCustomWorkflow, AgentRunResult
class MyRoutingWorkflow(BaseCustomWorkflow):
"""
This workflow checks the input for keywords and routes the request
to either a weather agent or a calculator agent.
"""
async def run(
self,
initial_input: Dict[str, Any],
executor: "AuriteEngine",
session_id: Optional[str] = None
) -> AgentRunResult:
user_message = initial_input.get("message", "")
if "weather" in user_message.lower():
agent_to_run = "weather-agent"
elif "calculate" in user_message.lower():
agent_to_run = "calculator-agent"
else:
agent_to_run = "general-qa-agent"
print(f"Routing to agent: {agent_to_run}")
# Run the selected agent using the provided executor
result = await executor.run_agent(
agent_name=agent_to_run,
user_message=user_message,
session_id=session_id
)
return result