Agents working together
When to use synchronous agents, and when to use asynchronous ones
When one agent needs something from another, it can call and wait for the answer, or it can send a message and get on with its work while the answer arrives later. For years most teams started with calls because asynchronous systems were harder to think through. That reason is gone, and most of the work agents are being asked to do is better done with messages.
Two ways for agents to work together
A synchronous call holds the caller until the answer comes back. The calling agent sends a request, keeps the connection open, and does nothing else on that thread until it gets a result or an error. Tool calls, most MCP servers and a plain HTTP request all work this way.
An asynchronous message lets the caller move on. The calling agent sends a request, gets a receipt saying the request is held, and carries on. The answer comes back later as another message, to an inbox that is still there when the caller returns. The work survives either side going away in the meantime.
The difference sounds like plumbing, but it decides how a system behaves when something is slow, offline or waiting on a person, and with agents, something usually is.
Why teams used to avoid asynchronous design, and why that has changed
Before AI, asynchronous systems had a reputation for being hard, and it was earned. A developer had to keep every in-between state in their head: the request that was sent and not yet answered, the answer that arrived after the caller gave up, the message delivered twice, the retry that raced the original, the step that failed halfway. Each of those needed code, and each was easy to get wrong and hard to debug. So teams reached for a call, accepted that it would break when something was slow or offline, and fixed it later.
That limitation belonged to people writing the code by hand, and it no longer holds. Coding agents such as Claude Code and Codex keep the whole flow in view at once. They write the correlation ids, the timeouts, the retries and the duplicate checks, write tests for every failure case, and read the logs when something goes wrong. Paired with a messaging system that already provides inboxes, task state and signed messages, they can build a well-designed asynchronous workflow in hours. The effort that used to push teams toward calls has mostly disappeared, so the choice can come down to what the work actually needs.
When a synchronous call is the right choice
A call is right when all of these hold:
- The answer takes seconds, as a lookup, a calculation or a short generation does.
- Someone is waiting for it right now, a person in a chat or an agent that cannot take its next step without it.
- The other side is reliably online. A service you run, or a tool with a published uptime.
- A failure can simply be retried or shown to the person as an error.
A chat assistant checking a calendar, an agent asking a pricing service for today's rate, or a coding agent running a test suite that finishes in under a minute are all good calls. Making them asynchronous would add bookkeeping and gain nothing.
When an asynchronous message is the right choice
Send a message when any of these is true:
- The work takes minutes, hours or days, as research, a build, a supplier's quote or a contract review does.
- A person has to approve something. People answer when they answer, and an agent should not hold a connection open for a manager on vacation.
- The other agent may be offline. Agents on laptops sleep. Personal agents run when their owner's device is on. A partner company's agents are up on its schedule, which you do not control.
- Several agents are involved. Asking five suppliers for a quote and taking the best one is a fan-out, and waiting on all five in turn multiplies every delay.
- You need a record that outlives the conversation. A message with a sender, a time and a signature can be checked after the fact. A finished call leaves nothing behind unless someone logged it.
- The other agent belongs to another company. Every reason above applies at once.
A quick way to decide
| Ask | If yes |
|---|---|
| Will the answer come back in a few seconds, every time? | A call is fine. |
| Is a person watching the screen for the result? | A call, or an acknowledgement now and the result later. |
| Could the other agent be offline when you ask? | Send a message. |
| Does a person need to approve before the work can finish? | Send a message. |
| Are you asking more than one agent and comparing answers? | Send messages to all of them at once. |
| Will anyone need to prove later what was asked and answered? | Send a signed message. |
The pattern that covers most real work
Much of the time the answer is both. The receiving agent answers the call at once with an acknowledgement and a task id, then delivers the result as a message when it is ready. The caller knows within a second that the work was accepted, the person sees that something is happening, and nothing is lost if the work takes an hour. Progress updates can stream back in between, and the caller can cancel the task if it no longer needs the answer.
The same pattern handles an agent that is offline: the request waits in its inbox, the caller is told it is queued, and the answer arrives when the agent comes back.
Mistakes that show up in production
- Chains of calls. When agent A calls B, which calls C, which calls D, the delays add up and a failure anywhere fails everything. Four agents that are each up 99 percent of the time give a chain that works about 96 percent of the time.
- Holding a connection open for long work. Timeouts at a load balancer or a proxy will cut it, usually at the worst moment, and the work is lost or done twice.
- Polling for a result. Asking "is it done yet?" every few seconds wastes money on both sides. A message when it is done costs one delivery.
- Messages without correlation. Every request needs an id that its answer carries, or a busy agent cannot tell which answer belongs to which question.
- Messages delivered twice. Networks redeliver. Each message needs an id the receiver remembers, so the same request is never acted on twice.
- Silence. An asynchronous system that does not tell the person what happens next feels broken even when it works. Say that the request was received, when to expect an answer, and where it will appear.
What asynchronous work needs from the network
Calls need little more than a reachable address. Messages need more from the infrastructure underneath them:
- An inbox that holds mail while the receiving agent is offline, with limits so it cannot fill forever.
- A sender you can verify later. A message read an hour after it was sent cannot rely on the connection it arrived on, so the message itself has to carry its sender's signature.
- Task state both sides can see: submitted, working, waiting for input, done or failed.
- Presence, so a caller can tell whether the other agent is there right now and choose a call or a message accordingly.
- A way to stop an agent that applies to the work it has queued as well as the work it is doing.
This is the layer Agent Messaging, the open standard AgentMesh sponsors, defines. Every message is signed by the agent that sent it and can be checked whenever it is read. A request to an agent that is online gets an immediate acceptance and a task, and a request to an agent that is away is held in its inbox and acknowledged as queued. Presence comes from signed heartbeats. AgentMesh runs that layer as a network, so agents in different companies can work this way without building it themselves.