Skip to main content
UnifiedMessage is the single message format used everywhere in Hiro League — between channel plugins and the server, between the server core and the agent, and on the wire between devices and the gateway. Every channel plugin translates its native format to and from this model. No other message format exists in the pipeline.

Structure

A UnifiedMessage is a thin envelope with four fields at the top level:
FieldTypeDefaultDescription
versionstr"0.1"Schema version — allows future parsers to handle multiple generations
message_typestr"message"Communication intent — see Message types
routingMessageRoutingrequiredWho/where/when — see MessageRouting
contentlist[ContentItem]requiredOrdered list of content pieces — see ContentItem

MessageRouting

Carries routing and identification: who sent the message, which channel it belongs to, where it’s going, and when it arrived. direction is always from the perspective of hirocli:
  • "inbound" — arriving from a third party (user sent something)
  • "outbound" — to be sent to a third party (server is replying)
FieldTypeDefaultDescription
idstrauto UUID hexMessage identifier, auto-generated
channelstrrequiredChannel name, e.g. "telegram", "devices"
directionstrrequired"inbound" or "outbound"
sender_idstrrequiredOriginating user or service identifier
recipient_idstr | NoneNoneTarget user or service identifier
timestampdatetimeauto UTCReceive time, auto-set
metadatadict{}Routing-level extras — channel IDs, device info, etc.

ContentItem

A single piece of content within the message. A message may contain multiple items — for example, a text caption alongside several images and a PDF attachment.
FieldTypeDefaultDescription
content_typestrrequiredSee Content types
bodystr""The payload: plain text, URL, base64 string, etc.
metadatadict{}Content-level extras — filename, MIME type, duration, etc.
body is always a string. Its interpretation depends on content_type: for text it is the text itself; for image, audio, video, and file it is typically a URL or file path; for location it may be "lat,lon" or a JSON string.

Message types

message_type identifies the communication intent. Only "message" is currently implemented.
ValueStatusDescription
"message"✅ ImplementedContent exchange — text, images, audio, files, etc. Requires at least one ContentItem.
"request"🔵 ReservedExpects a response. Planned for the device RPC protocol.
"response"🔵 ReservedAnswer to a request. Planned for the device RPC protocol.
"stream"🔵 ReservedStreaming chunks (e.g. LLM token-by-token). Planned for future use.

Content types

Standard values for ContentItem.content_type. Defined as constants in hiro-channel-sdk/constants.py.
ConstantValuebody contains
CONTENT_TYPE_TEXT"text"Plain text
CONTENT_TYPE_IMAGE"image"URL or file path
CONTENT_TYPE_AUDIO"audio"URL or file path
CONTENT_TYPE_VIDEO"video"URL or file path
CONTENT_TYPE_FILE"file"URL or file path
CONTENT_TYPE_LOCATION"location"Coordinate string or JSON
CONTENT_TYPE_JSON"json"Raw JSON string
Custom values are accepted — the system does not validate content_type against a fixed list.

Wire format

Simple text message

{
  "version": "0.1",
  "message_type": "message",
  "routing": {
    "id": "a3f9c2d1b4e5f6...",
    "channel": "devices",
    "direction": "inbound",
    "sender_id": "phone-1",
    "recipient_id": null,
    "timestamp": "2026-03-17T10:00:00+00:00",
    "metadata": { "channel_id": "conv-abc" }
  },
  "content": [
    { "content_type": "text", "body": "Hello!", "metadata": {} }
  ]
}

Multi-content message

{
  "version": "0.1",
  "message_type": "message",
  "routing": {
    "id": "b7e2f1a0c3d4...",
    "channel": "devices",
    "direction": "inbound",
    "sender_id": "phone-1",
    "recipient_id": null,
    "timestamp": "2026-03-17T10:01:00+00:00",
    "metadata": { "channel_id": "conv-abc" }
  },
  "content": [
    { "content_type": "text", "body": "Here are the files from yesterday" },
    { "content_type": "image", "body": "https://cdn.example.com/beach.jpg", "metadata": { "filename": "beach.jpg" } },
    { "content_type": "image", "body": "https://cdn.example.com/sunset.jpg", "metadata": { "filename": "sunset.jpg" } },
    { "content_type": "audio", "body": "https://cdn.example.com/voicenote.ogg", "metadata": { "duration_ms": 4200 } },
    { "content_type": "file",  "body": "https://cdn.example.com/report.pdf",  "metadata": { "filename": "report.pdf", "mime_type": "application/pdf" } }
  ]
}
Content item order is preserved and meaningful — consumers should respect the sequence as authored by the sender.

Python model

Defined in hiro-channel-sdk/src/hiro_channel_sdk/models.py. Import from the SDK:
from hiro_channel_sdk import UnifiedMessage, MessageRouting, ContentItem
from hiro_channel_sdk.constants import CONTENT_TYPE_TEXT, CONTENT_TYPE_IMAGE

See also