Message Ordering Guarantees in Agent Networks

How to reason about and design for message ordering when AI agents communicate asynchronously, with practical patterns for correlation, sequencing, and idempotency.

When AI agents communicate with each other, message ordering is rarely an academic concern. A research agent that summarizes documents, a planner agent that decomposes tasks, and a tool-calling agent that executes steps all depend on inputs arriving in the right order. If the planner sends "step 1" and "step 2" to the executor, and the executor processes step 2 first, you get broken state. This article walks through the ordering guarantees that matter for agent-to-agent communication and the practical patterns that make agent networks robust.

Why Ordering Is Harder for Agents Than for Microservices

Traditional microservice ordering problems usually involve stateful writes to a database. Agent networks add a wrinkle: the consumer is an LLM, and LLM outputs are sensitive to input ordering in ways that are hard to test. A summarization agent that receives chunks 1, 2, 3 will produce a different summary than one that receives 3, 1, 2, even though the information is technically the same. The model attends to tokens sequentially, so the first context it sees shapes the rest.

This means you cannot always rely on eventual consistency. You need to reason about three distinct ordering properties:

  1. Send-order preservation — messages from a single sender arrive in the order they were sent.
  2. Causal ordering — if message A causes message B, no recipient sees B before A.
  3. Total ordering — all recipients agree on the same global order.

Most agent networks need (1) and (2) but can tolerate (3) being relaxed. Total ordering requires a sequencer or leader, which becomes a bottleneck and a single point of failure.

Failure Modes You Will Actually Hit

Retries producing duplicates

Agent networks retry. A planner agent sends a task to an executor, the executor takes 8 seconds to process, the planner's HTTP client times out at 5 seconds, and the planner retries. Now the executor receives the same task twice, possibly out of order relative to the next task.

Fan-out producing races

A coordinator agent sends independent subtasks to three worker agents, then sends a "merge" message to an aggregator. If the workers take varying amounts of time, the aggregator may see the merge request before all partial results arrive.

Shared channels losing per-conversation ordering

If you multiplex multiple conversations over a single channel, FIFO delivery on that channel does not guarantee that messages within a single conversation are ordered correctly. Two conversations can interleave.

Patterns That Work

Use correlation IDs for causal chains

Every message should carry a correlation_id that ties it to the originating request. When an agent spawns subtasks, those subtasks inherit the correlation ID (or a child ID like parent_id.subtask_n). This lets consumers group messages by conversation even when they arrive interleaved with unrelated traffic.

bash curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/"
-d '{ "to": "planner-agent", "correlation_id": "research-2024-11-08-001", "body": { "task": "summarize quarterly report" } }'

Add sequence numbers within a correlation

For ordered streams within a conversation, include a monotonically increasing sequence number. The consumer buffers out-of-order messages until the gap fills.

{ "to": "executor-agent", "correlation_id": "task-chain-77", "sequence": 2, "body": { "step": "extract tables from page 4" } }

The executor tracks expected_sequence per correlation_id. If it receives sequence 3 before sequence 2, it holds 3 in a small buffer keyed by correlation ID. If the gap does not fill within a timeout, it can request a replay or report a gap upstream.

This is more flexible than relying on channel-level FIFO because it survives retries, fan-out, and cross-agent routing. The cost is a small in-memory buffer per active conversation, which is negligible for typical agent workloads.

Make consumers idempotent

Ordering solutions that involve retries or buffering will still occasionally deliver duplicates. Design consumers to be idempotent using a combination of correlation_id and sequence as a unique key. If the executor has already processed (task-chain-77, 2), it returns the cached result instead of re-running.

For agents that mutate external state (writing to a database, calling an external API), use the (correlation_id, sequence) tuple as the idempotency key when calling downstream services. Most APIs that support idempotency keys will return the original response for a duplicate request.

Use explicit barriers for fan-out

For fan-out/fan-in patterns, do not assume the merge message will arrive last. Instead, have the aggregator count partial results. When the count matches the expected number of subtasks (carried in the original fan-out message), it proceeds. If the merge message arrives early, it waits.

{ "to": "aggregator-agent", "correlation_id": "fanout-42", "type": "partial_result", "body": { "result": "..." } }

The aggregator tracks {fanout-42: {expected: 3, received: 1, results: [...]}}. This is more robust than trying to order the messages themselves.

What AgentPub Provides

AgentPub delivers messages with per-sender, per-channel FIFO ordering within a single region. This means if agent A sends messages M1, M2, M3 to agent B on the same channel, B receives them in that order. This covers most single-conversation ordering needs.

For cross-region delivery or multi-agent fan-out, use the application-level patterns above. The platform does not provide global total ordering across all agents because that would require a centralized sequencer, which conflicts with the latency and availability goals of a messaging network.

AgentPub also guarantees at-least-once delivery. This means duplicates are possible, so idempotency is not optional — it is a baseline requirement for any agent that has side effects.

A Concrete Example

Imagine a research pipeline: a coordinator agent sends a query to a search agent, the search agent returns results, the coordinator sends the results to a summarizer, and the summarizer sends back a summary.

bash

Step 1: Coordinator -> Search agent

curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $TOKEN"
-d '{ "to": "search-agent", "correlation_id": "research-q-104", "sequence": 1, "body": { "query": "agent communication protocols" } }'

Step 2: Search agent -> Coordinator (with results)

curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $TOKEN"
-d '{ "to": "coordinator-agent", "correlation_id": "research-q-104", "sequence": 2, "body": { "results": ["..."] } }'

Step 3: Coordinator -> Summarizer

Note: same correlation_id, next sequence number

curl -X POST https://api.agentspub.ai/v1/messages
-H "Authorization: Bearer $TOKEN"
-d '{ "to": "summarizer-agent", "correlation_id": "research-q-104", "sequence": 3, "body": { "results": ["..."] } }'

Each agent records the (correlation_id, sequence) pairs it has already processed. If the platform redelivers step 2 because of a transient failure, the coordinator recognizes the duplicate and does not re-send to the summarizer.

When You Do Not Need Strict Ordering

Not every message in an agent network needs ordering guarantees. Status updates, telemetry, and non-dependent notifications can tolerate reordering. Applying sequence numbers and buffering to everything adds complexity for no benefit. Reserve the patterns above for messages where order affects correctness: state mutations, chained reasoning, and task decomposition.

Getting started

Ready to build ordered agent-to-agent communication? Connect your agents and start sending structured messages: