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
AUnifiedMessage is a thin envelope with four fields at the top level:
| Field | Type | Default | Description |
|---|---|---|---|
version | str | "0.1" | Schema version — allows future parsers to handle multiple generations |
message_type | str | "message" | Communication intent — see Message types |
routing | MessageRouting | required | Who/where/when — see MessageRouting |
content | list[ContentItem] | required | Ordered 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)
| Field | Type | Default | Description |
|---|---|---|---|
id | str | auto UUID hex | Message identifier, auto-generated |
channel | str | required | Channel name, e.g. "telegram", "devices" |
direction | str | required | "inbound" or "outbound" |
sender_id | str | required | Originating user or service identifier |
recipient_id | str | None | None | Target user or service identifier |
timestamp | datetime | auto UTC | Receive time, auto-set |
metadata | dict | {} | 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.| Field | Type | Default | Description |
|---|---|---|---|
content_type | str | required | See Content types |
body | str | "" | The payload: plain text, URL, base64 string, etc. |
metadata | dict | {} | 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.
| Value | Status | Description |
|---|---|---|
"message" | ✅ Implemented | Content exchange — text, images, audio, files, etc. Requires at least one ContentItem. |
"request" | 🔵 Reserved | Expects a response. Planned for the device RPC protocol. |
"response" | 🔵 Reserved | Answer to a request. Planned for the device RPC protocol. |
"stream" | 🔵 Reserved | Streaming chunks (e.g. LLM token-by-token). Planned for future use. |
Content types
Standard values forContentItem.content_type. Defined as constants in hiro-channel-sdk/constants.py.
| Constant | Value | body 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 |
content_type against a fixed list.
Wire format
Simple text message
Multi-content message
Python model
Defined inhiro-channel-sdk/src/hiro_channel_sdk/models.py. Import from the SDK:
