Rich Output Protocol for Structured Media and Embeds

This page details the rich output protocol used for structured media, embeds, audio hints, and replies. Developers and integrators will learn how to handle attachment delivery and rendering instructions.

Read this when

  • Changing assistant output rendering in the Control UI
  • Debugging `[embed ...]`, structured media, reply, or audio presentation directives

Assistant output uses a small set of dedicated channels to carry delivery and rendering instructions:

  • Structured mediaUrl and mediaUrls fields handle attachment delivery.
  • [[audio_as_voice]] provides hints for audio presentation.
  • [[reply_to_current]] together with [[reply_to:<id>]] carries reply metadata.
  • [embed ...] supports rich rendering in the Control UI.

Delivery metadata consists of structured media fields and [[...]] tags. The [embed ...] field is a separate web-only path for rich rendering; it is not an alias for media.

Media attachments

Remote attachments must use public https: URLs. Attachment directives reject http: addresses, loopback, link-local, private, and internal hostnames; server-side media fetchers apply their own network-level protections on top.

Local attachments accept absolute paths, paths relative to the workspace, or home-relative ~/ paths. Before delivery they still pass through the agent's file-read policy and media type checks.

Warning

Do not emit text commands for attachments from tools, plugins, streaming blocks, browser output, or message actions. Instead use structured media fields:

{ "message": "Here is your image.", "mediaUrl": "/workspace/image.png" }

Legacy final-reply text may still be normalized for backward compatibility, but this is not a general protocol for plugins or tools.

By default, plain Markdown image syntax (![alt](url)) remains text. Channels that want Markdown images treated as media replies opt in at their outbound adapter; Telegram does this so ![alt](url) becomes a media attachment.

When block streaming is enabled, media must be placed on structured payload fields. If the same media URL appears in a streamed block and again in the final assistant payload, OpenClaw delivers it once and removes the duplicate from the final payload.

[embed ...]

For the Control UI, [embed ...] is the only agent-facing rich-render syntax. A self-closing example:

[embed ref="cv_123" title="Status" /]

Rules:

  • [view ...] is no longer valid for new output.
  • Embed shortcodes render only within the assistant message surface.
  • Only URL-backed embeds render; use ref="..." or url="...".
  • Block-form inline HTML embed shortcodes do not render.
  • The web UI removes the shortcode from visible text and renders the embed inline.

Stored rendering shape

The normalized and stored assistant content block is a structured canvas item:

{
  "type": "canvas",
  "preview": {
    "kind": "canvas",
    "surface": "assistant_message",
    "render": "url",
    "viewId": "cv_123",
    "url": "/__openclaw__/canvas/documents/cv_123/index.html",
    "title": "Status",
    "preferredHeight": 320
  }
}

present_view is not recognized; stored and rendered rich blocks always use this canvas shape.