Object.Server (object v0.1.2)
GenServer implementation for individual AAOS objects.
Each object runs as a separate process with its own state and mailbox, implementing the Actor model with message-passing for true concurrency.
Features
- Individual process per object for isolation and fault tolerance
- AI-enhanced reasoning and learning capabilities
- Periodic message processing and learning updates
- Heartbeat system for dyad maintenance
- Integration with schema registry and message routing
- Support for meta-DSL constructs and method execution
Process Lifecycle
- Initialization: Register with schema registry, initialize AI reasoning
- Active Phase: Handle calls/casts, process messages, perform learning
- Periodic Tasks: Heartbeats, message processing, learning updates
- Termination: Cleanup and unregister from schema registry
Objects communicate through structured messages routed via the message routing system, with support for interaction dyads and social learning.
Summary
Functions
Applies a meta-DSL construct to an object.
Returns a specification to start this module under a supervisor.
Executes a method on an object.
Forms an interaction dyad with another object.
Gets the current state of an object.
Gets communication statistics for an object.
Sends a message from one object to another.
Starts a new object server process.
Updates an object's internal state.
Functions
@spec apply_meta_dsl(Object.object_id(), atom(), any()) :: %{ optional(:state_updates) => map(), optional(:world_model_updates) => map(), optional(:goal_update) => Object.goal_function(), optional(:meta_dsl_updates) => map() }
Applies a meta-DSL construct to an object.
Executes meta-language constructs for self-reflection and modification, enabling objects to reason about and modify their own behavior, goals, and knowledge structures.
Parameters
object_id
- Object identifier (must be registered)construct
- Meta-DSL construct to execute::define
- Define new attributes or capabilities:goal
- Modify objective functions:belief
- Update world model beliefs:infer
- Perform inference on current knowledge:decide
- Make decisions based on current state:learn
- Process learning experiences:refine
- Adjust learning parameters
args
- Arguments specific to the construct
Returns
Result map containing updates to be applied:
:state_updates
- Updates to object state:world_model_updates
- Updates to world model:goal_update
- New goal function:meta_dsl_updates
- Updates to meta-DSL state
Meta-DSL Constructs
DEFINE - Create New Capabilities
Object.Server.apply_meta_dsl("agent_1", :define, {:confidence, 0.8})
# => %{state_updates: %{confidence: 0.8}}
INFER - Bayesian Reasoning
inference_data = %{observations: [%{light: :on}], priors: %{light: :off}}
Object.Server.apply_meta_dsl("agent_1", :infer, inference_data)
# => %{world_model_updates: %{beliefs: %{light: :on}}}
DECIDE - Goal-Directed Choice
context = %{options: [:explore, :exploit], current_reward: 0.5}
Object.Server.apply_meta_dsl("agent_1", :decide, context)
# => %{state_updates: %{last_action: :explore}}
REFINE - Meta-Learning
refinement = %{performance: 0.8, learning_rate: 0.01}
Object.Server.apply_meta_dsl("agent_1", :refine, refinement)
# => %{meta_dsl_updates: %{learning_parameters: %{...}}}
Examples
# Define new attribute
iex> result = Object.Server.apply_meta_dsl("agent_1", :define, {:trust, 0.9})
iex> result.state_updates
%{trust: 0.9}
# Update beliefs through inference
iex> inference = %{evidence: %{sensor_reading: 22.5}}
iex> Object.Server.apply_meta_dsl("agent_1", :infer, inference)
%{world_model_updates: %{beliefs: %{temperature: 22.5}}}
Self-Modification
Meta-DSL enables powerful self-modification:
- Behavioral Adaptation: Change response patterns
- Goal Evolution: Modify objectives based on experience
- Knowledge Integration: Update beliefs through reasoning
- Parameter Tuning: Optimize learning parameters
Safety
- Construct validation prevents invalid modifications
- Bounded update sizes prevent resource exhaustion
- Rollback capability for failed modifications
- Audit trail for all self-modifications
Returns a specification to start this module under a supervisor.
See Supervisor
.
@spec execute_method(Object.object_id(), Object.method_name(), [any()]) :: :ok | {:error, atom()}
Executes a method on an object.
Calls the specified method with given arguments on the target object with comprehensive error handling, resource protection, and performance monitoring. Methods are executed within the object's process context.
Parameters
object_id
- Object identifier (must be registered)method
- Method name (atom, must be in object's methods list)args
- Method arguments list (default: [])
Returns
:ok
- Method executed successfully{:error, reason}
- Execution failed::object_not_found
- Object not registered:method_not_available
- Method not in object's methods list:timeout
- Method execution exceeded time limit:resource_exhausted
- Insufficient system resources:method_error
- Method execution failed internally
Built-in Methods
Common methods available on most objects:
:update_state
- Update internal state:interact
- Process interaction with environment:learn
- Apply learning from experience:evaluate_goal
- Compute goal satisfaction
Subtype-specific methods:
- AI Agents:
:reason
,:plan
,:adapt
- Sensors:
:sense
,:calibrate
,:filter_noise
- Actuators:
:execute_action
,:queue_action
- Coordinators:
:coordinate
,:allocate_resources
Examples
# Execute learning method
iex> experience = %{reward: 1.0, action: :explore, state: %{x: 1}}
iex> Object.Server.execute_method("agent_1", :learn, [experience])
:ok
# Execute sensor calibration
iex> Object.Server.execute_method("temp_sensor_1", :calibrate, [])
:ok
# Error: Method not available
iex> Object.Server.execute_method("sensor_1", :fly, [])
{:error, :method_not_available}
Resource Protection
- Resource permission checked before execution
- Circuit breakers prevent system overload
- Execution timeouts prevent runaway methods
- Performance monitoring tracks method efficiency
Performance
- Method latency: ~1-10ms depending on complexity
- Timeout: 30 seconds default
- Retry logic: 3 attempts with exponential backoff
- Monitoring: Execution time and success rate tracked
@spec form_dyad(Object.object_id(), Object.object_id(), float()) :: :ok | {:error, atom()}
Forms an interaction dyad with another object.
Creates a bidirectional communication relationship between two objects with the specified compatibility score. Dyads enable enhanced communication, coordination, and social learning between object pairs.
Parameters
object_id
- First object ID (must be registered)other_object_id
- Second object ID (must be registered)compatibility_score
- Initial compatibility assessment (0.0-1.0, default 0.5)
Returns
:ok
- Dyad formed successfully{:error, reason}
- Formation failed::object_not_found
- One or both objects not registered:self_dyad_not_allowed
- Cannot form dyad with self:dyad_already_exists
- Dyad already established:compatibility_too_low
- Compatibility below minimum threshold
Compatibility Guidelines
0.0-0.3
- Low compatibility, limited interaction benefit0.3-0.7
- Moderate compatibility, good for specific tasks0.7-1.0
- High compatibility, excellent collaboration potential
Examples
# Form high-compatibility dyad
iex> Object.Server.form_dyad("ai_agent_1", "ai_agent_2", 0.8)
:ok
# Form sensor-coordinator dyad
iex> Object.Server.form_dyad("temp_sensor_1", "coordinator_1", 0.6)
:ok
# Error: Self-dyad not allowed
iex> Object.Server.form_dyad("agent_1", "agent_1")
{:error, :self_dyad_not_allowed}
Dyad Benefits
- Priority Messaging: Dyad partners get message priority
- Social Learning: Shared experiences and knowledge transfer
- Coordination: Simplified cooperation protocols
- Trust Building: Reputation and reliability tracking
- Performance: Reduced coordination overhead
Lifecycle Management
Dyads evolve over time:
- Formation: Initial creation with compatibility score
- Interaction: Regular communication and coordination
- Adaptation: Compatibility adjustment based on outcomes
- Maintenance: Heartbeat and health monitoring
- Dissolution: Automatic or manual termination
Performance
- Formation time: ~1-3ms
- Memory overhead: ~200 bytes per dyad
- Maximum dyads per object: 50 (configurable)
- Automatic cleanup of inactive dyads
@spec get_state(Object.object_id()) :: Object.object_state()
Gets the current state of an object.
Retrieves the complete current state of the specified object. This is a synchronous operation that returns the state at the time of the call.
Parameters
object_id
- Object identifier (must be registered)
Returns
- Object's current state map
- May raise if object not found or unresponsive
Examples
# Get state of a sensor object
iex> state = Object.Server.get_state("temp_sensor_1")
iex> state.temperature
22.5
# Check AI agent state
iex> Object.Server.get_state("ai_agent_alpha")
%{intelligence_level: :advanced, current_task: :learning}
Error Handling
- Raises
:noproc
if object process not found - Raises
:timeout
if object unresponsive (default: 5 seconds) - State is read-only snapshot at call time
Performance
- Operation time: ~0.1-1ms for local objects
- No side effects on object state
- Thread-safe read operation
@spec get_stats(Object.object_id()) :: %{ total_messages_sent: non_neg_integer(), total_messages_received: non_neg_integer(), pending_inbox: non_neg_integer(), pending_outbox: non_neg_integer(), active_dyads: non_neg_integer(), total_dyads: non_neg_integer(), history_size: non_neg_integer(), uptime: non_neg_integer(), message_rate: float(), dyad_efficiency: float() }
Gets communication statistics for an object.
Returns comprehensive metrics about the object's messaging patterns, interaction history, and communication performance. Useful for monitoring, debugging, and performance optimization.
Parameters
object_id
- Object identifier (must be registered)
Returns
Statistics map containing:
:total_messages_sent
- Number of messages sent by this object:total_messages_received
- Number of messages received:pending_inbox
- Current unprocessed inbox messages:pending_outbox
- Current unsent outbox messages:active_dyads
- Number of currently active interaction dyads:total_dyads
- Total dyads ever formed (including inactive):history_size
- Current message history size:uptime
- Object uptime in seconds since creation:message_rate
- Messages per second (sent + received):dyad_efficiency
- Ratio of active to total dyads
Examples
# Get basic communication stats
iex> stats = Object.Server.get_stats("agent_1")
iex> stats.total_messages_sent
42
iex> stats.active_dyads
3
# Calculate performance metrics
iex> stats = Object.Server.get_stats("coordinator_1")
iex> stats.message_rate
2.5 # messages per second
iex> stats.dyad_efficiency
0.75 # 75% of dyads are active
Performance Indicators
Key metrics for monitoring:
Communication Volume
- High volume (>100 msg/min): Active coordinator or hub object
- Medium volume (10-100 msg/min): Regular operational object
- Low volume (<10 msg/min): Peripheral or specialized object
Dyad Health
- High efficiency (>0.8): Well-connected, active collaboration
- Medium efficiency (0.5-0.8): Selective partnerships
- Low efficiency (<0.5): Poor partner selection or inactive
Processing Performance
- Low pending: Efficient message processing
- High pending: Processing bottleneck or overload
Monitoring Uses
- Performance Tuning: Identify communication bottlenecks
- Health Monitoring: Detect failed or overloaded objects
- Social Analysis: Understand interaction patterns
- Debugging: Trace message flow and delivery issues
- Capacity Planning: Plan for system scaling
Historical Trends
Statistics can be sampled over time to identify:
- Communication pattern changes
- Performance degradation
- Social network evolution
- Seasonal or cyclical behaviors
@spec send_message(Object.object_id(), Object.object_id(), atom(), any(), keyword()) :: :ok | {:error, atom()}
Sends a message from one object to another.
Routes a message through the message routing system with specified type, content, and delivery options. Messages are processed asynchronously with comprehensive error handling and delivery guarantees.
Parameters
object_id
- Sender object ID (must be registered)to_object_id
- Recipient object IDmessage_type
- Type of message for routing and handling::state_update
- State change notification:coordination
- Coordination request/response:learning_signal
- Learning data or feedback:heartbeat
- Connection health check:negotiation
- Multi-step negotiation protocol
content
- Message content (any serializable term)opts
- Delivery options::priority
-:low | :medium | :high | :critical
(default::medium
):ttl
- Time-to-live in seconds (default: 3600):requires_ack
- Delivery confirmation required (default: false):retry_count
- Maximum retry attempts (default: 3)
Returns
:ok
- Message sent successfully{:error, reason}
- Send failure::object_not_found
- Sender object not registered:throttled
- System under load, message delayed:invalid_recipient
- Recipient object invalid:message_too_large
- Content exceeds size limits
Examples
# Send coordination request
iex> Object.Server.send_message(
...> "agent_1", "coordinator_1", :coordination,
...> %{action: :join_coalition, priority: :high},
...> [priority: :high, requires_ack: true]
...> )
:ok
# Send learning signal with TTL
iex> Object.Server.send_message(
...> "learner_1", "teacher_1", :learning_signal,
...> %{reward: 1.0, experience: %{action: :explore}},
...> [ttl: 300, priority: :medium]
...> )
:ok
# Error: Object not found
iex> Object.Server.send_message(
...> "nonexistent", "agent_2", :hello, %{}
...> )
{:error, :object_not_found}
Delivery Guarantees
- Best Effort: Default delivery without acknowledgment
- At Least Once: With
requires_ack: true
- Circuit Breaker: Prevents cascade failures
- Dead Letter Queue: Failed messages queued for retry
Performance
- Message latency: ~1-5ms for local objects
- Throughput: ~1000 messages/sec per object
- Backpressure: Automatic throttling under load
- Resource usage: ~100 bytes per message overhead
@spec start_link(Object.t()) :: GenServer.on_start()
Starts a new object server process.
Creates a new GenServer process for the object and registers it in the object registry for lookup by ID. The server handles all object lifecycle management including initialization, message processing, and graceful shutdown.
Parameters
object_spec
- Object struct containing::id
- Unique object identifier:state
- Initial object state:methods
- Available methods:goal
- Objective function- Additional Object.t() fields
Returns
{:ok, pid}
- Success with process PID{:error, reason}
- Startup failure reasons::registration_failed
- Object ID already in use:init_error
- Initialization failure:resource_exhausted
- System resource limits
Process Lifecycle
- Registration: Register in schema registry and object registry
- Initialization: Set up AI reasoning, health monitoring
- Scheduling: Start periodic tasks (heartbeat, message processing)
- Ready: Process incoming calls and casts
Examples
# Start a basic object server
iex> object = Object.new(id: "test_obj", state: %{value: 1})
iex> {:ok, pid} = Object.Server.start_link(object)
iex> Process.alive?(pid)
true
# Start with registry lookup
iex> {:ok, _pid} = Object.Server.start_link(object)
iex> [{found_pid, _}] = Registry.lookup(Object.Registry, "test_obj")
iex> Process.alive?(found_pid)
true
Error Handling
- Duplicate object IDs are rejected
- Initialization failures are logged and reported
- Resource exhaustion triggers graceful degradation
- Process crashes are handled by the supervisor
Performance
- Startup time: ~5-10ms including registration
- Memory usage: ~2KB base + object state size
- Registry lookup: O(1) by object ID
@spec update_state(Object.object_id(), Object.object_state()) :: :ok | {:error, atom()}
Updates an object's internal state.
Merges the provided updates into the object's current state with validation and error handling. The update is atomic and will either completely succeed or leave the state unchanged.
Parameters
object_id
- Object identifier (must be registered)state_updates
- Map of state updates to merge with current state
Returns
:ok
- Update successful{:error, reason}
- Update failed::object_not_found
- Object not registered:invalid_state
- State update validation failed:state_too_large
- Update would exceed size limits:forbidden_keys
- Update contains forbidden keys
Validation Rules
- State updates must be maps
- Combined state cannot exceed 100 entries
- Cannot update system keys (:internal, :system, :meta)
- Numeric values must be finite numbers
Examples
# Update sensor readings
iex> Object.Server.update_state("temp_sensor_1", %{
...> temperature: 23.5,
...> humidity: 68,
...> last_reading: DateTime.utc_now()
...> })
:ok
# Incremental energy update
iex> Object.Server.update_state("robot_1", %{energy: 95})
:ok
# Error: Forbidden key
iex> Object.Server.update_state("agent_1", %{__system__: "hack"})
{:error, :forbidden_keys}
Atomicity
- Updates are applied atomically (all or nothing)
- Concurrent updates are serialized
- No partial state corruption possible
- Original state preserved on validation failure
Performance
- Update time: ~0.5-2ms depending on state size
- Memory overhead: Temporary copy during validation
- Throughput: ~500 updates/sec per object