opamp-core

Command Process Implementation Note

For the broader developer guide covering command flow, next-action flow, history semantics, and MCP exclusion, start with Provider Command And Event Flow Guide.

This note describes how command intents are accepted by the Provider API, queued in memory, transformed into OpAMP payloads, and marked as sent.

Scope

API Contract

The commands endpoint accepts an array of key/value pairs:

[
  { "key": "classifier", "value": "command" },
  { "key": "action", "value": "restart" }
]

Supported classifiers:

Required keys:

Queue And State Model

CommandRecord stores normalized intent data:

Queue behavior:

  1. API validates classifier/action and shape.
  2. Valid command intent is appended to ClientRecord.commands.
  3. Next poll from the client reads the first unsent command via next_pending_command(...).
  4. After a command/custom payload is emitted, the record is marked sent with mark_command_sent(...).

Startup Discovery And Registry

At provider startup (module import time), opamp_provider.commands scans command modules and discovers all concrete CommandObjectInterface implementations.

Discovery outputs:

Helper APIs:

Filtering and display behavior:

Any duplicate (classifier, operation) registration raises an error at startup.

Command Interface Contract

Command objects implement CommandObjectInterface and now expose:

Command objects that provide configuration metadata also implement:

Schema rows are JSON objects with:

Classifier/Action Dispatch

Dispatch happens in app.py via a mapping from (classifier, action) to builder methods.

Current mapping:

If no mapping exists for the submitted classifier/action, the API rejects it with 400.

Payload Construction

Restart Command

_build_restart_command(...) constructs ServerToAgent.command and sets:

This creates a ServerToAgentCommand payload for restart.

Custom Command

_build_custom_command_payload(...) constructs ServerToAgent.custom_message.

For classifier=custom and action=chatopcommand, the server builds a ChatOpCommand object via the command factory and uses to_custom_message().

ChatOpCommand payload behavior:

For classifier=custom and action=shutdownagent, the server builds a CommandShutdownAgent object via the command factory and uses to_custom_message().

CommandShutdownAgent payload behavior:

For classifier=custom and action=nullcommand, the server builds a CommandNullCommand object via the command factory and uses to_custom_message().

CommandNullCommand payload behavior:

Purpose note:

For generic custom_command payloads, additional optional key/value pairs can be supplied:

Defaults:

UI Custom Command Flow

The client dialogue UI uses the metadata endpoint to build the custom command experience:

  1. UI calls GET /api/commands/custom.
  2. Response returns only custom commands with fqdn, displayname, and schema.
  3. UI populates a custom command dropdown using displayname.
  4. On selection, UI renders a configuration table:
    • column 1: parameter label (parametername)
    • column 2: editable value field
    • column 3: info icon
  5. Hovering the info icon shows only the parameter description text (or a default fallback when missing).
  6. The UI validates all rows where isrequired/isRequired is true before enabling send.
  7. User submits via the Send Command button.
  8. Submitting queues the command through POST /api/clients/<client_id>/commands.

Notes:

Consumer ChatOps Command Execution

On the consumer side, ChatOpsCommand.execute_action(...) dispatches local HTTP requests based on the custom message payload:

Send Flow

For both HTTP and WebSocket OpAMP paths:

  1. Server resolves pending command intent.
  2. _apply_command_intent(...) runs classifier/action dispatch.
  3. Response is returned to the client.
  4. If response has command or custom_message, the queued record is marked sent.

Debug Logging

Debug logging exists at payload build points:

Enable DEBUG logging in the provider runtime to see these entries.