Class InMemoryAgentDirectory

java.lang.Object
dev.agenor.runtime.directory.InMemoryAgentDirectory
All Implemented Interfaces:
AgentDirectory, AgentDiscovery, AgentPresence, AgentRegistry, AgentResolver

public class InMemoryAgentDirectory extends Object implements AgentDirectory
In-memory implementation of AgentDirectory.

All registered agents are assigned a AgentEndpoint with transportType="local" and a runtime-generated nodeId. This allows the InMemoryMessageDispatcher to short-circuit point-to-point messages without a transport hop.

This implementation replaces the LocalAgentDirectory class removed at 0.22.0.

Since:
0.20.0
  • Constructor Details

    • InMemoryAgentDirectory

      public InMemoryAgentDirectory()
      Creates an InMemoryAgentDirectory with a randomly generated node ID and noop telemetry.
    • InMemoryAgentDirectory

      public InMemoryAgentDirectory(String nodeId)
      Creates an InMemoryAgentDirectory with the given node ID and noop telemetry.
      Parameters:
      nodeId - the node identifier for this JVM; must not be null
    • InMemoryAgentDirectory

      public InMemoryAgentDirectory(String nodeId, AgenorTelemetry telemetry)
      Creates an InMemoryAgentDirectory with the given node ID and telemetry.
      Parameters:
      nodeId - the node identifier for this JVM; must not be null
      telemetry - telemetry instance for directory.resolve spans; null treated as noop
  • Method Details

    • setTelemetry

      public void setTelemetry(AgenorTelemetry telemetry)
      Updates the telemetry instance after construction.
      Parameters:
      telemetry - the telemetry instance; null treated as noop
    • nodeId

      public String nodeId()
      Returns the node ID assigned to this JVM instance.
    • register

      public CompletableFuture<Void> register(AgentDescriptor descriptor)
      Description copied from interface: AgentRegistry
      Registers an agent in the directory, making it discoverable.

      If an agent with the same ID is already registered, the implementation should update the existing entry.

      Specified by:
      register in interface AgentRegistry
      Parameters:
      descriptor - the agent descriptor, must not be null
      Returns:
      a future that completes when registration succeeds
    • unregister

      public CompletableFuture<Void> unregister(String agentId)
      Description copied from interface: AgentRegistry
      Removes an agent from the directory.

      If the agent is not registered the call is a no-op.

      Specified by:
      unregister in interface AgentRegistry
      Parameters:
      agentId - the unique agent identifier, must not be null
      Returns:
      a future that completes when unregistration succeeds
    • updateStatus

      public CompletableFuture<Void> updateStatus(String agentId, AgentStatus status)
      Description copied from interface: AgentRegistry
      Updates the status of a registered agent.

      Implementations should also update the agent's lastSeen timestamp. If the agent is not registered the behaviour is implementation-defined (log-and-ignore is recommended for leniency).

      Specified by:
      updateStatus in interface AgentRegistry
      Parameters:
      agentId - the unique agent identifier, must not be null
      status - the new status, must not be null
      Returns:
      a future that completes when the update succeeds
    • resolveEndpoint

      public CompletableFuture<Optional<AgentEndpoint>> resolveEndpoint(String agentId)
      Description copied from interface: AgentResolver
      Resolves the transport endpoint for the given agent ID.
      Specified by:
      resolveEndpoint in interface AgentResolver
      Parameters:
      agentId - the unique agent identifier, must not be null
      Returns:
      a future containing the endpoint if the agent is registered and reachable, or empty if the agent is unknown
    • findById

      public CompletableFuture<Optional<AgentDescriptor>> findById(String agentId)
      Description copied from interface: AgentDiscovery
      Finds an agent by its unique identifier.
      Specified by:
      findById in interface AgentDiscovery
      Parameters:
      agentId - the unique identifier, must not be null
      Returns:
      a future containing the descriptor if found, or empty if not registered
    • findByCapability

      public CompletableFuture<List<AgentDescriptor>> findByCapability(String capability)
      Description copied from interface: AgentDiscovery
      Finds all agents that declare the given capability.
      Specified by:
      findByCapability in interface AgentDiscovery
      Parameters:
      capability - the capability tag, must not be null
      Returns:
      a future containing a (possibly empty) list of matching descriptors
    • findByType

      public CompletableFuture<List<AgentDescriptor>> findByType(String agentType)
      Description copied from interface: AgentDiscovery
      Finds all agents of the given type.
      Specified by:
      findByType in interface AgentDiscovery
      Parameters:
      agentType - the agent type string, must not be null
      Returns:
      a future containing a (possibly empty) list of matching descriptors
    • findAgents

      public CompletableFuture<Page<AgentDescriptor>> findAgents(AgentQuery query, PageRequest request)
      Description copied from interface: AgentDiscovery
      Finds agents matching the given query, returning a bounded page of results.

      Use AgentQuery.all() to retrieve all agents with pagination.

      Specified by:
      findAgents in interface AgentDiscovery
      Parameters:
      query - the search criteria, must not be null
      request - pagination parameters, must not be null
      Returns:
      a future containing the page of matching descriptors
    • heartbeat

      public CompletableFuture<Void> heartbeat(String agentId)
      Refreshes the agent's lastSeen timestamp, leaving its status alone.

      A heartbeat is a liveness signal and nothing more (ADR-028 D-1). It used to be updateStatus(agentId, RUNNING), which meant an agent stuck in STARTING was promoted by the mere fact of being alive. A backend with key expiry cannot implement that, so the three implementations would have disagreed.

      Unknown agent ids are ignored rather than rejected: a heartbeat for an agent that has just unregistered is a race, not an error.

      Specified by:
      heartbeat in interface AgentPresence
      Parameters:
      agentId - the agent to touch, must not be null
      Returns:
      a future completing when the timestamp is refreshed
      Throws:
      NullPointerException - if agentId is null
    • getStatus

      public CompletableFuture<AgentStatus> getStatus(String agentId)
      Description copied from interface: AgentPresence
      Returns the current status of the given agent.

      The answer is AgentStatus.UNKNOWN when the agent is not registered, and also when it has not been seen within the implementation's staleness window. That window is a property of the implementation, not of this contract: an unbounded window is a legal value, and means the backend never expires a status.

      Specified by:
      getStatus in interface AgentPresence
      Parameters:
      agentId - the unique agent identifier, must not be null
      Returns:
      a future containing the agent's status, or AgentStatus.UNKNOWN if it is unregistered or stale