Default `openclaw status --json` stays on the lean health-probe path while preserving the JSON task summary, local update/install metadata, explicit probe timeouts, and configured gateway handshake timeouts. Deeper memory, registry, remote git, and local status-RPC diagnostics remain behind `status --json --all`.
Also keeps generated diffs viewer output in its built form and ignores it in oxfmt so `pnpm build` leaves a clean tree.
Proof:
- `node scripts/run-vitest.mjs src/commands/status.scan.fast-json.test.ts src/commands/status-json-payload.test.ts src/commands/status.scan.shared.test.ts`
- `OPENCLAW_LOCAL_CHECK=0 node scripts/run-oxlint-shards.mjs --threads=8`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub checks green for head `47a63f87ea7c2351994fdb71e8cc18041aa0b64e`
Thanks @andyylin.
Co-authored-by: Andy <andyylin@users.noreply.github.com>
Forward canonical inbound media metadata to plugin message_received hooks so plugins can inspect the same mediaPath, mediaUrl, mediaType, mediaPaths, mediaUrls, and mediaTypes fields already available to inbound_claim.
Verification:
- node scripts/run-vitest.mjs src/hooks/message-hook-mappers.test.ts
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main
Refs: https://github.com/openclaw/openclaw/pull/87297
Co-authored-by: WarrenJones <8704779+WarrenJones@users.noreply.github.com>
Stop heartbeat runs from directly returning non-ack durable pending final text. Heartbeats now only clear ack-only pending state and otherwise continue the heartbeat turn, so stale prior final answers cannot be replayed through a later heartbeat/default route.
Keep the isolated heartbeat active-run guard so an immediate/manual heartbeat cannot overwrite an isolated heartbeat session that is still running.
Proof:
- node scripts/run-vitest.mjs src/auto-reply/reply/get-reply.fast-path.test.ts src/infra/heartbeat-runner.skips-busy-session-lane.test.ts
- git diff --check
- autoreview --mode local
- autoreview --mode branch --base origin/main
- GitHub CI 26543804437, CodeQL 26543804438, Critical Quality 26543804441, OpenGrep PR Diff 26543804440 rerun job 78197443511, Real behavior proof 26544027357
Refs #74257.
Co-authored-by: kesslerio <martin@kessler.io>
Stabilize isolated cron prompt cache affinity by deriving a stable prompt cache key per cron job/session/model and forwarding it separately from the rotating run session id.
Thread the key through embedded runs, stream resolution, provider options, proxy forwarding, custom streams, and prompt-cache observability. Keep OpenAI-compatible payloads valid by using hyphen-safe keys, clamping upstream prompt_cache_key values, and omitting affinity when cache retention is disabled.
Thanks @ferminquant.
Co-authored-by: Fermin Quant <ferminquant@hotmail.com>
Rewrites non-canonical api_key fields in auth-profiles.json to canonical key via openclaw doctor --fix, with backups, while preserving canonical key/keyRef credentials and active-agent auth stores.
Fixes#57389.
Co-authored-by: alkor2000 <200923177@qq.com>
* fix(sessions): preserve Matrix room-id case in session keys (#75670)
Matrix room IDs (and thread event IDs) are opaque, case-sensitive per the
Matrix spec, but session-key canonicalization lowercased them. That forked
one room into duplicate sessions and produced 403 M_FORBIDDEN on recovery /
delivery paths that reconstruct the target from the (lowercased) session key,
even though deliveryContext.to stayed correct.
Introduce a generic, opt-in case-preservation registry (CASE_PRESERVING_PEERS)
consulted at all three lowercasing sites:
- construction: normalizeSessionPeerId
- store canonicalization: normalizeSessionKeyPreservingOpaquePeerIds
- gateway send: explicit request.sessionKey
Signal group preservation is encoded to match prior behavior exactly (segment
span, unscoped, thread suffix still lowercased). Matrix channel/group enrolls
the opaque tail (room id with embedded :server + any 🧵<event> suffix).
Exact mixed-case keys now win over folded legacy aliases in
resolveSessionStoreEntry and delivery-info lookup; existing lowercased rows
collapse on the next write. Matrix DM/MXID and non-enrolled channels keep the
default lowercase behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(sessions): guard Matrix folded alias delivery proof
* test(agents): cover cold OpenAI gpt-5.5 fallback
* fix(sessions): preserve non-opaque alias freshness
* fix(sessions): prevent Matrix cross-room thread recovery
* build(protocol): refresh tools effective Swift models
* test(codex): include effective cwd in startup fixture
* test(codex): align startup failure cleanup expectation
* fix(sessions): keep Signal folded aliases fresh
* fix(sessions): preserve unscoped Matrix room keys
* fix(sessions): recover legacy Matrix thread aliases
* fix(sessions): preserve Matrix keys in state migrations
* fix(sessions): keep Matrix structural alias freshness
* fix(sessions): preserve unscoped Matrix migration keys
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fix iMessage native exec approval routing so approval prompts bind to the sent GUID without duplicate sends after RPC timeout. Also keeps chat.db GUID recovery on the local imsg path while avoiding local DB recovery for configured or detected SSH wrappers.
Thanks @kevinslin.
Avoid stale restart continuation reuse after a session key has rotated.
Queued restart agent turns now carry the session id they were queued for and fall back to a system wake if the key points at a different session by delivery time. Normal completed-run lifecycle fields stay reusable for fresh sessions, while new-session creation clears stale lifecycle markers.
Closes#86593.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Closes#87210.
Gateway probe now waits for GatewayClient.stopAndWait() before resolving so callers do not observe a successful probe while the client socket is still draining. If the drain fails, probe falls back to stop().
Adds mocked probe coverage plus a real WebSocket regression test that verifies no client socket handle remains when probeGateway() resolves.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Show active subagent detail rows in /status with labels and elapsed runtime while keeping completed-subagent summary behavior. Thanks @simplyclever914.
Fixes#83935.
Summary:
- clear stale legacy openai-codex auto route pins only when the canonical OpenAI provider is still using the Codex harness for the same model
- preserve usable Codex auth profiles while clearing stale route state
- keep explicit/custom OpenAI API route pins intact
Verification:
- git diff --check
- pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/model-selection.ts src/auto-reply/reply/model-selection.test.ts src/auto-reply/reply/agent-runner-execution.ts src/auto-reply/reply/agent-runner-execution.test.ts
- fnm exec --using 24.15.0 node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
- .agents/skills/autoreview/scripts/autoreview --mode local
- CI: https://github.com/openclaw/openclaw/actions/runs/26542490863
Co-authored-by: Paul Frederiksen <paul@paulfrederiksen.com>
Fixes#87191. Keeps Brave and Gemini runtime-injected web search provider config readable by providers without re-exposing legacy tools.web.search provider objects to config validation.
Fix Slack draft cleanup after final-visible delivery.
Track when Slack has already delivered a visible final reply and stop reusing the draft finalizer for later same-turn final/error payloads. This keeps the first fallback cleanup for transient previews while preventing late cleanup from deleting a visible answer.
Fixes#87363
Co-authored-by: tianxiaochannel-oss88 <tianxiaochannel@gmail.com>
The compaction retry loop checked the delivery-timeout deadline before
choosing a fixed backoff delay, then slept that whole delay. When the
remaining window was shorter than the next backoff entry, the final
retry could sleep past the deadline, overrunning the delivery timeout
the retry is meant to stay within. Clamp the wait to the remaining
window (min(scheduledDelay, deadline - now)) and stop retrying once no
time remains, so compaction waiting never exceeds the delivery timeout.
Addresses the near-deadline overrun raised in ClawSweeper review of #86606.
Follow-up to #85489. Active requester steering treated a `compacting`
outcome from queueEmbeddedPiMessageWithOutcome as a terminal wake
failure and fell through to the requester-agent/direct fallback, even
though the active run becomes steerable again as soon as compaction
finishes.
Introduce a shared resolveActiveWakeWithRetries helper used by both the
steer path (maybeSteerSubagentAnnounce) and the generated-completion
active wake (sendSubagentAnnounceDirectly). The helper treats
`compacting` as transient and waits through compaction, retrying the
same wake. Waiting is bounded by the active wake's delivery timeout (not
just the backoff schedule): the backoff schedule controls the gap
between attempts, and once it is exhausted its last delay is reused until
the delivery deadline, so a compaction that finishes after the schedule
but within the delivery timeout still re-steers. The best-effort
transcript-commit retry and the compaction retry share one loop, so a
run that compacts and then reports transcript_commit_wait_unsupported
still gets the best-effort retry. Other wake failures keep their
existing single-attempt fallback.
Fixes#86566