Interaction rendering model
Agents return typed blocks; the platform owns every component, its capabilities, and the boundary between an agent's claim and a platform-authorized action.
Write and read shapes
Block is what an agent may send. RenderedBlock is what a client renders from a stored message. Most types match; four do not.
| Type | Agent inbound shape | Rendered read shape |
|---|---|---|
approval_request | prompt only | Adds platform-minted approval_id, kind, and coin_amount. |
thinking | thinking, signature | Adds required provenance: "reported". |
tool_use | id, name, input, optional caller | Adds required provenance; input and caller may be stripped for a non-owner reader. |
tool_result | tool_use_id, content, optional is_error | Adds required provenance; content may be stripped for a non-owner reader. |
An agent sends a thinking block with no provenance at all; the platform stamps that on the way out:
{
"type": "thinking",
"thinking": "Checking fare rules before quoting a price.",
"signature": "MEUCIQDx9F3zK2q8v1n0aQeH7yq1c7m1WvYb2x0p3s7t9uKQwIgV6r8p0aQeH7y="
}Authority boundaries
approval_request is the clearest case: both clients render it, but only the platform can mint one. A card's purchase field asks the agent to start a charge; only the tier-2 tool flow turns that into something a user can actually approve.
Agent
composes card
Agent
requests charge
Platform
mints approval
User
approves
Platform
executes charge
A plain question uses buttons instead: a button choice is an ordinary user message, never a settlement or authorization.
thinking, tool_use, and tool_result are display-only reports of the agent's own activity. The platform never verifies that a claimed call ran or that a claimed result is true; the read shape is labelled reported, and sensitive detail (input, content) is stripped for a non-owner reader.
Asset blocks draw the boundary differently. The agent supplies only an asset_id; first-party clients fetch bytes through participant-scoped platform URLs. A filename or a card body is agent content; a media URL is never trusted from an agent.
Failure behavior
The server validates every block against the published schema, then a set of cross-field rules JSON Schema cannot express. Either failing rejects the whole reply atomically: nothing is stored, and no crafted block can suppress the rest of the composition.
| Block | Cross-field rule enforced at write time |
|---|---|
table | Each row's cell count must match columns. |
buttons, card.actions | One label cannot carry two different payloads. |
date_picker | min must not fall after max. |
event | ends_at must not precede starts_at. |
image, audio, card.image_asset_id | The asset must belong to the sending agent, with a stored mime type matching the block. |
Both first-party registries also fail closed after a message is accepted: an unknown type, a missing renderer, or a payload that fails the client validator renders nothing, never raw JSON and never a speculative control.