OpAMP Protocol Execution Sequence

Agent Connection and Message Exchange Flow

sequenceDiagram
    participant Agent as OpAMP Agent
    participant Controller as opamp.Controller
    participant OpAMPLib as OpAMP Server Lib
    participant Service as opamp.Service
    participant AgentUC as AgentUsecase
    participant ConnUC as ConnectionUsecase
    participant WS as WebSocketRegistry
    participant DB as MongoDB Repository

    Note over Agent,DB: Connection Phase
    
    Agent->>Controller: GET/POST /api/v1/opamp
    Controller->>OpAMPLib: handler(writer, request)
    OpAMPLib->>Controller: OnConnecting(request)
    Controller-->>OpAMPLib: ConnectionResponse {Accept: true}
    OpAMPLib-->>Agent: Connection Accepted
    
    OpAMPLib->>Service: OnConnected(ctx, connection)
    Service->>Service: detectConnectionType(conn)
    Service->>Service: NewConnection(conn, type)
    alt WebSocket
        Service->>WS: Register(connID, wsConn)
    end
    Service->>ConnUC: SaveConnection(ctx, connection)
    ConnUC->>DB: Save
    
    Note over Agent,DB: Message Exchange Phase
    
    loop Active Connection
        Agent->>OpAMPLib: AgentToServer Message
        Note right of Agent: - InstanceUID<br/>- AgentDescription<br/>- Health<br/>- Capabilities<br/>- EffectiveConfig<br/>- RemoteConfigStatus<br/>- PackageStatuses
        
        OpAMPLib->>Service: OnMessage(ctx, conn, message)
        Service->>ConnUC: GetConnectionByID(ctx, conn)
        ConnUC->>DB: Find
        DB-->>ConnUC: connection
        ConnUC-->>Service: connection
        
        Service->>Service: Update connection.InstanceUID
        alt WebSocket
            Service->>WS: UpdateInstanceUID(connID, instanceUID)
        end
        Service->>ConnUC: SaveConnection(ctx, connection)
        ConnUC->>DB: Save
        
        Service->>AgentUC: GetOrCreateAgent(ctx, instanceUID)
        AgentUC->>DB: Find/Create
        DB-->>AgentUC: agent
        AgentUC-->>Service: agent
        Service->>Service: Update agent.Status (Connected=true)
        
        Service->>Service: report(agent, message, server)
        Note right of Service: Update agent from message:<br/>- AgentDescription<br/>- Health<br/>- RemoteConfigStatus<br/>- PackageStatuses<br/>- EffectiveConfig
        
        Service->>AgentUC: SaveAgent(ctx, agent)
        AgentUC->>DB: Save
        
        Service->>Service: fetchServerToAgent(ctx, agent)
        Note right of Service: Build response:<br/>- RemoteConfig<br/>- ConnectionSettings<br/>- PackagesAvailable<br/>- Flags<br/>- Command
        
        Service-->>OpAMPLib: ServerToAgent Response
        OpAMPLib-->>Agent: ServerToAgent Message
        Note left of Agent: - InstanceUID<br/>- RemoteConfig<br/>- ConnectionSettings<br/>- PackagesAvailable<br/>- Flags<br/>- Command
    end
    
    Note over Agent,DB: Error Handling (if occurs)
    
    opt Read Error
        OpAMPLib->>Service: OnReadMessageError(conn, type, msg, err)
        Note right of Service: Log error details
    end
    
    opt Response Error
        OpAMPLib->>Service: OnMessageResponseError(conn, msg, err)
        Note right of Service: Log error details
    end
    
    Note over Agent,DB: Disconnection Phase
    
    Agent->>OpAMPLib: Disconnect
    OpAMPLib->>Service: OnConnectionClose(connection)
    Service->>Service: Queue background cleanup
    Note right of Service: Return immediately
    
    Service->>Service: Background Loop executes
    Service->>ConnUC: GetConnectionByID(ctx, conn)
    ConnUC->>DB: Find
    DB-->>ConnUC: connection
    ConnUC-->>Service: connection
    
    alt Not Anonymous
        Service->>AgentUC: GetAgent(ctx, instanceUID)
        AgentUC->>DB: Find
        DB-->>AgentUC: agent
        AgentUC-->>Service: agent
        Service->>Service: Update agent.Status (Connected=false)
        Service->>AgentUC: SaveAgent(ctx, agent)
        AgentUC->>DB: Save
    end
    Service->>ConnUC: DeleteConnection(ctx, connection)
    ConnUC->>DB: Delete
    Note right of WS: WebSocket registry<br/>auto-cleanup

OpAMP Callbacks Summary

CallbackWhen CalledPurpose
OnConnectingBefore accepting connectionValidate and decide whether to accept
OnConnectedAfter connection establishedInitialize connection tracking
OnMessageWhen message received from agentProcess agent data and send response
OnReadMessageErrorWhen failed to read messageLog and handle read errors
OnMessageResponseErrorWhen failed to send responseLog and handle send errors
OnConnectionCloseWhen connection closedCleanup resources asynchronously

Architecture Layers

The diagram follows Hexagonal Architecture (Ports and Adapters):

Primary Adapter (Infrastructure - In)

Application Layer

Secondary Adapter (Infrastructure - Out)

Connection Types


Server-Initiated Command Flow (SendCommand)

This flow shows how the server sends commands to agents, such as updating agent configuration.

sequenceDiagram
    participant Admin as Administrator/API
    participant Controller as agent.Controller
    participant AppService as agent.Service
    participant DomainService as domain.AgentService
    participant Agent as model.Agent
    participant CommandUC as CommandUsecase
    participant WS as WebSocketRegistry
    participant WSConn as WebSocketConnection
    participant OpAMPAgent as OpAMP Agent

    Note over Admin,OpAMPAgent: Command Initiation Phase
    
    Admin->>Controller: POST /api/v1/agents/{id}/send-command
    Note right of Admin: Request body contains<br/>command data
    Controller->>AppService: SendCommand(ctx, instanceUID, command)
    
    Note over AppService,Agent: Application Layer Processing
    
    AppService->>DomainService: UpdateAgentConfig(ctx, instanceUID, config)
    DomainService->>DomainService: GetOrCreateAgent(ctx, instanceUID)
    DomainService->>Agent: ApplyRemoteConfig(config)
    Note right of Agent: Agent model updates:<br/>1. NewRemoteConfigData(config)<br/>2. Apply to agent.Spec.RemoteConfig<br/>3. Add RemoteConfigUpdated command<br/>4. Command includes config hash
    
    DomainService->>DomainService: SaveAgent(ctx, agent)
    
    Note over DomainService,WSConn: Check if agent is connected
    
    alt Agent is connected via WebSocket
        DomainService->>DomainService: agent.IsConnected(ctx)
        DomainService->>DomainService: agent.HasPendingServerMessages()
        
        Note over DomainService,OpAMPAgent: Send Server Message
        
        DomainService->>DomainService: serverMessageUsecase.SendMessageToServer()
        Note right of DomainService: In standalone mode,<br/>message goes to in-memory channel
        
        Note over WS,OpAMPAgent: Message Processing (async)
        
        DomainService->>WS: GetByInstanceUID(instanceUID)
        WS-->>DomainService: wsConn
        
        DomainService->>WSConn: Send(ctx, ServerToAgent message)
        Note right of WSConn: ServerToAgent contains:<br/>- RemoteConfig<br/>- Flags<br/>- Command
        
        WSConn->>OpAMPAgent: Push ServerToAgent via WebSocket
        OpAMPAgent-->>WSConn: ACK
    else Agent is not connected (HTTP/Polling)
        Note over DomainService: Message will be delivered<br/>on next agent poll
    end
    
    Note over AppService,CommandUC: Audit Logging
    
    AppService->>CommandUC: SaveCommand(ctx, command)
    Note right of CommandUC: Save command for audit trail
    
    DomainService-->>AppService: Success
    AppService-->>Controller: Success
    Controller-->>Admin: 200 OK
    
    Note over OpAMPAgent: Agent applies new configuration

SendCommand Flow Details

1. API Request

2. Application Layer

3. Domain Layer

4. Agent Model

Key Types (all in model package):

5. Message Delivery (if connected)

6. Agent Processing

Key Components

ComponentLayerResponsibility
agent.ControllerPrimary AdapterHTTP endpoint handler
agent.ServiceApplication LayerCommand orchestration
AgentServiceDomain LayerAgent business logic
CommandUsecaseDomain LayerCommand audit logging
WebSocketRegistrySecondary AdapterWebSocket connection management
WebSocketConnectionSecondary AdapterWebSocket communication
model.AgentDomain ModelAgent state including RemoteConfig and Commands
model.RemoteConfigDomain ModelRemote configuration management
model.RemoteConfigDataDomain ModelConfig data with hash and status

Domain Model Structure

Agent
├── Metadata (InstanceUID, Description, Capabilities)
├── Spec
│   └── RemoteConfig (RemoteConfigData, LastErrorMessage)
├── Commands ([]AgentCommand)
│   └── RemoteConfigUpdated, ReportFullState, etc.
└── Status (EffectiveConfig, Health, PackageStatuses)

Message Delivery Modes

Configuration Update Flow

  1. API Request → Creates command with config data
  2. Application Layer → Validates and orchestrates
  3. Domain Layer
    • Calls agent.ApplyRemoteConfig(config)
    • Creates RemoteConfigData with hash
    • Updates agent.Spec.RemoteConfig
    • Adds RemoteConfigUpdated to agent.Commands
  4. Persistence → Saves agent with new config and pending command
  5. Message Delivery
    • Retrieves agent from WebSocketRegistry
    • Sends ServerToAgent message with RemoteConfig
    • Agent receives and applies configuration
  6. Status Report → Agent sends back status in next AgentToServer message