ACP Protocol

The Agent Communication Protocol (ACP) is AuraBoot's server-to-server interface for running agent turns. Where MCP exposes individual tools to external clients, ACP exposes whole agent runs to backend integrators. A caller submits an input, gets a server-sent event (SSE) stream of the turn's progress, and may resume a paused turn after an approval decision.

Concept

ACP wraps the same ConversationTurnService that backs the Copilot panel and Aura Bot. The difference is the transport and the caller. Where the Copilot is driven by a logged-in human, ACP is driven by another service that wants agent behavior with a durable contract.

EndpointPurpose
POST /api/ai/aurabot/chat/streamStart a new agent run; opens an SSE stream
POST /api/ai/aurabot/executeResume a paused turn after an approval decision
GET /api/admin/agent-runs/{runId}Inspect a run's state, including persisted messages and trace

All three endpoints require authentication and resolve permissions like any other call.

When To Use

  • A workflow engine wants to delegate a step to an agent and stream the result back.
  • A scheduled job runs an analyst agent every night and stores the output.
  • A third-party platform integrates an AuraBoot agent into its UI through SSE.
  • An approval gate needs to pause a turn until a human resolves it elsewhere.

For interactive UI use the Copilot panel; for IM use Aura Bot; for tool-by-tool calls use MCP.

Architecture

   Caller (service / job / platform)
        |
        | POST /api/ai/aurabot/chat/stream
        v
   +----+--------------------------+
   |  ACP Controller               |
   |  - auth, idempotency key      |
   |  - opens SSE response         |
   +----+--------------------------+
        |
        v
   +----+--------------------------+
   |  ConversationTurnService      |
   |  runTurn(input, sseSink)      |
   +----+--------------------------+
        |
        v
   +----+--------------------------+
   |  Agent Runtime + Command      |
   |  pipeline + Approval gate     |
   +----+--------------------------+
        |
        |  events: chunk, tool_start, tool_result,
        |          confirm_required, done, error
        v
   SSE stream back to caller

Event Stream

The SSE stream carries typed events. A caller MUST handle at least chunk, confirm_required, and done.

event: chunk
data: {"content":"Looking up customer..."}

event: tool_start
data: {"toolId":"toolu_01...","toolName":"customer.query","input":{"keyword":"acme"}}

event: tool_result
data: {"toolId":"toolu_01...","result":{"rows":3},"success":true}

event: confirm_required
data: {"toolId":"toolu_02...","toolName":"customer.archive","description":"destructive","input":{},"pendingTurnId":"01HX..."}

event: done
data: {"content":"3 customers match \"acme\". Archive them?","traceId":"..."}

A done event ends the SSE stream. If a confirm_required event was seen earlier in the stream, the next step is to resume the turn by calling execute with the pendingTurnId; otherwise the turn completed normally.

Approval Gate and resumeTurn

When a tool's risk requires approval, the turn pauses. The agent runtime emits confirm_required (carrying a pendingTurnId) and the SSE stream closes. The caller must store the pendingTurnId, deliver the approval question to a human (or another system), and call execute:

POST /api/ai/aurabot/execute
Content-Type: application/json

{
  "pendingTurnId": "01HX...",
  "toolId": "toolu_02...",
  "confirmed": true
}

execute opens a new SSE stream and continues the same turn through ConversationTurnService.resumeTurn. confirmed: true maps to APPROVED and confirmed: false maps to DENIED; a denied decision short-circuits the turn with a final assistant message explaining the refusal.

Idempotency

/chat/stream deduplicates inbound messages by conversationId + clientMsgId (mapped onto ab_im_message, dedup index idx_ab_im_message_dedup (conversation_id, client_msg_id)). Re-sending the same clientMsgId under the same conversationId returns the previously persisted message row instead of inserting a duplicate. Generate a stable clientMsgId per inbound message so it covers network and scheduler retries.

POST /api/ai/aurabot/chat/stream
Content-Type: application/json

{
  "agentCode": "analyst",
  "message": "Summarize yesterday's orders and flag anomalies.",
  "conversationId": 1024,
  "clientMsgId": "nightly-analyst-2026-05-28"
}

Permissions and Audit

  • The caller authenticates as a service principal or as an impersonated user.
  • Tool calls inside the run respect that principal's permissions.
  • Every run writes an audit record with source: "acp", the caller, the agent, the model, and a trace ID.
  • Persisted messages and tool calls are inspectable through /api/admin/agent-runs/{runId}.

Verify Checklist

  • Caller handles the events actually emitted (chunk, tool_start, tool_result, confirm_required, done, error; plus the optional thinking, warning, result_contract).
  • Resume path posts to /api/ai/aurabot/execute and consumes a fresh SSE stream.
  • A stable clientMsgId (paired with conversationId) is set for retryable callers (jobs, queues).
  • Audit log shows source: "acp" with caller identity.
  • Permissions of the calling principal cover every tool the agent might choose.

Related