Current section
Files
Jump to
Current section
Files
lib/object_application.ex
defmodule Object.Application do
@moduledoc """
Main OTP Application for the AAOS Object system.
This module implements the main supervision tree and system initialization
for the Autonomous Agent Object Specification (AAOS) framework. It manages:
- Core object supervision and lifecycle management
- Message routing infrastructure
- System-wide coordination services
- Performance monitoring and telemetry
- Demonstration system creation
- Health monitoring and alerts
The application follows OTP principles with a hierarchical supervision
strategy that ensures fault tolerance and system resilience.
"""
use Application
require Logger
@doc """
Starts the AAOS Object System application.
Initializes the complete supervision tree including:
- Core object supervisor
- Message routing subsystem
- Telemetry configuration
- Post-startup system initialization
## Parameters
- `_type` - Application start type (typically `:normal`)
- `_args` - Application arguments (unused)
## Returns
- `{:ok, pid}` - Success with supervisor PID
- `{:error, reason}` - Failure with error reason
## Examples
iex> Object.Application.start(:normal, [])
{:ok, #PID<0.123.0>}
"""
def start(_type, _args) do
Logger.info("Starting AAOS Object System...")
# Configure telemetry
configure_telemetry()
children = [
# Core supervisor containing all subsystems
Object.Supervisor
]
opts = [strategy: :one_for_one, name: Object.ApplicationSupervisor]
case Supervisor.start_link(children, opts) do
{:ok, pid} ->
Logger.info("AAOS Object System started successfully")
post_startup_initialization()
{:ok, pid}
error ->
Logger.error("Failed to start AAOS Object System: #{inspect(error)}")
error
end
end
@doc """
Stops the AAOS Object System application.
Performs graceful shutdown including cleanup of system resources
and orderly termination of all objects.
## Parameters
- `_state` - Application state (unused)
## Returns
- `:ok` - Always returns ok after cleanup
"""
def stop(_state) do
Logger.info("Stopping AAOS Object System...")
cleanup_system_resources()
:ok
end
# Public API for system management
@doc """
Creates a new object in the system.
Dynamically starts a new object server under the dynamic supervisor
with the provided specification.
## Parameters
- `object_spec` - Object specification struct with id, state, methods, etc.
## Returns
- `{:ok, pid}` - Success with the object's process PID
- `{:error, reason}` - Failure reason
## Examples
iex> spec = %Object{id: "test_obj", state: %{value: 1}}
iex> Object.Application.create_object(spec)
{:ok, #PID<0.456.0>}
"""
def create_object(object_spec) do
DynamicSupervisor.start_child(
Object.DynamicSupervisor,
{Object.Server, object_spec}
)
end
@doc """
Stops an object by its ID.
Looks up the object in the registry and terminates its process
under the dynamic supervisor.
## Parameters
- `object_id` - String identifier of the object to stop
## Returns
- `:ok` - Object stopped successfully
- `{:error, :object_not_found}` - Object not found in registry
- `{:error, reason}` - Other termination error
"""
def stop_object(object_id) do
case Registry.lookup(Object.Registry, object_id) do
[{pid, _}] ->
DynamicSupervisor.terminate_child(Object.DynamicSupervisor, pid)
[] ->
{:error, :object_not_found}
end
end
@doc """
Lists all currently active objects in the system.
## Returns
- List of object IDs currently registered in the system
## Examples
iex> Object.Application.list_objects()
["ai_agent_alpha", "sensor_1", "coordinator_main"]
"""
def list_objects() do
Registry.select(Object.Registry, [{{:"$1", :"$2", :"$3"}, [], [:"$1"]}])
end
@doc """
Gets comprehensive system status information.
Returns detailed metrics about system health, performance,
and operational status across all subsystems.
## Returns
Map containing:
- `:objects` - Object count and type information
- `:performance` - System performance metrics
- `:coordination` - Coordination service metrics
- `:evolution` - Schema evolution metrics
- `:message_routing` - Message routing statistics
- `:uptime` - System uptime in milliseconds
## Examples
iex> Object.Application.get_system_status()
%{
objects: %{total: 5, by_type: %{ai_agent: 2, sensor: 3}},
performance: %{avg_response_time: 12.5},
uptime: 3600000
}
"""
def get_system_status() do
base_status = %{
objects: %{
total: count_objects(),
by_type: count_objects_by_type()
},
uptime: get_system_uptime()
}
# Add optional metrics if services are available
optional_metrics = %{}
optional_metrics = try do
Map.put(optional_metrics, :performance, Object.PerformanceMonitor.get_system_metrics())
rescue
_ -> optional_metrics
end
optional_metrics = try do
Map.put(optional_metrics, :coordination, Object.CoordinationService.get_metrics())
rescue
_ -> optional_metrics
end
optional_metrics = try do
Map.put(optional_metrics, :evolution, Object.SchemaEvolutionManager.get_evolution_metrics())
rescue
_ -> optional_metrics
end
optional_metrics = try do
Map.put(optional_metrics, :message_routing, Object.MessageRouter.get_routing_stats())
rescue
_ -> optional_metrics
end
Map.merge(base_status, optional_metrics)
end
@doc """
Creates a complete demonstration system with various object types.
Sets up a realistic demonstration environment including:
- AI agents with different capabilities
- Human client objects
- Sensor and actuator objects
- Coordinator objects
- Interaction dyads between related objects
- Coordination tasks and scenarios
This is useful for testing, demos, and understanding system behavior.
## Returns
Map containing:
- `:objects_created` - Number of successfully created objects
- `:total_objects` - Total objects attempted
- `:results` - Detailed results for each object creation attempt
## Examples
iex> Object.Application.create_demonstration_system()
%{
objects_created: 7,
total_objects: 7,
results: [{:ok, "ai_agent_alpha", #PID<0.789.0>}, ...]
}
"""
def create_demonstration_system() do
Logger.info("Creating demonstration AAOS system...")
# Create different types of objects for demonstration
demonstration_objects = [
# AI Agents
%Object{
id: "ai_agent_alpha",
subtype: :ai_agent,
state: %{intelligence_level: :advanced, specialization: :problem_solving},
methods: [:learn, :reason, :plan, :execute, :adapt, :self_modify]
},
%Object{
id: "ai_agent_beta",
subtype: :ai_agent,
state: %{intelligence_level: :intermediate, specialization: :coordination},
methods: [:learn, :coordinate, :communicate, :adapt]
},
# Human Clients
%Object{
id: "human_client_alice",
subtype: :human_client,
state: %{expertise: :engineering, trust_level: 0.8},
methods: [:communicate, :provide_feedback, :request_service]
},
# Sensor Objects
%Object{
id: "temperature_sensor_1",
subtype: :sensor_object,
state: %{sensor_type: :temperature, accuracy: 0.98, sampling_rate: 2.0},
methods: [:sense, :calibrate, :filter_noise, :transmit_data]
},
%Object{
id: "pressure_sensor_1",
subtype: :sensor_object,
state: %{sensor_type: :pressure, accuracy: 0.95, sampling_rate: 1.0},
methods: [:sense, :calibrate, :filter_noise, :transmit_data]
},
# Actuator Objects
%Object{
id: "motor_actuator_1",
subtype: :actuator_object,
state: %{actuator_type: :motor, precision: 0.95, response_time: 0.05},
methods: [:execute_action, :queue_action, :calibrate_motion, :monitor_wear]
},
# Coordinator Object
%Object{
id: "system_coordinator",
subtype: :coordinator_object,
state: %{coordination_strategy: :consensus, managed_objects: []},
methods: [:coordinate, :resolve_conflicts, :allocate_resources, :monitor_performance]
}
]
# Create all demonstration objects
results = Enum.map(demonstration_objects, fn object_spec ->
case create_object(object_spec) do
{:ok, pid} ->
Logger.info("Created object #{object_spec.id} (#{object_spec.subtype})")
{:ok, object_spec.id, pid}
error ->
Logger.error("Failed to create object #{object_spec.id}: #{inspect(error)}")
{:error, object_spec.id, error}
end
end)
# Form interaction dyads between related objects
form_demonstration_dyads()
# Start demonstration coordination tasks
start_demonstration_coordination()
success_count = Enum.count(results, fn {status, _, _} -> status == :ok end)
Logger.info("Demonstration system created: #{success_count}/#{length(demonstration_objects)} objects started")
%{
objects_created: success_count,
total_objects: length(demonstration_objects),
results: results
}
end
# Private functions
defp configure_telemetry do
# Set up telemetry for performance monitoring
:telemetry.attach_many(
"aaos-system-metrics",
[
[:object, :server, :start],
[:object, :server, :stop],
[:object, :message, :route],
[:coordination, :session, :complete],
[:evolution, :proposal, :vote]
],
&__MODULE__.handle_system_telemetry/4,
%{}
)
end
def handle_system_telemetry(event, measurements, metadata, _config) do
# Forward to performance monitor
case event do
[:object, :server, :start] ->
Object.PerformanceMonitor.record_metric("system", :objects_started, 1, metadata)
[:object, :server, :stop] ->
Object.PerformanceMonitor.record_metric("system", :objects_stopped, 1, metadata)
[:object, :message, :route] ->
Object.PerformanceMonitor.record_metric("system", :messages_routed, 1, %{
route_time: measurements[:duration]
})
_ ->
:ok
end
end
defp post_startup_initialization do
# Perform any post-startup initialization
Logger.info("Performing post-startup initialization...")
# Initialize default performance thresholds if available
try do
Object.PerformanceMonitor.set_performance_threshold(
:method_execution_time,
%{warning: 1000, critical: 5000, low_warning: 10}
)
Object.PerformanceMonitor.set_performance_threshold(
:goal_evaluation_score,
%{warning: 0.3, critical: 0.1, low_warning: 0.0}
)
rescue
_ ->
Logger.debug("Performance Monitor not available, skipping threshold setup")
catch
:exit, _ ->
Logger.debug("Performance Monitor not available, skipping threshold setup")
end
# Start system health monitoring
spawn_link(fn -> system_health_monitor() end)
Logger.info("Post-startup initialization complete")
end
defp cleanup_system_resources do
# Clean up any system resources before shutdown
Logger.info("Cleaning up system resources...")
# Stop all objects gracefully
Object.Registry
|> Registry.select([{{:"$1", :"$2", :"$3"}, [], [:"$2"]}])
|> Enum.each(fn pid ->
try do
GenServer.stop(pid, :normal, 5000)
catch
:exit, _reason -> :ok
end
end)
Logger.info("System cleanup complete")
end
defp count_objects do
Registry.count(Object.Registry)
end
defp count_objects_by_type do
try do
Object.SchemaRegistry.list_objects()
|> Enum.group_by(fn {_id, schema} -> schema.subtype end)
|> Enum.into(%{}, fn {type, objects} -> {type, length(objects)} end)
rescue
_ -> %{} # Schema registry not available
end
end
defp get_system_uptime do
# Simple uptime calculation (would be more sophisticated in production)
{uptime_ms, _} = :erlang.statistics(:wall_clock)
uptime_ms
end
defp form_demonstration_dyads do
# Form dyads between related objects for demonstration
dyad_pairs = [
{"ai_agent_alpha", "system_coordinator"},
{"ai_agent_beta", "human_client_alice"},
{"temperature_sensor_1", "ai_agent_alpha"},
{"pressure_sensor_1", "ai_agent_beta"},
{"motor_actuator_1", "system_coordinator"}
]
Enum.each(dyad_pairs, fn {obj1_id, obj2_id} ->
case Registry.lookup(Object.Registry, obj1_id) do
[{_pid, _}] ->
Object.Server.form_dyad(obj1_id, obj2_id, 0.8)
Logger.debug("Formed dyad between #{obj1_id} and #{obj2_id}")
[] ->
Logger.warning("Could not form dyad: object #{obj1_id} not found")
end
end)
end
defp start_demonstration_coordination do
# Start a demonstration coordination task
spawn_link(fn ->
:timer.sleep(5000) # Wait for objects to initialize
coordination_task = %{
type: :system_optimization,
objectives: [:efficiency, :responsiveness],
constraints: [:energy_budget, :safety_limits]
}
participating_objects = [
"ai_agent_alpha",
"ai_agent_beta",
"system_coordinator"
]
try do
case Object.CoordinationService.coordinate_objects(participating_objects, coordination_task) do
{:ok, session_id} ->
Logger.info("Started demonstration coordination session: #{session_id}")
error ->
Logger.warning("Failed to start demonstration coordination: #{inspect(error)}")
end
rescue
_ ->
Logger.debug("Coordination service not available, skipping demonstration coordination")
end
end)
end
defp system_health_monitor do
# Continuous system health monitoring
:timer.sleep(30000) # Wait 30 seconds before first check
monitor_loop()
end
defp monitor_loop do
try do
# Check system health metrics if available
try do
_system_metrics = Object.PerformanceMonitor.get_system_metrics()
alerts = Object.PerformanceMonitor.get_performance_alerts()
# Log any critical issues
critical_alerts = Enum.filter(alerts, fn {_id, alert} ->
alert.alert_level == :critical and not alert.acknowledged
end)
if length(critical_alerts) > 0 do
Logger.warning("System has #{length(critical_alerts)} critical performance alerts")
end
rescue
_ -> :ok # Performance monitor not available
end
# Check object health
object_count = count_objects()
if object_count == 0 do
Logger.debug("No objects currently running in the system")
end
# Schedule next check
:timer.sleep(60000) # Check every minute
monitor_loop()
rescue
error ->
Logger.error("System health monitor error: #{inspect(error)}")
:timer.sleep(60000)
monitor_loop()
end
end
end