You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Chat: render in-bubble Allow/Deny approval banner + harden plumbing
Render gateway-emitted exec.approval.requested events as an interactive
banner in the chat composer (header + plain-English subtitle + monospace
command + caption + Allow/Deny buttons), matching the dashboard modal
experience but inline. Allow/Deny posts a /approve <slug> allow-once or
/deny <slug> slash command back to the gateway; the banner clears on
phase=resolved.
Feature
- ChatTimelineReducer: preserve PendingPermission across follow-on
tool item events (previously wiped ~1ms after set).
- OpenClawChatDataProvider: full approval lifecycle (map requested,
track id-asymmetry between approvalSlug and approvalId, clear on
positive request-id match only).
- OpenClawComposer + Resources.resw (en, fr, nl, zh-CN, zh-TW):
banner copy + Allow/Deny buttons.
Plumbing hardening
- Slash-command echo handling: pre-register /approve|/deny in the
local-echo queue when sent, suppress on our own echo, surface
remote-issued slashes as dim audit-trail status entries (instead of
rendering them as user bubbles). chat.history rebuild applies the
same audit rendering. FetchRemoteUserMessage filters slash commands.
- Slash matcher uses a strict regex
(^/(?:approve\s+[A-Za-z0-9_-]{4,64}(?:\s+allow-once)?|deny\s+...)$)
to avoid accidentally suppressing user text that starts with /approve.
- ClearPendingPermissionAndPublish takes an expectedRequestId so a
fresh approval that arrives between the user's tap and the post-send
clear is not stomped.
- Terminal-clear path inverted to clear only on positive id match;
empty or no-match -> preserve banner + log.
- Approval LRU is instance-scoped, cleared on disconnect; alt-id map
shares LRU eviction with the dedupe set.
- On RespondToPermissionAsync send failure: remove the pre-registered
slash entry from the local-echo queue so it doesn't block subsequent
echo consumption for 30s.
- IChatGatewayBridge: subscribe-first-then-reconcile ctor pattern with
an idempotent Disconnected seed so an in-flight Connecting edge is
preserved.
Content-block seam repair
- Tighten the s_seamSentencePunct regex to require a multi-char
trailing Pascal word AND a non-EOS terminator
((?<=[a-z0-9][.!?:])(?=[A-Z][a-z]+[\s,;:!?])). Eliminates a class of
false positives where the regex was shredding identifiers like
Path.Combine and System.IO.File. Add ContentBlockSeamRepairTests
with both positive and negative fixtures.
- char.ToUpper -> char.ToUpperInvariant on agent labels in
OpenClawChatRoot to keep label casing stable across locales.
Tests
- ContentBlockSeamRepairTests (new): positive seam-repair cases from
real Sonnet/Opus captures + negative EOS fixtures.
- ChatTimelineReducerTests, OpenClawChatDataProviderTests,
ToolMetaCacheTests: extend coverage of new lifecycle paths.
ProgressPage.xaml.cs: minor unrelated tidy that was on the branch.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix nullability warnings in OpenClawChatRoot after warning-clean-build enforcement
Master enabled TreatWarningsAsErrors (commit 6bbc74b "eng: enforce
warning-clean builds"). After merging master, the existing
`effectiveThread.Id` usage in the composer construction and its lambda
callbacks tripped CS8604 because `ChatThread.Id` is typed `string?`
even though the surrounding `effectiveThread is not null` guard
implies it's safe to access.
Add `!` null-forgiving operators to `effectiveThread.Id` in the
composer props (ChannelId, synthetic ChannelGroup Sessions entry) and
in the OnSend/OnStop/OnPermissionResponse/OnModelChanged/
OnThinkingLevelChanged/OnPermissionsChanged callbacks so the build
stays clean under the new warning-as-error policy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Salt ChatTrace hash with per-process random seed
The [ChatTrace] log line included a stable FNV-1a hash of every chat
message so two near-duplicate frames could be told apart while hunting
the duplicate-bubble bug. ClawSweeper flagged that a stable content-
derived hash is itself a content fingerprint: anyone with the log can
rainbow-table common short messages back to their hash and confirm
what was sent.
Keep the diagnostic by seeding FNV-1a with a per-process random uint
from RandomNumberGenerator. Within one tray run, identical text still
collides (so duplicate-frame detection still works), but the hash is
not reproducible from a guessed plaintext and rotates on every restart.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Move chat permission approval UI into the timeline
Approval requests previously rendered as a floating bubble pinned above
the composer, which made them disappear from history once resolved and
made it impossible to scroll back to confirm what was approved/denied.
This change folds the approval flow into ChatTimelineReducer so each
request becomes a real ChatTimelineItem alongside user/assistant/tool
entries.
Reducer changes (OpenClaw.Chat):
- New ChatTimelineItemKind.PermissionRequest and ChatPermissionDecision
enum (Pending/Allowed/Denied/Expired).
- ApplyPermissionRequest expires any prior Pending entries, appends the
new request, and sets PendingPermission. Empty/whitespace RequestId
events are dropped to avoid orphaning a Pending entry whose buttons
are permanently disabled.
- ResolvePermission stamps the matching entry without downgrading an
already-decided one (gateway backstop events can't clobber a local
Allow/Deny click). Mismatched RequestId is a no-op for both entries
and PendingPermission.
- ClearPermission delegates to ResolvePermission(Expired).
WinUI changes:
- RenderPermissionEntry in OpenClawChatTimeline renders the live bubble
(Allow/Deny buttons) and decided badges (Allowed / Denied / Expired)
inline. Decided detail is truncated at 120 chars with surrogate-safe
boundary handling so emoji/CJK supplementary chars don't render as
U+FFFD.
- AutomationProperties.Name on Allow/Deny buttons and the decided badge
so screen readers hear 'Allow shell.exec' / 'Allowed run script.sh'
instead of bare glyphs. Omits the suffix when no IntentSummary is set
to avoid awkward 'Allow Approval needed' phrasing.
- OpenClawComposer no longer renders the floating bubble.
- OpenClawChatRoot's isEmptyConversation guard documents that the
pendingPermissionOverride check is now preview-only (live data always
has entries.Count > 0 when PendingPermission != null).
Localization:
- Added Chat_Permission_DecisionAllowed/Denied/Expired keys in all five
locales (en-us, fr-fr, nl-nl, zh-cn, zh-tw).
Tests: +ResolvePermission_MismatchedRequestId_NoOp,
+ApplyPermissionRequest_EmptyRequestId_DroppedToAvoidOrphanedEntry,
and extended ResolvePermission_Denied_StampsEntry with a
PendingPermission null-assertion.
Validated: ./build.ps1, Shared 2023/29 skipped, Tray 897/0.
Addresses ClawSweeper feedback on PR #567 plus two rounds of
adversarial code review (Opus 4.6 + Sonnet 4.6).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Nudge ClawSweeper
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0 commit comments