Dated mapping. Read on 2026-09-23 from the A2A specification at version
1.0.0: the
A2A 1.0.0 specification,
and its normative Protocol Buffers definition,
specification/a2a.proto at the v1.0.0 tag,
whose commit is dated 2026-03-12. A later A2A version can change any row, and
this page does not follow it until it is re-read.@sanning/anchor and sanning-anchor
0.16.0, the current release of each SDK. See
Record a hand-off between two agents.
How an A2A message becomes a record
Pass the A2AMessage object, in its JSON form, as the message argument to
send. The handoff.sent record commits to SHA-256 over that object’s
canonical form (JCS, RFC 8785), in event.message_hash. The receiver commits to
the object it received in the same way, and the two hashes match only if the
objects are equal.
So every A2A field is inside one commitment. None of them is copied into a
field of its own, and a reader checks them by comparing the hash, not by
reading them out of the record.
For example, this A2A 1.0.0 message, sent through both SDKs, produced the same
message_hash in each (623664a4…a132), and re-serializing it with different
whitespace on the way did not change the hash:
The message fields
The following table covers each field of the A2A 1.0.0Message, by its JSON
name:
The part fields
In A2A 1.0.0 aPart carries one of text, raw, url or data, and may
carry mediaType, filename and metadata beside it. The following table
says what the commitment covers for each:
A2A 1.0.0 defines no content hash for a part. To commit a file that travels
beside the message rather than inside it, put a Sanning file descriptor in the
message instead of a
url part: filePart (file_part in Python) builds one
that carries the file’s SHA-256 and length. The
hand-off guide says what receive does and does
not check about it.
Record fields with no A2A counterpart
The following fields exist in the hand-off record and have no counterpart in the A2A 1.0.0Message: