Source-grounded rewrite of 529 published docs pages with per-unit information-loss verification: 1,713 factual corrections cited to src/**, generated surfaces regenerated, frontmatter titles preserved for i18n, release notes pages untouched. All docs gates green. Closes #100141
7.7 KiB
summary, read_when, title
| summary | read_when | title | |
|---|---|---|---|
| Loopback WebChat static host and Gateway WS usage for chat UI |
|
WebChat |
Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket. No embedded browser, no local static server.
What it is
- A native chat UI for the gateway.
- Uses the same sessions and routing rules as other channels.
- Deterministic routing: replies always go back to WebChat.
- History is always fetched from the gateway (no local file watching). If the gateway is unreachable, WebChat is read-only.
Quick start
- Start the gateway.
- Open the WebChat UI (macOS/iOS app) or the Control UI chat tab.
- Ensure a valid gateway auth path is configured (shared-secret by default, even on loopback).
How it works
- The UI connects to the Gateway WebSocket and uses the
chat.history,chat.send,chat.inject, andchat.message.getRPC methods. chat.historyis bounded for stability: Gateway may truncate long text fields, omit heavy metadata, and replace oversized entries with[chat.history omitted: message too large]. API clients can send a per-requestmaxCharsto override the default limit for one call.- When a visible assistant message was truncated in
chat.history, Control UI can open a side reader and fetch the full display-normalized entry on demand throughchat.message.get, without increasing the default history payload.chat.message.getuses the same transcript branch and display rules aschat.history, but targets one entry bymessageIdand returns an honest unavailable reason when the full content can no longer be returned. chat.historyfollows the active transcript branch for append-only session files, so abandoned rewrite branches and superseded prompt copies are not rendered in WebChat.- Compaction entries render as a "Compacted history" divider explaining that the compacted transcript is preserved as a checkpoint, with an action to open session checkpoints (branch or restore, when permissions allow).
- Control UI remembers the backing Gateway
sessionIdreturned bychat.historyand includes it on follow-upchat.sendcalls, so reconnects and page refreshes continue the same stored conversation unless the user starts or resets a session. chat.sendtakes an idempotency key (Control UI uses the run id); the Gateway dedupes repeated requests that reuse the same key, so retried or duplicate in-flight submits for the same session/message/attachments do not create a second run.- Workspace startup files and pending
BOOTSTRAP.mdinstructions are supplied through the agent system prompt's# Project Contextsection, not copied into the WebChat user message. If bootstrap content is truncated, the system prompt gets a short "Bootstrap Context Notice" instead; detailed counts and config knobs stay on diagnostic surfaces. - Display normalization on
chat.historystrips: runtime-only OpenClaw context, inbound envelope wrappers, inline delivery directive tags such as[[reply_to_current]],[[reply_to:<id>]], and[[audio_as_voice]], plain-text tool-call XML payloads (<tool_call>,<function_call>,<tool_calls>,<function_calls>, including truncated blocks), and leaked ASCII/full-width model control tokens. Assistant entries whose whole visible text is only the silent tokenNO_REPLY(case-insensitive) are omitted. - Reasoning-flagged reply payloads (
isReasoning: true) are excluded from WebChat assistant content, transcript replay text, and audio content blocks, so thinking-only payloads do not surface as visible assistant messages or playable audio. chat.injectappends an assistant note directly to the transcript and broadcasts it to the UI (no agent run).- Aborted runs can keep partial assistant output visible in the UI. Gateway persists that partial text into transcript history when buffered output exists, and marks the entry with abort metadata.
Transcript and delivery model
WebChat has two separate data paths:
- The session JSONL file is the durable model/runtime transcript. For normal agent runs, the embedded OpenClaw runtime persists model-visible
user,assistant, andtoolResultmessages through its session manager. WebChat does not write arbitrary delivery, status, or helper text into that transcript. - Gateway
ReplyPayloadevents are the live delivery projection: normalized for WebChat/channel display, block streaming, directive tags, media embedding, TTS/audio flags, and UI fallback behavior. They are not themselves the canonical session log. - Harnesses that require visible replies through
tools.messagestill use WebChat as a current-run internal source reply sink. A targetlessmessage.sendfrom that active WebChat run is projected into the same chat and mirrored to the session transcript; WebChat does not become a reusable outbound channel and never inheritslastChannel. - WebChat injects assistant transcript entries only when the Gateway owns a displayed message outside a normal embedded agent turn:
chat.inject, non-agent command replies, aborted partial output, and WebChat-managed media transcript supplements. - If live assistant text appears during a run but disappears after history reload, check in order: whether the raw JSONL contains the assistant text, whether
chat.historydisplay projection stripped it, then whether the Control UI optimistic-tail merge replaced local delivery state with the persisted snapshot.
Normal agent-run final answers should be durable because the embedded runtime writes the assistant message_end. Any fallback that mirrors a delivered final payload into the transcript must first avoid duplicating an assistant turn that the embedded runtime already wrote.
Control UI agents tools panel
- The Control UI
/agentsTools panel has an "Available Right Now" view backed bytools.effective(sessionKey=...): a server-derived, read-only projection of the current session's tool inventory, including core, plugin, channel-owned, and already-discovered MCP server tools. - A separate config-editing view (backed by
tools.catalog) covers profiles, per-agent overrides, and catalog semantics. - Runtime availability is session-scoped. Switching sessions on the same agent can change the "Available Right Now" list. If configured MCP servers have not been connected or changed since the last discovery, the panel shows a notice instead of silently starting MCP transports from the read path.
- The config editor does not imply runtime availability; effective access still follows policy precedence (
allow/deny, per-agent and provider/channel overrides).
Remote use
- Remote mode tunnels the gateway WebSocket over SSH/Tailscale.
- You do not need to run a separate WebChat server.
Configuration reference (WebChat)
Full configuration: Configuration
WebChat has no persisted config section. Gateway uses the built-in chat.history display limit; API clients can send per-request maxChars to override it for a single call. Legacy channels.webchat and gateway.webchat config is retired; run openclaw doctor --fix to remove it.
Related global options:
gateway.port,gateway.bind: WebSocket host/port.gateway.auth.mode,gateway.auth.token,gateway.auth.password: shared-secret WebSocket auth.gateway.auth.allowTailscale: browser Control UI chat tab can use Tailscale Serve identity headers when enabled.gateway.auth.mode: "trusted-proxy": reverse-proxy auth for browser clients behind an identity-aware non-loopback proxy source (see Trusted Proxy Auth).gateway.remote.url,gateway.remote.token,gateway.remote.password: remote gateway target.session.*: session storage and main key defaults.