/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.