# Chat

> Composer controls, transcript rendering, side chat, and hosted embeds

- 网址：https://funcoding.ai/agents/openclaw/web/control-ui/chat/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/web/control-ui/chat

---
How the chat pane behaves: the session rail, the composer, and how the transcript renders.

Tool activity shows a tool-specific icon beside its purpose or details instead of
repeating the tool name. When no distinct purpose or detail is available, the row
shows the tool label instead of leaving the text blank. Hover the icon to see the
exact tool name; screen readers retain that identity. Expanding an activity group keeps the individual tool details
and outcomes available. Completed group summaries retain their operation counts.
Tool Search calls use the called tool's name, icon, and input details in tool rows
and activity summaries. Built-in tools use semantic icons, including an envelope
for messages, a calendar clock for scheduled jobs, and an image for image generation.
Unknown tools use a puzzle icon unless their plugin supplies an activity icon.

A tool stops showing **Running** when its completion arrives, even while the
parent turn continues. If that completion does not establish success or failure,
the row shows **Outcome unknown**. Partial output alone does not finish a tool.

While a turn is still working and has subagents running, its working indicator
ends with their count, such as **3 subagents running**, and counts down as they
finish. Selecting the count opens the **Subagents** panel on its list. Child
sessions that are not subagents are not part of that count.

Under the reply, each unfinished subagent has its own row
showing its name and current activity headline. Rows stay in launch order as
activity changes and disappear when the subagent finishes. Until a current-run
headline is available, the row shows **Running**, **Queued**, or **Waiting on
subagents** when that child has delegated work of its own. Select a row to open
that subagent in the **Subagents** panel, or its session when the panel does not
list it. The rows reuse the chat's loaded subagent list; they do not load each
child's transcript.

When a turn hands off with `sessions_yield` and its subagents are still active,
their live rows stay under that reply without a separate **Waiting on…** line
or wait timer. The same applies when a turn ends without a handoff. Until the
subagent list is available, **Waiting on subagents** remains as a fallback;
its elapsed time counts from the handoff when known. The parent's own working
indicator remains visible while the parent is actively working. Child sessions that are
not subagents are counted without names once no subagent is left, as **Waiting
on 2 sessions**. Once everything it waited on has finished, the line goes away
until the agent resumes. Tool rows you opened stay open through the handoff. A
successful `sessions_yield` leaves no marker in the transcript, and its private
continuation context stays hidden.

When the last subagent finishes, the wait line ends and the block stays as it
is, without a working indicator, until the turn resumes. Its answer then
continues in that same block, with one footer at the end. Tool activity that
resumes with nothing written in between joins the activity row from before the
handoff. In dashboard sessions, tool activity recorded after the resumed
answer, such as the step that sent it, joins the activity before that answer,
so the answer stays last; a step that failed there stays where it happened. The
working indicator
and the closing **Done in…** line then
describe the whole request: time since you asked, including the wait, and
output tokens from the runs in that block. The token count is left out when the
pane did not see all of those runs, for example after a reload during the wait.
When the loaded transcript does not show your request leading straight into that
block, for example when the request is older than the loaded history, both
lines describe the resumed run alone. A message you send after the handoff
starts a block of its own, with that run's own clock and closing line.

In the tool activity, a subagent's launch row shows the label its launch gave
it, when it gave one, rather than its instructions, followed by **running**
while it works and by its duration once it has finished. A subagent that failed
or timed out reads **failed** instead, and one that was stopped reads
**stopped**. Selecting the name opens that subagent in the **Subagents** panel;
the rest of the row still expands the launch's details. Collapsed activity counts subagents on
their own, such as **1 other operation · 3 subagents**. A launch that was
refused started no subagent and is counted with the other operations. While the
step in progress has no title of its own, the collapsed row keeps showing that
count. A launch that opens a
child session in its own right, such as one asked for with `visible`, is not a
subagent: its row and its place in that count stay those of an ordinary
operation.

The running count, the wait's count and name, and a launch row's state and link
come from the session's subagent list. Until the pane has loaded it, the working
indicator shows no count and a wait reads **Waiting on subagents**; a launch
row whose subagent is not in the list shows its name alone. The pane does not
load that list when
[Swarm is turned off](https://funcoding.ai/agents/openclaw/tools/swarm/) with `tools.swarm: false`.

The count and the names lead to the **Subagents** panel only for subagents that
panel lists, including swarm workers, and only in a pane that has the panel. A
subagent on the ACP runtime is not in that list, so its name opens its session
instead, and a count that includes one is plain text. A pane without a side
panel of its own, such as the transcript the **Subagents** panel shows or a
session embedded in Home, opens the subagent's session as well. **Waiting on 2
sessions** is always plain text.

When your role or session policy blocks messages, the composer is disabled and
shows the reason before you try to send. This includes sandbox requirements,
shared-session write restrictions, and read-only operator access. Your existing
draft stays in place when access changes.

Saved split panes keep their conversation and arrangement. If an older saved pane
does not identify its agent, it shows **Choose a conversation** instead of opening
another agent's history. Select that pane, then choose **Home** or a conversation
in the sidebar. Home works even when you are already on its route; the other
panes stay unchanged.

When the macOS app embeds a single conversation beside its native sidebar, the
chat header fills the window's titlebar row. Drag an empty area of the header to
move the window; its buttons keep their normal actions.

## Collaborator drafts

In a shared session, another person’s in-progress message stays visible when they pause typing. Draft previews update up to four times per second, keeping the latest text when input arrives faster. After 10 seconds without typing, its label changes from **is typing...** to **Draft** without removing the bubble or shifting the transcript. Typing again updates the same bubble. Sending, clearing the draft, leaving the composer, or leaving the session removes it. An idle preview fades out and smoothly closes its space during the final 300 milliseconds before its 30-second expiry, so an abandoned tab cannot leave it visible indefinitely. Typing again cancels the exit. With reduced motion enabled, the preview stays still and disappears at the same deadline without animation. Draft previews are temporary browser state, not saved messages; changing sessions or reconnecting clears them.

Busy sessions keep the first two people’s preview bubbles in arrival order, including their separate **Draft** lifecycle. Only actively typing people beyond those two appear in the overflow row: its bounded stack shows up to five avatars and one sentence. One, two, or three active overflow collaborators are named naturally; four or five use the first two names and the number of others. With more than five active overflow people, the sentence becomes **Several people are typing…**. Stopping, pausing, sending, or leaving removes a person from that row immediately; the row disappears when nobody remains active there, even while the first two preview bubbles retain drafts. Long names remain visibly part of the sentence, with responsive ellipsis and full accessible names; enlarged text can wrap. The group reserves two text lines. Its first avatar aligns with the preview avatars, and the sentence follows the actual stack width with a small gap. Active typing text uses a subtle shared shimmer; preview **Draft** labels, reduced motion, and forced colors retain legible static text. Editing or pausing does not reorder the two preview slots; a slot opens only when its person sends, leaves, clears, or expires.

## Reactions

Hover a saved prompt or assistant reply and select **Add reaction** beside the
message actions, or the **+** chip at the end of an existing reaction row. The
quick palette offers **👍**, **❤️**, **🎉**, **👀**, **🚀**, and **😂**; an emoji
you already placed shows pressed, and selecting it again removes it. Arrow keys
move through the palette and Escape closes it.

Select **…** for any other emoji. Type or paste one, or open the system emoji
picker with **⌃⌘Space** on macOS or **Win+.** on Windows: a complete emoji is
applied as soon as it lands in the field, so the system picker needs no extra
keystroke. Anything that is not a single emoji stays in the field with a hint.
Backspace in an empty field returns to the palette.

Reaction chips appear directly below each message with a count and animate when
the count changes. Hover a chip to see who reacted, with you listed first.
Select a chip to add your reaction, or select a pressed chip again to remove
yours. Viewers can read the chips; adding or toggling requires permission to
send or suggest in that session. See
[Multi-user reactions](https://funcoding.ai/agents/openclaw/concepts/multi-user/#reactions) for agent and channel behavior.

## Session rail and side chat

While you watch a running session, the Gateway shows the model's latest safe preamble immediately as the session headline. When a utility model is available, it can replace that headline with a richer compact status digest after enough activity accumulates. Chat carries the result in a **session rail**: its compact pill shows the live digest, while the expanded rail shows pull requests, elapsed time, and a read-only Side chat thread. The rail can expand once when a run becomes stuck or needs input, and done or failed runs keep a frozen “finished” time based on the final digest. On wide chat panes the expanded rail docks as a 400 px right column; on narrower and mobile layouts it remains an overlay.

Side chat answers questions about the selected session and its project without entering or interrupting the main agent run. On the first question, the Gateway lazily loads a bounded visible snapshot of the selected session before starting the utility model. If history is temporarily unavailable, the question stays visible with **Retry** instead of being treated as an empty session. Side chat uses read-only access to the target session's history/search and agent workspace. Its bounded thread is held in Gateway memory, is restored when you switch sessions in the Control UI, and is cleared by the rail's trash button, a session reset or deletion, Gateway restart, or idle expiry. It never enters `chat.history`, and private reference context is not stored as operator dialogue. Open it with Shift-Command-S on Apple platforms or Ctrl-Shift-S elsewhere, or type `/btw` or `/side` in the main Control UI composer and press Enter to open the rail and focus its question box. Selecting `/btw` from the slash menu does the same. Add a question after either command to send it to Side chat; focus moves to its question box when the request finishes. Other clients keep their existing BTW behavior.

When the agent's primary model runs on a CLI runtime such as `claude-cli`, no utility model is set explicitly, and direct provider authentication is unavailable, Side chat answers through that same CLI runtime. Subscription-only installs need no provider API key. On that route each answer is a tool-free, one-shot side question that uses the bounded session snapshot and observer notes instead of the read-only session tools, and image questions are not supported. Installs with working direct provider authentication keep the direct route, including read-only tools and image support.

Opening Side chat, reopening its panel, or selecting its tab focuses the question box. If you focus another input or keep typing while Side chat loads or answers, that newer input keeps focus.

Confirming text with an input method does not send the Side chat question. Finish composition, then use your configured send shortcut or the Ask button.

Editing a Side chat draft does not interrupt loading its earlier answers. **Clear side chat** removes the earlier content after the Gateway confirms it; drafts, images, and questions added after the click remain.

The Control UI keeps the latest 24 Side chat turns, including failed questions. Sending a follow-up keeps earlier failures in order; **Retry** resends that question in place. Failed questions stay in the current pane through a reconnect, but are not persisted across a page reload.

The question box wraps and grows like the main composer; Enter (or your configured send shortcut) asks the question, and Shift+Enter adds a line. Highlighting text in a chat message offers **Ask in side chat**. Add an optional comment in the selection editor, then save it to stage an editable comment in Side chat. An empty question box starts with a short quote; an existing Side chat draft and the main composer stay unchanged. The full selection and comment accompany that question as bounded, temporary context. After the answer, the restored thread keeps the question text, including its quote, but not the attached context. Reselect the passage for a later question.

If the selection alone exceeds the context limit, Side chat opens without adding the selection and shows a notification. An empty question box still gets a short quote; an existing draft stays intact. If a comment or the combined selections exceed the limit, the editor stays open so you can shorten the comment or adjust the pending selections.

Drop an image onto Side chat or paste one into its question box. You can send it
with a written question or on its own. Side chat accepts image attachments, not
other file types; its previews never add attachments to the main composer.
Image questions require an image-capable Side chat utility model. A text-only
model produces a visible error instead of answering without the image; choose
an image-capable utility model before retrying.
Images are available only for the current question and are not retained in the
restored text thread. Reattach an image when asking a later question about it.
A failed question keeps its image for **Retry** while the current pane is retained;
reloading the page discards that failed input.

Highlight text and choose **Add to chat** to attach a comment to the main
composer. The optional comment field starts on one line, grows to five lines,
then scrolls internally. Confirm or press Enter to save; Shift+Enter adds a line.
Saving keeps your existing draft and does not send a message.

Saving leaves a small, filled comment marker beside the selected passage. Click
that marker, or the pencil in the comment count's hover preview, to reopen the
same editor beside it. **Save** or Enter saves changes; **Cancel** or Escape discards the edit; and the trash
button deletes the comment. Hover, keyboard-focus, or click the composer's comment
count to open its preview. Deleting one comment keeps the remaining list open;
Escape, a click outside, or moving the pointer away dismisses it. The count's
**Remove all comments** action clears pending comments in one click and returns
focus to the composer without showing a notification. Cleared comments cannot
be undone. The clear action appears on hover or keyboard focus and stays visible on touch.
Clearing pending comments preserves ordinary attachments, the message draft,
and comments already sent in the conversation.
Archiving another split pane leaves the current comment editor and keyboard focus in place.
Saved comments and their source markers follow the composer's existing draft and
queue recovery behavior. When you send, each comment is attached as a text file
containing the selection, comment, and source message reference; its draft marker is removed.
Hover, keyboard-focus, or tap the sent comment count to read its selection and
comment in a compact, scrollable preview. Sent comments remain read-only.
Press Escape or tap outside the preview to dismiss it.

The headline owns that run's sidebar subtitle instead of heuristic live activity. It is shared with the official iOS and Android session lists. A final done or failed digest remains visible while the session is unread, then the row returns to its normal work subtitle.

Session observation is enabled by default. Safe preamble headlines do not require a utility model; the utility model only owns richer assessments and terminal summaries. In **Settings > Appearance > Sidebar**, you can turn observation off gateway-wide, inspect the resolved small model and its provenance, or choose automatic routing, disable utility tasks, or select an explicit `agents.defaults.utilityModel`. The equivalent config controls are `gateway.controlUi.sessionObserver: false` and `agents.defaults.utilityModel: ""`.

## Session links in messages

Session links in messages open inside the Control UI. This includes `agent:` keys,
root-relative chat URLs, and URLs on the current origin or the Gateway's public origin
when its applied configuration is loaded. Hovering a link shows the session card
when the session is known locally. Unknown or ambiguous session references remain
navigable without a card; links to other origins keep normal browser behavior.
Document-relative hrefs are never session links; file references such as
`src/utils/foo.ts` and `qa-café/index.md` retain workspace file handling, including
Unicode names and percent-encoded Markdown link destinations. Explicit Markdown
file links also support spaces, emoji, and punctuation in filenames; for example,
`[Read notes](notes/caf%C3%A9%20note.md)` opens the workspace file. Bare CSV
filenames in authored links, such as `[Read inventory](inventory.csv)`, and code
spans also open the file preview. Plain-text and inline-code file detection stays
conservative to avoid turning prose into links.

File links in forwarded messages open against the sending session's workspace,
including links inside collapsed update groups and message details. Their
filename tabs stay in the current chat pane. Files outside the session root
follow that session's file-tool read boundary and also require permission to
start a turn in that session. These out-of-root previews are read-only.

In Chat and New Session, provider groups retain their expanded or collapsed state when you close and reopen the same model picker. Closing clears the search text without resetting those toggles. Reloading the page initializes the groups from the selected model again.

While composing text with an input method in model search, Enter, Escape, and arrow keys stay with the input method. They do not select a model, clear the search, or move the highlighted model until composition finishes. Open tooltips also leave Escape to the input method.

When authentication status is available, each provider heading in the chat model picker says how that provider is signed in: **API** for an API key (or an explicitly selected API-key account), the plan name for a provider with one subscription, and **Subscription** for a provider with several. With several subscriptions, the heading adds the email of an explicitly selected account when the Gateway supplies it, and the **Account** rows show each account's email; automatic selection shows no account identity. Hover a truncated heading to read the full text.

## Suggested tasks

Suggested task cards offer **Start in a new session** and **Start in a new
worktree**. Both start the task in the background and keep your current
conversation and draft open. The card disappears after the task starts; select
the new session in the sidebar when you want to follow its progress.
**Start in this session** runs the task in the current conversation.

Before starting a worktree, OpenClaw checks that the suggested folder is a Git
repository with a commit. If it is not, the card keeps the prompt and lets you
select a registered project or enter the correct repository path. Select
**Start in a new worktree** again to continue; no child session is started for
an invalid source folder.

## Composer capability menu

Select **+** beside the chat composer to open attachments and session capabilities in one menu:

- **Skills** enables or disables individual skills for this session.
- **Connectors** enables or disables configured MCP servers for this session. A **session** tag marks values that differ from the inherited configuration.
- **Web search** enables or disables managed web search plus native OpenAI and Codex search for this session.
- **Manage plugins** opens the Plugins page.

These controls are sparse session overrides, like the model and thinking settings in the chat header. A capability with no override inherits the current agent or global configuration, and OpenClaw applies the resolved values when the next run materializes its tools and skills. When overrides are set, open **+** and select **1 override** or **N overrides** at the bottom of the menu to clear all capability overrides for this session and return to inherited settings.

When `tools.web.search.enabled` is `false`, **Web search** stays off in Chat and New Session. The disabled control explains the global setting. If a session has an older enable override, selecting the control clears that override while search stays off. An explicit session disable remains saved.

For attachments in Chat and New Session, Android Chrome, Edge, Firefox, and Samsung Internet send **Take photo** straight to the device capture input, without opening a web-camera preview first. **Photo** and **File** remain separate choices. Desktop browsers keep the preview, capture, and retake flow; iPhone and iPad Safari keep their single **Attach…** picker. Embedded native hosts keep their existing behavior. Canceling capture leaves the message draft unchanged.

Video files selected in Chat or New Session show a small local frame preview with a play badge beside the filename. The slot keeps its size while loading. If the browser cannot decode the video promptly, the play icon remains. Removing the attachment releases its preview; generating the preview does not upload the video.

In **Connectors**, administrators can select **Add MCP server…** and choose a scope. **This session** saves the server definition globally but disabled by default, then enables it only for the current session. **Everywhere** saves the definition enabled globally. Transport, authentication, and other server-definition fields are always global. Session policy can override server enablement and deny individual tools through **Tool access**.

**Tool access** lists a connector's tools once a run has discovered them. Before that, it explains why the list is empty rather than reporting zero tools: a newly added server has not connected yet, a connected server has not finished listing its tools, or the runtime catalog predates a config change. Sessions that run on the Codex harness keep their MCP connections inside Codex, so their tools do not appear here.

Capability toggles stay disabled until the Gateway, session, and runtime config are loaded, and read-only operators cannot change them. Adding a server requires administrator access. See [Connect MCP servers](https://funcoding.ai/agents/openclaw/tools/mcp/) for the Settings, CLI, and config paths.

## Emoji shortcodes

In Chat and New Session, type a colon followed by an emoji name, such as
`:smi`, to see a compact list above the shortcode. The list sizes to its matches
and stays inside the viewport. Use the up and down arrows
to choose a match, then press Enter or Tab to insert it. You can also click a
match. Escape dismisses the suggestions without changing your draft. Selecting
an emoji does not send the message.

Typing a recognized complete shortcode, such as `:smile:`, inserts its Unicode
emoji directly into your draft. Code spans and code blocks, URLs, escaped
shortcodes, and unknown names stay literal. Existing messages are not rewritten.
You can still paste emoji or use your operating system’s emoji keyboard; there
is no separate emoji picker in the composer.

## JSON in chat

Completed JSON objects and arrays in assistant messages and code fences share a
**Tree** view with expandable nested values and a **Raw** view of the original
source. **Copy** copies the source in either view, preserving duplicate keys,
large numbers, and escape sequences. Raw keeps the usual long-code preview,
reveal control, and word wrapping.

Unfinished streaming fences, invalid JSON, and JSON beyond the tree rendering
budget stay readable as source. User-message fences and passive previews remain
plain code without interactive controls.

## Chat behavior

The model picker displays your selected preference, even while a reply is sending,
preparing, or streaming. You can change the model and reasoning effort without
interrupting that reply. Successfully saved choices apply to ordinary queued
messages that have not started; explicit per-message overrides keep their existing
precedence. The current turn keeps its execution settings, and its recorded model
(including any fallback) does not replace the picker label.

During a model change, model and effort controls wait for the new model’s supported
settings. Fast mode and context-window changes remain unavailable during an active
reply. Read-only, disconnected, and unavailable-backend protections still apply.
Sending does not reload the cached model catalog; catalog loading and refresh
feedback stays in the picker.

New Session shows the agent's known default model while the model catalog loads.
Model choices are cached in memory for the current connection, agent, session,
and account, so reopening a picker or returning to a draft can show them
immediately. Catalog and account changes invalidate these copies; reconnecting
loads current choices again. Reopening a picker after a reported cooldown expires
checks readiness again. A catalog refresh keeps existing controls visible,
and the Gateway still validates the model and account when starting a run.
Repeated changes while a model lookup is pending are collected into one
follow-up lookup for the latest choices.

Loading chat history does not disable the model picker. In **Settings > Models**,
the primary-model picker opens as soon as model rows are known; selecting a new
default still waits for configuration readiness and mutation access.

Catalog refreshes update the open conversation's model and context facts without
reloading unrelated session lists. The shared session store applies lifecycle row snapshots to existing active
members locally. Membership or configuration changes and events without a row
snapshot refresh the affected lists through its paced event scheduler.

Chat refreshes its available commands after skill selections or session settings
change. Repeated changes share one pending refresh per conversation and connection;
if a read is already running, one follow-up read picks up the latest changes.
Older results cannot replace the current command list.

If a New Session model lookup does not finish within 30 seconds, the controls
show **Models unavailable**. Open the model picker to retry; your draft stays
in place. A retry waits for the earlier lookup to finish before starting more
work, and its 30-second deadline includes that wait. Reconnecting clears pending
lookups from the previous connection.

When you open an existing session, the conversation appears before supporting
panels and pull-request details load. You can start typing as soon as its identity
is resolved, while the transcript still shows its loading skeleton. The same
composer keeps your draft and focus when the conversation appears. You can send
ordinary messages and attachments while history loads: the message enters the
outbox immediately, leaving the composer ready for your next draft. The open
chat confirms its current session and conversation branch before delivery
continues automatically. Switching chats keeps queued messages tied to their
original conversation. If history fails to load, the queued message stays
available while you resolve the history error. Goals and other slash commands
wait for history; `/stop` and `/approve` remain available. The initial task progress
read reserves only its card slot; the transcript and composer stay available.

When you open a short chat link, identity prepared during the current connection
can make the composer ready sooner. The original link stays in place until the
session lookup confirms the same conversation and its current title.

Other conversations warm only when you hover or focus their navigation entry,
after the visible transcript is ready. Simply connecting does not fetch unopened
conversations.

Background refreshes for saved sidebar filters, groups, automation status, and the
Inbox wait until the conversation appears. Task suggestions and the progress
card then refresh after the transcript paints. Changing a filter or opening a
group-targeted New Session remains immediate.

Panes share outbox recovery for the same conversation. Activity in another
conversation does not restart that recovery; reconnecting checks every saved outbox.

Files remain in the composer while a submitted message waits for attachment
storage. If you begin another draft during that wait, saving the first message
removes its unchanged files unless another pending submission still owns them.
Your newer text and added or replaced files stay in the composer. A storage
failure keeps those files available for retry.

On wide desktop panes, a compact rail of horizontal marks sits in the transcript's left gutter only when the conversation exceeds the visible height. It gently fades in as the conversation grows and hides again if the whole conversation fits after a resize; reduced motion disables the fade. Hover for a short message preview, or click a mark to jump to that message. Tab focuses the rail; arrow keys move between marks, Enter or Space jumps, Home and End select the endpoints, and Escape dismisses the preview. At rest, all marks are identical 8 × 2px strokes at 12px spacing. They stay faint; marks for messages currently visible in the transcript light up together as you scroll. Hovering a mark grows it to 32px and lights only that mark in text color, with progressively shorter strokes across three neighbors on either side. The wave and highlighted mark stay in place while the pointer moves onto the preview card. Leaving the rail and card, or pressing Escape, clears the wave. The other marks keep their resting colors. Outside that hover range, widths stay fixed. An empty message preview shows “Preview unavailable.” Each visible user message has a mark, and assistant messages from the same run share one mark. Tool calls, results, and progress alone do not create marks. An assistant mark jumps to the first currently displayed response in its run and previews the latest displayed response. Its identity stays stable as streaming output becomes persisted history, and its current-position highlight follows later response content in the same run. The rail covers loaded history; messages without run identity retain their transcript grouping. Long rails scroll internally within 45% of the viewport height, with fades only at ends that hide more messages. Scrolling the transcript keeps the current mark visible; you can also scroll the rail to explore other messages. The rail stays hidden on mobile, in narrow or short panes, and when your saved message width leaves too little gutter space. A jump briefly tints the target message with a soft background, fading over 1.2 seconds without a border or ring. Reduced motion disables mark transitions and shows the target tint statically for one second.

Session dashboards follow the selected conversation's agent, including when multiple agents each use a `global` session. Split panes keep their owners separate; panes showing the same agent and conversation share dashboard updates.

Automatic session titles describe the topic or intended task in your first message.
The naming model is asked for a plain-text label of that message, not of injected
harness or project instructions, and not a copy of the input's JSON wrapper.
They are generated separately from the agent's work, so a title is not a completion
status or a report of tool access. Existing titles and manual names are left
unchanged; click a title to rename it.

Worktree creation waits up to 30 seconds for a title, then proceeds while naming
finishes in the background. A late title still updates the session without
renaming its existing Git branch. Concurrent naming requests share the same work;
if that request fails, a waiting dashboard request retries once. Naming starts
when the first reply begins; if it fails while that reply is still running, as on
a model server that handles one request at a time, it retries once after the turn
ends. If both model routes fail, the session uses a two-word crustacean-themed name.
The Gateway logs a warning when chat naming uses this fallback.

Collapsed tool rows keep the tool label visible and truncate long summaries with an ellipsis. Completed answers stay visible outside collapsed work, including when a later Gateway notice arrives. The completed response footer keeps the final answer's timestamp when earlier tool activity is restored after a reload. Expand a tool row to inspect its command, path, or query. Inspect subagent status from the parent conversation with `/subagents list` and `/subagents info <id|#>`, or read recent child messages with `/subagents log <id|#>`. See [Sub-agent slash command](https://funcoding.ai/agents/openclaw/tools/subagents/slash-command/).

While the agent works, its latest tool-activity disclosure shows the current
operation's purpose instead of operation counts. Within that disclosure, each title
gets three seconds to read before a newer title replaces it; rapid calls keep only the newest
pending update. The last purpose stays visible between tools, without a running
ellipsis after that operation ends. The row stays expandable throughout. Failed
or blocked operations and the end of the run bypass the hold, and settled activity
returns to counts, or to a lone workflow's own row as described below. A new
disclosure after inline narration starts with its own
current purpose rather than moving an older operation across the narration.
Reduced motion disables the title transition.

Tool activity summaries count the operations inside a workflow rather than counting its wrapper again. A workflow whose recorded calls are all routine, such as plan or progress updates, is counted itself instead. Once it is no longer the live activity, activity that consists of one such successfully completed workflow shows that workflow's own titled row rather than a count; expand it for the routine calls and **Tool input**. A workflow that failed, was blocked, has no recorded outcome, or went through an approval review keeps the counted row with its status. Execution calls show the agent-provided purpose when available; titles describe intended work, while results determine success or failure. Recorded child calls appear under their operation instead of as separate peer rows. Expand the operation to inspect its children, then expand a child for its command, full output, and reported exit status. **Tool input** retains the wrapper's source and output. Collapsed operations include failures from their children, even when the wrapper or later calls succeed. Error messages and diagnostic paths stay inside the expandable tool details. Nested relationships use recorded call metadata from the same run and survive reloading; calls without an available, unambiguous parent stay separate. Untitled command previews flatten line breaks and truncate long commands; expanded details retain the original source.

Native Codex Code Mode calls show **run JavaScript** when no purpose is available. Expand **Tool input** to read the source. Captured text-block responses display their text directly, and completed command envelopes show readable output with nonzero exit codes kept visible. JSON output is indented without changing number or string values. **Raw details** retains the original response, including execution metadata. For long results, choose **Show full output** to inspect the complete response; copy and download preserve those captured bytes.

Filesystem paths remain readable in tool activity and error messages; credential values are still masked. Compact tool labels shorten macOS, Linux, and Windows home-directory prefixes to `~` while retaining the directory and filename.

A turn that fails before producing any reply leaves a durable notice in the thread. Failed and timed-out turns also show the available failure reason in the sidebar's compact summary and run-error tooltip, including while a session refresh is still catching up.

Chat error banners, including cloud runner failures, show short messages in full. Use **Copy error** beside **Details** in the header to copy the complete diagnostic received by the UI, even while collapsed. **Details** appears only when the complete diagnostic adds information beyond the preview, such as additional lines or text shortened for the preview; repeated lines and whitespace-only differences do not add details. Open it to read and select the complete diagnostic. The disclosure works with Enter or Space; the expanded text wraps long lines and can be scrolled with the keyboard. Copying does not open or close the details, and neither copying nor expanding an error retries the failed operation. Retry and other recovery actions remain separate from the disclosure.

When an active run compacts the conversation while your next message is being prepared, OpenClaw follows the verified continuation automatically, even if the earlier run finishes before preparation does. This keeps the original message and send identity without displaying a retry error.

Run-error banners offer **Refresh** to reload the conversation without resending a message or replacing your draft. If the conversation changes before a message can run and dispatch cannot verify a safe continuation, the banner explains that the message did not run and asks you to refresh before sending it again. The original diagnostic remains under **Details**. OpenClaw does not automatically redirect that message into a replacement conversation.

<details>
<summary>Send and history semantics</summary>

- `chat.send` is **non-blocking**: it acknowledges admission with `{ runId, status: "started" }` and the response streams via `chat` events. An optional `messageSeq` identifies an already committed transcript position; it is omitted when input remains only in accepted custody. Trusted Control UI clients may also receive optional ACK timing metadata for local diagnostics.
- Chat uploads accept images plus non-video files. Images keep the native image path; other files are stored as managed media and shown in history as attachment links. Files appear in their final composer slots as soon as preparation starts, with a per-file progress fill and an in-place error icon if reading fails. Before sending, use **Remove attachment** at the corner of a staged attachment, including one still being prepared; the control supports touch and keyboard input in both Chat and New Session.
- Opening a Markdown attachment (`.md`, `.markdown`, or a Markdown MIME type) in the side panel shows formatted headings, lists, tables, and code blocks. HTML attachments open a sandboxed page with a **Source** switch; other text attachments stay literal. HTML attachment previews accept up to 2 MiB of UTF-8 content; other text previews keep the 256 KiB limit. All retain the original download link; Markdown does not execute embedded HTML or automatically load remote images.
- Same-origin PDF attachments up to 16 MiB open in a native reader that fills the side panel. Background download-link renewal keeps the reader’s page and zoom when the document is unchanged. Unavailable or oversized previews offer the original download instead; external PDFs and Office documents remain download-only.
- Staged attachments scroll horizontally when they no longer fit. Faded edges show where more attachments remain, including after adding files or resizing the composer.
- Re-sending with the same `idempotencyKey` returns `{ status: "in_flight" }` while running, and `{ status: "ok" }` after completion.
- `chat.history` responses are size-bounded for UI safety. When transcript entries are too large, Gateway may truncate long text fields, omit heavy metadata blocks, and replace oversized messages with a placeholder (`[chat.history omitted: message too large]`).
- Long tool output uses 2,000-character text previews in history. Complete structured results keep their existing display limit so source cards and embedded views remain available. Choose **Show full output** to load the captured result on demand; copying or downloading from that view uses the full result. User and assistant text keep their separate display limits.
- When a visible assistant message was truncated in `chat.history`, the Control UI automatically fetches the full display-normalized transcript entry through `chat.message.get` by `sessionKey`, active `agentId` when needed, and transcript `messageId`. The preview remains visible while the entry loads; recovered text replaces it inline.
- Assistant/generated images are persisted as managed media references. New clients resolve their stable artifact ids through authenticated `artifacts.download` and receive short-lived, exact-resource media URLs, so reloads do not depend on raw base64 payloads or reusable credentials in image URLs. The chat uses bounded thumbnails and provides Open, Download, and Copy actions for the full image. These actions share the browser's bounded in-memory image cache, avoiding repeated full-image downloads while the image remains cached.
- When rendering `chat.history`, the Control UI strips display-only inline directive tags from visible assistant text (for example `[[reply_to_*]]` and `[[audio_as_voice]]`), plain-text tool-call XML payloads (including `<tool_call>...</tool_call>`, `<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`, `<function_calls>...</function_calls>`, and truncated tool-call blocks), and leaked ASCII/full-width model control tokens. It omits assistant entries whose whole visible text is only the exact silent token `NO_REPLY` / `no_reply` or the heartbeat acknowledgement token `HEARTBEAT_OK`.
- During an active send and the final history refresh, the chat view keeps local optimistic user/assistant messages visible if `chat.history` briefly returns an older snapshot; the canonical transcript replaces those local messages once the Gateway history catches up. Pending sends in shared sessions remain a single bubble while incremental history catches up, even when another participant's reply arrives first. Saved commentary also replaces its matching live item when incremental history arrives after completion, cancellation, or failure, keeping the progress text in its original place.
- Your pending prompt stays before its own saved assistant reply even when the reply arrives before history recovery finishes after reconnect; existing saved messages keep their transcript order.
- Live `chat` events are delivery state, while `chat.history` is rebuilt from the durable session transcript. After tool-final events the Control UI reloads history and merges only a small optimistic tail; the transcript boundary is documented in [WebChat](https://funcoding.ai/agents/openclaw/web/webchat/). After an in-place `/clear` or `/reset`, fresh turns keep their user-before-reply order across live updates, incremental history catch-up, and reload.
- `chat.inject` appends an assistant note to the session transcript and broadcasts a `chat` event for UI-only updates (no agent run, no channel delivery).
- Root sessions and ordinary Home-linked dashboard sessions can be pinned. Spawned and nested-child sessions retain their sidebar nesting and reject pin requests. Subagent runs also reject pin requests and do not appear in sidebar navigation.
- The sidebar lists every loaded active session by agent section and pinned/channel/work/custom/Chats buckets with a single New Session action that opens the draft dialog. Opening a visible row moves only the highlight. Sessions can be dropped onto Pinned to pin them, or onto a custom group or Chats to move them; custom groups are collapsible and drag-reorderable, group names and order sync through the gateway, and collapsed state stays in the browser. A new dashboard session asynchronously gets a concise generated title from its first non-command message; explicit names and authenticated sender identity remain separate, so account names are never used as generated titles. When New Session creates a worktree without an explicit worktree name, OpenClaw also uses the session label or generated title for its branch name, falling back to a readable crustacean-themed name. Set `agents.defaults.utilityModel` (or `agents.entries.*.utilityModel`) to route this separate model call to a lower-cost model; if that distinct model fails, title generation retries once with the primary model. Expanding another agent section browses that agent's sessions without leaving the open chat.
- Search the active transcript with **⌘F** on Mac or **Ctrl+F** on Windows/Linux; Mac **Ctrl+F** remains available for native text navigation. Search includes recovered full-message text and updates when an in-flight recovery finishes. Press **Escape** while search is focused to close it, clear the query, and return focus to the control that opened it. Clearing the search keeps recovered text available in the thread.
- Thread search in the command palette (⌘K on Mac, Ctrl+K on Windows/Linux, or the search button in the top-left control cluster) searches the authorized active-session scope across configured agents on the Gateway, filters internal child/cron/system rows before result limits, and lists the best visible matches next to navigation commands. The result limit does not restrict which sessions can match. Only actual indexing, unavailable transcript history, or search failures show status messages; more matches than the displayed limit is normal. On the **Sessions** page at `/sessions`, the quick filter searches visible session metadata on the Gateway before pagination, including names, agent identity, model/runtime labels, run status, and goal text and usage. The selected agent (or **All agents**) and **Active / Archived / All** filters still apply. **Limit** sets the server page size (50 by default); **Load more sessions** appends the next matching page. Table sorting, grouping, overview counts, and **Rows per page** operate on the loaded rows, not a globally sorted result. **Search transcripts** searches message content across the complete selected session scope on the Gateway, separately from the quick filter and roster page size. Available session titles stay with transcript matches even when their sessions are outside the filtered table. Opening a session link preserves its full UUID identity when session identifiers share a prefix, including after reloading links from Sessions and Worktrees.
- Each sidebar row keeps direct pin access plus a full context menu for unread state, rename, fork, grouping, archive, and delete. Cmd/Ctrl-click opens the session in a new browser tab. Multi-selected rows (Alt/Option-click, Shift-click for ranges) get a batch menu covering unread state, grouping, archive, and delete; batch Archive reports per-session failures while archiving eligible rows, whereas batch Delete keeps its separate idle-or-already-archived eligibility. Archive stays disabled for agent main sessions (including `global` in global scope) and the `unknown` sentinel. For any other session, including one with active work, the Gateway stops and fully drains that session's work before archiving it. The selected archived session stays open with an archived notice and **Unarchive** action; deleting the selected session switches Chat back to that agent's main session. If you switch agents while a rename, archive, delete, or batch update is finishing, its completion preserves the newly selected agent's session list, pagination, and ongoing updates, including in Archived and All views.
- Channel-linked sessions show their messaging service in the sidebar. Hover or keyboard-focus a session to see its linked conversation, chat type, and available contact or account details. Direct chats can show a phone number, email address, or Matrix handle; channel conversations retain their recorded names, and threads or Telegram topics are identified separately. The **In this session** people chip describes session contributors, not current external group membership. Main and dashboard sessions do not become channel-linked just because they last delivered a reply through a messaging service.
- In the macOS app, the OpenClaw mark uses the otherwise-empty native titlebar strip next to the window controls instead of consuming a sidebar row.
- On desktop widths, chat controls stay on one compact row and collapse while scrolling down the transcript; scrolling up, returning to the top, or reaching the bottom restores the controls.
- The session header shows a small facepile beside the workspace chip when other people are viewing the same session; it lists up to four viewer avatars with an overflow count and disappears when you are alone. On multi-user gateways the header also carries the permanent session owner chip and a facepile of up to four participants who have prompted the session (owner excluded); sidebar rows compress the same information into a pair-stack — owner in front, one peeking participant or a +N count behind (see [Multi-user mode](https://funcoding.ai/agents/openclaw/concepts/multi-user/#reading-the-avatars)).
- Consecutive duplicate text-only messages render as one bubble with a count badge. Messages that carry images, attachments, tool output, or canvas previews are left uncollapsed.
- User-message bubbles carry transcript actions: a hover rewind button (confirm popover with a "Don't ask again" option) plus right-click **Rewind to here** and **Fork from here**. Rewind repoints the session to the state just before that message and returns its text to the composer for edit and resend (`sessions.rewind`, `operator.admin`). Files still loading for a draft that rewind replaces are discarded, so they cannot attach to the restored prompt. If you edit the composer or select another file while rewind is pending, your newer draft and attachments stay in place, even if that file is still loading. Fork creates a new session from the active-path prefix before the message, opens it, and seeds its composer with the same text (`sessions.fork`, `operator.write`). Both actions disable with an explanatory tooltip while the agent is working, apply only to persisted user messages, and are rejected for sessions whose conversation is owned by an external agent harness. Rewind moves chat context only — files and other tool side effects are not reverted — and the pre-rewind transcript remains preserved in the append-only session store. When that store contains multiple transcript branches, the chat title bar shows a branch menu with each branch's latest message, message count, and recency; selecting an inactive branch switches the current session back to that preserved path (`sessions.branches.list`, `operator.read`; `sessions.branches.switch`, `operator.admin`). Generated images and files on preserved branches are kept with their messages, so they load again after you switch back. The branch menu refreshes as messages are saved, including replies after a rewind, without a page reload. Branch switching is also unavailable while the agent is working, and selecting the already-active branch is a typed no-op error at the RPC boundary. Open chats follow rewinds and branch switches from other tabs without losing their unsent drafts.
- For GitHub sessions, **Details → Session details → Pull requests** lists pull requests associated with the session's working branch instead of placing separate bars above the composer. Mentioning or linking a PR in conversation does not create a banner. Branch-based PR chips stop appearing when the checkout becomes detached or returns to the default branch; the publication flow separately retains its applicable recorded result. Each chip shows PR number, repo, branch, diff counts, a CI pill, and draft/merged/closed state, each linking to the PR. The section lists every returned PR, with live (open/draft) PRs first. The CI pill opens a CI monitoring popover with passed/failed/running/skipped totals and named checks, with failed and running work first. Expand a GitHub Actions job to inspect its ordered steps, statuses, and durations; skipped checks stay in a collapsed group. Details load when the popover opens rather than on every background summary refresh. Job links open GitHub for full logs. Checks from other CI services remain visible without invented step details. Press Escape to close the active pane's CI popover. The Gateway polls only sessions visible in a connected Control UI and pushes changed snapshots through `controlUi.sessionPullRequests.changed`; it uses the explicit Control UI GitHub credential or the shared process-environment fallback for this read-only preview. When the GitHub API rate limit is hit, chips keep the last known status and show a warning that the status may be out of date; dismissing a chip hides it for that session in the current browser profile. Before any PR exists, the row shows the branch itself — repo, branch name, and the +/− size of the diff against the default-branch merge base (committed and uncommitted work). The account arrow beside **Publish PR** appears only when both shared and personal accounts are available, with a compact account menu and a checkmark on the selected account. A sole shared account needs only **Publish PR**; a sole personal account uses **Publish as @account** to explicitly select and publish in one click. If both routes use the same account name, the menu distinguishes their sources. The arrow disappears once publication is locked or has a result. Connection setup stays in Settings; inline guidance appears only for a missing account or a blocked personal publication. Pending status, retry actions, confirmation details, errors, and results stay inline. Account discovery and status reads show **Loading**, not **Publishing**; the controller records read, publish, and confirmation activity separately. Publication only begins after an explicit request. Shared publication status reads the existing receipt instead of replaying Publish. Reconnect restores the latest applicable shared receipt, and a lost acknowledgement can be looked up by its original invocation key. Committed receipt changes refresh that scoped view through session events, without another polling loop. If GitHub cannot refresh a cached PR snapshot, the row marks that state unavailable instead of presenting it as current. Automatic PR refresh hints wait for five seconds of quiet per session; explicit refresh requests are sent immediately. The Gateway coalesces forced refreshes for each watched session within a ten-second window, with one trailing refresh, while switching sessions or hiding the tab updates the watched set immediately. Local Git facts are shared by checkout across sessions and clients; refresh revalidates the relevant refs and staged index instead of discarding unchanged facts. Unstaged-only diff counts update on the five-minute fallback. Recovery keeps an unfinished Git transaction pending without blocking settlement of publication receipts for independent workspaces. The Gateway-owned broker derives the repository and branch from session ownership, verifies the selected connection rather than using the preview credential, and returns the draft pull request URL or an actionable typed failure. Personal publication requires an idle, reconciled workspace and current write access to the session. Repository-only sessions publish an accepted Git-normalized checkpoint while their worker is idle or after Stop, without creating a Gateway checkout. Remote sessions sourced from a Gateway worktree still require **Stop cloud worker…** first. It never follows another participant's later turn or falls back to another account; unfinished personal publication needs same-owner confirmation after a Gateway restart. See [Publish with your account](https://funcoding.ai/agents/openclaw/concepts/user-model/#publish-with-your-account). The row hides itself while an open or draft PR exists for that branch; for Gateway-source checkouts, once the branch's PR is merged and the pushed tip still matches the merged head, the row disappears too. The branch row comes from local Git or the repository session's recorded URL and branch, so it stays available while GitHub is rate limited and carries the same stale-status warning, since "no PR found" cannot be trusted until the limit resets.
- The CI popup also provides **Auto-fix CI & address comments**, **Auto-merge when ready**, and **Auto-archive on merge or close**. Each opt-in creates a separate, durable agent automation for the PR whose popup you opened, checked every five minutes while the Gateway runs. Additional PRs in the session are not included and do not block that PR’s auto-merge. These checks use the session agent and consume model usage; they continue when the browser is closed and survive Gateway restarts. Repair and merge runs use the named session and normal repository workflow, verifying the selected PR’s checkout without disturbing unrelated work. A conversation reset does not change their PR target. Merge readiness includes required reviews and checks—not just the green CI total—and never grants an approval or bypass. Archive runs independently, verifies the PR is merged or closed, uses the archive API’s exact-session-ID guard, and defers if the session has other active work or PRs; normal archive behavior can clean up its managed worktree. Changing a toggle requires automation administration permission. Turning one off requests cancellation of its current run and prevents future runs, but does not undo effects already accepted by GitHub. Toggles update immediately while saving in the background, without adding status rows or reloading the panel. Other toggles remain usable while one saves. The popup reports only errors and blockers, including scheduler pauses and run failures. After an uncertain save, use **Try again** to refresh the saved state before making another change.
- The session diff panel shows what a session's checkout actually changed: the branch button in the workspace rail or chat title bar opens a dense per-file viewer with normalized added/deleted/modified counts, collapsible files, wrapping and unified/split layouts with source syntax highlighting, file copy/open/editor actions, and "N unmodified lines" markers between hunks. The footer switches between all changes, uncommitted work, and individual commits while showing how far the branch is ahead of its merge base; committed branches also provide a copyable local sync command. Diffs are computed server-side through the `sessions.diff` Gateway method (`operator.read` scope); binary and oversized files degrade to stats-only entries, and the button only appears when the connected Gateway advertises `sessions.diff`. Incomplete results show a warning even when no files could be displayed; only a complete empty result reports no changes. Review follows the session checkout once a new worktree is prepared and shows no changes before then. It keeps the current diff visible while refreshing.
- Every Chat pane has a title bar. Click the session title to rename it; the workspace chip copies the checkout path or branch and can reveal local Gateway workspaces in the host file manager. Remote and exec-node sessions keep copy actions but hide reveal.
- The **Files** tab in each Chat pane's unified side panel lists thread files, project files, and artifacts. Search at the top covers session files, artifacts, and the project tree; surrounding whitespace is ignored while spaces inside the query remain literal; filter chips show changed files, read files, or artifacts, and collapsible groups share one scroll region. **Show in Files** from Review clears search and filters so the destination project directory is visible. For an active repository-only session it reads the node checkout. After Stop it exposes retained changed-file previews; unchanged upstream files, editing, and full diffs require the worker to run again. The stopped diff panel explains this limitation. Reopen it with ⇧⌘B, **Panels → Show session files** in the chat header's **…** menu, or the panel's **+** menu. The Files action in **Panels** shows a changed-file count badge when files have changed.
- File paths recognized in chat messages read as their basename with a small glyph for the file type in front — a Markdown page, a `package.json` manifest, a TypeScript source, a `.tsx` component, a config or data file, a shell script, and an image each get their own mark, and anything else falls back to a plain document. When two links in the same message share a basename, each keeps just enough of its trailing path to stay distinct. The full path stays on the link: it is what the tooltip shows, what opens in the file panel, and what the message's **Copy** action returns, since copy hands back the original Markdown. Hover or keyboard-focus a file link to copy its path with the tooltip's copy button. Clicking or tapping the filename still opens the file panel directly; touch does not require opening the tooltip first. Labels you write yourself in a `[label](path)` link are never rewritten. The glyph is drawn from the bundled icon set, never fetched from the network, and is decorative only: it is not read by screen readers and is not part of copied text. Text that is not a recognizable path — anything carrying spaces, parentheses, a `#` fragment, or a `?` query — stays plain prose.
- Clicking a file reference in chat, a file path in an expanded read/edit/write tool card, or a file row in **Files** opens its own filename tab in the shared side-panel header. Reopening the same file from the same owning session selects its existing tab and rereads its content when there is no unsaved draft. Selecting a filename tab keeps its current preview; unsaved drafts are never replaced by a file reopen. The folder action returns to the file browser without closing previews. The last opened file stays highlighted in both session and project lists, including after refreshing the file list. A pending listing cannot clear a newer file selection or replace results and errors for a different folder or search. If the folder being browsed becomes unavailable, **Files** keeps its parent-folder action so you can continue browsing without reloading or changing sessions. Session file labels show the filename and enough parent folders to distinguish matching names; hovering or copying a path keeps the full path. Closing a filename tab closes only its preview, never the underlying file. Closing or replacing a file preview cancels a delayed copy fallback; an already issued native clipboard write may still finish. Open previews are scoped to the current pane, session, agent, and connection, and are not persisted across reconnects. A forwarded file retains its sending session as its read and edit target; identical paths from different sessions have separate tabs and drafts. HTML files open a sandboxed **Preview**, with **Source** in the same filename tab. Other UTF-8 text files use a CodeMirror-based code view with syntax highlighting, line numbers, jump-to-line, in-file search, copy actions, and an open-in-external-editor menu. The code view has a **Word wrap** toolbar toggle, including in HTML **Source** view. Wrapping starts off; the browser remembers your choice across files and reloads without changing file contents. Search follows the displayed line numbers for LF, CRLF, and CR line endings; editing preserves the original line endings, including when pasted text uses different line endings. Read-only previews, including files with mixed line endings, do not create unsaved drafts or block interface reloads. Escape closes in-file search and returns keyboard focus to **Search in file** in the toolbar. AVIF, GIF, JPEG, PNG, and WebP images no larger than 256 KiB render inline; other binary files show metadata without lossy text decoding. When the Gateway advertises `sessions.files.set` to an `operator.admin` connection, the text panel adds an Edit mode with dirty tracking and Cmd/Ctrl-S save; unsaved drafts survive file, panel, and session navigation in the current browser tab until explicitly saved or discarded. If a server update blocks editing and reloading, choose **Review file drafts** in the reload notification to copy or download the retained edits, then explicitly discard each resolved draft and try **Refresh** again. **Keep drafts** leaves them protected in this tab; recovery never writes files on the disconnected or updated Gateway. Saves are compare-and-swap on a content hash returned by `sessions.files.get`: if the file changed on disk since it was loaded (for example because the agent kept working), the panel shows a conflict notice with Reload (take the latest content) and Overwrite (keep the local edit) actions. Writes retain fs-safe workspace guards — path containment, symlink/hardlink rejection, and a 256 KiB UTF-8 cap — and only overwrite existing files; the editor never creates or deletes them. If the editor cannot load, use **Retry** or **View Raw Text**. A missing editor chunk after an update offers **Reload**, which waits for the Gateway to become reachable.
- Open the side panel and select **Subagents** from its **+** menu to follow child sessions, including swarm workers, or select the subagent count or a subagent's name in the transcript. A pane too narrow to show the side panel beside the conversation shows **Subagents** in place of the conversation instead of under it, however the panel was opened; closing the panel returns to the conversation, and a wider pane shows the two side by side again. Keyboard focus moves to the panel's tab when it takes the conversation's place, and returns to the control that had it once the panel is closed, or to the first control in the pane's header when that control is gone. **Running** and **Finished** keep the list compact: titles and Stop controls sit above available call counts and public activity text, with elapsed time on the right. Activity falls back to the tool’s display name when no public description is available; a count is omitted when the bounded history cannot establish an exact total. All child pages load automatically so older running workers remain visible. The parent’s parallel-tasks view also shows aggregate swarm progress. Selecting a child opens its existing view-only transcript in the panel. **Back to Subagents**, the task title, and the existing **Stop** action appear above the transcript; there is no elapsed-time row, composer, or parent notice in that embedded view. Opening the child directly keeps a compact **View-only subagent** notice naming its parent and an **Open parent session** button. Subagents remain outside left-sidebar navigation. Saved-draft recovery stays in the parent or another ordinary conversation; neither the embedded nor direct subagent view shows its Restore or Delete actions. Message input, reply actions, model and access pickers, microphone, and attachment controls remain unavailable; copy and fork keep their existing behavior. Persistent sessions created with `visible: true` remain ordinary conversations that you can type in and steer.
- **Processes** is a separate side-panel tab for the conversation's background exec commands. Open it through **Panels → Processes** or the side-panel **+** menu. A narrow pane shows it in place of the conversation, as it does **Subagents**. Its **Running** and **Finished** lists show derived command names, status, elapsed time, and available exit codes. Select a row to inspect the retained output tail without consuming the agent's pending output. **Stop** requests termination of that exact process; **Stopping…** remains until the process owner reports completion. Finished records expire under the normal process retention limits. An unavailable worker or failed read is shown as an error, not an empty process list. The panel refreshes only while visible and preserves the parent draft.
- **Review** and file tabs retain their own content. A pending file or artifact updates only its own open tab: it cannot select itself over a newer tab, reopen a closed preview, or return after you leave the chat page. Switching tabs or hiding the whole side panel preserves the pending preview without changing your chosen layout when it finishes. Text attachments retain their Preview or View Raw Text mode while switching between open files. Background download-link refreshes keep an unchanged attachment's reader in place, including keyboard focus and code-block controls.
- Each chat pane has a main view and a unified side panel. The pane toolbar's **Swap** button exchanges the main view and active side-panel tab; its tooltip names both views, for example **Swap Chat and Dashboard**. Chat, Dashboard, Browser, Terminal, Files, and Review can all be main. Other side-panel tabs remain available. **Focus** in the main pane header gives that view the full pane area; **Restore split** brings the side panel back. Swapping or focusing preserves live content and drafts. Closing the whole side panel hides it without changing the main view, and the browser remembers each session's arrangement.
- The pane toolbar's **Layout** menu positions the side panel left, right, or below the main area. It adapts to each pane's own width rather than the window, falls back to a bottom strip in a narrow pane or compact window, and hides its dock controls until the pane widens. **Subagents** and **Processes** are the exception: a narrow pane shows them in place of the main view. Phone-sized viewports still open review content full-screen.
- In **Processes**, **Finished** starts collapsed; click its heading to expand or collapse the list.
- A new Browser side panel uses the chat pane's available width and the rendered chat column to reclaim unused chat margins. This default applies on web, macOS, and Tauri; saved widths and manual divider adjustments take precedence.
- The chat header model and thinking pickers patch the active session immediately through `sessions.patch`; they are persistent session overrides, not one-turn-only send options. A confirmed model selection stays visible if the following session refresh fails; later Gateway updates can still change it. For catalog-backed OpenAI models, the effort picker offers **Off** only when the model advertises disabled reasoning. Inheriting the model's default effort does not turn reasoning off.
- Diff syntax highlighting uses each file's language and the current theme; unknown file types and oversized previews remain plain text. Inline and session diffs do not require the optional [Diffs plugin](https://funcoding.ai/agents/openclaw/tools/diffs/), which creates standalone viewer links and PNG/PDF attachments.
- **Split view:** open it from the chat title bar (beside the thread diff and thread files toggles), then split the active pane right or down for as many panes as fit. Each pane has its own session title, thread, transcript, composer, and tool stream. Titles stay with their conversations when you focus a pane belonging to another agent.
- Agents with the `screen` tool can request pane, sidebar, terminal, browser, desktop, portal, focus, and navigation changes in the capable Control UI browser that requested the turn. Other connected browsers keep their own layout; see [Screen](https://funcoding.ai/agents/openclaw/tools/screen/).
- Drag a session from the sidebar into chat to open it in a pane. An animated drop preview glides between zones and labels the outcome — "Split" over the exact half a new pane will occupy, "Open here" over a whole pane — and drops also work from single-pane mode.
- The active split pane drives the sidebar selection and URL. Selecting another pane or closing the active pane uses the surviving conversation's Chat or Dashboard preference; it does not copy the previous pane's view. Closing a pane that holds keyboard focus returns focus to the surviving pane's header, which is labeled with the session title for assistive technology. Its title bar adds split and close controls; dividers resize columns and stacked panes, and the browser stores the layout locally across reloads.
- On narrow screens, split view keeps the layout but renders only the active pane at the full available width and height, including its header with the close control. Widening the window restores the saved column and row proportions without losing drafts.
- If you send a message while a model picker change for the same session is still saving, the composer waits for that session patch before calling `chat.send` so the send uses the selected model.
- On the New Session page, submitting opens the created conversation automatically. **Cmd+Enter** on macOS or **Ctrl+Enter** elsewhere is ordinary submit with either send preference. Use **Cmd/Ctrl+Shift+Enter** to explicitly start in the background without leaving the page; a completion notice offers to open that session. The selected local, cloud-profile, or paired-device placement is preserved. Explicit Draft visibility keeps its create-only behavior.
- Typing `/new` creates and switches to the same fresh dashboard session as New Chat, except when `session.dmScope: "main"` is configured and the current parent is the agent's main session; then it resets the main session in place. Typing `/reset` keeps the Gateway's explicit in-place reset for the current session.
- The chat model picker requests the Gateway's configured model view. If `agents.defaults.modelPolicy.allow` is non-empty, that policy drives the picker, including `provider/*` entries that keep provider-scoped catalogs dynamic. Otherwise the picker shows configured entries plus providers with usable auth; aliases and settings under `agents.defaults.models` do not restrict it. The full catalog stays available through the debug `models.list` RPC with `view: "all"`.
- Expand the **Account** category in the model menu to choose a saved account for the selected provider in Chat or **New Session**, even when **Automatic** has no eligible models. A New Session choice previews eligible models and is attached when the session is created; it does not change the personal new-chat default or saved model preference. See [Per-person model accounts](https://funcoding.ai/agents/openclaw/concepts/multi-user/#per-person-model-accounts).
- Chat and New Session block sending when the Gateway reports missing provider credentials or a confirmed authentication failure. Missing credentials point to **Models → Connect provider**; authentication failures ask you to review the credential or sign-in. An explicit account choice in New Session also waits for a successful preview confirming that account and an eligible model; pending or failed previews show why Start is blocked. Otherwise, temporary credential cooldowns and unknown model availability do not block sending or show an authentication banner; run errors remain visible in the transcript. Unavailable model choices stay disabled in the picker.
- After a config change or a published credential update, connected Chat and New Session views re-read model readiness automatically; no page reload or picker action is needed. Chat also re-reads its session projection after a model or auth-profile selection changes. An existing missing-credential or authentication-failure block stays in place while that read is pending or fails, until replacement metadata changes it. Existing chats keep their session's selected auth profile; New Session readiness reflects its draft account choice when one is set. This refresh is event-driven, not a timed polling guarantee.
- The chat composer usage ring follows the selected session and agent, including global sessions. Open it for the current context window, latest-run token counts, and the current provider's account, plan, and quota when reported. Subscription quota replaces dollar estimates; other sessions can show estimated total cost and the latest provider response's input/output/cache cost breakdown. Fresh usage switches to warning styling at high context pressure; stale token snapshots remain visible as approximate usage without that warning. During an agent switch, the previous agent's session row is not reused for the ring.

</details>

<details>
<summary>Talk mode (browser realtime)</summary>

Talk mode uses a registered realtime voice provider. Configure OpenAI with `talk.realtime.provider: "openai"`. GA `gpt-realtime-*` browser WebRTC uses Platform auth in this order: `talk.realtime.providers.openai.apiKey`, an `openai` API-key profile, then `OPENAI_API_KEY`. The released GPT-Live browser and Gateway-relay WebRTC route tries a ChatGPT OAuth subscription profile first and falls back to Platform API-key access. Unlisted or private GPT-Live browser sessions and the direct Gateway-relay transport require Platform API-key access. Both keep the authenticated GPT-Live control path on the Gateway. GPT-Live has its own voice choices, shown by the model-aware Talk picker; GA Realtime voices do not apply. See [Talk mode](https://funcoding.ai/agents/openclaw/nodes/talk/) for setup and transport details. Configure Google with `talk.realtime.provider: "google"` plus `talk.realtime.providers.google.apiKey`. The browser never receives a standard provider API key or a ChatGPT OAuth token: Platform GA OpenAI receives an ephemeral Realtime client secret, native GPT-Live WebRTC receives a one-use Gateway reservation, and Google Live receives a one-use constrained Live API auth token for a browser WebSocket session. Gateway relay keeps provider credentials and vendor sockets server-side while browser audio moves through authenticated Gateway RPCs. Platform GA sessions use the Gateway's direct-tool prompt, while GPT-Live uses provider delegations. `talk.client.create` does not accept caller-provided instruction overrides.

Persistent provider, model, voice, transport, reasoning effort, exact VAD threshold, silence duration, and prefix padding defaults live in **Settings → Communications → Talk**; changing them requires `operator.admin` access. Configuring Gateway relay forces the backend relay path; configuring WebRTC keeps the session client-owned and fails instead of silently falling back to relay if the provider cannot create a browser session.

The Talk control itself is the microphone button in the composer toolbar. Its caret lists **System default** and every microphone exposed by the browser, including USB, Bluetooth, and virtual inputs. The selected device ID stays browser-local and is never sent to the Gateway; if that exact device disappears or the browser cannot open it, Talk asks you to choose another input instead of silently recording from a different microphone.

If Talk is unavailable or its provider is still being checked, clicking the microphone opens its picker with **Configure** actions, even while chat history is loading. Starting a Talk session still waits for history to load.

For a selected-microphone constraint failure, click **Use System default for this call** to explicitly retry with the system default. This does not change your saved microphone preference. Until you click, no different microphone opens and no provider session is allocated. Dismissing the error, leaving the chat, disconnecting, or starting another call cancels that recovery action. For dictation, choose another input or **System default** from the existing microphone picker, then start again; dictation never switches microphones automatically.

While Talk is live, the microphone button becomes a pill showing the live input-level meter; clicking it stops voice input, and hovering it reveals the stop glyph. Screen readers announce `Connecting voice input...`, `Listening...`, or `Asking OpenClaw...` while a realtime tool call is consulting the configured larger model through `talk.client.toolCall`. Stopping a running agent response stays a separate square **Stop** control next to the pill.

**Video Talk** is available for OpenAI Platform Realtime WebRTC and Google Live browser sessions; GPT-Live is audio-only. Click the camera button, allow camera and microphone access, and confirm the local preview. OpenAI sends one bounded JPEG frame over its browser data channel when `describe_view` requests visual context. Google Live sends bounded JPEG frames directly from the browser to the provider at the supported maximum of one frame per second and answers `describe_view` function calls with the camera-stream state. Camera frames never pass through the Gateway. Stopping Talk closes the preview and releases both media tracks. See Google's [Live API capabilities](https://ai.google.dev/gemini-api/docs/live-api/capabilities#video) and [function-calling guide](https://ai.google.dev/gemini-api/docs/live-api/tools) for the provider wire contracts.

</details>

<details>
<summary>Stop and abort</summary>

- Click **Stop**. Runs with an exact local run ID call `chat.abort`; when selected-session state reports active work but the Control UI has no local run ID, it calls `sessions.abort` instead. For non-global sessions, that selected-session path also discards queued follow-ups so they cannot restart work after the stop.
- Exact-run Stop cancels that parent's associated sub-agents and Swarm collectors, including their descendants. Successful cancellation prevents selected queued children from starting while running siblings stop; it leaves unrelated parent turns and session-wide queues alone.
- If Stop reports incomplete descendant cancellation, inspect the remaining native subagent runs with `/subagents list` and ask the agent to retry their cancellation with `subagents`. Do not treat the parent's stopped state as confirmation that every child stopped or that runtime cleanup was instantaneous. See [Sub-agent stopping](https://funcoding.ai/agents/openclaw/tools/subagents/#stopping) for scope details.
- While a run is active, normal follow-ups use the Gateway's effective `messages.queue` mode. `steer` injects into the running turn; other modes keep the browser's durable queued delivery. If the Gateway queues an input instead of steering it, the message appears above the composer until consumed or canceled. Reconnecting also recovers queued inputs from older history pages without changing the page you are viewing. Once the Gateway accepts input for an existing session, its database owns the approved input until it reaches the transcript. Collected messages are retired together with their combined transcript entry. Unconsumed input survives a Gateway restart as interrupted input requiring an explicit resend. Click **Steer** on a browser-owned queued message to inject it manually; removing a server-owned queued message requests its cancellation. A message you steer moves once from the queue to the bottom of the transcript when delivery starts. It stays there while acknowledgment and history catch up, until its saved copy replaces it. Accepted messages keep their saved transcript positions: earlier saved output stays above the steer and later output appears below it. This order survives history refreshes, reconnects, and reloading a finished run. Unsaved assistant text remains a single live tail after saved rows until its own transcript entries arrive.
- With **Settings → Appearance → Send shortcut** set to **Enter**, **Cmd/Ctrl+Enter** submits the opposite follow-up action while connected to an active run: queue when Enter steers, or steer when Enter queues (including inherited `collect` and `followup` modes). The send button tooltip shows both actions for the current follow-up setting. This affects only that message, not your saved preference. With the **Cmd/Ctrl+Enter** send shortcut selected, modified Enter remains the normal send action and plain Enter inserts a newline. Interrupt mode keeps its normal behavior.
- Reorder the queue from the handle on the left of a queued message: drag it, or focus it and press the up and down arrow keys. The position is stored with the message, so it survives a reload and decides delivery order, not just what the list looks like. Rows already handed to a run — sending, steering, running a command, awaiting settings, or waiting on an uncertain delivery — hold their place and split the queue: a message moves only among the rows between two of them, so it can never reach the Gateway ahead of work already handed over.
- Edit a queued message with the pencil on its row, or by double-clicking the row. The row becomes its own textarea and stays in place while the main composer remains independent, including any separate draft and attachments. Submit replaces the row in the same slot and preserves its attachments and delivery choice, even when the composer currently defaults to Steer or Interrupt; Cancel or Escape discards the row-local draft and restores the queued message. A normal composer send remains a separate queued item even while a row edit is open. The queue behind an edited row waits rather than delivering a message you are still rewriting, so that row splits the queue for reordering the same way an in-flight row does. Queued slash commands keep the discard-and-retype flow.
- **Settings → Appearance → Chat → Follow-ups while the agent is working** can override that server default for the current browser. The page marks an override explicitly and offers **Reset to server default**. `Steer into the active run` sends follow-ups immediately, while `Queue until the run ends` holds them until the run finishes.
- Type `/stop` (or standalone abort phrases like `stop`, `stop action`, `stop run`, `stop openclaw`, `please stop`) to abort out-of-band. Typed `/stop` stops the whole selected session through `sessions.abort`: it aborts the active run and, for non-global sessions, discards queued follow-ups such as background command and subagent completions, so the agent does not start again right after the stop. The **Stop** button keeps its exact-run scope. While offline, typed `/stop` queues the same exact-run stop as the button.
- `chat.abort` supports `{ sessionKey }` (no `runId`) to abort authorized active runs for that session, including runs admitted or queued without a Gateway chat controller before their runner starts (such as OpenAI-compatible HTTP requests), as well as active channel replies, without cascading to children. The Control UI uses the broader `sessions.abort` path when it has no local run ID.

</details>

<details>
<summary>Abort partial retention</summary>

- When a run is aborted, retained partial assistant replies show **Interrupted** beneath the text. The marker remains after reloading when the reply was saved, and also labels replies recorded as timed out or canceled.
- Gateway persists aborted partial assistant text into transcript history when buffered output exists.
- Persisted entries include abort metadata so transcript consumers can tell abort partials from normal completion output.
- If a reply cannot be saved, stopping still succeeds and the chat shows a save warning. Copy any visible text you want to keep before leaving the chat; it may not be available when you reopen the conversation.

</details>

### ClawHub recommendation cards

Ask to find or install a plugin or skill, such as “Find the WhatsApp plugin”, to
let the agent search ClawHub. The agent uses available tools and skills first;
it suggests cards for explicit discovery or installation requests, or when a
needed capability is missing. Routine tasks, tool errors, and permission fixes
do not call for a catalog search. When the `message` tool is available, it can
present up to three matching cards in the conversation.

If you use the `coding` tool profile, include `"message"` in `tools.alsoAllow`
(for example, `tools: { profile: "coding", alsoAllow: ["message"] }`). Existing
deny rules still apply. See [Tool access configuration](https://funcoding.ai/agents/openclaw/gateway/config-tools/).

Select a card to open its listing inside the Control UI: plugins open in
**Plugins**, and skills open in **Skills**. A card's **Install** button opens
the capability details. Select **Install** on a plugin overview to start installation
immediately. Configured install-policy warnings still require an explicit
acknowledgment; see [Manage plugins](https://funcoding.ai/agents/openclaw/web/control-ui/settings/#manage-plugins).
**Dismiss** dismisses the card from the current view.

An installed capability shows a green checkmark and **Installed**. This means the
plugin package or linked skill is present. A plugin may still need to be enabled,
configured, or connected to an account before the agent can use it. The card
checks the current installation status; select **Status unavailable · Retry** if
that check fails.

The agent requests cards through `message` with a capability query:

```json
{
  "action": "send",
  "clawhub": { "query": "whatsapp", "kind": "plugin" }
}
```

`query` is required; `kind` can be `plugin` or `skill`. Omit `kind` to check plugins
first, then skills if no official plugin matches. Omit `channel` and `target` to
reply to the current Control UI conversation. ClawHub supplies the official
designation, and the Gateway checks installation status; the agent cannot assign
those badges. A search with no official match or an unavailable catalog returns
an explanation in chat.

### Source previews and copying code

Long clipboard text appears as a file-sized card in the composer and a compact
chip in the transcript. Its label shows the first 30 characters of a plain-text
excerpt, with HTML and Markdown formatting removed. Empty or unavailable excerpts
show **Pasted text**. In the transcript, chips sit above the text bubble alongside
other attachments; multiple chips share a row and wrap when needed. Click the
composer excerpt or icon, or a transcript chip, to open the existing attachment
side panel and copy the original text, preserving markup, line breaks, and
indentation. The excerpt and chip also support keyboard activation. Select
**Show in text field** on the second row inside the composer card to return its
text to the draft without opening the side panel.
Use the **X** at the card's top-right corner to discard the pasted text without
changing your draft or other attachments. The composer side panel also offers
the same action and removal. Messages
containing only comment or pasted-text chips
use a transparent shell.
Newly uploaded text files remain file cards, even when their names resemble
pasted-text attachments. Older history without origin metadata recognizes
`text/plain` attachments named `pasted-text-<digits>.txt` as pasted text.

Uploaded attachments keep their original filenames on download, including spaces and Unicode characters.
Uploaded images also retain their names in accessible transcript image and image-viewer labels after sending and reloading; descriptive alt text takes precedence when provided.
Select **Open** on an uploaded text attachment to read it directly in the **Files** side
panel. Plain-text attachments, CSV, and JSON preserve line breaks and indentation. Markdown attachments render as documents
with interactive code blocks. When an open attachment refreshes with unchanged
text, its code blocks keep your expansion and wrapping choices after loading.
A different attachment or changed text starts with fresh controls. Long previews
scroll inside their file tab; switching tabs preserves your reading position. HTML files
(`.html`, `.htm`, or `text/html`, including MIME parameters) render as a sandboxed
page by default. **Source** and **Preview** share the same filename tab and slim
toolbar. Same-origin HTML attachment previews accept UTF-8 content up to 2 MiB;
other text attachment previews remain limited to 256 KiB. Unsupported, external,
oversized, or unavailable attachments keep their original **Download** action. Cross-origin HTML attachments are download-only.

Self-contained HTML can use inline CSS and JavaScript under the default
`scripts` sandbox setting. The page runs on the existing separate-origin sandbox
host, not in the Control UI document. It receives no agent-prompt, tools, or
dashboard APIs. The global `strict` setting disables document JavaScript while
retaining the same sandbox resource policy and descendant-frame restrictions; `trusted` does
not give ordinary HTML files access to the Control UI origin. External resources
remain subject to the sandbox's default content security policy.

Session-file HTML previews load relative images, media, stylesheets, and scripts
from the file's folder through the same session read boundary. This also applies
to unsaved HTML drafts. Each asset request accepts at most 64 references, with a
1 MiB limit per asset and a 4 MiB total before base64 encoding. Stylesheets get one
additional asset request for relative CSS `url(...)` resources; inline styles use
the same resource handling. Cloud repository assets retain their existing 256 KiB
preview limit; stopped repositories expose only retained changed artifacts.
Fonts and CSS `@import` are left untouched, so local
fonts are not loaded. Documents with an authored `<base href>` keep all their
original references. Missing, denied, unsupported, or oversized assets remain
unchanged and produce a compact notice in the preview toolbar. Attachment HTML
previews have no session folder and do not load relative assets.
Loaded classic scripts with `defer` run after parsing, in document order with
non-async module scripts, while retaining classic script globals.

Authored in-page HTML links such as `href="#section"` scroll within the preview, including
in `strict` mode. This leaves the original file and **Source** unchanged; authored
base URLs, links targeting another window, and download links keep their behavior.

Workspace file reads and edits retain their existing 256 KiB limit. After a successful save, Files refreshes its metadata and Review refreshes its diff without switching the active panel or clearing the current Files search.
Code previews and editors are named by their filename and reachable with Tab,
including read-only previews. In-file search announces its result count.
For workspace HTML, **Edit**, in-file search, and explicit `file:line` navigation
open **Source**. Switching back to **Preview** renders the latest unsaved editor
text without saving it. Switching views preserves the editor, undo history, and
draft; switching file tabs preserves each file's mode and unchanged page state.
A reopened unsaved draft can be saved directly from **Preview**, including the
same conflict detection and **Reload**/**Overwrite** actions as **Source**.
A preview transport failure shows **Retry** without retrying in a loop, and
**Source** remains available, including when the optional preview cannot load.

**View Raw Text** opens a **Source** view that keeps Markdown notation literal,
including nested code fences. The raw-text action disappears while that view is open.
Decoded text artifacts use the same literal preview. **Copy code** preserves the
code's leading whitespace and final newline when present. Indented Markdown code
blocks also work at the start of a message and remain literal while streaming,
including blank lines within the block.

Code blocks keep your expansion and wrapping choices when their closing fence
arrives and later paragraphs stream into the same assistant reply. Replacing the
message, correcting earlier content, or changing rendering options starts a fresh
view. References that change earlier Markdown can also reset the view.
Completed lists also stay cached as later blocks arrive; loose or nested list
continuations remain together until the list ends.

Browser results for X and Twitter posts use a wider card with the author, handle,
available post text, and preview image. **Open post** and **More actions** stay
visible on touch screens. Text and social images reuse the anonymous page preview;
when metadata is unavailable, the card keeps the post link and handle. It does
not load an X embed script or require an X account.

**Copy URL** in browser tab cards also works on plain HTTP connections where the
browser does not provide its Clipboard API.

If the browser rejects a text clipboard write, starting another text or image
copy cancels its delayed fallback. Code blocks replaced during streaming and
Mermaid diagrams whose source changes also cancel that fallback. This does not
cancel native clipboard writes that the browser has already accepted.

### Markdown tables

Markdown tables wrap headings and cell text to fit the conversation. On wide desktop
panes, top-level assistant tables stay at the reading width when their content fits
and use extra space only as needed, without widening the surrounding prose. Long
cells wrap within the pane limit; genuinely dense tables still scroll horizontally.
Short values such as byte counts stay intact beside long filenames or hashes, including on mobile.
Table controls appear below the table. Wide desktop tables use compact icon-only
controls; mobile and phone-landscape views retain larger touch controls and a visible
**Expand table** label.
Ordinary inline tables grow vertically instead of adding a vertical scrollbar.
**Copy table** copies tab-separated cells, and **Expand table** opens a larger view
with a sticky header. If copying fails, the button clears any earlier success checkmark. In Chat, workspace
file and session links work in either view, including Enter and Space keyboard
activation. Following a link closes the expanded view so you can use its destination.

The **Ask OpenClaw** panel supports table scrolling, copying, expansion, and web
links. Its session links open with a click or Enter. Space does not activate
those links, and workspace-file references do not open a preview.

### Mermaid diagrams

Use a `mermaid` fenced code block in chat. The Control UI renders it as a diagram
automatically:

````markdown
```mermaid
flowchart LR
  Gateway --> Worker
  Worker --> State
```
````

Open the **Diagram options** menu in the top-right corner to switch between the
diagram and source or choose **Expand diagram** for the image viewer with zoom.
The copy button appears on hover or keyboard focus and stays visible on touch
screens. It copies the original Mermaid text.
Diagram colors and fonts follow the current UI theme.

An unfinished streaming fence stays readable as code. Rendering starts when the
closing fence arrives or the response finishes. Invalid or overly complex
diagrams keep their source visible with an error; correct the syntax or simplify
the diagram. Diagram source cannot run scripts or click handlers, load external
images, or add custom CSS to the Control UI.

Renderer loading or timeout errors instead suggest reloading the dashboard and
checking proxy authentication. The renderer runs in an isolated frame, so its
`assets/mermaid.min-*.js` and `assets/frame-*.js` requests do not send `SameSite=Lax`
or `SameSite=Strict` cookies. Behind a cookie-authenticated reverse proxy, those
static asset URLs must be reachable without those cookies, including under any
configured `gateway.controlUi.basePath`. Check the browser Network panel for
blocked requests or redirects to a login page. Keep authentication on the
dashboard and Gateway APIs; any proxy exception should cover only these static
renderer assets. Reload after correcting the asset access rules.

## Hosted embeds

Assistant messages can render hosted web content inline with the `[embed ...]` shortcode. The iframe sandbox policy is controlled by `gateway.controlUi.embedSandbox`:

**strict**

Disables script execution inside hosted embeds.

**scripts (default)**

Allows interactive embeds while keeping origin isolation; usually enough for self-contained browser games/widgets.

**trusted**

Adds `allow-same-origin` on top of `allow-scripts` for same-site documents that intentionally need stronger privileges.

```json5
{
  gateway: {
    controlUi: {
      embedSandbox: "scripts",
    },
  },
}
```

<div class="callout callout-warning">

Use `trusted` only when the embedded document genuinely needs same-origin behavior. For most agent-generated games and interactive canvases, `scripts` is the safer choice.

</div>

Absolute external `http(s)` embed URLs stay blocked by default, except for the dedicated [YouTube video card](https://funcoding.ai/agents/openclaw/web/control-ui/chat/#youtube-videos). To let `[embed url="https://..."]` load other third-party pages, set `gateway.controlUi.allowExternalEmbedUrls: true`.

Widgets created by `show_widget` load through the authenticated Gateway connection in every sandbox mode, including while settings are loading. In `strict` mode, their content remains visible but scripted interactions are disabled.

When a live widget moves into the assistant's final reply, Chrome and Edge 133+
and Firefox 144+ preserve its playback and local interaction state. Browsers
without atomic DOM moves, including Safari, reload the widget during that move.

While a widget loads, a subtle shimmer reserves its space without displaying loading text. With reduced motion enabled, the placeholder stays still.

The core [`show_widget`](https://funcoding.ai/agents/openclaw/tools/show-widget/) tool renders self-contained SVG or HTML directly from a tool call. The browser and supported native chat clients advertise the `inline-widgets` Gateway capability, and the resulting Canvas document remains available when chat history reloads. Channel plugins such as Discord Activities can register contextual presenters behind that same tool. Channel-originated runs without an eligible presenter or inline client do not receive it.

### YouTube videos

An assistant can embed a YouTube video directly in its reply:

```text
[embed url="https://www.youtube.com/watch?v=VIDEO_ID" title="Trailer" /]
```

The Control UI shows a thumbnail and **Play** button. The player loads only after
the user presses **Play**; no HTML widget or media download is needed. An **Open
on YouTube** link remains available when a video cannot play inline.

Supported HTTPS links include `youtube.com/watch?v=...`, `youtu.be/...`, YouTube
`shorts`, `live`, and `embed` URLs, and `youtube-nocookie.com/embed/...`. A start
time in `start`, `t`, or `#t` is preserved; unrelated URL parameters are discarded.

The dedicated card recognizes YouTube video URLs independently of
`gateway.controlUi.allowExternalEmbedUrls`. It does not enable arbitrary nested
iframes in `show_widget`. With `gateway.controlUi.embedSandbox: "strict"`, the card
offers the watch link without loading a player. Other chat surfaces should use a
regular YouTube link; the card is a Control UI feature, separate from native inline
widgets.

Thumbnails load from `i.ytimg.com`, which contacts Google before playback. After
activation, the player loads from `www.youtube-nocookie.com`. Its frame sends only
the Control UI origin as the referrer, never the chat URL or query string; YouTube
requires that origin to permit embedded playback. Direct video attachments and
HTML widget media keep their existing behavior.

## Session Details

Select **Details** at the top-right of the conversation to open the session’s compact information surface.
It opens only on request, not when progress or background activity updates.
**Session details** and **Task progress** have independent disclosure states.
Session context groups workspace information, pull requests, people, subagents,
and attached automations; it reuses their existing actions rather than duplicating
their data. The former pull-request and task-progress bars are not repeated above
the composer.

The expanded progress card’s options include **Don’t show task progress again**.
This turns off the existing browser-local **Show task progress cards** preference
and offers **Undo**. It does not stop work or delete saved progress. Session details
remain available, as do dashboard progress widgets and session hover previews.
Re-enable cards from **Settings → Appearance → Chat**.

## Chat transcript layout

Suggested-task cards show their short summaries in full. Unusually long summaries
scroll within the card, and **Show instructions** expands the complete task prompt.
In short windows, the card body scrolls while the header and Start controls stay visible.

Use the mouse wheel or trackpad over the composer or its surrounding space to
scroll the conversation while the footer stays pinned. Persistent notices and
the composer reserve their own space below the transcript; session context and
task progress are available in **Details**. Long drafts, Details sections, and
menus keep their own scrolling when their content overflows. At the footer’s
edge, the wheel continues into the conversation. On touch devices, swipe the
transcript or footer to scroll that region.

Scrolling down at the end keeps the final reply above the composer as images
or other message content finish resizing. Scrolling upward
keeps your reading position instead.

Task progress cards are enabled by default. Toggle **Show task progress cards** in
**Settings → Appearance → Chat** to hide or show the card in Details in this browser.
Hiding it does not stop agent work or clear saved progress.

Opening Details does not couple the two sections’ disclosure states. Sending
messages, run completion, and progress updates do not automatically open Details
or reopen a card the user collapsed. See
[Task progress cards](https://funcoding.ai/agents/openclaw/tools/progress-card/#where-the-card-appears) for card-lifetime
and preference behavior.

Streaming output and layout adjustments keep reading mode intact. While you are
at or near the end, new messages and replies keep the transcript pinned to the
latest content, including turns started from another browser, device, channel,
or automation. Typing previews preserve this follow state. Scrolling up pauses
following and preserves your reading position as incoming content grows.
Scroll back to the end, select **Latest**, or send a message from this pane to
resume following. Assistant text stays visible as it streams and becomes saved
history, without a reply entry fade or slide. Submitted prompts slide upward once without fading out;
the smooth send scroll starts after the composer and new rows have settled their
layout. Reduced motion disables the prompt slide and smooth scrolling.

Hover an external web link, or focus it with the keyboard, to see its page title,
description, and social image when available. GitHub repository and public
landing-page links use the same card; issue and pull-request links keep their
dedicated previews. The card uses
OpenClaw's theme and includes **Open in your browser**. Press Escape to dismiss it.
Pages without metadata keep the link label and destination. Touch taps open links
normally. GitHub sign-in, account, and profile links do not trigger page previews.
These anonymous previews respect **Automatically Fetch Link Favicons**; see
[the request and privacy details](https://funcoding.ai/agents/openclaw/web/control-ui/security-model/#content-security-policy).

Completed replies can show a compact **Sources** strip when their web links match
recorded `web_search` or `web_fetch` results from the same run. Select a title and
domain card to preview its **Search snippet** or **Page excerpt**, then use
**Open source** to open the recorded page. Previews reuse retrieved content without
fetching pages again. Site icons use the existing **Automatically Fetch Link Favicons**
preference and Gateway icon loader, with a globe when disabled or unavailable.
Session links and GitHub issue or pull-request links keep their dedicated previews
instead of appearing again in the source strip. Citation-only results keep a link
and show **No excerpt available**. Uncited results, failed tools, and results from
other runs are not included. Source cards require run identity in the transcript
and follow tool-activity visibility. They are hidden while a run is active or
transcript search is filtering messages.

In completed dashboard turns, commentary, reasoning-only messages, and tool activity
share one **Worked for…** disclosure above the answers. Expanding it shows the
activity in its original order; explicit answer segments and visual results stay
visible below it. Browser tab previews keep their execution order relative to those
visible results, so a page opened after an inline widget appears after that widget.
Failed tool results after the last answer stay visible outside
the disclosure until a later answer follows them. This is display grouping, not a
change to stored history. Live turns, search results, and turns without an answer
stay expanded. So does a turn that handed off with `sessions_yield`, whether it
is waiting, has resumed, or never did: its activity stays in place, and once it
resumes the closing line reports the request. User messages,
forwarded inputs, and structural markers remain boundaries for grouping.
Selecting the author's name on a reply's **Replying to** line scrolls to the
original message and briefly highlights it, first opening its containing
**Worked for…** group when the original sits inside one.

On wide desktop panes, the conversation position rail provides keyboard shortcuts
to messages. In right-to-left interface languages, the rail uses the right gutter
and its previews open toward the conversation. Tab enters at the current message, or the first marker if no message
is current. ArrowUp and ArrowDown move focus; Home and End go to the first and last
markers. Enter or Space jumps to the focused message. Tab or Shift+Tab leaves the
rail in one step, and Escape closes the preview and returns focus to the transcript.
In split view, Escape handles the focused pane before a hovered preview in another pane.
Focusing a marker also shows its preview without jumping to the message.
Changing the draft height or entering Goal mode keeps the rail's scroll position
stable. Navigation and keyboard focus still reveal the selected marker.

The chat transcript uses a centered readable frame aligned with the composer. Assistant and tool output stay left-aligned while your own messages stay right-aligned inside that frame. In multi-user sessions (for example a group chat relayed from a channel plugin), messages from other attributed participants render left-aligned with the author's avatar, name, and a stable per-identity color, so only the signed-in viewer's messages read as "mine". A reply can carry one "Replying to" line with the author's avatar and name, and no message excerpt. Assistant replies show it when they answer an older message, or when the conversation is shared: two or more people appear in the session participants or anywhere in the transcript, including messages hidden by search or not yet loaded. A reply in a one-to-one conversation that answers the prompt of its own turn shows no line. The line appears only once its origin and author are known, from a loaded message, a fetched original, or a reply snapshot that names its sender; until then, or when the author stays unknown, it is omitted rather than guessed. A reply to the current message resolves only through the run that prompt started, so legacy, mirrored, or ambiguous replies without that link show no line. When the original is confirmed deleted or inaccessible, the line shows "Original message unavailable" without an avatar or link, after the sender's name when the snapshot names it. A line whose row is reserved while the original is fetched never changes height: it fills in place, and a lookup that cannot reach the Gateway keeps the row reserved until a new connection retries. One exception is a shared conversation where the fetched original has no sender metadata and no reply snapshot names its sender: the author stays unknown, so the line ends hidden and its reserved row is released when the answer arrives. On desktop, the agent avatar stays at the top of attributed reply groups, with a short curved connector running from behind it to that line. On narrow screens, agent and participant avatars beside messages stay hidden to preserve content width; a small reply arrow introduces the line instead of the connector, while the author's avatar remains visible. Your own replies keep the line inside the bubble. Select the author to scroll to and briefly highlight the original. System entries such as local slash-command output render as centered notice rows without an avatar.

Images and video previews in your own messages appear above any accompanying text, without a surrounding bubble background. Videos use a still frame with a play icon; select the preview to open the video in the Files panel. If a preview cannot load, the attachment card remains available. Hovering media leaves that layout unchanged, and the text keeps its normal bubble color, including any per-identity tint. Assistant videos retain their inline player. Expand a video to sweep through assistant videos in the same turn with the previous/next buttons or Left/Right arrow keys. On touch screens, swipe the video picture or surrounding space left/right; the bottom native control strip remains available for seeking. When the video player itself has keyboard focus, its native playback shortcuts take precedence. Navigation stops the previous clip, and closing the viewer stops playback and returns focus to the original control. Videos from another turn or session are not included.

Images use a plain, lightly tinted shimmer while their availability or preview is loading. An image that needs explicit permission keeps a compact **Allow image** card until you choose to allow it; unavailable images retain their status and retry controls.

Managed image previews retain enough detail for high-density displays. Open an image tile
to inspect it immediately in the image viewer; the cached preview stays visible
while the original loads and is replaced as soon as the original is ready.
Reopening an image reuses the cached original. If loading fails, the preview remains visible.
When the message contains
multiple images, use **Previous image** / **Next image**, the left and right arrow
keys, or a horizontal swipe to move through that message's images. Navigation
stops at either end and reverses direction in right-to-left layouts. Pinch or use
the zoom controls to inspect details; dragging or holding Shift while pressing
an arrow key pans the zoomed image. The keyboard shortcuts dialog lists these controls.
Press Escape, select **Close image preview**, or click outside the image to close
and return focus to the tile you opened.

Inline audio players support five-second seeking with the arrow keys, including
when the seek slider has focus. The slider announces the current time and duration.

Images attached to assistant progress messages appear inline while the task continues and remain visible after reloading the conversation. Progress attachments are preserved for runs started by any Gateway owner, including chat sends, restart recovery, and internal dispatch. Remote attachment URLs do not need a filename extension: the Gateway detects the media type and serves the preview through the same authenticated media path used for final replies. Documents keep their file cards.

Computer screenshots retained in the session transcript also load as image previews,
including after a reload. Opening a preview shows the saved screenshot in the image
viewer. The Control UI retrieves the pixels through authenticated artifact access;
computer observations are not automatically sent as outgoing attachments. Historical
entries that contain only omission metadata keep the **Omitted from history** card.

In automatic visible-reply mode, this includes standalone `MEDIA:` lines in model-authored commentary committed to the transcript, not just final replies. Only references captured before transcript hooks and retained in that commentary are eligible; hook-added references remain text, and normal media access and live run/session checks still apply. Message-tool-only delivery uses `message(action=send)` with structured attachment fields instead. Tool/plugin output and streamed block payloads must also use structured fields. See [WebChat commentary compatibility](https://funcoding.ai/agents/openclaw/reference/rich-output-protocol/#webchat-commentary-compatibility).

Messages forwarded by `sessions_send` render as left-aligned speech bubbles with a **From** attribution row above the message. Known senders, including the current agent, retain their agent identity. Unknown or unlisted senders show no avatar beside the bubble or in the attribution row, and no empty inline avatar space remains. The message column stays aligned with neighboring messages. Select a linked source to open its session; hover it to see session progress. Each source session has a stable bubble tint. Forwarded messages without a known source session show the source agent when available, or a generic forwarded-message label. The receiving agent's own replies remain flat text.

Your name is hidden beneath your own messages when no other human participant is known in the session. Shared conversations keep sender names, including while searching the transcript. Web messages do not show a "via Web" label; other recorded client sources remain visible.

## Run transcripts

Open a session to inspect its recorded messages and tool calls.

Automation run transcripts stay tied to the recorded run, including after its
temporary continuation session is removed or the automation runs again. If that
recorded transcript is unavailable, the viewer reports an error instead of
showing a newer run. Select **View transcript** under **Automations → Run history**
to read that exact run without opening its temporary session. Selecting **All
automations**, opening another automation, or starting a new automation closes the
run viewer; refreshing the same panel keeps it open.

The automation run viewer displays the supplied transcript. Core session transcripts
are currently capped at 8,000 characters per text block; loading earlier messages
does not recover a capped reply's missing text.

## Conversations stopped for review

When a provider stops a conversation as a misalignment precaution, chat holds
ordinary sends, queued input, and Talk. **Review findings** opens the available
explanation. If the provider and runtime support continuation, the dialog shows
the exact continuation message and asks you to **Acknowledge findings and
continue**. Sending that request keeps the chat paused until the provider accepts
it; a refresh, another session, or newer findings cannot confirm an older review.

Queued messages remain held after continuation. Review and retry each one
separately if it is still needed. Without a supported continuation, the
conversation remains stopped. See [misalignment precautions](https://funcoding.ai/agents/openclaw/concepts/model-failover/#misalignment-precautions)
for runtime support and recovery limits.

## Chat message width

Wide-monitor users can override the transcript width under **Settings → Appearance → Chat →
Message width**. The preference stays in that browser's local storage. Supported
forms include plain lengths and percentages such as `960px` or `82%`, plus
constrained `min(...)`, `max(...)`, `clamp(...)`, `calc(...)`, and
`fit-content(...)` width expressions supported by your browser. Invalid input
shows an error and keeps the last saved width. Clear the field to restore the default.
