A2A Analytics
This document explains A2A Analytics and how it works in Moesif’s API Analytics suite.
A2A Analytics lets you observe Agent-to-Agent (A2A) protocol traffic in the same event pipeline as your API calls. The A2A protocol lets AI agents discover each other, exchange messages, and delegate work as tasks. Related messages and tasks share a context. A2A Analytics turns these protocol details into fields that you can filter, group, and chart.
A2A Analytics supports the following:
- A2A protocol version 1.0
- Every remote procedure call (RPC) operation that the A2A specification defines
- All three A2A transports: JSON-RPC, HTTP+JSON, and gRPC
For a hands-on walkthrough, see Analyze Agent-to-Agent (A2A) Protocol Traffic in Moesif.
How A2A Analytics Works
To mark an event as an A2A call, add an a2a object to the event, alongside the request and response objects. Moesif reads the a2a object and makes its fields available under the A2A Analytics filter.
The a2a object is optional. Add it only to events where you observe an A2A protocol call. Leave it out of all other events, such as REST API calls or large language model (LLM) calls. Moesif ingests those events as regular API events.
Fields in the a2a Object
The a2a object contains two kinds of fields:
- Protocol fields: These fields use the A2A specification’s own vocabulary. Examples include
operation,task_id,context_id, andtask_state. - Analytics fields: Moesif adds these fields to turn raw protocol data into metrics that the A2A specification doesn’t provide. Examples include
outcome,terminal,failure_origin,is_error, andtime_to_first_event_ms.
Only the operation and transport fields are required. For the full list of fields, their allowed values, and validation rules, see A2A Analytics Filters.
Example: JSON-RPC Event
The following example shows the a2a object for a SendMessage call over JSON-RPC. A user asks a weather agent about the weather. The agent replies with a completed task:
{
"request": {},
"response": {},
"a2a": {
"operation": "SendMessage",
"transport": "JSONRPC",
"protocol_version": "1.0",
"agentId": "weatheragent2",
"agentName": "Weather Agent v2",
"request_type": "operation",
"request": {
"message_id": "m-001",
"input_part_count": 1,
"return_immediately": false
},
"response": {
"is_error": false,
"is_streaming": false,
"payload_type": "task",
"task_id": "t-a1b2c3",
"context_id": "c-xyz-1",
"task_state": "TASK_STATE_COMPLETED"
},
"terminal": true,
"outcome": "SUCCESS"
}
}
The request and response objects at the top level hold the raw HTTP exchange, like any other Moesif event. For a complete event with request and response data, see the tutorial.
Transports
The a2a object has the same shape for every transport. You can analyze all A2A traffic together or split it by transport. The following parts of an event differ between transports:
- The
transportfield: The value isJSONRPC,HTTP+JSON, orGRPC. - The raw request: The URL, headers, and body shape depend on the transport.
- Error codes: The
response.error_codefield uses the error codes of the transport. These are JSON-RPC codes in the-32xxxrange, gRPC status codes from0to16, or HTTP status codes of400and above.
The following examples show the top-level request object for the same SendMessage call over each transport.
JSON-RPC
JSON-RPC calls post to the agent’s base URL. The method field of the body holds the operation name. The params field holds the operation’s parameters:
"request": {
"uri": "http://agent.example.com/",
"verb": "POST",
"headers": {"content-type": "application/json"},
"body": {
"jsonrpc": "2.0",
"id": "req-001",
"method": "SendMessage",
"params": {
"message": {
"kind": "message",
"messageId": "m-001",
"role": "user",
"parts": [{"kind": "text", "text": "What is the weather in Colombo?"}]
},
"configuration": {"blocking": true}
}
}
}
In the a2a object, transport is JSONRPC.
HTTP+JSON
HTTP+JSON calls use REST-style paths, such as /v1/messages:send or /v1/tasks/{id}. The path identifies the operation. The body holds the operation’s parameters directly:
"request": {
"uri": "http://agent.example.com/v1/messages:send",
"verb": "POST",
"headers": {"content-type": "application/json"},
"body": {
"message": {
"kind": "message",
"messageId": "m-001",
"role": "user",
"parts": [{"kind": "text", "text": "What is the weather in Colombo?"}]
},
"configuration": {"blocking": true}
}
}
In the a2a object, transport is HTTP+JSON.
gRPC
gRPC calls use paths that name the service and method, such as /lf.a2a.v1.A2AService/SendMessage. The headers carry gRPC metadata. Message roles use the ROLE_ prefix:
"request": {
"uri": "https://agent.example.com:443/lf.a2a.v1.A2AService/SendMessage",
"verb": "POST",
"headers": {
"content-type": "application/grpc",
"te": "trailers"
},
"body": {
"message": {
"kind": "message",
"messageId": "m-001",
"role": "ROLE_USER",
"parts": [{"kind": "text", "text": "What is the weather in Colombo?"}]
},
"configuration": {"blocking": true}
}
}
The response headers carry the gRPC status in the grpc-status header. In the a2a object, transport is GRPC. The response.error_code field holds the same status code. For a successful call, both are 0.
Errors and Outcomes
A2A Analytics answers two separate questions about each call:
- Did the response carry an error? The
response.is_errorfield answers this question. The value istruefor a JSON-RPC error body, a gRPC status other than OK, or an HTTP status of400or higher. - Did the call achieve its goal? The
outcomefield answers this question. If the outcome isFAILURE, thefailure_originfield identifies the responsible party: the client, a policy, the gateway, or the upstream agent.
The two fields can disagree. For example, an agent can return a task with HTTP status 200, but end the task in the TASK_STATE_FAILED state. In that case, is_error is false and outcome is FAILURE. A chart that counts only HTTP errors misses this failure.
The terminal field shows whether the reported task state is final. A task in a terminal state doesn’t change any further.
Streaming Metrics
For a streaming call, the overall response time mostly reflects how long the stream stays open. The following fields measure streaming performance more precisely:
response.time_to_first_event_ms: The time from the start of the request to the first complete data event in the server-sent events (SSE) stream. This is how long the caller waits before receiving any data.response.stream_duration_ms: The time from the first frame to the end of the stream.
Send A2A Events to Moesif
You can send A2A events to Moesif in the following ways:
- Moesif SDKs: Include the
a2aobject in the event payload. For a list of SDKs, see Server Integrations. - Collector API: Send events to the Collector API directly, for example from an API gateway. Send single events to
https://api.moesif.net/v1/events, or arrays of events tohttps://api.moesif.net/v1/events/batch.
If your Moesif organization uses the EU region, use eu.api.moesif.net instead of api.moesif.net. For more information, see Data Residency.
Use Cases
Use A2A Analytics to answer questions such as the following:
- Agent traffic: Which agents and operations receive the most traffic? Group A2A events by
agentNameandoperation. To see which agents use which transports, group bytransport. - Task outcomes: How many tasks complete, fail, get canceled, or get rejected? Group terminal events by
response.task_state. Among non-terminal events, growth inTASK_STATE_INPUT_REQUIREDandTASK_STATE_AUTH_REQUIREDcan show that agents can’t complete work without help from the user. - Failure attribution: When a call fails, which party is responsible? Filter events where
outcomeisFAILURE. Then group them byfailure_origin. - Streaming responsiveness: How quickly do streaming agents respond? Chart the average
response.time_to_first_event_msof streaming events by agent. - Conversation tracing: Which calls belong to one conversation? Filter events by
response.context_id. ForGetTaskandCancelTaskcalls, the client sends the task ID in the request. To find every call for a task, filter onrequest.task_idas well asresponse.task_id. - Customer dependency: Which customers depend on which agents? Group A2A events by user or company. For more information, see Identify Customers.
You can save these charts to a dashboard and set up alerts on them.
You can also use the prebuilt Dashboard template for A2A Analytics to quickly get started. The template creates charts that give insights into latency trend by agent, error rate, breakdown of agents by operations and traffic volume, and more. Follow these steps from Moesif Portal:
- Select + Create New in the navigation menu.
- Select Dashboard Templates.
- Select the A2A Analytics template.
Related Resources
- Analyze Agent-to-Agent (A2A) Protocol Traffic in Moesif: A tutorial that sends sample A2A events and analyzes them.
- A2A Analytics Filters: The full list of fields, allowed values, and validation rules.
- Logging API Calls: How Moesif events are structured.
- A2A protocol specification: The official A2A protocol documentation.