mirror of
https://github.com/openclaw/openclaw.git
synced 2026-09-28 14:12:28 +08:00
The pending-work guard dropped new scheduling requests while another
session's cooldown retry could hold a timer for almost 30 seconds. Keep
the earliest pending deadline, preserve the minimum running-cycle delay,
and carry intent through coalescing so it bypasses unbounded idle waits.
Use a 75 ms intent delay to coalesce row sweeps before a click; automatic
warming retains its 250 ms delay and idle callback. Preserve per-key
cooldown, serial history fetches, Web Locks, visibility, presented-pane
readiness, cache ownership, counts, and request budgets.
Controller-boundary regressions fail on base 6652f7eac8 for both intent
and list revisions arriving behind a cooldown. Also cover later requests
not postponing automatic warming, held idle callbacks, pointer sweeps,
and intent coalesced behind an in-flight history request. Document the
intent behavior in the Control UI reference.
Validation: 308 tests across 17 prefetch, chat-history, and session-snapshot
files; UI typecheck; CI oxlint wrapper on touched TypeScript; UI build;
format and diff checks; independent P2 review with no actionable findings.
The broader changed check found TS2532 in the new idle-callback test;
fixed its indexed access and reran the ui-chat type graph, all 31 prefetch
tests, touched-file lint, and review successfully. The other five selected
test type graphs and all preceding changed-file guards passed unchanged.
The prefetch file passed 31 tests in 13.35 s single-worker wall time
(about 0.35 s test time). No remote CI was run.
Live proof: three interleaved before/after rounds per dwell, four targets
per round (12 samples per variant/dwell), separate synthetic Gateways.
Medians from the requested probe, before -> after:
- 150 ms dwell: first completed prefetch send unavailable -> 89.5 ms
(0/12 -> 2/12 observable samples); click-to-visible 123 -> 205 ms.
- 300 ms dwell: first completed prefetch send 235 -> 88 ms
(12/12 -> 5/12 observable samples); click-to-visible 111 -> 116.5 ms.
The supplied probe records requests only on response, hiding pending sends.
One additional interleaved round with send-time instrumentation measured
87.5 ms (150 ms dwell) and 85 ms (300 ms dwell) after, including requests
whose responses took seconds. The next supplemental round hit repeated
Gateway authentication timeouts and multi-second SQLite writes; stopped
that probe. Earlier scheduling is proven; end-to-end click improvement
under this host load is not. Stopped the isolated Gateway and removed
its seeded state and temporary browser profiles.
43 KiB
43 KiB
doc-schema-version, summary, read_when, title, sidebarTitle
| doc-schema-version | summary | read_when | title | sidebarTitle | ||
|---|---|---|---|---|---|---|
| 1 | What the Control UI can do today, grouped by capability with its Gateway RPC names |
|
Feature and RPC reference | Feature and RPC reference |
Control UI capabilities grouped by area, each with the Gateway RPC methods behind it.
Feature and RPC reference
- Subagent transcripts hide author avatars in the main chat view. Assistant and peer sender names remain visible; your name is hidden when no other human participant is known. - Chat with the model via Gateway WS (`chat.history`, `chat.send`, `chat.abort`, `chat.inject`). Archived sessions keep the composer disabled and show a banner with an **Unarchive** action before the conversation can continue. - Thinking controls and `/think` use the selected model's published choices and default. A model with no choices offers no effort control or default. Missing capability metadata is shown as unknown, without guessed levels; an explicit command still uses server validation. Saved overrides and matching inherited choices remain separate from the active fallback model. - Opening or refreshing chat requests up to 80 recent messages. Each background warming pass reads at most two inactive sessions sequentially, with up to 20 messages per session, after presented chat loads finish. Automatic warming waits for a visible conversation on the current page; dashboard-only views still warm the session you hover or keyboard-focus. Hover and keyboard intent use a short delay without waiting for browser idle time or another session's cooldown; the intended session's own cooldown still applies. Scrolling back requests up to 1,000 older messages per page and prefetches the next page. Per-message text caps and response-byte limits can reduce these counts. - A previous run's error banner clears when Chat adopts a new run or history confirms a newer successful run. Retiring the banner does not erase recorded diagnostics. A late error from the same run can remain visible beside its delivered answer; reconnecting or refreshing metadata alone does not establish recovery. - Run error banners preserve diagnostic file paths while masking credentials. Expand **Details** to read a long error and use **Copy error** to copy the complete displayed diagnostic. After reopening a chat, recorded failures before a reply supply the diagnostic for their exact run instead of the shortened session-list summary. - A saved assistant answer replaces its live stream without waiting for the run to finish. Refreshing history or reconnecting while that reply finishes does not add another copy of the saved answer. Later streamed continuations remain visible. Remote workspace reconciliation can keep the working indicator and Stop control active after the answer appears; a later reconciliation failure remains visible beside the answer. - Scroll up to read earlier messages without following incoming output. Messages from another participant preserve your position, even at the end; typing indicators do not move the transcript. Sending a message from this pane, submitting a transcript command such as `/help`, or using the down-arrow button returns to the latest message, including when the composer or progress card resizes. Scrolling manually interrupts that movement or a restored scroll position; keys handled by text fields or media controls do not. Messages continue to reserve their space as full text, images, and tool output load. - Session and GitHub hover cards close when their source pane is hidden or retired, including when you use browser Back or Forward. - Links to `github.com` in chat messages — yours and the agent's — show issue and pull-request references as compact chips with an issue or pull-request icon. Bare item URLs show `#number`, including links to files, commits, comments, and diff anchors; matching `#number` or `owner/repo#number` labels also become chips. A code span that contains nothing but a GitHub URL is treated like a bare URL, so backtick-quoted links get the same chip, tooltip, and hover card. The tooltip preserves the exact destination, and the hover card opens that same link. Repository file URLs show the filename. Nested tree URLs show the owner, repository, and final path segment with an ellipsis for the omitted path; this also covers branch names containing slashes without guessing where the branch ends. Their full destinations remain in the tooltip. Other GitHub paths retain the owner and repository in their URL label. All keep the GitHub mark, and custom labels stay unchanged. Icons are bundled, never fetched from the network, and decorative only: they are skipped for image-only links such as badges, never appear inside code blocks or code spans with other text, are not read by screen readers, and are not part of copied text. - In assistant messages, sessions whose checkout has a GitHub remote also turn references such as `PR #141270`, `pull request #123`, `pull #123`, `issue #123`, and `fixes`/`closes`/`resolves #123` into chips with hover cards. Bold and italic formatting between a keyword and its number, such as `PR **#123**`, preserves the item kind. Bare `#N` references require at least four digits with no leading zero; references inside code, existing links, or headings stay unchanged. Unqualified references use the session checkout repository. A repository-qualified form such as `owner/repo PR #123` or `PR owner/repo#123` works without a checkout; `owner/repo#123` uses an issue link. A known project display name or repository basename immediately before the keyword, such as `Release Tools PR #123`, selects that repository for that reference only. Names match case-insensitively at identifier boundaries, across bold/italic formatting and surrounding quotes or punctuation. The UI uses only the registered projects already returned by `projects.list` and the current session repository; it does not search GitHub or guess an owner. Project origins remain restricted to `operator.write`. Ambiguous names and known projects with missing, hidden, or non-GitHub origins remain plain text rather than falling back to the checkout. Unknown quoted names, explicit `repo`/`repository`/`project` qualifiers, and CamelCase or internal-dot/underscore identifiers also remain plain; ordinary prose such as `Original PR #123` and `Follow-up PR #123` still uses the checkout. Other unknown natural-language names are not inferred. Checkout-based links wait for the authorized project catalog to load; if that read fails, they stay plain rather than briefly linking a named project to the wrong repository. Explicit `owner/repo` references and URLs still work. Existing explicit links always retain their authored destination. - Hovering or keyboard-focusing a public GitHub issue or pull request link shows its state, title, author, recent activity, comments, and change statistics. Visible chat links warm up to eight distinct previews per mounted conversation and Gateway connection, one background request at a time, so cards can open with their data already cached. Hidden conversations, background tabs, and disconnected Gateways pause warming. Canceled work resumes when visible again, and reconnecting starts a fresh warming budget for the new connection; other links still load on hover or keyboard focus. Warming and hover share the same cache and pending request. Inline item chips consume that same fetched state: unknown and draft items stay neutral, open items are green, merged pull requests are purple, and closed pull requests are red. Chip state is scoped to the exact repository and item under the current connection and agent; it never settles publication for a different workspace. The connected Gateway fetches and caches public metadata without changing the link target, including when the UI uses a remote Gateway. The card's title and repository reference open the exact link you hovered or focused, including comment fragments and query parameters, even when another link to the same item has already filled the cache. Previews use the selected agent's configured GitHub identity, inheriting the system identity when there is no agent override. Without a managed identity, they retain the explicit Control UI GitHub credential, then the shared Gateway process-environment fallback; public previews still work anonymously without credentials. Configured managed identities never silently switch accounts, and authenticated previews remain restricted to public repositories. Signing into GitHub in your browser or connecting a personal GitHub account does not select the preview identity. Preview requests remain silent until one preview has successfully appeared in the current page, Gateway connection, and agent identity context. That success is shared across preview providers: later uncached links can show a loading skeleton. Client, connection, or identity changes reset the gate, and it is never persisted across page reloads. Failures show the Gateway’s explanation, including rate limits, authentication or access problems, and timeouts. Cached session details remain visible with that notice; reopening a failed preview shows the cached failure during the 30-second backoff without another request. Leaving a link while its request is pending cancels that activation, and stale responses cannot enable loaders in a new context. Supported links inside the preview provider suppress competing title tooltips from the initial hover or focus, including while the preview runtime loads. The original link, its accessible name, and the browser’s destination-URL display remain unchanged. - Talk through browser realtime sessions. OpenAI supports browser WebRTC and Gateway-relayed provider WebSockets, Google Live uses a constrained one-use browser token over WebSocket, and backend-only realtime voice plugins use Gateway relay. Video-capable browser sessions can choose a device-local camera in Settings or flip cameras from the live preview; the browser captures JPEG frames for the realtime provider without streaming camera video through the Gateway. Client-owned provider sessions start with `talk.client.create`; Gateway relay sessions start with `talk.session.create`. The relay keeps provider credentials on the Gateway while the browser streams microphone PCM through `talk.session.appendAudio`, forwards provider delegations or `openclaw_agent_consult` tool calls through Gateway policy and the larger configured OpenClaw model, and routes active-run voice steering through `talk.client.steer` or `talk.session.steer`. Browser WebRTC GPT-Live delegates on the Gateway-owned sideband, but each delegation has the same spoken-confirmation gate and browser-owned `talk.client.steer` lifecycle; a newer spoken task can also supersede the running delegation. Gateway-relayed GPT-Live uses the normal relay consult and steering path. Configure the realtime provider, model, and speaker voice on **Settings → Talk**, whose pickers come from `talk.catalog` and show whether the selection is ready to use. - Stream tool calls and live tool output cards in Chat (agent events). Tool activity renders as kind-aware rows: shell commands show the syntax-highlighted command with terminal-style output; supported edit and write calls show bounded inline diffs with source syntax highlighting, line numbers when available, and `+added -removed` stats; and consecutive calls collapse into bounded operation counts such as "13 commands · 6 reads · 9 edits", with failed, blocked, and unknown outcomes called out. These are operation counts, not distinct-file counts or claims that changes succeeded. While a run is live, the newest running call names the group header. Expand a row to inspect its remaining arguments and raw output. - Tool activity counts distinct calls, not start/update/result events, repeated history or live projections, or Gateway observation RPCs. Nested calls count independently, even when their names and arguments match. Expand the activity to see each call; read and edit counts can include repeated attempts on the same file. - Tool activity automatically displays a short purpose description supplied by the acting agent when available, with commands and results expandable underneath. Calls without descriptions keep deterministic labels. Viewing activity makes no additional model calls. The former `gateway.controlUi.toolTitles` option is retired; `openclaw doctor --fix` removes it from existing configs. - Start or dismiss ephemeral model-suggested follow-up tasks. **Start in a new session** opens the proposed task in the suggested folder without requiring Git or creating a worktree. The new session asks the user before using a worktree if the task needs one later. - Activity tab with browser-local, redaction-first summaries of live tool activity from existing `session.tool` / tool event delivery. - Channels: built-in plus bundled/external plugin channels status, QR login, and per-channel config (`channels.status`, `web.login.*`, `config.patch`). - Channel probe refreshes keep the previous snapshot visible while slow provider checks finish, and label partial snapshots when a probe or audit exceeds its UI budget. - Threads (a workspace page at `/sessions`, with a **Worktrees** tab alongside it): list configured-agent sessions by default, pin frequent root sessions, rename them, archive or restore sessions, fall back from stale unconfigured agent session keys, and apply per-session model/thinking/fast/verbose/trace/reasoning overrides (`sessions.list`, `sessions.patch`). A three-way **Active / Archived / All** filter controls both this page and the sidebar; All dims archived rows and labels them explicitly. Archived sessions keep their transcripts and remain shelved until explicitly unarchived or deleted. Sessions archived automatically at the active-session cap can also be deleted automatically when the session store exceeds its disk budget; manually archived and legacy sessions stay protected. Rows show an unread dot for active sessions with activity since they were last read, with mark-unread/mark-read actions (`sessions.patch { unread }`), and a Fork action that branches the transcript into a new session (`sessions.create { parentSessionKey, fork: true }`). Overview tiles above the table summarize the loaded roster (session count, live runs, unread sessions, total tokens, and archived count when available), each row carries a kind glyph with a live-run dot, status renders as a plain dot plus label, and the Tokens column shows a context-window usage meter when the session reports token and context sizes. Row management actions live in a per-row menu (kebab button or right-click) mirroring the sidebar's session menu, and the row drawer carries the agent runtime and run duration alongside the other session details. - Native Claude and Codex sidebar catalogs stream one host at a time, then reconcile after node connectivity changes, on page focus, and at most every 30 seconds while visible. Catalog changes trigger a faster follow-up pass, so sessions created in the native tools appear without reloading the Control UI. Claude Desktop rows also retain their local custom-group label when present; OpenClaw reads that mapping from Desktop's local store and never writes it. - Session grouping: a Group by control organizes the sessions table into sections by custom groups, channel, kind, agent, or date. Custom groups persist per session via `sessions.patch` (`category`), so sessions started from message channels (Discord, Telegram, WhatsApp, ...) can be categorized too; assign groups by dragging rows onto a section, or with the per-row group selector, and create groups with the New group action. - Memory (a tab on the Agents page, scoped to the selected agent): dreaming status, enable/disable toggle, and Dream Diary reader (`doctor.memory.status`, `doctor.memory.dreamDiary`, `config.patch`). When the `memory-wiki` plugin is enabled, the Diary view adds **Imported Insights** and **Memory Wiki** sub-tabs that browse imported source chats and the compiled wiki — clustered synthesis, entity, and concept pages plus annotated sources and reports, with claims, open questions, contradictions, and inline page previews (`wiki.importInsights`, `wiki.overview`, `wiki.get`). - Import Memory (`/memory-import`, reached from the Agents page's Memory tab): preview and copy local Claude Code auto-memory, Codex consolidated memory, or Hermes memory files into the selected agent workspace (`migrations.memory.plan`, `migrations.memory.apply`). - Onboarding memory offer: when the Control UI opens in [onboarding mode](/web/urls#other-special-documents-and-startup-modes), a one-page dialog offers to import detected memories with the same plan/apply flow; skipping leaves the settings page as the later entry point. - Automations (cron jobs): stat cards (automation count, failing count, scheduler state, next wake) above an Automations/Run history tab switch; the Automations tab lists jobs in a filterable table (All/Active/Paused, search, schedule and last-run filters, per-row action menu) with starter suggestions below, and the Run history tab shows recent runs across all automations (`cron.*`). - Plugins: browse the installed inventory and curated store, search ClawHub, install and remove plugin code, and enable or disable installed plugins (`plugins.*`). **Install** starts immediately and accepts the staged plugin’s declared capabilities without changing your hook and model permissions. Configured install-policy warnings still require an explicit acknowledgment. Catalog categories remain available while you search. MCP server rows edit `mcp.servers` through the config methods. - Skills: status, enable/disable, install, API key updates (`skills.*`). - Devices: one inventory joins paired device records, the node catalog, and live presence (`device.pair.list`, `node.list`, `system-presence`). The Gateway host is pinned first; paired clients show connection status, roles, tokens, capabilities, and commands. Duplicate pairings collapse into an expandable group, and **Clean up N stale** bulk-removes admin-confirmed offline duplicates that were auto-approved (silent local, trusted-CIDR, or SSH-verified) or predate approval provenance. Paired rows have an **Actions** menu to copy its device ID, **Edit alias** (a non-empty operator label of up to 64 characters, preserving the device ID and client-reported name), remove its pairing (`node.pair.remove`, `device.pair.remove`), or approve/reject a pending node re-approval (`node.pair.approve`/`reject`). Device pairing requests retain their visible **Approve** and **Reject** buttons (`device.pair.*`), and mobile setup codes can be created from the same card. **Details** groups device identity, IP, scopes, token rotation/revocation, and commands into labeled facts. Resource meters show Gateway host load, memory, disk, and uptime from `system.info`, and node meters appear when the node reports `hostStats`. Offline nodes with a retained snapshot show muted last-known meters with the snapshot age. The connected page refreshes host stats every 60 seconds and alongside quiet node reloads; node stats also refresh on `node.hostStats` events. Capability chips explain each capability on hover. **Desktop** opens that machine in a standalone desktop window (the docked Desktop panel stays hidden on Settings routes) and appears only when the Gateway reports an available desktop environment. Desktop sharing starts enabled on desktop nodes. On a Mac, change it under **Settings → This Mac → Capabilities → Desktop sharing**; the app reconnects automatically. CLI nodes use `desktop.host.enabled` and need a restart after config changes. An existing node may reconnect with a pending reapproval for the new command, which you approve from the row’s **Actions** menu or with `openclaw nodes approve `. No extra Gateway allow entry is needed; an explicit deny still blocks streaming. The node needs macOS Screen Sharing or an authenticated loopback VNC server. A dashed Desktop chip explains this setup when only the command is advertised.- Exec approvals: edit gateway or node allowlists and ask policy for `exec host=gateway/node` (`exec.approvals.*`).
The session timeline's range handles support Tab, arrow keys to move one recorded point, and Home/End to select a boundary. Each handle has an accessible label and current time.
- Session-derived token and estimated-cost analysis stays separate from provider billing.
- Session rows and selected details show saved conversation names, including generated titles. Explicit renames take precedence; unnamed sessions show their keys.
- The Sessions card counts the rows currently shown: up to 50 in **All**, or matching sessions selected on this Usage page in **Recently viewed**. The total is the loaded session count for the agent scope; the separate selected-session comparison does not increase the shown count.
- Filter sessions with the provider, model, channel, or tool menus, or type case-insensitive `key:value` terms. Values within one category match as alternatives. Toggling a menu option preserves the other filters and their quoted text.
- Selecting days narrows token and cost totals to those days within the active session filters. Daily charts and exports retain that session scope. Provider/model/tool queries select matching sessions, including all usage within each matched session; hour filters select sessions active in those hours.
- Whole-session totals count each tool call, including repeated uses of the same tool in one assistant message. Drag the handles in a session’s usage timeline to inspect an interval; its counts use assistant invocations in the loaded conversation. Tool results do not add calls. Tool-only assistant messages remain visible in the loaded conversation.
- Interval message and tool-call counts use timestamped entries in the loaded conversation. Messages include only user and assistant roles. Loaded history can be incomplete; unavailable or undated data does not establish a complete interval total. Conversation search and role filters do not change these summaries. Clear the interval to restore the session summary counts.
- Select **Local** or **UTC** for hourly charts and peak error hours. Historical hour labels stay tied to the selected time zone, including when you view them across a daylight-saving transition.
- Provider cards call `usage.status` and show live plan names, quota windows, balances, spend, and budgets reported by configured provider plugins.
- A provider usage failure does not block the session/cost dashboard; unavailable provider cards show their own error state.
- Session/cost totals keep the previous committed values visible during a background refresh. The page reads the new totals when the Gateway announces a completed refresh, including after returning to a hidden tab. Sessions without a committed rollup show that usage is still being computed.
- If a background refresh fails, the page keeps any committed totals and shows a paused notice for the affected agent scope. The failure stays with that agent across filter changes and navigation; another agent's refresh does not clear it. Use **Refresh** to try again. Session refresh notifications do not restart provider-card retry limits.
- Changing the date range, agent, session scope, or time zone hides the previous query's session/cost totals until the new query loads. A failed refresh of the same query keeps its last totals visible. Provider billing cards remain separate from these filters.
- **Refresh** also reloads the selected session's timeline, conversation, and system-prompt breakdown.
- If a selected session is deleted and recreated, its new details replace the old ones and clear the previous timeline interval without clearing your session selection. An unfinished drag on the old timeline cannot change the new interval. Refreshing the same instance retains its selected interval. Context details from a different session instance show an error and can be retried with **Refresh**.
- The overview loads session summaries first. Full system-prompt breakdowns load when you select a session; the `has:context` filter still works before opening details.
- Sessions CSV and JSON exports include only selected sessions that match the active filters; with no selection, they include all matching sessions. JSON exports keep the displayed usage snapshot and load prompt details for the same session instance. If that session has been replaced, refresh Usage and export again.