* fix(cron): accept null fallbacks in cron update patch payload
createCronPatchObjectSchema passes nullableStringArraySchema for model and
toolsAllow, but fallbacks was still hardcoded as a non-nullable array in
cronPayloadObjectSchema, rejecting null clears before they reach the
Gateway service layer.
Switch fallbacks to a parameter so the patch context can pass the nullable
variant, matching the existing pattern for model and toolsAllow.
Fixes#100707
Co-Authored-By: Claude <noreply@anthropic.com>
* test(cron): cover model+fallbacks null clear in patch schema test
---------
Co-authored-by: Claude <noreply@anthropic.com>
Gateway (additive, no protocol version bump): SessionEntry gains
lastReadAt/markedUnreadAt/lastActivityAt; session rows expose a derived
unread flag (explicit mark, or last read before latest activity; never-read
sessions stay read so upgrades do not light up). lastActivityAt is stamped
in the canonical post-run store update - user, channel, and cron runs count
as activity; heartbeat, internal-event, and preserved-state runs do not.
sessions.patch gains unread; sessions.create gains fork (transcript fork
from parentSessionKey under the parent lifecycle lock, refusing active,
concurrently-changed, and oversized parents, cross-agent aware).
Web sidebar: Pinned/custom-group/Ungrouped sections, unread dots, kebab and
right-click context menu (pin, mark unread/read, rename, fork, move to group,
archive, delete guarded for agent main sessions and active runs), mark-read
on view with loop-safe re-acknowledgement and failure retry; sessions page
gets unread + fork actions and shared custom-group helpers.
iOS Command Center: grouped sections, unread/pin indicators, Show Archived
gated on per-entry state, full context menu with rename/new-group alerts and
delete confirmation, current-session preview guarantee, read-episode
re-acknowledgement; new patch/delete/fork transport calls; Swift protocol
models regenerated.
Android SessionsScreen: grouped headers, unread/pin indicators, Archived
filter gated on per-entry state, long-press menu with the full control set,
agent-scoped forks, explicit label/category clears from session events,
main-session fallback when archiving/deleting the open chat, read-episode
re-acknowledgement with failure retry.
Closes#100739
* fix(auto-reply): warn when /export-session only contains user messages (backend-delegated)
Closes#90844 (minimum-fix option 2).
When a session is driven by a CLI/ACP backend, OpenClaw's own transcript only
records the inbound user messages. /export-session would still produce a
successful HTML export with empty summary stats and no assistant/tool/usage
data, which is misleading.
This change detects the backend-delegated case (a transcript whose message
entries are exclusively role: user) and surfaces a clear warning in the command
reply text and the exported HTML header.
* fix(auto-reply): correct template literal closure in export session HTML
* fix(auto-reply): warn on backend-delegated session exports
* fix(session): harden backend export warning
* fix(session): read persisted ACP export metadata
* fix(session): keep ACP metadata lookup best-effort
* fix(session): avoid shadowed export locals
* test(session): type export store mock
---------
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
* feat: correlate native search outcomes in audit history
Metadata-only audit ledger for agent runs and tool actions in the shared
state DB: stable event identity, closed action/status/error vocabularies,
one-way-hashed tool-call ids, never-inferred terminal outcomes for native
web-search (explicit completed/failed only; otherwise unknown), bounded
retention, audit.list gateway RPC and openclaw audit CLI. Squashed from
the 82-commit audit stack for replay onto current main.
* feat(audit): add audit.enabled config gate (default on)
The metadata-only audit ledger records by default: an audit trail enabled
only after an incident cannot explain the incident, and the rows are
strictly less sensitive than the transcripts every install already
stores. audit.enabled=false stops new writes at the gateway subscription
seam; audit.list and openclaw audit keep serving existing records until
they expire. Documented in the configuration reference, protocol page,
and CLI reference.
* fix: repair full-matrix CI findings after rebase
- break the dynamic-tools/dynamic-tool-execution import cycle by
extracting resolveCodexToolAbortTerminalReason into a leaf module
- restore main's session-worktree protocol exports lost in the
index.ts auto-merge
- register the audit event writer worker as a knip entry point
- docs table formatting; subagent wait-cancellation test scoped to its
audit intent (outcome + timing) and advanced past main's new
lifecycle-timeout retry grace
* fix: release stale reply work during reset cleanup
* fix: release archived reply runs during reset
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* [AI] fix(memory): add batch completed and batch failed logs for embedding ops
The embedBatchWithRetry function logged 'batch start' but never logged
'batch completed' or 'batch failed' after the embedding batch call,
leaving operators with no post-request feedback. When batches hang or
time out, only 'batch start' appears in logs with no diagnostic signal.
Add 'batch completed' log after runEmbeddingOperationWithTimeout success
and 'batch failed' log in the catch handler. This is an observability
improvement, not a functional fix for the underlying hang (#93312).
Related to #93312
* [AI] fix(memory): use formatErrorMessage for embedding batch error log
Replace String(err) with formatErrorMessage(err) in the batch failed
catch handler to redact sensitive provider error text (e.g. API keys
and tokens embedded in error messages) before logging.
Related to #94732
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>