Agents¶
The Agent class is the central abstraction in AgentsPype. An agent owns exactly one instance of each of its components — a state machine, an event listener, an event publisher, a configuration object, and a status object. These are assembled via an immutable AgentDefinition declared on the class.
Lifecycle¶
__init__()
├── build configuration
├── build publishing, listening, state_machine, status
├── Agency.register_agent(self)
└── initialize() ← override this hook
machine.start()
└── on_start() ← calls listening.subscribe()
...agent is running...
machine.stop() or teardown()
├── listening.unsubscribe()
└── Agency.deregister_agent(self)
machine.on_enter_end()
└── calls teardown()
initialize()¶
Override initialize() to run code after all components have been wired together but before the agent starts processing events. The default implementation is a no-op.
class MyAgent(Agent):
definition = ...
def initialize(self):
super().initialize()
self.logger().info("Agent ready")
# load initial data, connect to resources, etc.
teardown()¶
teardown() unsubscribes all event listeners and deregisters the agent from Agency. It is safe to call multiple times (subsequent calls after deregistration are silently ignored by Agency).
teardown() is called automatically:
- When the state machine enters any final=True state (via on_enter_end).
- When the agent is garbage-collected (via __del__, with exceptions suppressed).
You can also trigger it explicitly:
agent.teardown()
clone()¶
clone() creates a new agent of the same type with a copy of the current configuration. The new agent goes through the full initialization sequence independently.
original = MyAgent({"worker_id": "w-001"})
copy = original.clone()
# copy is a brand-new MyAgent with the same configuration
Defining an Agent¶
The Definition¶
AgentDefinition is a frozen Pydantic model that wires together all five component classes:
from agentspype.agent.definition import AgentDefinition
class MyAgent(Agent):
definition = AgentDefinition(
configuration_class=MyConfiguration,
events_publishing_class=MyPublishing,
events_listening_class=MyListening,
state_machine_class=MyStateMachine,
status_class=MyStatus,
)
All five fields are required. This declaration is evaluated once at class definition time. Because AgentDefinition is frozen, it cannot be changed at runtime.
Minimal Agent¶
If you do not need custom configuration, status, listening, or publishing, you can use the base classes directly:
from agentspype.agent.agent import Agent
from agentspype.agent.configuration import AgentConfiguration
from agentspype.agent.definition import AgentDefinition
from agentspype.agent.listening import AgentListening
from agentspype.agent.publishing import StateAgentPublishing
from agentspype.agent.state_machine import BasicAgentStateMachine
from agentspype.agent.status import AgentStatus
class NoOpListening(AgentListening):
def subscribe(self): pass
def unsubscribe(self): pass
class MinimalAgent(Agent):
definition = AgentDefinition(
configuration_class=AgentConfiguration,
events_publishing_class=StateAgentPublishing,
events_listening_class=NoOpListening,
state_machine_class=BasicAgentStateMachine,
status_class=AgentStatus,
)
Initialization from Dict¶
Agents accept either an AgentConfiguration instance or a plain dict. When a dict is passed, it is forwarded to configuration_class(**configuration) — Pydantic validates and coerces the values.
agent1 = MyAgent({"worker_id": "w-001", "max_retries": 5})
agent2 = MyAgent(MyConfiguration(worker_id="w-002"))
Properties¶
| Property | Type | Description |
|---|---|---|
name |
str |
AID:<id>|<ClassName> — unique identifier including the Python object id |
complete_name |
str |
Adds PID:<parent_id>| prefix for child agents |
configuration |
AgentConfiguration |
The agent's configuration instance |
machine |
AgentStateMachine |
The agent's state machine instance |
listening |
AgentListening |
The agent's event listening instance |
publishing |
AgentPublishing |
The agent's event publishing instance |
status |
AgentStatus |
The agent's runtime status instance |
parent_id |
int | None |
Optional parent agent id (for hierarchical agents) |
Parent–Child Relationships¶
Agents can optionally track a parent by passing parent_id at construction time. Once set, parent_id cannot be changed to another value (it can only be cleared back to None).
parent = MyAgent({})
child = MyAgent({}, parent_id=id(parent))
print(child.complete_name) # PID:<parent_id>|AID:<child_id>|MyAgent
Logging¶
Each agent class lazily initializes a logger named after the class:
MyAgent.logger().info("Class-level log")
agent = MyAgent({})
agent.logger().debug("Instance log — same logger")
Visualization¶
Every agent provides four visualization methods. These are documented in detail in the Visualization guide.
agent.visualize(save_file=True) # full diagram
agent.visualize_state_machine(save_file=True)
agent.visualize_publishing(save_file=True)
agent.visualize_listening(save_file=True)
agent.create_all_diagrams(save_files=True) # all four at once