/docs/schema/messages
Messages & content parts
obsrv normalizes all conversational content as a sequence of typed content parts. This is what makes multimodal traces work the same everywhere.
Roles
system— instructions to the model.user— input from the user.assistant— output from the model.tool— output from a tool/function invocation.
Content parts
A message has a list of content parts. Each part declares its type and the fields specific to that type.
{
"role": "user",
"content": [
{ "type": "text", "text": "Is this receipt valid?" },
{ "type": "image", "uri": "gs://…/receipt.png", "mime": "image/png" }
]
}Why a normalized shape
Different model providers represent conversational content differently. obsrv normalizes on the way in so the dashboard, the SDK, the eval surface, and OTel export all see the same shape — and you don't have to write a renderer per provider.