Configuration, Definitions, and Status¶
AgentsPype uses three Pydantic-based structures to describe and configure agents: AgentConfiguration, AgentDefinition, and AgentStatus.
AgentConfiguration¶
AgentConfiguration is the base class for all agent configuration models. It is a Pydantic BaseModel with frozen=False (mutable) and arbitrary_types_allowed=False.
Defining Configuration¶
Add fields using standard Pydantic syntax:
from agentspype.agent.configuration import AgentConfiguration
class WorkerConfiguration(AgentConfiguration):
worker_id: str
max_retries: int = 3
queue_name: str = "default"
timeout_seconds: float = 30.0
Creating Configuration Instances¶
Configuration can be created directly from a Pydantic model instance or from a plain dict. Agent.__init__ accepts both:
# From a dict — Pydantic validates and coerces values
agent = WorkerAgent({"worker_id": "w-001", "max_retries": 5})
# From a configuration object
config = WorkerConfiguration(worker_id="w-002")
agent = WorkerAgent(config)
When a dict is passed, the agent calls configuration_class(**configuration) internally.
Accessing Configuration¶
agent.configuration.worker_id # "w-001"
agent.configuration.max_retries # 3
Configuration is accessible at any time via agent.configuration. Because the model is mutable (frozen=False), fields can be updated at runtime, though this is typically not recommended.
Validation¶
Because AgentConfiguration is a Pydantic BaseModel, all fields are validated on construction. Invalid data raises a ValidationError:
WorkerConfiguration(worker_id=123) # OK — coerced to str
WorkerConfiguration() # ValidationError — worker_id is required
WorkerConfiguration(worker_id="w", max_retries="not_an_int") # ValidationError
AgentDefinition¶
AgentDefinition is an immutable (frozen) Pydantic model that binds the five component classes for an agent type. It is declared as a class variable on the Agent subclass.
from agentspype.agent.definition import AgentDefinition
class MyAgent(Agent):
definition = AgentDefinition(
state_machine_class=MyStateMachine,
events_listening_class=MyListening,
events_publishing_class=MyPublishing,
configuration_class=MyConfiguration,
status_class=MyStatus,
)
Fields¶
| Field | Type | Description |
|---|---|---|
state_machine_class |
type[AgentStateMachine] |
The FSM class to instantiate |
events_listening_class |
type[AgentListening] |
The event listener class to instantiate |
events_publishing_class |
type[AgentPublishing] |
The event publisher class to instantiate |
configuration_class |
type[AgentConfiguration] |
Used to parse dicts and by Agency factory |
status_class |
type[AgentStatus] |
The status class to instantiate |
All five fields are required. The definition is validated once when the class is defined. Because the model is frozen, it cannot be modified after creation.
How Agent Uses the Definition¶
During Agent.__init__, the definition is read to construct each component:
self._events_publishing = self.definition.events_publishing_class(self)
self._events_listening = self.definition.events_listening_class(self)
self._state_machine = self.definition.state_machine_class(self)
self._status = self.definition.status_class()
The configuration_class is also used by Agency.register_agent_class to build the class-to-configuration bidirectional mapping.
Shared Definitions¶
Multiple agent classes can share component classes (e.g., the same configuration or status type), but each AgentDefinition is its own frozen instance:
SHARED_CONFIG = AgentConfiguration # use the base class as-is
class AgentA(Agent):
definition = AgentDefinition(
configuration_class=SHARED_CONFIG,
state_machine_class=MachineA,
...
)
class AgentB(Agent):
definition = AgentDefinition(
configuration_class=SHARED_CONFIG, # same config class
state_machine_class=MachineB,
...
)
Warning
If two agent classes share the same configuration_class, Agency.register_agent_class can only map one of them to that configuration type (the bidirectional mapping enforces a 1-to-1 relationship). Use distinct configuration subclasses if you need the Agency factory to distinguish between them.
AgentStatus¶
AgentStatus is the base class for runtime status models. Unlike configuration (which is set at startup), status is intended to be updated during agent execution.
from agentspype.agent.status import AgentStatus
class WorkerStatus(AgentStatus):
jobs_processed: int = 0
errors_encountered: int = 0
last_job_id: str | None = None
is_busy: bool = False
Updating Status¶
The status object is accessible via agent.status. Update fields directly:
agent.status.jobs_processed += 1
agent.status.last_job_id = "job-42"
agent.status.is_busy = False
Using Status in State Machine Hooks¶
class WorkerStateMachine(AgentStateMachine):
...
def on_enter_processing(self):
self.agent.status.is_busy = True
def on_exit_processing(self):
self.agent.status.is_busy = False
self.agent.status.jobs_processed += 1
Default Configuration¶
AgentStatus uses ConfigDict() with no additional constraints. Extend it freely with any Pydantic-compatible field types.
Combining All Three¶
A complete example showing all three structures:
from agentspype.agent.configuration import AgentConfiguration
from agentspype.agent.definition import AgentDefinition
from agentspype.agent.status import AgentStatus
from agentspype.agent.agent import Agent
from agentspype.agent.state_machine import BasicAgentStateMachine
from agentspype.agent.listening import AgentListening
from agentspype.agent.publishing import StateAgentPublishing
class PipelineConfiguration(AgentConfiguration):
pipeline_name: str
batch_size: int = 100
dry_run: bool = False
class PipelineStatus(AgentStatus):
batches_processed: int = 0
records_total: int = 0
started_at: str | None = None
class PipelineListening(AgentListening):
def subscribe(self): pass
def unsubscribe(self): pass
class PipelineAgent(Agent):
definition = AgentDefinition(
configuration_class=PipelineConfiguration,
events_publishing_class=StateAgentPublishing,
events_listening_class=PipelineListening,
state_machine_class=BasicAgentStateMachine,
status_class=PipelineStatus,
)
def initialize(self):
self.logger().info(
f"Pipeline '{self.configuration.pipeline_name}' ready "
f"(batch_size={self.configuration.batch_size})"
)
agent = PipelineAgent({
"pipeline_name": "etl-prod",
"batch_size": 500,
})
agent.status.started_at = "2026-01-01T00:00:00Z"
agent.machine.start()