A2A Part: Text, File, and Structured Data Content
A Part is the smallest unit of content in A2A. Both Messages and Artifacts are lists of parts, which is what makes the protocol independent of the kind of content exchanged: plain text, a file, or a structured JSON value.
One part, one kind of content
In v1.0 there is a single Part type. It holds exactly one of four content fields, and the field name tells you the kind:
| Field | Content | In JSON |
|---|---|---|
text | A string of text | A string |
raw | The bytes of a file | A base64-encoded string |
url | A URL pointing to the file’s content | A string |
data | Any structured value: an object, array, string, number, boolean, or null | A JSON value |
Every part can also carry these fields, whatever its content kind:
| Field | Description |
|---|---|
mediaType | The MIME type of the content, for example text/plain, application/json, or image/png |
filename | An optional file name, for example document.pdf |
metadata | A key-value object with extra information about the part |
Text
A text part is the simplest case, and the one used in most requests:
{
"text": "Hello, world!"
}Files: inline bytes or a URL
Use raw to send a file inside the message, and url to point to a file stored elsewhere. The specification’s file exchange scenario shows both directions. The client uploads an image with raw:
POST /message:send HTTP/1.1
Host: agent.example.com
Content-Type: application/a2a+json
Authorization: Bearer token
{
"message": {
"role": "ROLE_USER",
"parts": [
{
"text": "Analyze this image and highlight any faces."
},
{
"raw": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
"filename": "input_image.png",
"mediaType": "image/png"
}
],
"messageId": "6dbc13b5-bd57-4c2b-b503-24e381b6c8d6"
}
}The example is adapted: the specification’s version is missing the comma after the raw value and has a trailing comma after mediaType, so it is not valid JSON as printed. The agent answers with an artifact whose part points to the result by url:
HTTP/1.1 200 OK
Content-Type: application/a2a+json
{
"task": {
"id": "43667960-d455-4453-b0cf-1bae4955270d",
"contextId": "c295ea44-7543-4f78-b524-7a38915ad6e4",
"status": {
"state": "TASK_STATE_COMPLETED",
"timestamp": "2024-03-15T12:05:00Z"
},
"artifacts": [
{
"artifactId": "9b6934dd-37e3-4eb1-8766-962efaab63a1",
"name": "processed_image_with_faces.png",
"parts": [
{
"url": "https://storage.example.com/processed/task-bbb/output.png?token=xyz",
"filename": "output.png",
"mediaType": "image/png"
}
]
}
]
}
}Which to use is a trade-off. raw keeps everything in one request but grows the payload by the base64 overhead. url keeps messages small, but the receiver must be able to fetch the URL. The URL in the example carries a token, so treat URLs like it as credentials.
Structured data
The specification’s structured data scenario asks for open tickets in a given JSON shape. The client describes the shape in the text part’s metadata:
POST /message:send HTTP/1.1
Host: agent.example.com
Content-Type: application/a2a+json
Authorization: Bearer token
{
"message": {
"role": "ROLE_USER",
"parts": [
{
"text": "Show me a list of my open IT tickets",
"metadata": {
"mediaType": "application/json",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ticketNumber": { "type": "string" },
"description": { "type": "string" }
}
}
}
}
}
],
"messageId": "85b26db5-ffbb-4278-a5da-a7b09dea1b47"
}
}The specification’s response returns the list as a JSON string inside a text part:
{
"artifactId": "c5e0382f-b57f-4da7-87d8-b85171fad17c",
"parts": [
{
"text": "[{\"ticketNumber\":\"REQ12312\",\"description\":\"request for VPN access\"},{\"ticketNumber\":\"REQ23422\",\"description\":\"Add to DL - team-gcp-onboarding\"}]"
}
]
}The data field carries the same information as a native JSON value, with mediaType set to application/json. This is the same ticket list written as a data part, adapted from the response above:
{
"artifactId": "c5e0382f-b57f-4da7-87d8-b85171fad17c",
"parts": [
{
"data": [
{"ticketNumber": "REQ12312", "description": "request for VPN access"},
{"ticketNumber": "REQ23422", "description": "Add to DL - team-gcp-onboarding"}
],
"mediaType": "application/json"
}
]
}Using data avoids escaping JSON inside a string, and the receiver gets a native JSON value.
Matching what the other side accepts
An agent declares the media types it works with in its Agent Card through defaultInputModes and defaultOutputModes, and each skill can override them. A client can send acceptedOutputModes in the send configuration so the agent tailors its output. If a part uses a media type the agent does not support, the agent returns ContentTypeNotSupportedError. See Agent Card
.
Coming from v0.3?
Version 1.0 removed the kind discriminator. The member name now identifies the content, and the three part types became one:
| v0.3 | v1.0 |
|---|---|
{"kind": "text", "text": "..."} | {"text": "..."} |
{"kind": "file", "file": {"name": "...", "mimeType": "...", "fileWithBytes": "..."}} | {"raw": "...", "filename": "...", "mediaType": "..."}, or url instead of raw |
{"kind": "data", "data": {...}} | {"data": {...}, "mediaType": "application/json"} |
The same change applies to streaming events: {"kind": "status-update", ...} became {"statusUpdate": {...}}, and {"kind": "artifact-update", ...} became {"artifactUpdate": {...}}. More in What’s New in A2A Protocol v1.0
.
Related pages
- Message and Artifact : the two objects that hold parts.
- Interoperability Reference : how parts and streaming events changed on the wire between v0.3.0 and v1.0.1.
- Data Structures : the complete field reference.
Source: A2A official specification: Part, File Exchange, Structured Data Exchange, and Appendix A.2.1