* fix(telegram): use truncateUtf16Safe for raw update log truncation
* refactor(telegram): own raw log bounds in formatter
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(active-memory): use truncateUtf16Safe for log value truncation
* fix(active-memory): use truncateUtf16Safe for log value truncation
* test(active-memory): cover UTF-16-safe log limits
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(tts-local-cli): handle stdout/stderr stream errors in speech provider
CLI TTS speech provider spawns a child process to generate audio and
registers stdout/stderr data listeners but omits stream error handlers.
stdout carries synthesized audio data. A pipe error mid-generation must
reject the promise so the caller does not silently receive truncated
audio when the child later exits zero. stderr carries diagnostic logs
only — errors there are benign and should not crash the provider.
Apply separate strategies matching vincentkoc's requirement:
- stdout (audio): error → reject(Promise) — surface the failure
- stderr (diagnostic): error → ignore — does not affect audio output
* fix lint: remove unused signal param from mock kill()
* fix(tts-local-cli): contain child stream failures
Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>
* chore(tts-local-cli): keep release notes in PR body
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(diagnostics-prometheus): use truncateUtf16Safe for error message truncation
The safeErrorMessage function uses naive .slice(0, 500) on error messages
which can split surrogate pairs. Replace with truncateUtf16Safe().
* test(diagnostics-prometheus): cover UTF-16-safe errors
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(codex-supervisor): use truncateUtf16Safe for stderr tail truncation
StdioCodexJsonRpcConnection includes stderr output in the transport-closed
error message with a naive .slice(0, 1200) which can split surrogate pairs.
Replace with truncateUtf16Safe().
* test(codex-supervisor): cover UTF-16-safe stderr tails
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(ui): keep workboard capture text truncation UTF-16 safe
Replace raw .slice(0, N - 3) with truncateUtf16Safe in
clampSessionCaptureText and clampSessionCaptureTitle to prevent
lone surrogates when emoji cross the truncation boundary.
Completes the UTF-16 hardening started in #101685, which added the
import but only covered buildCardSessionLabel.
* test(ui): cover workboard UTF-16 boundaries
* docs(changelog): note Workboard UTF-16 fix
* docs(changelog): leave release notes to release flow
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(mac): unified Liquid Glass pairing approval panel
Replace the serial node/device pairing NSAlerts with one floating
approval panel. Both prompters feed request cards into a shared
PairingApprovalCenter; each card shows a hardware icon, platform and
model, app/core version, source IP, a copyable short id, request age,
a trust line (first connection / already-paired-id caution / repair
token rotation), and a friendly access summary with an elevated
warning for system.run-class commands. Requests resolved elsewhere
disappear live; Not Now snoozes without resolving (gateway TTL
applies) and the menu-bar pending line reopens the panel. Liquid
Glass surface on macOS 26+, material fallback on macOS 15. Deletes
the NSAlert + invisible-host-window machinery, dead node isRepair
handling, and text-only describe() body.
Closes#102535
* fix(mac): satisfy swiftformat conditionalAssignment and resync native i18n inventory
Session-scoped tool-result projection freeze (shrink-only, stable
fallback identities for ambiguous tool ids) and a sent-watermark so
late-resolving inbound media appends a new user turn instead of
rewriting an already-sent slot. Stops Anthropic prompt-cache tail
invalidation on busy/media-heavy embedded sessions.
* feat(ui): add session context menu to sessions page rows
Extract the sidebar session menu into a shared <openclaw-session-menu>
component and open it from a kebab button or row right-click on the
Sessions page, replacing the per-row unread/fork/pin/archive/workboard
icon buttons. Adds Open chat, Rename, Move to group, and per-row Delete
to the page; guards (main/global/active-run) now flow through
canArchiveSessionRow on both surfaces.
* fix(ui): retarget gateway session after deleting the current session from the sessions page
Deleting the currently selected session via the new row menu (or the
bulk bar) left gateway.snapshot.sessionKey pointing at the deleted key;
fall back to the agent main session, mirroring the archive path and the
sidebar delete path.
* fix(logging): use truncateUtf16Safe in diagnostic log text clamp
Replace naive .slice(0, maxChars) with truncateUtf16Safe() in
clampDiagnosticLogText() — the core helper used by all diagnostic
log output (sanitizeDiagnosticLogText, formatDiagnosticAttributes,
etc.). This prevents surrogate pair splitting across the entire
diagnostic logging subsystem.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(logging): preserve UTF-16 in bounded log text
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(ui): keep streamed talk voice-turn transcripts readable
Talk voice turns collapsed to one character per line in the macOS app
(WKWebView) while streaming: WebKit never re-runs shrink-to-fit intrinsic
sizing for a grid flex-item as its content grows, so the turn froze at
first-delta width. Convert the turn to a flex row (same visual layout).
Assistant transcript deltas also merged through the user-ASR word-boundary
spacing heuristic, mangling verbatim fragments ("Chat G PT"). Assistant
entries now concatenate fragments verbatim, space only sentence-punctuation
joins, and accept both full-transcript and tail-fragment finals.
Fixes#102556
* fix(ui): keep assistant talk fragments strictly verbatim
Drop the sentence-punctuation separator: it invented characters in real
content (Version 1. 2, docs.openclaw. ai) and Google Live tail-finals
could never heal it. The punctuation-spacing heuristic remains user-only.
* fix(mistral): use truncateUtf16Safe for error text truncation
Replace naive .slice(0, maxChars) with truncateUtf16Safe() in
truncateErrorText() to prevent surrogate pair splitting in
Mistral provider error messages shown to users.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ai): keep Mistral errors UTF-16 safe
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>