* feat(ui): redesign dashboard chrome with tiny top bar and sidebar search
Move the sidebar toggle to the top bar as a macOS-style panel button
(collapse on desktop, drawer on tablet/mobile), move search into a
sidebar field that opens the command palette, and move the color-mode
toggle into the sidebar footer. Shrink the top bar to 44px, make the
terminal toggle a quiet ghost button, and drop the shadow plate behind
the macOS titlebar brand mark so the transparent mascot renders bare.
Adds the missing common.colorModeOption i18n key (theme buttons were
announcing the raw key) and removes the dead theme-orb styles.
* fix(ui): translate common.colorModeOption across locale bundles
The i18n sync initially recorded English fallbacks for the new key,
which the ships-no-recorded-English-fallbacks gate rejects. Regenerated
with a real translation provider; all 20 locales now carry translated
values (fallbacks=0).
* refactor(ui): unify the topbar sidebar toggle into one button
One button drives both modes: rail collapse on desktop and the
slide-over drawer at the ≤1100px breakpoint, decided via matchMedia
(with the legacy addListener fallback used elsewhere in bootstrap).
Replaces the previous pair of CSS-swapped buttons.
* ci(mantis): add web ui chat proof lane
* ci(mantis): tighten web ui proof candidate parsing
* ci: tighten Mantis Web UI proof lane
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
sessions.delete gains an explicit archivedOnly param (additive protocol
schema change, Swift models regenerated): with archivedOnly=true, the
dispatcher grants operator.write and the handler requires the target to
already be archived (archive-then-delete keeps destructive intent a
two-step action). Without the flag nothing changes: deletes require
operator.admin, so internal fallback/synthetic dispatch, subagent cleanup,
and CLI minting keep their admin contracts, and the session-kill HTTP
endpoint pins admin explicitly since it terminates live runs.
Android sends archivedOnly and offers Delete only on archived rows, where
its bounded (non-admin) operator session is now authorized; active rows
archive first. iOS/web connect with admin and keep unrestricted deletes.
Refs #100712
* fix(backup): close archive stream before retry cleanup
Own the tar source and file writer with stream.pipeline so live-file EOF failures close the partial archive before Windows cleanup. Keep one native Windows handle-release regression and focused CI coverage.
Fixes#101382
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
* test(backup): track archive retry temp directory
* test(backup): model tar archive streams
* test(backup): model retry cleanup streams
---------
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
- Raise typing-breaker default from 2 to 5 consecutive failures via a
named constant, keeping explicit overrides intact.
- Extend rich-plain-fallback trigger map to classify
RICH_MESSAGE_CONTENT_REQUIRED alongside existing invalid-entity
errors so both durable and streaming send funnels benefit.
- Add empty rendered-rich-HTML guards before sendRichMessage in both
the durable chunk loop (send.ts) and the streaming delivery funnel
(delivery.send.ts), preventing doomed Bot API calls and preserving
later valid chunks.
- Add regression tests for the default typing breaker, delivery-side
and durable-side RICH_MESSAGE_CONTENT_REQUIRED fallback behavior.
* @
fix(status): surface auto-fallback model in status and session_status (#96126)
When a session falls back to an alternate model via auto-fallback
(modelOverrideSource: "auto"), both `openclaw status` and `session_status`
silently showed the active fallback model without indicating it differs
from the configured primary. The mismatch gate used
hasUserPinnedModelSelection() which returns false for auto-fallback.
- status.summary.ts: widen mismatch gate from hasUserPinnedModelSelection
to entry?.modelOverride != null; emit distinct "fallback selected"
reason alongside existing "session override"
- status.command-sections.ts: add fallback-specific wording ("auto
fallback" / "check provider availability") while keeping the
modelSelectionReason filter intact (no false-positive null-reason rows)
- status-message.ts: add sessionHasAutoFallback detection for the
session_status RPC path; show "auto fallback" / "check provider" label
instead of "pinned session" / "clear /model default"
Co-Authored-By: Claude <noreply@anthropic.com>
@
* fix(status): narrow fallback detection to real fallback provenance
Replace entry?.modelOverride != null with
hasSessionAutoModelFallbackProvenance(entry) to avoid mislabeling
configured subagent automatic model selections as provider fallback.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(status): distinguish configured models from fallback
Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(gateway): persist agent request transcript media
Route inline and offloaded agent.request images through the canonical user-turn transcript recorder across embedded, CLI, and ACP runtimes. Share ordered media persistence with chat.send and cover media-only empty-reply turns.
Co-authored-by: Petros Dhespollari <info@peterdsp.dev>
* fix(gateway): avoid transcript media shadowing
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(anthropic): resolve thinking as disabled when legacy budget is below 1024
When adjustMaxTokensForThinking collapses the thinking budget below the
Anthropic minimum (1024), option resolution now sets thinkingEnabled to
false instead of always forcing it to true. This keeps every downstream
consumer (payload, replay, temperature, tool-choice) consistent — they
all see the same disabled state instead of an enabled flag with a
missing or API-rejected thinking block.
|| → ?? in both builders is defensive: the resolution layer already
prevents invalid budgets from reaching the builder through the normal
path, but ?? preserves an explicit zero when the builder is called
directly.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(anthropic): guard raw streamAnthropic builder path against sub-minimum budgets
Add budget guards in both Anthropic payload builders so direct
streamAnthropic and bundled-plugin callers (e.g. Mantle) that bypass
option resolution also get the disabled-state rule instead of producing
API-rejected { type: "enabled", budget_tokens: < 1024 } requests.
Add proof-anthropic-thinking-budget.mts driving real production
functions with terminal output and negative control.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(anthropic): normalize legacy thinking budgets
Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(memory-host-sdk): handle stdout/stderr stream errors in runCliCommand
Register error handlers on stdout and stderr streams in
runCliCommand() to prevent uncaught exceptions when a pipe
breaks (e.g. EPIPE after child process exit).
Without these listeners, Node.js throws an uncaught exception
that crashes the process.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(memory-host-sdk): extract listenForChildOutputErrors helper
Refactor the inline stream error handling into a reusable
listenForChildOutputErrors helper, matching the pattern
established in the merged #101370 (agent-core).
The helper registers error listeners on stdout/stderr via a
shared loop, keeping the pattern consistent across the codebase.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(memory-host-sdk): harden qmd stream failures
* fix(memory-host-sdk): harden qmd stream failures
* docs(changelog): note qmd stream hardening
* chore: keep release changelog out of contributor PR
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>