Inter-Agent Protocols: What to Look Out For
Date Published

As Agentic AI has taken off, the need to enable agents to communicate with one another, often across disparate systems, has become apparent. In May 2025, Google launched the open A2A protocol in an attempt to achieve just that. The protocol has been widely adopted, with Amazon incorporating A2A into its own Stands Agent SDK in July of 2025.
However, this is still the early days of inter-agent communication and implementations still have gaps and difficulties. Below I discuss several issues that often crop up regarding agent-to-agent communication, especially within deep nested chains of agents.
Async vs Sync
A2A offers the option of using sync or async and the A2A protocol provides good support for async through both task polling and streaming for real time events. As always there are trade-offs between Async and Sync approaches. Sync offers simplicity and is well suited for simple fast operations. However, for long running tasks or when you need to scale up due to blocking whist waiting for other agents to complete their executions, it is often unsuitable. There is also an issue of cascading timeouts as the nest of calls to other agents get deeper.
Async allows you to scale up and is well suited to long running tasks. However, this comes at the price of complexity, with the developer left to handle the implementation of that complexity themselves such as ensuring guaranteed delivery and the lack of a standard webhook format, means dealing with varying implementation practices.
One approach favoured by many businesses is a mixed approach, using sync to handle human to agent communication often to an orchestration agent who then communicates with other agents asynchronously.
As a rule of thumb, if an operation is going to take >30 seconds, go with async from the start.
Nesting Problem and HITL
As work streams begin to use multiple agents communicating with each other, a scenario arises where we get a deep chain of nested calls to agents. One of the issues that this causes regards the human in the loop (HITL) scenario, where an agent deep within the chain requires user authorisation to continue with its tasks. How does the request to the human bubble up? If every interruption is sent to the user, they may not understand the context of what is be asked or be overwhelmed with constant requests. At the other end, the user may sit there waiting indefinitely as an agent deep in the layer requires permission, but does not bubble up, and the user is completely unaware of what is happening.
Here are a few patterns that can help improve this issue:
Bubble up.
A HITL request bubbles up to the user, passing through the layers. Each agent can add context, and we can also configure it to allow a parent to auto approve or auto escalate depending on the scenario.
Direct to User:
The agent sends a HITL request direct to the user, providing quick feedback. However, this approach can involve the user being asked for requests without any context of why they are being asked.
Direct to Orchestrator
A third approach is having an orchestrator agent whose responsibility is to manage the context of any HITL requests. Agents bypass the chain and pass any requests to the orchestration agent that then can provide additional context or auto approve any requests. This however comes at the price of tight coupling to the orchestrator.


Keeping Agents Independent
As the number of agents increase, we need to develop good practices to ensure that agents are not tightly coupled to each other. If done correctly, it allows to agents to call agents when needed without knowing specific details about the agents it is calling.
A popular approach to this is to have some sort of gateway or registry which provides details and capabilities of agents. Agents register with the gateway and when an agent requires an agent with a specific capability, it can interrogate the gateway to find the most appropriate agent to handle the work.
To ensure flexibility, it is important to have contract-based interfaces, so that agents know what an agent will provide them but do not need to know how they implement their behaviour.
Another important practice is to ensure decoupled communication between agents using an intermediary such as a message bus.
To ensure that agents are independent it is important that when developed, the agents do not leak external state across agent boundaries and that they handle their own errors.
Manager in the Loop and Autonomous Agents
Manager in the Loop (MITL) describes a scenario when an agent needs to escalate to a human to get approval to perform some action, for example a HR agent requiring approval from a manager to book leave on behalf of an employee.
A specific issue that can arise with the MITL scenario, is when we have autonomous agents that either require permission to perform some action or spawn up other agents in a chain that requires permissions. If no human started the action, who is responsible for approving any requests.
One possible solution to this scenario is the use of authority chains. It needs to define various levels of risks and who is responsible for handling any permission requests. Low risk activities or a pre-approved list of tasks can have their requests auto accepted, where as a risky action may require approval of a senior human being.
One thing to ensure is that an agent cannot spawn up a sub agent without any authority context - the agent that is responsible for spawning up the sub agent must pass along its authority context so no agent is left without knowledge of the authority chain.

Visibility of Long Running Tasks Through a Chain of Agents
One problem that occurs when you have deep nested chains of agents is ensuring visibility of what is happening with long running tasks without bombarding the user with lots of noisy notifications. Without visibility, a user has no idea whether a long running task deep within the chain is running as planned or has stalled. Bubbling up events through the chain mean that every agent in the chain is responsible passing notifications up and down the chain. They must also provide context to the user if they are to understand what the notification is about. If each agent passes these notifications direct to the user, the user could be bombarded with many notifications often without being able to understand the context.
One possible solution to this is the use of a message bus and notification service. Each agent sends notification of status to the message bus. These are then consumed by the notification service which can then process and combine to the user, giving them clear visibility of the status whilst abstracting away the specific notifications from the user.

Tokens in Agent Chains
A very tricky problem is how to deal with passing along user authorisation through deep nested chains of agents. The naïve solution of passing the user token through a chain of agents has several problems.
- Inability to refresh token if process is long running and the user has logged off.
- Token expires preventing work from continuing.
- The more systems that have the token, the more risk there is of leakage.
- A token may give broad based permissions, creating over-privileged agents.
A possible solution for this is the use of grants rather than tokens for identity and permissions. A grant is a short-lived object, that grants a very strict set of permissions and references a token. First the user communicates with an orchestration agent. Here the token will be passed to orchestration agent which then uses the token to create grants to be stored in an authentication service.
When a sub agent now needs permission to perform some action, it requests a reference to a grant from the orchestrator rather than a token. The agent then communicates with the authentication service to get short lived tokens for itself to perform the actions on behalf of the user. The user is free to revoke any grants it has given, for example after a period time, which will mean the sub agents will no longer be authorised to act on the user’s behalf.

Identity in Agent Chains
When we have deep nested chains of agents, the question arises as to who the agent is acting as. There are three possible scenarios:
Use the Human Identity
This approach is the simplest: pass along the user’s credentials, use the user’s permissions, and every action is attributed to the user.
The problem however is that the agent now has all the user’s permissions, and we have audit issues with external systems accessed by the agent. How do we distinguish between an action performed directly by the user or one by an agent acting on behalf of a user?
Use the Agent Identity
This allows us to define a limited set of agent specific permissions, and we can clearly identify that the agent performed a particular action. The downsides are that we lose context: who asked the agent to do this, and who is the agent performing the action on behalf of?
Hybrid Identity
The best solution is a hybrid approach. At each step of the chain, the agent needs to know the human it is acting on behalf of. It must ensure that this context is passed along the chain of agents. But it must also indicate to the agent it is calling, its own identity.
That addresses the issues above with the downside of more complexity. Also, the target systems need to understand the dual identity paradigm.

Summary
The solutions to these often share commonalities. One is separation of concerns, a common pattern in many software architecture patterns. Another is ensuring clear accountability in terms of who is doing what in terms of agent and human. A third is the use of shared services or orchestration agents to handle cross-cutting concerns rather than baking this into the agent logic themselves.
