This page provides detailed technical information about the Events system in Meta Agents Research Environments.
For a higher-level overview, see Foundations.
All events inherit from the AbstractEvent class, which contains shared fields between completed and future events:
@dataclass(order=True)classAbstractEvent(ABC):""" Abstract event class, that contains shared field between completed and future events. """# The action that will be executed when the event happens, which is an App API callaction:Action# The type of the event, either AGENT, ENV or USER.event_type:EventType=field(default=EventType.ENV)# The time at which the event will happen, this can get overridden in various places for e.g. in case of conditional triggers.event_time:float=field(default_factory=lambda:global_time.time())# The relative time wrt the simulation start time# WARNING when the event is going to be added to the queue, this information is going to be used to set event_timeevent_relative_time:float|None=field(default=None)# The unique id of the event, this is used to identify the event in the logs.# This is created automatically and does NOT need to be handled by the userevent_id:str=field(default=None)
Note
Events have an event_type which describes the origin of the event. By default, each app_tool call made by the agent will be of type EventType.AGENT, each event definition in the scenario script will be of type EventType.ENV. You can also decide to manually add the type EventType.USER to events when defining a scenario to simulate that the user is the source of the event. This field is only used for logging purposes and does not have any impact on the execution of the scenario.
Events execute Actions, which define what actually happens:
@dataclassclassAction:function:Callable# Function to callargs:dict[str,Any]# Function argumentsapp:App|None=None# App instanceaction_id:str=None# Unique identifier
fromare.simulation.core.eventsimportEventfromare.simulation.core.actionimportAction# Create a basic eventaction=Action(function=my_function,args={"param":"value"})event=Event(action=action,event_time=simulation_time+30)# Schedule the eventenvironment.schedule(event)
# Schedule with relative timeevent.event_relative_time=60# 60 seconds from simulation startenvironment.schedule(event)# Schedule with dependenciesevent1=Event(...)event2=Event(...)event2.depends_on(event1,delay_seconds=10)
# Get all completed eventscompleted=environment.event_log.list_view()# Filter events by typeagent_events=[eforeincompletedife.event_type==EventType.AGENT]
Validation events are special events that check whether certain conditions are met during scenario execution:
defboth_responses_validator(env:AbstractEnvironment)->bool:"""Check if agent gave both responses."""aui_app=env.get_app("AgentUserInterface")agent_messages=aui_app.get_all_messages_from_agent()has_correct=any(msg.content=="I am a robot"formsginagent_messages)has_incorrect=any(msg.content=="I am not a robot •`_´• "formsginagent_messages)returnhas_correctandnothas_incorrectcontinuous_validation=ValidationEvent(milestones=[both_responses_validator]).with_id("continuous_validation")continuous_validation.depends_on(user_request,delay_seconds=1)continuous_validation.schedule(every_ticks=1,timeout=15)self.events.append(continuous_validation)
Condition check events monitor the environment state and trigger other events when conditions are met:
fromare.simulation.core.eventsimportConditionCheckEventdefcheck_file_exists(env,event):"""Check if a specific file exists"""fs_app=env.get_app("FileSystemApp")returnfs_app.file_exists("/important/document.txt")condition=ConditionCheckEvent(condition_function=check_file_exists,schedule_every_ticks=5,# Check every 5 tickstimeout=600,# Timeout after 10 minutes)# Trigger another event when condition is metfollowup_event=Event(...)followup_event.depends_on(condition)
For practical examples of event usage, see the tutorials and scenario development guides.
Oracle Events are specialized events that represent actions the agent should perform during scenario execution. They serve as templates or blueprints for generating actual executable events at runtime. Oracle Events are particularly useful for defining expected agent behaviors in scenarios and for creating validation trajectories.
fromare.simulation.core.eventsimportEvent,OracleEventfromare.simulation.core.actionimportAction# Create a regular eventaction=Action(function=email_app.send_email,args={"to":"user@example.com"})regular_event=Event(action=action)# Convert to Oracle Eventoracle_event=OracleEvent.from_event(regular_event)# Or use the convenience methodoracle_event=regular_event.oracle()
Direct Creation
defmake_email_event(env):email_app=env.get_app("EmailClientApp")returnEvent.from_function(email_app.send_email,recipients=["client@company.com"],subject="Project Update")oracle_event=OracleEvent(make_event=make_email_event,event_type=EventType.AGENT,event_relative_time=30# Execute 30 seconds after dependencies)
Oracle Events generate actual executable events through the make() method:
# Generate the executable eventexecutable_event=oracle_event.make(environment)# The generated event inherits timing and dependenciesassertexecutable_event.event_time==oracle_event.event_timeassertexecutable_event.dependencies==oracle_event.dependencies
Oracle Events support time-based filtering through event time comparators:
fromare.simulation.typesimportEventTimeComparatororacle_event=OracleEvent(make_event=make_email_event,event_time_comparator=EventTimeComparator.LESS_THAN)# This oracle event can be used to find events that occur before a certain time
Oracle Events automatically capture action metadata when created from existing events:
# The action description includes app name, function name, and argumentsoracle_event=regular_event.oracle()action_desc=oracle_event.action_descprint(f"App: {action_desc.app}")print(f"Function: {action_desc.function}")print(f"Args: {action_desc.args}")
Completed Oracle Events
When Oracle Events are executed, they become CompletedOracleEvent instances that preserve timing information:
fromare.simulation.typesimportCompletedOracleEvent# After execution, create a completed oracle eventcompleted_oracle=CompletedOracleEvent.from_completed_event_and_oracle_event(completed_event,original_oracle_event)# Access timing metadataprint(f"Original scheduled time: {completed_oracle.absolute_event_time}")print(f"Time comparator: {completed_oracle.event_time_comparator}")
Capture mode makes sure a function call is not executed but only a “fictitious” CompletedEvent is returned.
This is useful for debugging and testing, as well as easily creating CompletedEvent instances for validation
This decorator is used to wrap API calls, so that we can register the event and add the appropriate CompletedEvent instance.
The CompletedEvent instance is only added to the Event Log if the App is already registered in the environment.
This decorator is also used to capture fictitious CompletedEvent instances when capture mode is active.
Capture mode allows to easily simulate and create CompletedEvent instances without actually executing the API call.
This is useful for debugging and testing, as well as defining validation trajectories.
This decorator is used to wrap API calls, so that we can register the event and add the appropriate CompletedEvent instance.
The CompletedEvent instance is only added to the Event Log if the App is already registered in the environment.
This decorator is also used to capture fictitious CompletedEvent instances when capture mode is active.
Capture mode allows to easily simulate and create CompletedEvent instances without actually executing the API call.
This is useful for debugging and testing, as well as defining validation trajectories.
This decorator wraps app methods to automatically create and log events when they are executed.
It supports different operation types and event types, and can be used in capture mode for testing and validation.
Example usage:
fromare.simulation.typesimportevent_registered,OperationType,EventTypefromare.simulation.apps.appimportAppclassMyApp(App):@event_registered(operation_type=OperationType.WRITE,event_type=EventType.AGENT)defsend_message(self,message:str):# This method call will automatically create and log an eventreturnf"Sent: {message}"
The state of the environment.
- SETUP: the environment is being setup, this is the initial state of the environment
- RUNNING: the environment event loop is running and events are being registered and logged
- PAUSED: the environment is paused, and no events are being registered or logged, but can be restarted
- STOPPED: the environment is completely stopped
Hint associated with an event
- hint_type: Type of the hint, depends on the linked event
- content: Content of the hint
- associated_event_id: The id of the event that this hint is associated with
Type of the events, depends on who initiated them.
- AGENT: events initiated by the agent
- ENV: events initiated by the environment, or the scenario designer.
- USER: events initiated by the user or user proxy (unused for now).
- CONDITION: events that check a condition and trigger other events.
- VALIDATION: events that validate the state of the environment.
- STOP: events that stop the simulation.
Action associated with an event, this is a function that will be called when the event is executed.
function: Function to be called when the action is executed, it can be a class method, or a regular function
args: Dict mapping the argument names to values to call the function with at execution time
app: The actual App instance to use for the action execution
If not specified at creation time, it can be deducted from the function instance
e.g. if function=email_app.add_emails then we can deduct that app=email_app
action_id: The unique id of the action, this is used to identify the event in the logs.
This is created automatically and does NOT need to be handled by the user
tool_metadata: Optional metadata from the AppTool that this action is associated with
Metadata for a completed event, which includes details such as the return value, exception, etc.
This is particularly useful for completed events from App API calls, where:
- return_value: the return value of the API call.
- exception: any exception that occurred during the API call.
- exception_stack_trace: the stack trace of the exception, if any.
- completed: a flag indicating whether the execution was completed.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to add successors to the event.
If e1 is followed by e2 and e3, then e2 and e3 will only be executed after
e1 is executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to check if the event is ready to be scheduled i.e. put into the event_queue.
An event is ready to be executed if all its dependencies are executed.
When an event has its event_time set, it means it is ready to be scheduled.
Executes the action corresponding to the events and returns the completed event with its metadata.
Here by default we make sure we only have ONE event, and that whatever happens inside the action is not registered as individual events.
This is to guarantee 2 things:
1/ Events are transactional, either the whole Event (and associated action) happened or not
2/ Not duplicating what is registered in the event log (otherwise we will register BOTH the current event, and every underlying one)
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
Create a completed oracle event from a completed event and an oracle event.
The absolute event time is taken from the oracle event, and the event time comparator is taken from the oracle event if it exists.
Represents the result of a validation event.
- success: whether the validation was successful or not.
- message: a message describing the result of the validation.
- failed_milestones: the list of milestones that failed during the validation.
- triggered_minefields: the list of minefields that were triggered during the validation.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
Capture mode makes sure a function call is not executed but only a “fictitious” CompletedEvent is returned.
This is useful for debugging and testing, as well as easily creating CompletedEvent instances for validation
This decorator is used to wrap API calls, so that we can register the event and add the appropriate CompletedEvent instance.
The CompletedEvent instance is only added to the Event Log if the App is already registered in the environment.
This decorator is also used to capture fictitious CompletedEvent instances when capture mode is active.
Capture mode allows to easily simulate and create CompletedEvent instances without actually executing the API call.
This is useful for debugging and testing, as well as defining validation trajectories.
This decorator is used to wrap API calls, so that we can register the event and add the appropriate CompletedEvent instance.
The CompletedEvent instance is only added to the Event Log if the App is already registered in the environment.
This decorator is also used to capture fictitious CompletedEvent instances when capture mode is active.
Capture mode allows to easily simulate and create CompletedEvent instances without actually executing the API call.
This is useful for debugging and testing, as well as defining validation trajectories.
are.simulation.types.disable_events()
Context manager to disable event firing, and just return the result of the function call as if decorator is not applied.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to add successors to the event.
If e1 is followed by e2 and e3, then e2 and e3 will only be executed after
e1 is executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to check if the event is ready to be scheduled i.e. put into the event_queue.
An event is ready to be executed if all its dependencies are executed.
When an event has its event_time set, it means it is ready to be scheduled.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to add successors to the event.
If e1 is followed by e2 and e3, then e2 and e3 will only be executed after
e1 is executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to check if the event is ready to be scheduled i.e. put into the event_queue.
An event is ready to be executed if all its dependencies are executed.
When an event has its event_time set, it means it is ready to be scheduled.
Executes the action corresponding to the events and returns the completed event with its metadata.
Here by default we make sure we only have ONE event, and that whatever happens inside the action is not registered as individual events.
This is to guarantee 2 things:
1/ Events are transactional, either the whole Event (and associated action) happened or not
2/ Not duplicating what is registered in the event log (otherwise we will register BOTH the current event, and every underlying one)
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
This function is used to add dependencies to the event.
If e1 depends on e2 and e3, then e1 will only be executed after e2 and e3 are executed.
If a delay is specified, then the event will be executed after the delay after the dependencies are executed.
Action associated with an event, this is a function that will be called when the event is executed.
function: Function to be called when the action is executed, it can be a class method, or a regular function
args: Dict mapping the argument names to values to call the function with at execution time
app: The actual App instance to use for the action execution
If not specified at creation time, it can be deducted from the function instance
e.g. if function=email_app.add_emails then we can deduct that app=email_app
action_id: The unique id of the action, this is used to identify the event in the logs.
This is created automatically and does NOT need to be handled by the user
tool_metadata: Optional metadata from the AppTool that this action is associated with
Type of the events, depends on who initiated them.
- AGENT: events initiated by the agent
- ENV: events initiated by the environment, or the scenario designer.
- USER: events initiated by the user or user proxy (unused for now).
- CONDITION: events that check a condition and trigger other events.
- VALIDATION: events that validate the state of the environment.
- STOP: events that stop the simulation.
Metadata for a completed event, which includes details such as the return value, exception, etc.
This is particularly useful for completed events from App API calls, where:
- return_value: the return value of the API call.
- exception: any exception that occurred during the API call.
- exception_stack_trace: the stack trace of the exception, if any.
- completed: a flag indicating whether the execution was completed.