Files
openclaw/docs/channels/matrix-presentation.md
Vito Cappello 5621979a46 fix(models): preserve session selection across fallback turns (#119325)
* feat(models): add session-only model selection

* fix(models): use trailing session scope option

* test(models): satisfy session scope lint

* fix(models): reject duplicate model options

* fix(models): clarify default and session scope

* fix(models): require complete session option tokens

* fix(models): report configured default dispatch

* fix(models): keep directive handler within lint limit

* fix(models): parse model options in either order

* fix(models): apply session scope to aliases

* fix(models): align alias scope with reply routing

* fix(discord): surface model selection scope in picker

* fix(models): preserve mixed-text model selection

* fix(models): centralize command selection ownership

* fix(models): align session scope lifecycle

* fix(models): preserve command and auth ownership

* fixup! fix(models): preserve command and auth ownership

* fix(auth): preserve scoped CLI provider discovery

* test(models): align result and cron fixtures

* test(models): nest result timing metadata

* fix(discord): narrow silent dispatch results

* fix(transcript): preserve admitted turn identity

* fix(context-engine): fence the admitted transcript turn

* fix(context-engine): stabilize plugin compatibility contract

* chore(plugin-sdk): refresh context engine API baseline

* chore(plugin-sdk): use Linux context engine API baseline

* fix(context-engine): align fallback ownership

* fix(fallback): scope auth skip cache by profile

* fix(context-engine): settle only accepted fallback turns

* refactor(sessions): issue canonical turn admissions

* refactor(context-engine): own logical turn advancement

* fix(context-engine): settle cron fallback winners

* fix(models): align picker and fallback transactions

* fix(delivery): notify block admission after queueing

* fix(sessions): preserve canonical admission receipts

* chore(plugin-sdk): refresh API baseline hash

* fix(context-engine): commit accepted turns durably

* fix(context-engine): validate durable host transitions

* fix(context-engine): preserve fallback turn ownership

* fix(context-engine): preserve queued turn order

* fix(models): preserve fallback retry ownership

* fix(context-engine): enforce durable transcript anchors

* fix(runtime): close fallback persistence gaps

* fix(context-engine): preflight fallback harnesses

* chore(plugin-sdk): use Linux API baseline

* fix(context-engine): drain durable commits before reads

* fix(models): scope harness auth failures by profile

* fix(codex): fence legacy transcript history

* fix(commands): honor suppressed directive interpretation

* chore(runtime): remove unused branch exports

* test(context-engine): derive private outbox payload type

* fix(context-engine): apply durable drain degradation

* fix(context-engine): recover durable turn intents

* fix(context-engine): settle durable turn intents

* refactor(context-engine): satisfy branch quality gates

* fix(context-engine): close durable recovery gaps

* fix(discord): preserve dropped model command outcome

* test(copilot): keep journal fixture types local

* fix(auto-reply): preserve model alias provenance

* fix: close model scope review gaps

* fix(models): close review-found scope leaks

* fix(review): satisfy branch line budgets

* fix(agents): preserve context engine turn facts

* fix(agents): finalize silent context turns

* fix(context-engine): preserve compatibility window

* test(agents): cover both harness preparations

* fix(context-engine): retain blocked turn advancements

* fix(models): parse compact runtime options

* fix(telegram): report runtime resets accurately

* fix(models): isolate automatic auth failure skips

* fix(context-engine): project commit turn host params

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-07 16:19:12 +08:00

85 lines
4.4 KiB
Markdown

---
summary: "Matrix MessagePresentation metadata for OpenClaw-aware clients"
read_when:
- Building Matrix clients that render OpenClaw rich responses
- Debugging com.openclaw.presentation event content
title: "Matrix presentation metadata"
---
OpenClaw attaches normalized `MessagePresentation` metadata to outbound Matrix `m.room.message` events under the `com.openclaw.presentation` content key.
Stock Matrix clients keep rendering the plain text `body`. OpenClaw-aware clients can read the structured metadata and render native UI such as buttons, selects, context rows, and dividers.
## Event content
```json
{
"msgtype": "m.text",
"body": "Select model\n\nChoose model:\n- DeepSeek",
"com.openclaw.presentation": {
"version": 1,
"type": "message.presentation",
"title": "Select model",
"tone": "info",
"blocks": [
{
"type": "select",
"placeholder": "Choose model",
"options": [
{
"label": "DeepSeek",
"value": "/model deepseek/deepseek-chat -s"
}
]
}
]
}
}
```
- `version` is the metadata schema version; the current version is `1`. `type` is a stable discriminator, always `"message.presentation"`. The Matrix adapter only emits payloads with exactly this version and type; clients should likewise ignore unknown versions they cannot safely interpret, unknown `type` values, and unknown block types.
- `title` and `tone` (`info`, `success`, `warning`, `danger`, `neutral`) are optional hints.
- Buttons and select options can carry a typed `action` (`{ "type": "command", "command": "/..." }` or `{ "type": "callback", "value": "..." }`) alongside the legacy string `value`. Prefer `action` when both are present.
## Fallback behavior
OpenClaw always renders a readable plain text fallback into `body`. The structured metadata is additive and must not be required for basic Matrix interoperability.
Fallback rendering rules:
- `title`, `text`, and `context` content renders as plain lines.
- Buttons with a `command` action render as ``label: `/command` `` so the command stays copyable. Buttons with a `callback` action or only a legacy `value` render label-only so opaque callback values stay private; disabled buttons are always label-only. URL and web-app buttons render as `label: URL`.
- Select blocks render the placeholder (or `Options:`) as a heading plus label-only option lines.
- If nothing renders, for example a divider-only presentation, the body falls back to `---`.
Unsupported clients keep showing the fallback text. OpenClaw-aware clients may prefer the structured metadata for display while preserving the fallback for copy, search, notifications, and accessibility.
## Supported blocks
The Matrix outbound adapter advertises native support for:
- `buttons`
- `select`
- `context`
- `divider`
`text` blocks are always supported through the fallback body. Treat all blocks as best-effort presentation hints; ignore unknown fields and block types rather than failing the whole message.
## Interactions
This metadata does not add Matrix callback semantics. Button and select values are fallback interaction payloads, usually slash commands or text commands. A Matrix client that wants to support interaction resolves the control value (`action.command`, then `action.value`, then `value`) and sends it back to the room as a normal message.
For example, a button with value `/model deepseek/deepseek-chat -s` can be handled by sending that value as an encrypted Matrix text message in the same room. The explicit session flag prevents a presentation control from requesting a configured-default update.
## Relationship to approval metadata
`com.openclaw.presentation` is for general rich message presentation.
Approval prompts use the dedicated `com.openclaw.approval` metadata because approvals carry safety-sensitive state, decisions, and exec/plugin details. If both metadata keys are present on the same event, clients should prefer the dedicated approval renderer.
## Media messages
When a reply contains multiple media URLs, OpenClaw sends one Matrix event per media URL. Caption text and presentation metadata attach only to the first event so clients get one stable structured payload without duplicate renderers. The same rule applies when long text is chunked across events: the metadata rides on the first event only.
Keep presentation metadata compact. Large user-visible text should stay in `body` and use the normal Matrix text chunking path.