docs/web/webchat.md
Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket. No embedded browser, no local static server.
chat.history, chat.send, chat.inject, and chat.message.get RPC methods.chat.history is 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-request maxChars to override the default limit for one call.chat.history, Control UI can open a side reader and fetch the full display-normalized entry on demand through chat.message.get, without increasing the default history payload. chat.message.get uses the same transcript branch and display rules as chat.history, but targets one entry by messageId and returns an honest unavailable reason when the full content can no longer be returned.chat.history follows the active transcript branch for append-only session files, so abandoned rewrite branches and superseded prompt copies are not rendered in WebChat.sessionId returned by chat.history and includes it on follow-up chat.send calls, so reconnects and page refreshes continue the same stored conversation unless the user starts or resets a session.chat.send takes 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.BOOTSTRAP.md instructions are supplied through the agent system prompt's # Project Context section, 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.chat.history strips: 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 token NO_REPLY (case-insensitive) are omitted.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.inject appends an assistant note directly to the transcript and broadcasts it to the UI (no agent run).WebChat has two separate data paths:
user, assistant, and toolResult messages through its session manager. WebChat does not write arbitrary delivery, status, or helper text into that transcript.ReplyPayload events 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.tools.message still use WebChat as a current-run internal source reply sink. A targetless message.send from 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 inherits lastChannel.chat.inject, non-agent command replies, aborted partial output, and WebChat-managed media transcript supplements.chat.history display 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.
/agents Tools panel has an "Available Right Now" view backed by tools.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.tools.catalog) covers profiles, per-agent overrides, and catalog semantics.allow/deny, per-agent and provider/channel overrides).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.