Replace the native <select> on the Agents page with an accessible custom
listbox dropdown (openclaw-agent-select) that renders each agent's avatar
image, identity emoji, or initial. Local /avatar/<id> routes are fetched
with the bearer credential and rendered as cached blob URLs when gateway
token auth is active, matching the chat-avatar contract.
Refs #102792, #57067
* fix(googlechat): add 30 s request timeout to withGoogleChatResponse
* fix(googlechat): satisfy ResolvedGoogleChatAccount in api.test.ts
* fix(googlechat): bound control and media requests
Co-authored-by: NIO <nocodet@mail.com>
---------
Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(ui): merge voice level meter into the stop-voice pill and disambiguate stop controls
* docs(web): describe the live voice pill control in Talk mode
* test(ui): capture dark-mode voice control proof in talk e2e
* fix(ui): keep the live voice pill wide at phone widths
* fix(ui): show the stop glyph instead of a fake listening meter when a talk session errors
* test(ui): assemble the mock talk client secret so scanners do not flag it
* feat(webchat): composer lobster mascot perches on the empty prompt
A decorative OpenClaw lobster (smooth icons.lobster style) sits on the
composer edge while the prompt is idle, ducks away on typing/runs, and
plays personality-weighted idle acts (scuttle, wave, snip, hop, spin,
peek, bubbles, nap with z's; poke to startle). Look and personality are
seeded per session + page load: palette, size, antennae, accessory,
perch, facing, temperament. Decorative contract: aria-hidden, no config,
reduced-motion stays fully static, timers pause on hidden tabs and clean
up on disconnect. Hidden on short-landscape viewports where the composer
scrolls.
Closes#102754
* refactor(webchat): move lobster mascot from composer to sidebar status pet
The composer perch read too close to Claude Code's input mascot. The pet
now lives on the sidebar footer ledge above the connection dot and
mirrors gateway state: idle personality acts when quiet, a faster scurry
pool while runs are active, grey-eyed worried pacing while disconnected,
and a startle on every status flip. Composer wiring reverted; element
renamed openclaw-lobster-pet; hidden in the collapsed rail.
* fix(release): validate prepared npm package sets
Forward-port the beta3 package-set preflight, Telegram, and Parallels validation to main while preserving main's existing Bun install smoke. Recompute decoded proxy response lengths and require artifact tarballs to exactly match the verified manifest.
* fix(release): lock fixture registry proxy origin
Drops the decorative layer from the sessions roster per maintainer feedback:
overview tiles, the drawer hero, detail sections, stat cards, checkpoint
cards, and the goal chip become flat token surfaces (no gradients, no inset
highlight shadows, no translucent color-mix glass); kind avatars and overview
icon chips lose their nested borders and read as flat tints; the skeleton
shimmer gradient becomes a plain opacity pulse. Focus rings, the drag-drop
target outline, and the live status dot ring stay - those are signal, not
decoration.
* fix(agents): allow model fallback when takeover wrapper holds classifiable promptError
When EmbeddedAttemptPromptErrorWithCleanupTakeoverError wraps a real
provider-level failure (e.g. timeout, rate_limit) inside .promptError but
inherits the name "EmbeddedAttemptSessionTakeoverError", the fallback
classifier isNonProviderRuntimeCoordinationError aborts the fallback chain
without checking whether the underlying cause is a retryable provider error.
Fix: in isNonProviderRuntimeCoordinationError, check err.promptError before
returning true for takeover-named errors. If promptError is a classifiable
provider failure (timeout, rate_limit, etc.), let fallback proceed — the
takeover is a cleanup side-effect, not the root cause.
Tests:
- Unit tests for the classifier: timeout, rate_limit, unclassifiable,
and pure takeover (regression)
- Integration tests for the runWithModelFallback pipeline: timeout
and rate_limit promptError both produce correct fallback and reason;
pure takeover still aborts
Related to #99963
* fix(agents): carry preserved prompt failures
* fix(agents): keep pure takeovers fatal
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(codex-dynamic-tools): use truncateUtf16Safe for notice text truncation
* fix(codex): keep dynamic tool text UTF-16 safe
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(agents): use truncateUtf16Safe for runner error text truncation
One .slice(0, 200) truncation site in the embedded agent runner
may cut UTF-16 surrogate pairs in half when the error text contains
multi-byte characters such as emoji. Replace it with
truncateUtf16Safe to keep the truncated output valid Unicode.
* test(agents): cover UTF-16 overflow diagnostics
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(onboard): guided CLI onboarding with live AI verification and classic fallback
Interactive `openclaw onboard` (and bare `openclaw` on a fresh install) now
runs a guided flow with macOS-app parity: detect existing AI access, live-test
candidates with a real completion before persisting anything, walk down the
ladder on failure with mapped reasons, and offer verified manual API-key entry
from installed provider manifests (masked input). In-flow escapes: classic
wizard, Crestodian chat, skip-AI. Classic wizard gains an optional post-auth
live verification step. `--classic`, `--modern`, and `--non-interactive`
contracts unchanged. Docs corrected for post-#99935 routing.
Closes#101851
* improve(onboard): quiet probe diagnostics in wizard TTY, carry risk ack into classic escape
Candidate live-tests during guided setup are probes: rename their run id and
lane to the existing probe conventions (logging/subsystem.ts console
suppression, command-queue quiet probe lanes) so expected failures stop
leaking raw diagnostics into the Clack UI; file diagnostics unchanged. The
classic-wizard escape now passes the already-collected risk acknowledgement
through instead of re-prompting in the same session.
* fix(onboard): quiet the session-derived setup-inference probe lane too
The live-test run enqueues on two lanes: the explicit probe lane and one
derived from its temp session key. Extend the shared quiet-probe predicate to
cover the derived lane so a failing candidate cannot leak lane-task
diagnostics into the wizard TTY.
* improve(onboard): suppress subsystem console output during wizard live tests
Provider-transport subsystem loggers (model-fetch start/response, transport
errors) carry no run id, so probe suppression cannot catch them and a failing
candidate printed raw log lines into the Clack TTY. Reuse the TUI console
subsystem-filter seam via a finally-safe scoped helper around guided
activation and the classic live-verify; file logging is unchanged and the
gateway (macOS app) surface is unaffected.
* fix(onboard): never auto-replace a configured model when its live check fails
The re-run verification probe executes outside the configured workspace (setup
never runs workspace plugins), so a workspace-backed current model can fail
the check while working fine in the agent. Stop the auto ladder on an
existing-model failure and hand the decision to the manual stage instead of
silently persisting a different candidate as the default. Docs note the
fail-safe and the workspace caveat.
* feat(onboard): two-way switching between Crestodian chat and the menu wizards
From the chat, `open setup wizard`, `open classic wizard`, and `open channel
wizard for <channel>` hand off to the guided flow, the classic wizard, or the
masked `channels add` wizard after the chat TUI tears down (mirrors the
open-tui handoff; gateway surface gets a text pointer instead). The hosted
channel wizard no longer dead-ends at sensitive steps — it offers the switch
and remembers the channel. New read-only `channel info <channel>` operation
and ring-zero action surface label, blurb, configured state, and the real
docs URL from channel-setup discovery so the assistant can explain Slack or
Telegram prerequisites instead of guessing; both prompts instruct it to use
them. `channels add --channel <id>` now preselects the channel. Docs cover
the interchangeable flows.
* fix(onboard): avoid param reassignment in open-setup handoff
* improve(onboard): separate ask-about vs connect intent in channel prompt guidance
Live test showed the agent detouring an explicit connect request through
channel_info because the guidance said to consult it first. Both prompts now
distinguish asking about a channel (channel info + docs link) from asking to
connect (connect right away).
* fix(channels): mark channel token entry as sensitive input
The shared single-token prompt lacked sensitive:true, so terminal wizards
echoed pasted channel tokens and the Crestodian chat bridge (which refuses
plain-text secrets based on this flag) hosted the Telegram token step in
visible chat. Found live-testing the chat-to-wizard switch; pre-existing on
main but load-bearing for the masked-wizard contract this PR documents.
* fix(onboard): restore terminal state around the guided flow's TUI launch
Mirror the classic finalize handoff so the chat TUI never inherits the wizard
prompter's raw/paused terminal state on the default first-run path.
* fix(channels): type the token prompter mock for the sensitive-flag assertion
* fix(gateway): map the TUI-only open-setup action to none for app clients
Engine-side surface gating already prevents open-setup replies on the gateway
surface; this keeps the client-visible action enum stable even if that gate
ever regresses. (Reviewed with the switching round; missed in its commit.)
* docs: regenerate docs map for onboarding page changes
* fix(nodes): defer and back off remote bin probes
* chore: leave release changelog ownership centralized
* fix(nodes): probe the live post-pairing surface
* fix(nodes): retry probes after reconnect
* fix(nodes): bind probes to live connections
* test(skills): isolate remote bin signature configs
* test(skills): place remote skills under workspace root
* style(skills): satisfy probe delay lint
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(google-meet): use truncateUtf16Safe for log value truncation
One .slice(0, 180) truncation site in the Google Meet extension
may cut UTF-16 surrogate pairs in half when the log value contains
multi-byte characters such as emoji. Replace it with
truncateUtf16Safe to keep the truncated output valid Unicode.
* test(google-meet): cover UTF-16 model log boundary
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(migrate-claude): use truncateUtf16Safe for skill description truncation
One .slice(0, 180) truncation site in the migrate-claude extension
may cut UTF-16 surrogate pairs in half when the skill description
contains multi-byte characters such as emoji. Replace it with
truncateUtf16Safe to keep the truncated output valid Unicode.
* test(migrate-claude): cover UTF-16 skill description
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>