Routed Agent
The engine/agent
module in AgentOpera provides a core set of agent implementations that serve as the foundation for building agent-based systems. These components enable asynchronous messaging, type-based message routing, and managing the lifecycle of agents within the engine runtime.
Agent Identity
AgentId
An AgentId
uniquely identifies an agent instance within an agent engine, including distributed engines. It functions as the "address" of the agent instance for receiving messages.
from agentopera.engine.types.agent import AgentId, AgentType
# Create an AgentId
agent_id = AgentId("assistant", "user_session_123")
# or
agent_type = AgentType("assistant")
agent_id = AgentId(agent_type, "user_session_123")
# Convert to string representation
agent_id_str = str(agent_id) # "assistant/user_session_123"
# Create from string
agent_id = AgentId.from_str("assistant/user_session_123")
An AgentId
consists of two components:
Agent Type: Identifies the category of agent and associates it with a specific factory function
Agent Key: Instance identifier for the given agent type
An AgentId follows the string format: Agent_Type/Agent_Key
. Both types and keys must contain only alphanumeric characters (a-z, 0-9) or underscores (_) and cannot start with a number.
AgentType
AgentType
represents a category of agents that share the same implementation or behavior patterns.
from agentopera.engine.types.agent import AgentType
agent_type = AgentType("assistant")
Agent types are typically defined directly in application code, while agent keys are often generated dynamically based on messages delivered to agents.
RoutedAgent
RoutedAgent
provides type-based message routing through decorators:
from agentopera.engine.agent import RoutedAgent, message_handler
from agentopera.engine.types.msg_context import MessageContext
from dataclasses import dataclass
@dataclass
class GreetingMessage:
content: str
class MyGreetingAgent(RoutedAgent):
def __init__(self) -> None:
super().__init__("Greeting agent that handles greeting messages")
@message_handler
async def handle_greeting(self, message: GreetingMessage, ctx: MessageContext) -> str:
return f"Hello! You said: {message.content}"
RoutedAgent
enables you to:
Define message handlers with the
@message_handler
decoratorRoute messages to appropriate handlers based on message type
The message handling in RoutedAgent
follows these steps:
When a message arrives, the agent examines the message type
The agent looks up registered handlers that can process this message type
The first matching handler is called with the message and context
Agent Lifecycle
Agents in AgentOpera follow a managed lifecycle:
Registration: An agent type is registered with the engine using the
register
methodInstantiation: The engine creates an agent instance when a message is delivered to that agent ID
Message Handling: The agent processes messages through its message handlers
Integration with Chat Agents
The engine module agents are designed to be used with chatflow agents. Since chatflow agents like AssistantAgent
are created directly by the application and not by the engine runtime, they need to be wrapped with an engine-managed agent like RoutedAgent
:
from agentopera.engine.agent import RoutedAgent, message_handler
from agentopera.engine.types.msg_context import MessageContext
from agentopera.chatflow.agent import AssistantAgent
from agentopera.chatflow.messages import TextMessage
class WorkerAgent(RoutedAgent):
def __init__(self, name: str) -> None:
super().__init__(f"Wrapper for assistant agent {name}")
# Create the chatflow agent
self._assistant = AssistantAgent(name, model_client=some_model_client)
@message_handler
async def handle_text_message(self, message: TextMessage, ctx: MessageContext) -> TextMessage:
# Delegate to chatflow agent
response = await self._assistant.on_messages([message], ctx.cancellation_token)
return response.chat_message
With this pattern, the engine can manage the wrapper agent, which delegates message processing to the chatflow agent.
Last updated