defmodule Object do require Logger @moduledoc """ Object-Oriented Reinforcement Learning (OORL) Object implementation based on Autonomous Agent Object Specification (AAOS). Represents an autonomous object with internal state, methods, goals, world model, interaction history, and self-descriptive meta-DSL capabilities. ## Core Features - **Autonomous State Management**: Each object maintains its own internal state - **Method Execution**: Objects can execute predefined and dynamic methods - **Goal-Oriented Behavior**: Objects have objective functions that guide their actions - **World Model**: Objects maintain beliefs about their environment - **Interaction History**: Complete record of all interactions with other objects - **Meta-DSL**: Self-descriptive language for introspection and self-modification - **Communication**: Mailbox system for message passing with other objects - **Learning**: Reinforcement learning capabilities with experience replay - **Social Learning**: Ability to learn from interactions with peer objects ## Object Lifecycle 1. **Creation**: Objects are created with initial state and capabilities 2. **Interaction**: Objects interact with environment and other objects 3. **Learning**: Objects update their policies based on experiences 4. **Evolution**: Objects can modify their own behavior through meta-DSL 5. **Coordination**: Objects form dyads and coalitions for collaborative tasks ## Meta-DSL Constructs Objects support several meta-language constructs for self-modification: - `: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 ## Examples # Create a basic object object = Object.new(id: "agent_1", state: %{energy: 100}) # Update object state object = Object.update_state(object, %{energy: 95}) # Execute a method {:ok, updated_object} = Object.execute_method(object, :learn, [experience]) # Apply meta-DSL construct result = Object.apply_meta_dsl(object, :infer, inference_data) """ defstruct [ :id, :state, :methods, :goal, :world_model, :interaction_history, :meta_dsl, :parameters, :mailbox, :subtype, :created_at, :updated_at ] @typedoc """ Core Object type representing an autonomous agent in the AAOS system. ## Fields - `id` - Unique identifier for the object (must be unique across the system) - `state` - Internal state map containing object's current state variables - `methods` - List of available methods this object can execute - `goal` - Objective function that evaluates state for goal achievement - `world_model` - Beliefs and knowledge about the environment - `interaction_history` - Complete history of interactions with other objects - `meta_dsl` - Meta-language constructs for self-reflection and modification - `parameters` - Configuration parameters for object behavior - `mailbox` - Communication mailbox for message passing - `subtype` - Specific object subtype (ai_agent, sensor_object, etc.) - `created_at` - Timestamp when object was created - `updated_at` - Timestamp of last modification """ @type t :: %__MODULE__{ id: object_id(), state: object_state(), methods: [method_name()], goal: goal_function(), world_model: world_model(), interaction_history: [interaction_record()], meta_dsl: meta_dsl_state(), parameters: parameters_map(), mailbox: Object.Mailbox.t(), subtype: object_subtype(), created_at: DateTime.t(), updated_at: DateTime.t() } @typedoc "Unique object identifier" @type object_id :: String.t() @typedoc "Object's internal state containing any key-value pairs" @type object_state :: map() @typedoc "Name of a method that can be executed on an object" @type method_name :: atom() @typedoc "Function that evaluates how well the object's current state satisfies its goals" @type goal_function :: (object_state() -> number()) @typedoc """ Object's beliefs and knowledge about its environment. Contains: - `beliefs` - Current beliefs about the world state - `uncertainties` - Uncertainty estimates for beliefs """ @type world_model :: %{ beliefs: map(), uncertainties: map() } @typedoc """ Record of a single interaction with another object or the environment. Contains: - `timestamp` - When the interaction occurred - `type` - Type of interaction (message, coordination, etc.) - `data` - Interaction-specific data - `outcome` - Result of the interaction """ @type interaction_record :: %{ timestamp: DateTime.t(), type: atom(), data: any(), outcome: term() } @typedoc """ Meta-DSL state for self-reflection and modification capabilities. Contains: - `constructs` - Available meta-DSL constructs - `execution_context` - Current execution context - `learning_parameters` - Parameters for learning algorithms """ @type meta_dsl_state :: %{ constructs: [atom()], execution_context: map(), learning_parameters: %{ learning_rate: float(), exploration_rate: float(), discount_factor: float() } } @typedoc "Configuration parameters for object behavior" @type parameters_map :: map() @typedoc "Object subtype defining specialized behavior" @type object_subtype :: :ai_agent | :human_client | :sensor_object | :actuator_object | :coordinator_object | :generic @doc """ Creates a new Object with the specified attributes. Initializes a complete autonomous object with all AAOS-compliant capabilities including communication, learning, and meta-reasoning. Objects are created with default behaviors that can be customized through the options. ## Parameters - `opts` - Keyword list of options for object creation: - `:id` - Unique identifier for the object (auto-generated if not provided) - `:state` - Internal state parameters (default: empty map) - `:methods` - Available methods/functions (default: [:update_state, :interact, :learn]) - `:goal` - Objective function (default: maximize state values) - `:world_model` - Beliefs about environment (default: empty beliefs) - `:meta_dsl` - Self-descriptive meta-language constructs (auto-initialized) - `:parameters` - Configuration parameters (default: empty map) - `:subtype` - Object specialization type (default: :generic) ## Returns New Object struct with all fields initialized and ready for use. ## Examples # Create a basic sensor object # iex> Object.new(id: "sensor_1", state: %{readings: [1, 2, 3]}) %Object{id: "sensor_1", state: %{readings: [1, 2, 3]}, ...} # Create an AI agent with custom goal function # iex> goal_fn = fn state -> Map.get(state, :performance, 0) end # iex> Object.new(id: "ai_agent", subtype: :ai_agent, goal: goal_fn) %Object{id: "ai_agent", subtype: :ai_agent, goal: #Function<...>, ...} # Create object with specific methods and parameters # iex> Object.new( ...> id: "coordinator", ...> methods: [:coordinate, :allocate_resources, :monitor], ...> parameters: %{max_coordination_objects: 10} ...> ) %Object{id: "coordinator", methods: [:coordinate, :allocate_resources, :monitor], ...} ## Performance Characteristics - Object creation: ~0.1ms for basic objects - Memory usage: ~1KB base + state size - Mailbox initialization: ~0.05ms - Meta-DSL setup: ~0.02ms """ @spec new(keyword()) :: t() def new(opts \\ []) do now = DateTime.utc_now() object_id = Keyword.get(opts, :id, generate_id()) %__MODULE__{ id: object_id, state: Keyword.get(opts, :state, %{}), methods: Keyword.get(opts, :methods, [:update_state, :interact, :learn]), goal: Keyword.get(opts, :goal, &default_goal/1), world_model: Keyword.get(opts, :world_model, %{beliefs: %{}, uncertainties: %{}}), interaction_history: [], meta_dsl: init_meta_dsl(), parameters: Keyword.get(opts, :parameters, %{}), mailbox: Object.Mailbox.new(object_id), subtype: Keyword.get(opts, :subtype, :generic), created_at: now, updated_at: now } end @doc """ Updates the object's internal state with comprehensive error handling. Performs a safe merge of the new state with the existing state, validating the update before applying it. If validation fails, the original object is returned unchanged and an error is logged. ## Parameters - `object` - The object to update - `new_state` - Map of state updates to merge into current state ## Returns Updated object with merged state, or unchanged object if validation failed. ## Validation Rules - New state must be a map - State size cannot exceed 100 entries - Cannot contain forbidden keys (:__internal__, :__system__, :__meta__) ## Examples # Update sensor readings # iex> sensor = Object.new(id: "temp_sensor", state: %{temp: 20.0}) # iex> updated = Object.update_state(sensor, %{temp: 22.5, humidity: 65}) # iex> updated.state %{temp: 22.5, humidity: 65} # Incremental updates preserve existing state # iex> agent = Object.new(state: %{energy: 100, position: {0, 0}}) # iex> updated = Object.update_state(agent, %{energy: 95}) # iex> updated.state %{energy: 95, position: {0, 0}} ## Error Handling - Invalid state formats are rejected and logged - State size limits prevent memory exhaustion - Forbidden keys are blocked to maintain system integrity - All errors are handled gracefully without crashing the object """ @spec update_state(t(), object_state()) :: t() def update_state(%__MODULE__{} = object, new_state) do try do # Validate the new state case validate_state_update(object.state, new_state) do :ok -> %{object | state: Map.merge(object.state, new_state), updated_at: DateTime.utc_now() } {:error, reason} -> Logger.error("Invalid state update for object #{object.id}: #{inspect(reason)}") # Return object unchanged on validation failure object end rescue error -> Logger.error("Critical error in update_state for object #{object.id}: #{inspect(error)}") # Return object unchanged on exception object end end @doc """ Processes an interaction with another object or environment with error protection. Handles various types of interactions including messages, coordination requests, and environmental events. All interactions are recorded in the object's history for learning and analysis purposes. ## Parameters - `object` - The object processing the interaction - `interaction` - Map describing the interaction with required fields: - `:type` - Type of interaction (atom) - Other fields depend on interaction type ## Returns Updated object with interaction recorded in history. ## Interaction Types - `:message` - Message from another object - `:coordination` - Coordination request or response - `:environmental` - Environmental event or observation - `:learning` - Learning signal or feedback ## Examples # Process a message interaction # iex> interaction = %{type: :message, from: "agent_2", content: "hello"} # iex> updated = Object.interact(object, interaction) # iex> length(updated.interaction_history) 1 # Process coordination request # iex> coord = %{type: :coordination, action: :form_coalition} # iex> Object.interact(object, coord) %Object{interaction_history: [%{type: :coordination, outcome: :success, ...}], ...} ## Error Recovery - Failed interactions are still recorded with error outcomes - Circuit breaker prevents cascade failures - Retry logic for transient failures - Graceful degradation maintains object functionality """ @spec interact(t(), map()) :: t() def interact(%__MODULE__{} = object, interaction) do try do {:ok, process_interaction_internal(object, interaction)} rescue error -> {:error, error, :retry} end |> case do {:ok, updated_object} -> updated_object {:error, reason, _recovery_action} -> # Log the error and return object with failed interaction recorded failed_interaction = %{ timestamp: DateTime.utc_now(), type: Map.get(interaction, :type, :unknown), data: interaction, outcome: {:error, reason} } %{object | interaction_history: [failed_interaction | object.interaction_history], updated_at: DateTime.utc_now() } end end @doc """ Executes a method on the object with comprehensive error handling and resource protection. Invokes the specified method with given arguments, ensuring the method is available and the system has sufficient resources. All method executions are protected by circuit breakers and retry logic to ensure system stability. ## Parameters - `object` - The object to execute the method on - `method` - Method name (must be in object's methods list) - `args` - List of arguments to pass to the method (default: []) ## Returns - `{:ok, updated_object}` - Method executed successfully - `{:error, reason}` - Method execution failed ## Error Conditions - `:method_not_available` - Method not in object's methods list - `:throttled` - System under high load, execution delayed - `:timeout` - Method execution exceeded time limit - `:resource_exhausted` - Insufficient system resources ## Examples # Execute a learning method # iex> experience = %{reward: 1.0, action: :move_forward} # iex> {:ok, updated} = Object.execute_method(object, :learn, [experience]) # iex> updated.state.q_values %{move_forward: 0.01} # Execute state update method # iex> {:ok, updated} = Object.execute_method(object, :update_state, [%{energy: 95}]) # iex> updated.state.energy 95 # Method not available # iex> Object.execute_method(object, :invalid_method, []) {: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 """ @spec execute_method(t(), method_name(), [any()]) :: {:ok, t()} | {:error, atom() | tuple()} def execute_method(%__MODULE__{} = object, method, args \\ []) when is_atom(method) do # Check method availability with :ok <- :ok, # Skip resource check true <- method in object.methods do # Execute method directly result = try do {:ok, execute_method_internal(object, method, args)} catch {:error, reason} -> {:error, reason, :retry} error -> {:error, error, :retry} rescue error -> {:error, error, :retry} end # Skip operation reporting case result do {:ok, updated_object} -> {:ok, updated_object} {:error, reason, recovery_action} -> Logger.warning("Method execution failed: #{inspect(reason)}, suggested recovery: #{inspect(recovery_action)}") {:error, reason} end else false -> {:error, :method_not_available} {:error, reason} -> {:error, reason} {:throttle, delay} -> {:error, {:throttled, delay}} end end @doc """ Updates the object's world model based on observations. Merges new observations into the object's current beliefs about the world. This is a fundamental operation for maintaining accurate environmental knowledge and enabling effective decision-making. ## Parameters - `object` - The object whose world model to update - `observations` - Map of new observations to incorporate ## Returns Updated object with modified world model. ## Examples # Update environmental observations # iex> obs = %{temperature: 22.5, other_agents: ["agent_2", "agent_3"]} # iex> updated = Object.update_world_model(object, obs) # iex> updated.world_model.beliefs.temperature 22.5 # Incremental belief updates # iex> Object.update_world_model(object, %{light_level: :bright}) %Object{world_model: %{beliefs: %{light_level: :bright}, ...}, ...} ## World Model Structure The world model contains: - Current beliefs about environmental state - Uncertainty estimates for each belief - Historical observations for trend analysis """ @spec update_world_model(t(), map()) :: t() def update_world_model(%__MODULE__{} = object, observations) do updated_beliefs = Map.merge(object.world_model.beliefs, observations) updated_world_model = %{object.world_model | beliefs: updated_beliefs} %{object | world_model: updated_world_model, updated_at: DateTime.utc_now() } end @doc """ Implements learning functionality using meta-DSL constructs with error resilience. Processes learning experiences using reinforcement learning principles, updating the object's internal policies and knowledge. Learning is protected by resource monitoring and circuit breakers to ensure system stability. ## Parameters - `object` - The object to perform learning on - `experience` - Learning experience map containing: - `:reward` - Numerical reward signal - `:action` - Action that was taken - Additional context-specific fields ## Returns Updated object with learning applied, or unchanged object if learning failed. ## Learning Algorithm Uses Q-learning with the following update rule: ``` Q(s,a) = Q(s,a) + α * (r - Q(s,a)) ``` Where: - α = learning rate - r = reward - Q(s,a) = action-value function ## Examples # Learn from positive reward # iex> exp = %{reward: 1.0, action: :explore, state: %{position: {1, 1}}} # iex> learned = Object.learn(object, exp) # iex> learned.state.q_values[:explore] 0.01 # Learn from negative reward # iex> exp = %{reward: -0.5, action: :retreat} # iex> Object.learn(object, exp) %Object{state: %{q_values: %{retreat: -0.005}}, ...} ## Resource Management - Learning requests resource permission before execution - Exponential backoff retry strategy for failures - Circuit breaker prevents learning system overload - Performance monitoring tracks learning effectiveness """ @spec learn(t(), map()) :: t() def learn(%__MODULE__{} = object, experience) do # Execute learning directly without resource monitoring case learn_internal(object, experience) do {:ok, learned_object} -> learned_object {:error, reason} -> # Log error and return original object Logger.warning("Learning failed for #{object.id}: #{inspect(reason)}") object end end @doc """ Evaluates the object's goal function against current state. Computes how well the object's current state satisfies its objectives by applying the goal function to the current state. This is used for decision-making and learning signal generation. ## Parameters - `object` - The object whose goal to evaluate ## Returns Numerical goal satisfaction score. Higher values indicate better goal achievement. ## Examples # Object with energy maximization goal # iex> object = Object.new(state: %{energy: 80}) # iex> Object.evaluate_goal(object) 80 # Custom goal function # iex> goal_fn = fn state -> state.x + state.y end # iex> object = Object.new(state: %{x: 3, y: 4}, goal: goal_fn) # iex> Object.evaluate_goal(object) 7 ## Goal Function Types - **Maximization**: Maximize sum of numeric state values (default) - **Distance**: Minimize distance to target state - **Composite**: Weighted combination of multiple objectives - **Learned**: Evolved through meta-learning processes """ @spec evaluate_goal(t()) :: number() def evaluate_goal(%__MODULE__{} = object) do object.goal.(object.state) end @doc """ Applies meta-DSL constructs for self-reflection and modification. Executes meta-language constructs that allow objects to reason about and modify their own behavior, state, and goals. This is a core capability for autonomous self-improvement and adaptation. ## Parameters - `object` - The object to apply meta-DSL construct to - `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 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 ## Examples # Define a new attribute # iex> result = Object.apply_meta_dsl(object, :define, {:confidence, 0.8}) # iex> result.state_updates %{confidence: 0.8} # Update beliefs through inference # iex> inference_data = %{observations: [%{light: :on}], priors: %{light: :off}} # iex> Object.apply_meta_dsl(object, :infer, inference_data) %{world_model_updates: %{beliefs: %{light: :on}}, ...} # Make a decision # iex> context = %{options: [:explore, :exploit], current_reward: 0.5} # iex> Object.apply_meta_dsl(object, :decide, context) %{state_updates: %{last_action: :explore}, ...} ## Meta-DSL Constructs Each construct implements specific self-modification capabilities: - **DEFINE**: Create new state variables or capabilities - **GOAL**: Modify or replace objective functions - **BELIEF**: Update world model through reasoning - **INFER**: Bayesian inference on observations - **DECIDE**: Goal-directed decision making - **LEARN**: Experience-based learning - **REFINE**: Meta-learning parameter adjustment """ @spec apply_meta_dsl(t(), atom(), any()) :: %{ optional(:state_updates) => map(), optional(:world_model_updates) => map(), optional(:goal_update) => goal_function(), optional(:meta_dsl_updates) => map() } def apply_meta_dsl(%__MODULE__{} = object, construct, args) do case construct do :define -> define_new_attribute(object, args) :goal -> modify_goal(object, args) :belief -> update_belief(object, args) :infer -> perform_inference(object, args) :decide -> make_decision(object, args) :learn -> process_learning(object, args) :refine -> refine_attributes(object, args) _ -> %{state_updates: %{}, world_model_updates: %{}} end end @doc """ Calculates similarity between two objects. Computes a similarity score between two objects based on their state, methods, and goal functions. This is useful for clustering, coalition formation, and social learning partner selection. ## Parameters - `obj1` - First object for comparison - `obj2` - Second object for comparison ## Returns Similarity score between 0.0 (completely different) and 1.0 (identical). ## Similarity Metrics The overall similarity is the average of: - **State similarity**: Based on common state variables and their values - **Method similarity**: Jaccard similarity of method sets - **Goal similarity**: Functional similarity based on sample evaluations ## Examples # Identical objects # iex> obj1 = Object.new(state: %{x: 1}) # iex> obj2 = Object.new(state: %{x: 1}) # iex> Object.similarity(obj1, obj2) 1.0 # Partially similar objects # iex> sensor1 = Object.new(methods: [:sense, :transmit]) # iex> sensor2 = Object.new(methods: [:sense, :filter]) # iex> Object.similarity(sensor1, sensor2) # 50% method overlap 0.67 ## Use Cases - **Coalition Formation**: Find compatible partners - **Social Learning**: Identify good imitation targets - **Object Clustering**: Group similar objects - **Dyad Formation**: Assess interaction compatibility """ @spec similarity(t(), t()) :: float() def similarity(%__MODULE__{} = obj1, %__MODULE__{} = obj2) do state_sim = state_similarity(obj1.state, obj2.state) method_sim = method_similarity(obj1.methods, obj2.methods) goal_sim = goal_similarity(obj1, obj2) (state_sim + method_sim + goal_sim) / 3 end @doc """ Generates an embedding representation of the object. Creates a dense vector representation of the object that captures its essential characteristics. This embedding can be used for similarity calculations, clustering, and machine learning applications. ## Parameters - `object` - The object to embed - `dimension` - Embedding vector dimension (default: 64) ## Returns List of floats representing the object in the embedding space. Values are normalized to the range [-1, 1]. ## Embedding Strategy The embedding is based on: - Object state hash for state information - Methods hash for capability information - Deterministic random generation for reproducibility ## Examples # Generate 64-dimensional embedding # iex> embedding = Object.embed(object) # iex> length(embedding) 64 # iex> Enum.all?(embedding, fn x -> x >= -1 and x <= 1 end) true # Custom dimension # iex> small_embed = Object.embed(object, 8) # iex> length(small_embed) 8 ## Use Cases - **Similarity Search**: Find similar objects efficiently - **Clustering**: Group objects by embedded characteristics - **Visualization**: Project objects to 2D/3D for analysis - **Machine Learning**: Features for ML models ## Properties - **Deterministic**: Same object always produces same embedding - **Stable**: Small object changes produce small embedding changes - **Distributed**: Similar objects have similar embeddings """ @spec embed(t(), pos_integer()) :: [float()] def embed(%__MODULE__{} = object, dimension \\ 64) do # Simple embedding based on object attributes state_hash = :erlang.phash2(object.state) methods_hash = :erlang.phash2(object.methods) # Generate pseudo-random embedding based on object characteristics :rand.seed(:exsplus, {state_hash, methods_hash, dimension}) for _ <- 1..dimension do :rand.uniform() * 2 - 1 # Values between -1 and 1 end end @doc """ Sends a message to another object via the mailbox system with delivery guarantees. Routes a message through the mailbox and message routing system with comprehensive error handling, delivery guarantees, and dead letter queue fallback for failed deliveries. All messages are tracked for debugging and performance analysis. ## Parameters - `object` - The sending object - `to_object_id` - ID of the recipient object - `message_type` - Type of message (atom) for routing and handling - `content` - Message content (any term) - `opts` - Delivery options: - `:priority` - Message priority (:low, :medium, :high, :critical) - `:requires_ack` - Whether delivery confirmation is required - `:ttl` - Time-to-live in seconds (default: 3600) - `:retry_count` - Number of retry attempts on failure ## Returns Updated object with message sent and mailbox updated. ## Message Types Common message types include: - `:state_update` - State change notification - `:coordination` - Coordination request/response - `:learning_signal` - Learning feedback or data - `:heartbeat` - Connectivity check - `:negotiation` - Negotiation protocol messages ## Examples # Send a coordination request # iex> updated = Object.send_message(object, "coordinator_1", ...> :coordination, %{action: :form_coalition}, ...> priority: :high, requires_ack: true) # iex> length(updated.mailbox.outbox) 1 # Send learning signal with TTL # iex> Object.send_message(object, "learner_2", ...> :learning_signal, %{reward: 1.0}, ttl: 300) %Object{mailbox: %{outbox: [%{ttl: 300, ...}], ...}, ...} ## Delivery Guarantees - **At-least-once**: Messages with `requires_ack: true` - **Best-effort**: Regular messages (may be lost under extreme load) - **Dead letter queue**: Failed messages are queued for retry - **Circuit breaker**: Prevents cascade failures from unreachable objects ## Error Handling - Message validation before sending - Automatic retry with exponential backoff - Dead letter queue for persistent failures - Graceful degradation under resource pressure """ @spec send_message(t(), object_id(), atom(), any(), keyword()) :: t() def send_message(%__MODULE__{} = object, to_object_id, message_type, content, opts \\ []) do # Create enhanced message with error handling metadata enhanced_opts = Keyword.merge(opts, [ sender_id: object.id, timestamp: DateTime.utc_now(), retry_count: 0, circuit_breaker: :message_delivery ]) try do updated_mailbox = Object.Mailbox.send_message(object.mailbox, to_object_id, message_type, content, enhanced_opts) %{object | mailbox: updated_mailbox, updated_at: DateTime.utc_now() } rescue error -> Logger.error("Exception in send_message for object #{object.id}: #{inspect(error)}") object # Return unchanged object on exception end end @doc """ Receives a message into the object's mailbox with error resilience. Accepts an incoming message into the object's mailbox with comprehensive validation, error recovery, and poison message handling. Messages are processed according to their type and priority. ## Parameters - `object` - The receiving object - `message` - Message to receive with required fields: - `:id` - Unique message identifier - `:from` - Sender object ID - `:to` - Recipient object ID (should match this object) - `:type` - Message type (atom) - `:content` - Message content - `:timestamp` - Message timestamp ## Returns - `{:ok, updated_object}` - Message received successfully - `{:error, reason}` - Message reception failed ## Error Conditions - `:malformed_message` - Message missing required fields - `:mailbox_full` - Mailbox capacity exceeded - `:invalid_timestamp` - Message timestamp invalid - `:poison_message` - Message failed validation multiple times ## Examples # Receive a valid message # iex> message = %{ ...> id: "msg_123", ...> from: "sender_1", ...> to: object.id, ...> type: :coordination, ...> content: %{action: :join_coalition}, ...> timestamp: DateTime.utc_now() ...> } # iex> {:ok, updated} = Object.receive_message(object, message) # iex> length(updated.mailbox.inbox) 1 # Invalid message format # iex> bad_message = %{invalid: true} # iex> Object.receive_message(object, bad_message) {:error, {:malformed_message, {:missing_fields, [:id, :from, ...]}}} ## Message Processing - **Validation**: Format and field validation - **Deduplication**: Prevents duplicate message processing - **Priority Ordering**: High-priority messages processed first - **Acknowledgments**: Automatic ACK for messages requiring confirmation ## Resilience Features - Malformed messages sent to poison message queue - Transient errors trigger retry logic - Circuit breaker prevents mailbox overload - Graceful degradation under resource pressure """ @spec receive_message(t(), map()) :: {:ok, t()} | {:error, atom() | tuple()} def receive_message(%__MODULE__{} = object, message) do try do # Validate message format before processing case validate_message_format(message) do :ok -> case Object.Mailbox.receive_message(object.mailbox, message) do {:error, reason} -> Logger.error("Mailbox error for object #{object.id}: #{inspect(reason)}") {:error, reason} updated_mailbox -> updated_object = %{object | mailbox: updated_mailbox, updated_at: DateTime.utc_now() } {:ok, updated_object} end {:error, validation_error} -> # Log malformed message instead of dead letter queue Logger.warning("Malformed message for object #{object.id}: #{inspect(validation_error)}") {:error, {:malformed_message, validation_error}} end rescue error -> Logger.error("Critical error in receive_message for object #{object.id}: #{inspect(error)}") {:error, {:exception, error}} end end @doc """ Processes all messages in the object's mailbox. Processes all pending messages in the inbox according to priority and type, applying appropriate message handlers and updating object state as needed. This is typically called periodically by the object server. ## Parameters - `object` - The object whose messages to process ## Returns `{processed_messages, updated_object}` where: - `processed_messages` - List of processed messages with outcomes - `updated_object` - Object with updated state and cleared inbox ## Processing Order Messages are processed in priority order: 1. `:critical` - System-critical messages 2. `:high` - Important coordination messages 3. `:medium` - Regular operational messages 4. `:low` - Background and maintenance messages ## Examples # Process accumulated messages # {processed, updated} = Object.process_messages(object) # length(processed) == 3 # length(updated.mailbox.inbox) == 0 # Check processing outcomes # {[{msg1, result1}, {msg2, result2}], _obj} = Object.process_messages(object) # result1 == {:coordination_received, %{action: :form_coalition}} ## Message Handlers Each message type has a specific handler: - `:state_update` → Update object state - `:coordination` → Process coordination request - `:learning_signal` → Apply learning update - `:heartbeat` → Update connection status - `:negotiation` → Handle negotiation step ## Performance - Batch processing for efficiency - Priority-based ordering prevents starvation - Bounded processing time prevents blocking - Error isolation prevents cascade failures """ @spec process_messages(t()) :: {[{map(), term()}], t()} def process_messages(%__MODULE__{} = object) do {processed_messages, updated_mailbox} = Object.Mailbox.process_inbox(object.mailbox) updated_object = %{object | mailbox: updated_mailbox, updated_at: DateTime.utc_now() } {processed_messages, updated_object} end @doc """ Forms an interaction dyad with another object. Creates a bidirectional interaction relationship with another object, enabling enhanced communication, coordination, and social learning. Dyads are fundamental units of social interaction in the AAOS system. ## Parameters - `object` - First object in the dyad - `other_object_id` - ID of the second object - `compatibility_score` - Initial compatibility assessment (0.0-1.0, default: 0.5) ## Returns Updated object with dyad information added to mailbox. ## Compatibility Scoring Compatibility scores guide dyad effectiveness: - `0.0-0.3` - Low compatibility, limited interaction benefit - `0.3-0.7` - Moderate compatibility, good for specific tasks - `0.7-1.0` - High compatibility, excellent collaboration potential ## Examples # Form dyad with high compatibility # iex> updated = Object.form_interaction_dyad(object, "agent_2", 0.8) # iex> dyads = Object.Mailbox.get_active_dyads(updated.mailbox) # iex> map_size(dyads) 1 # Default compatibility # iex> Object.form_interaction_dyad(object, "sensor_1") %Object{mailbox: %{interaction_dyads: %{"obj_1-sensor_1" => %{...}}, ...}, ...} ## Dyad Benefits - **Enhanced Communication**: Priority message routing - **Social Learning**: Shared experience and knowledge - **Coordination**: Simplified cooperation protocols - **Trust Building**: Reputation and reliability tracking ## Lifecycle 1. **Formation**: Initial dyad creation with compatibility assessment 2. **Interaction**: Regular communication and coordination 3. **Evolution**: Compatibility adjustment based on outcomes 4. **Dissolution**: Automatic or manual dyad termination """ @spec form_interaction_dyad(t(), object_id(), float()) :: t() def form_interaction_dyad(%__MODULE__{} = object, other_object_id, compatibility_score \\ 0.5) do updated_mailbox = Object.Mailbox.form_dyad(object.mailbox, other_object_id, compatibility_score) %{object | mailbox: updated_mailbox, updated_at: DateTime.utc_now() } end @doc """ Gets the object's mailbox statistics. Retrieves comprehensive statistics about the object's communication patterns, interaction history, and mailbox performance. Useful for monitoring, debugging, and performance optimization. ## Parameters - `object` - The object to get statistics for ## Returns Map containing: - `:total_messages_sent` - Number of messages sent - `:total_messages_received` - Number of messages received - `:pending_inbox` - Current inbox message count - `:pending_outbox` - Current outbox message count - `:active_dyads` - Number of active interaction dyads - `:total_dyads` - Total dyads (including inactive) - `:history_size` - Current message history size - `:uptime` - Object uptime in seconds ## Examples # iex> stats = Object.get_communication_stats(object) # iex> stats.total_messages_sent 15 # iex> stats.active_dyads 3 # iex> stats.uptime 3600 ## Monitoring Uses - **Performance**: Message throughput and latency - **Health**: Mailbox capacity and processing rates - **Social**: Interaction patterns and dyad effectiveness - **Debugging**: Message flow analysis and error tracking ## Performance Metrics Key performance indicators: - Messages per second: `total_messages / uptime` - Dyad efficiency: `active_dyads / total_dyads` - Processing ratio: `pending_inbox / total_received` """ @spec get_communication_stats(t()) :: %{ 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() } def get_communication_stats(%__MODULE__{} = object) do Object.Mailbox.get_stats(object.mailbox) end @doc """ Creates a specialized object subtype. Factory function for creating objects with specialized behaviors and capabilities based on their intended role in the system. Each subtype comes with predefined methods, state structure, and behavioral patterns. ## Parameters - `subtype` - Object subtype to create: - `:ai_agent` - AI reasoning and learning agent - `:human_client` - Human user interaction interface - `:sensor_object` - Environmental sensing and data collection - `:actuator_object` - Physical action and control - `:coordinator_object` - Multi-object coordination and management - `opts` - Additional options passed to subtype constructor ## Returns Specialized object with subtype-specific capabilities. ## Subtype Characteristics ### AI Agent - Methods: [:learn, :reason, :plan, :execute, :adapt, :self_modify] - Capabilities: Advanced reasoning, meta-learning, adaptation - Use cases: Autonomous decision making, complex problem solving ### Human Client - Methods: [:communicate, :provide_feedback, :request_service] - Capabilities: Natural language interface, preference learning - Use cases: Human-AI collaboration, user interfaces ### Sensor Object - Methods: [:sense, :calibrate, :filter_noise, :transmit_data] - Capabilities: Environmental monitoring, data preprocessing - Use cases: IoT sensors, monitoring systems ### Actuator Object - Methods: [:execute_action, :queue_action, :calibrate_motion, :monitor_wear] - Capabilities: Physical control, motion planning, safety monitoring - Use cases: Robotics, industrial control, automation ### Coordinator Object - Methods: [:coordinate, :resolve_conflicts, :allocate_resources, :monitor_performance] - Capabilities: Multi-agent coordination, resource management - Use cases: System orchestration, resource allocation ## Examples # Create an AI agent with advanced capabilities # iex> agent = Object.create_subtype(:ai_agent, ...> id: "reasoning_agent", ...> state: %{intelligence_level: :advanced} ...> ) # iex> agent.subtype :ai_agent # iex> :reason in agent.methods true # Create a sensor with specific configuration # iex> sensor = Object.create_subtype(:sensor_object, ...> id: "temp_sensor", ...> state: %{sensor_type: :temperature, accuracy: 0.98} ...> ) # iex> :calibrate in sensor.methods true ## Customization All subtypes can be further customized: - Add additional methods - Modify state structure - Override default behaviors - Extend capabilities """ @spec create_subtype(object_subtype(), keyword()) :: t() def create_subtype(subtype, opts \\ []) do case subtype do :ai_agent -> Object.Subtypes.AIAgent.new(opts) :human_client -> Object.Subtypes.HumanClient.new(opts) :sensor_object -> Object.Subtypes.SensorObject.new(opts) :actuator_object -> Object.Subtypes.ActuatorObject.new(opts) :coordinator_object -> Object.Subtypes.CoordinatorObject.new(opts) _ -> new([subtype: subtype] ++ opts) end end # Private functions defp generate_id do :crypto.strong_rand_bytes(8) |> Base.encode16() |> String.downcase() end defp init_meta_dsl do %{ constructs: [:define, :goal, :belief, :infer, :decide, :learn, :refine], execution_context: %{}, learning_parameters: %{ learning_rate: 0.01, exploration_rate: 0.1, discount_factor: 0.95 } } end defp default_goal(state) do # Default goal: maximize state value sum state |> Map.values() |> Enum.filter(&is_number/1) |> Enum.sum() end defp define_new_attribute(_object, {attribute, value}) do %{state_updates: %{attribute => value}} end defp modify_goal(_object, new_goal) when is_function(new_goal) do %{goal_update: new_goal} end defp update_belief(_object, {belief_key, belief_value}) do %{world_model_updates: %{beliefs: %{belief_key => belief_value}}} end defp perform_inference(object, inference_data) do # Bayesian inference on world model updated_beliefs = process_bayesian_update(object.world_model.beliefs, inference_data) %{world_model_updates: %{beliefs: updated_beliefs}} end defp make_decision(object, decision_context) do # Decision making based on goal and current state action = select_optimal_action(object, decision_context) %{state_updates: %{last_action: action}} end defp process_learning(object, experience) do # Learning from experience using reinforcement learning principles reward = extract_reward(experience) state_updates = update_q_values(object, experience, reward) # Update world model based on experience world_model_updates = extract_world_model_updates(experience) %{ state_updates: state_updates, world_model_updates: world_model_updates } end defp refine_attributes(object, refinement_data) do # Meta-learning: refine learning parameters new_params = adjust_learning_parameters(object.meta_dsl.learning_parameters, refinement_data) %{meta_dsl_updates: %{learning_parameters: new_params}} end defp state_similarity(state1, state2) do common_keys = Map.keys(state1) -- (Map.keys(state1) -- Map.keys(state2)) if Enum.empty?(common_keys) do 0.0 else similarities = for key <- common_keys do val1 = Map.get(state1, key) val2 = Map.get(state2, key) cond do val1 == val2 -> 1.0 is_number(val1) and is_number(val2) -> 1 / (1 + abs(val1 - val2)) true -> 0.0 end end Enum.sum(similarities) / length(similarities) end end defp method_similarity(methods1, methods2) do intersection = MapSet.intersection(MapSet.new(methods1), MapSet.new(methods2)) union = MapSet.union(MapSet.new(methods1), MapSet.new(methods2)) if MapSet.size(union) == 0 do 1.0 else MapSet.size(intersection) / MapSet.size(union) end end defp goal_similarity(obj1, obj2) do # Compare goal function outputs on sample states cond do obj1.goal == nil and obj2.goal == nil -> 1.0 # Both have no goal, perfect similarity obj1.goal == nil or obj2.goal == nil -> 0.5 # One has no goal, moderate similarity is_function(obj1.goal) and is_function(obj2.goal) -> sample_states = [%{value: 1}, %{value: 5}, %{value: 10}] similarities = for state <- sample_states do try do goal1_result = obj1.goal.(state) goal2_result = obj2.goal.(state) if is_number(goal1_result) and is_number(goal2_result) do 1 / (1 + abs(goal1_result - goal2_result)) else if goal1_result == goal2_result, do: 1.0, else: 0.0 end rescue _ -> 0.5 # Handle function errors gracefully end end Enum.sum(similarities) / length(similarities) true -> # Goals exist but are not functions, compare directly if obj1.goal == obj2.goal, do: 1.0, else: 0.0 end end defp process_bayesian_update(current_beliefs, evidence) do # Simplified Bayesian update Map.merge(current_beliefs, evidence) end defp select_optimal_action(object, _context) do # Epsilon-greedy action selection exploration_rate = get_in(object.meta_dsl, [:learning_parameters, :exploration_rate]) || 0.1 if :rand.uniform() < exploration_rate do :explore else :exploit end end defp extract_reward(experience) do Map.get(experience, :reward, 0) end defp extract_world_model_updates(experience) do # Extract updates to world model from experience case experience do %{world_model: updates} when is_map(updates) -> updates %{observations: obs} when is_map(obs) -> %{observations: obs} %{new_beliefs: beliefs} when is_map(beliefs) -> %{beliefs: beliefs} _ -> %{} end end defp update_q_values(object, experience, reward) do # Q-learning update learning_rate = get_in(object.meta_dsl, [:learning_parameters, :learning_rate]) || 0.01 current_q = Map.get(object.state, :q_values, %{}) action = Map.get(experience, :action, :default) old_q = Map.get(current_q, action, 0) new_q = old_q + learning_rate * (reward - old_q) %{q_values: Map.put(current_q, action, new_q)} end defp adjust_learning_parameters(current_params, refinement_data) do # Adaptive parameter adjustment performance = Map.get(refinement_data, :performance, 0.5) adjusted_lr = current_params.learning_rate * (1 + 0.1 * (performance - 0.5)) adjusted_er = max(0.01, current_params.exploration_rate * 0.99) %{ learning_rate: max(0.001, min(0.1, adjusted_lr)), exploration_rate: adjusted_er, discount_factor: current_params.discount_factor } end # Enhanced error handling support functions defp validate_state_update(_current_state, new_state) do cond do not is_map(new_state) -> {:error, :new_state_not_map} map_size(new_state) > 100 -> {:error, :state_too_large} has_forbidden_keys?(new_state) -> {:error, :forbidden_keys} true -> :ok end end defp has_forbidden_keys?(state) do forbidden_keys = [:__internal__, :__system__, :__meta__] Enum.any?(Map.keys(state), fn key -> key in forbidden_keys end) end defp process_interaction_internal(object, interaction) do interaction_record = %{ timestamp: DateTime.utc_now(), type: Map.get(interaction, :type, :unknown), data: interaction, outcome: :success } updated_history = [interaction_record | object.interaction_history] %{object | interaction_history: updated_history, updated_at: DateTime.utc_now() } end defp execute_method_internal(object, method, args) do case method do :update_state -> [new_state] = args update_state(object, new_state) :interact -> [interaction] = args interact(object, interaction) :learn -> case learn(object, args) do {:ok, updated_object} -> updated_object error -> throw(error) end _ -> throw({:error, :method_not_implemented}) end end defp learn_internal(object, experience) do # Apply LEARN construct from meta-DSL learned_updates = apply_meta_dsl(object, :learn, experience) updated_object = object |> update_state(learned_updates.state_updates || %{}) |> update_world_model(learned_updates.world_model_updates || %{}) |> Map.put(:updated_at, DateTime.utc_now()) {:ok, updated_object} end defp validate_message_format(message) do required_fields = [:id, :from, :to, :type, :content, :timestamp] cond do not is_map(message) -> {:error, :message_not_map} not Enum.all?(required_fields, &Map.has_key?(message, &1)) -> missing_fields = Enum.reject(required_fields, &Map.has_key?(message, &1)) {:error, {:missing_fields, missing_fields}} not is_binary(message.id) -> {:error, :invalid_message_id} not is_atom(message.type) -> {:error, :invalid_message_type} true -> :ok end end end