Make Workboard cards compact by moving expanded task/run metadata, proof, diagnostics, worker logs, automation, protocol state, events, and operator notes into a detail drawer.
Keep execution state simple and safe: active, linked, and archived cards avoid duplicate start paths; stale task cache is ignored when session lifecycle is authoritative; recent proof/events stay visible; dispatcher capacity distinguishes unclaimed review cards from claimed cards.
* fix(cron): include job name in single-job run history
The cron.runs gateway handler enriches log entries with jobName in the all-jobs scope, but the single-job scope did not pass any job-name lookup into the SQLite run-log reader. Entries returned for one job could therefore reach Control UI without jobName, making the run-history title fall back to the raw job id.
Build a one-entry jobNameById map for the current job and pass it through the same reader enrichment path used by all-jobs history. If the job no longer exists, the map stays undefined and existing fallback behavior is unchanged.
* test(cron): cover single-job run history job name enrichment
Asserts that readCronRunLogEntriesPage stamps a supplied jobNameById map onto single-job page entries, matching the gateway data shape used for both all-jobs and single-job cron.runs responses.
Addresses review feedback on #88294.
* test(cron): preserve nullable tool schema validation
* test(cron): assert runtime nullable tool schema
* test(cron): refresh prompt snapshots
---------
Co-authored-by: Kip Claw <kip@kipclaw.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Routes Mattermost send attachments through the upload path so local file paths and structured attachment media are uploaded instead of being posted as plain text. Preserves scoped media access for local uploads, rejects unsupported or ambiguous attachment payloads, and keeps HTTP media fallback behavior.
Fixes#87930.
Proof:
- autoreview clean
- node scripts/run-vitest.mjs extensions/mattermost/src/channel.test.ts extensions/mattermost/src/channel.message-adapter.test.ts extensions/mattermost/src/mattermost/send.test.ts src/infra/outbound/message-action-params.test.ts src/infra/outbound/outbound-send-service.test.ts src/infra/outbound/message-action-runner.media.test.ts src/media/load-options.test.ts
- pnpm prompt:snapshots:check
- GitHub Actions completed with no pending/failing checks for head 2a65cbb1ee
Fail closed when bundled trusted tool policy registry, registration, owner id, evaluation, or decision reads fail, so malformed trusted-policy state cannot crash diagnostics or accidentally allow a tool call.
Route before-tool-call diagnostics through guarded trusted-policy readers and keep healthy no-op policy behavior unchanged.
Add focused host-hook contract and before-tool-call e2e coverage for the new fail-closed paths.
PR: #88394
HTTP auth challenges (basic, digest, negotiate) only fire the browser's
native credentials dialog when the response comes straight from the
network. Service worker responses bypass the WWW-Authenticate flow, so
reverse-proxy deployments with HTTP auth in front of the gateway show
a bare 401 after the browser's HTTP-auth memory cache expires (e.g. on
full browser restart) — forcing users to clear site data to recover.
Skip event.request.mode === "navigate" so the browser handles those
requests natively. Offline navigation of the app shell is lost, but
the SPA cannot function without network (all API calls go to the
network), so the trade-off is acceptable.
Refs: #85939, #71669, #53274
Adds broad inline comments and JSDoc for CLI, cron, outbound/channel, plugin SDK, ACP, shared helpers, net policy, and related utility contracts. Proof: git diff --check on latest exact head plus focused cron tests passed; CI had no failing checks observed before merge attempt.
Fixes#88521.
Expose finalized inbound reply metadata on plugin-visible hook payloads so before_dispatch and message hooks can implement reply-aware behavior without channel-specific workarounds.
Return unknown config.schema.lookup paths as an in-band agent gateway tool result instead of throwing into channel warning surfaces.
The direct gateway RPC still reports INVALID_REQUEST, preserving the existing protocol contract, while the agent-facing gateway tool returns schema_path_not_found for exploratory misses.
Fixes#88813.
Thanks @ksj3421.
Reported by @cjalden.
* test(agents): include Ollama in small live model matrix
* test: avoid Ollama cloud key in local live runs
* test: recognize Ollama env secret refs
* test: type Ollama live key fixtures
* test: prevent Ollama cloud auth in local live probes
* test: preserve equivalent Ollama live credentials
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Make the iOS app a universal iPhone+iPad app by targeting device family 1,2 in the XcodeGen source of truth.
Update iOS docs and App Store metadata so user-facing copy no longer describes the app as iPhone-only.
Verification:
- git diff --check
- cd apps/ios && xcodegen generate
- xcodebuild -project apps/ios/OpenClaw.xcodeproj -scheme OpenClaw -configuration Debug -destination 'platform=iOS Simulator,id=410B81D3-784E-4A01-B69C-490B79EAFCEA' CODE_SIGNING_ALLOWED=NO build
- GitHub CI: Real behavior proof, macos-swift, macos-node, check-docs, preflight, security-fast, actionlint, no-tabs, dependency-guard, OpenGrep
Thanks @EmpX2025.
Restore TUI switch-back adoption for backgrounded visible chat-send runs by surfacing a bounded `chat.history.inFlightRun` snapshot.
The snapshot keeps the run id even when buffered text is empty or over budget, filters live text through the same projection path as streaming chat, scopes bare global history to the default agent, and excludes hidden internal agent runs.
Proof:
- node scripts/run-vitest.mjs run src/gateway/chat-abort.test.ts src/tui/tui-session-actions.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json
- pnpm --silent exec oxfmt --check src/gateway/chat-abort.ts src/gateway/chat-abort.test.ts src/gateway/server-methods/chat.ts src/tui/tui-session-actions.ts src/tui/tui-session-actions.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- CI: Real behavior proof, TUI PTY, dependency guard, OpenGrep precise diff, workflow sanity passed on PR head 2b8bf5f214.
Co-authored-by: William Liu <william@williamliu.ai>
Respect explicit PI/OpenClaw runtime policy when deciding whether Codex plugin diagnostics are actionable.
Diagnostics now use the resolved OpenAI route: intentional PI and custom OpenAI-compatible routes suppress only the missing `plugins.entries.codex` noise, while enabled/stale Codex policy still warns.
Proof: focused doctor/config/agent routing Vitest coverage, full lint, test types, dependency checks, isolated live doctor configs, autoreview clean, and GitHub CI green at c5a84de4ca.
Fixes#88706.
Co-authored-by: Elfka Toruviel <aeb31988340aa87b@toruviel.online>
Fixes#88333
Preserves contributor workspace contents when an attested workspace disappears or is partially regenerated, and clears OpenClaw-owned attestation state on delete/reset/uninstall.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Resolve gateway auth SecretRef targets in status deep audit.
The static secret target coverage now includes gateway auth and remote token/password keys for both status and security audit scans. Focused status/secret-target tests passed, Auto Review reported no actionable findings, and CI is running on rebased head 41b052a181.
Fixes#87815
* fix(config): skip state-dir dotenv values that are unresolved shell references
readStateDirDotEnvVarsFromStateDir accepted any non-empty value from the
state-dir .env file and passed it into the managed service env. When a value
contains an unresolved shell variable reference such as "${SUPERMEMORY_KEY}"
or "$MY_VAR", dotenv preserves the literal string. The value then reaches
the LaunchAgent/systemd wrapper as a single-quoted literal, so the credential
is never resolved.
Add containsUnresolvedShellReference() and skip any value matching
$IDENTIFIER, ${...}, or $(...) in parseStateDirDotEnvContent(). Real credential
values (e.g. "sm_abc123") are unaffected.
Fixes#88274
* fix(config): narrow shell-reference detector to whole-value patterns only
The previous /$[\w{(]/ regex matched any value containing $ followed by
a word character, which would incorrectly drop real credentials that merely
contain a dollar sign (e.g. a password like abc$2!xyz).
Replace with isUnresolvedShellReference() that only matches values whose
ENTIRE content is a recognised reference form:
- $VAR_NAME (simple reference)
- ${VAR_NAME} (brace-form reference)
- $(command) (command substitution)
Add a regression test that verifies dollar-bearing real secrets are kept.
* fix(config): use letter/underscore-anchored pattern to avoid matching dollar-numbers
$100, $2, etc. are NOT shell variable references — shell variable names must
begin with a letter or underscore. The previous /^$[\w_]/ would match them.
Change to /^$[A-Za-z_]\w*$/ so only genuine named-variable references like
$MY_VAR are rejected. Dollar-number sequences are now preserved.
* fix(daemon): drop stale systemd env-file refs for skipped state-dir dotenv keys
When a state-dir .env value is an unresolved shell reference ($VAR/${VAR}/$(cmd))
the parser skips it from the managed environment. A prior install could have
written that literal reference into gateway.systemd.env; because the skipped key
no longer appeared in the incoming env or the managed-key removal sets, the stale
literal survived re-stage and could override fresh inline Environment= values.
Surface the skipped shell-reference keys from the state-dir dotenv parser and add
them to the systemd env-file managed-key removal set so re-staging strips the
obsolete literal while preserving operator-only secrets that were never managed
via state-dir .env. launchd regenerates its env file wholesale, so it is
unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(config): skip quoted shell parameter dotenv refs
* fix(config): preserve lowercase dollar-prefixed dotenv literals
* fix(daemon): clear stale unresolved systemd env refs
* fix(daemon): avoid re-staging unresolved file env refs
* fix(daemon): drop unresolved file env refs inline
* fix(daemon): drop inline-and-file unresolved env refs
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Preserve the active per-plugin managed npm project when npm-backed install validation blocks a candidate after npm has already mutated local state.
This snapshots package.json, package-lock.json, and node_modules before managed npm installs, restores that exact project state on failed validation, and rolls back staged npm-pack archives so blocked pack installs do not leave candidate debris.
Validation:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/install.npm-spec.test.ts
- pnpm tsgo:core && pnpm tsgo:core:test
- node scripts/run-oxlint.mjs src/plugins/install.ts src/plugins/install.npm-spec.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub CI 26729255950
- Crabbox run_26e9f9f7591c
Thanks @zhuisDEV.
Co-authored-by: Brian <95547369+zhuisDEV@users.noreply.github.com>
Adds regression coverage for Google Vertex API-key model config planning when the credential comes from an env-backed auth profile. This keeps the planner-level guard around the Vertex static catalog rows that fixed#88816 on main.
Verification:
- `node scripts/run-vitest.mjs src/agents/models-config.applies-config-env-vars.test.ts extensions/google/provider-catalog.test.ts extensions/google/provider-models.test.ts`
- `./node_modules/.bin/oxfmt --check --threads=1 src/agents/models-config.applies-config-env-vars.test.ts extensions/ollama/src/stream.ts extensions/qa-lab/src/mantis/slack-desktop-smoke.runtime.ts extensions/qa-lab/src/mantis/telegram-desktop-builder.runtime.ts extensions/qa-lab/src/mantis/visual-task.runtime.ts`
- `git diff --check`
- `pnpm deadcode:dependencies`
CI note: PR CI had an unrelated `check-dependencies` failure for `ui/package.json: three`; the PR diff is one `src/agents` test file.
Refs #88816
Routes MiniMax OAuth device-code and token polling directly to account-hosted OAuth2 endpoints for global and CN regions, avoiding guarded-fetch cross-origin redirect body stripping. Keeps provider API base URLs unchanged and adds regression coverage for both endpoint pairs.
Proof: local minimax OAuth tests, oxfmt check, lint, autoreview clean, official MiniMax CLI/source check, live MiniMax endpoint probes, and CI run 26729242892 on 6bfe20eb06.
Co-authored-by: Matt Schleder <schledermatthew@gmail.com>
Fixes#88520.
Adds focused regression coverage for the embedded attempt trajectory recorder cleanup boundary so a stalled trajectory flush resolves after the cleanup timeout and logs pending write details instead of rejecting attempt cleanup.
Verification:
- node scripts/run-vitest.mjs src/agents/run-cleanup-timeout.test.ts
- git diff --check origin/main...origin/pr/88802
- PR CI green: https://github.com/openclaw/openclaw/actions/runs/26727232564
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Retire isolated cron session MCP runtimes on timeout and dispose so orphaned MCP servers do not accumulate after cron cleanup. Bound MCP session disposal to 5 seconds and force-close hung transports, including streamable-HTTP DELETE hangs, to prefer gateway availability over unbounded teardown.
Fixes#87821.
PR: #87981.
Proof: latest Real behavior proof check passed after body fix; local autoreview clean with focused cron/gateway/MCP tests covering 108 tests.
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
* refactor: move imessage monitor state to sqlite
* test: use OpenClaw temp root in iMessage state helper
* test: avoid pending promise lint in chat tests
* test: harden gateway ci flakes
* test: align session list merge expectation
Fixes#57376.
Hide placeholder agent store keys from sessions.list while preserving real agent-scoped sessions.
Co-authored-by: Alix-007 <li.long15@xydigit.com>
Preserve task and TaskFlow durability by persisting before in-memory registry mutation and surfacing explicit persistence failures instead of reporting fake success.
Adds non-throwing try-create runtime helpers while keeping existing throwing public create APIs compatible. Maintainer follow-up keeps task/TaskFlow sync repair bounded, prevents split task/delivery-state writes, and keeps CI green on the current base.
Thanks @Feelw00.
Roll both subagent token usage formatters over to the million unit when rounded thousands reach the next unit.
The original fix covers `formatTokenShort`, which feeds the subagent list usage line. The maintainer follow-up applies the same unit-boundary rule to compact subagent announcement stats, preserving that formatter's one-decimal style while preventing `1000.0k` output.
Verification:
- focused runtime probe for list and compact announce stats at 999,999 tokens
- `oxfmt --check` on touched formatter/test files
- `git diff --check origin/main..HEAD`
- `node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test-pr88209.tsbuildinfo`
- autoreview local closeout clean
- exact-head CI passed for Real behavior proof, check-test-types, check-prod-types, check-guards, security-fast, and preflight
Known unrelated current-main reds at merge: `check-lint`, `checks-node-agentic-gateway-methods`, and `checks-node-agentic-control-plane-agent-chat`.
Co-authored-by: coder999999999 <coder999999999@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Skip the generic DeepSeek V4 OpenAI-compatible `thinking` payload wrapper for Microsoft Foundry fallback models. Foundry's OpenAI-compatible gateway rejects the non-standard top-level `thinking` argument, while the rest of the DeepSeek proxy path still keeps the wrapper.
Proof:
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "node scripts/run-vitest.mjs src/agents/embedded-agent-runner-extraparams.test.ts"
- node scripts/run-vitest.mjs src/agents/embedded-agent-runner-extraparams.test.ts passed, 130/130
- CI run 26681069909 passed for c950ac112e
Thanks @silvesterxm.
Stop memory-core dream diary fallback paths from persisting raw memory staging snippets or promotions into DREAMS.md when narrative generation times out, returns empty output, or fails in request-scoped runtime. Successful generated narratives are unchanged.
Maintainer fixup: align current gateway session-list tests with the full loadSessionEntry mock shape and model-derived context token behavior on main.
Fixes#88391
Co-authored-by: Alix-007 <li.long15@xydigit.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Cap the in-memory workspace bootstrap snapshot cache to 64 session keys so long-lived gateway processes do not retain one loaded bundle per distinct session key indefinitely. Older entries are evicted while active keys continue refreshing against the guarded workspace loader.
Verification:
- node scripts/run-vitest.mjs src/agents/bootstrap-cache.test.ts
PR: #88149
sanitizeTransportPayloadText() called text.replace() directly, so runtime-undefined content from malformed replay/error handling could crash embedded agent transport serialization with "Cannot read properties of undefined (reading 'replace')".
Return an empty string for non-string runtime payloads at the shared sanitizer boundary, preserving existing unpaired-surrogate cleanup for strings. Empty values still degrade through sanitizeNonEmptyTransportPayloadText() to "(no output)" where that non-empty fallback is required.
Proof:
- pnpm test src/agents/transport-stream-shared.test.ts
- pnpm exec oxfmt --check --threads=1 src/agents/transport-stream-shared.ts src/agents/transport-stream-shared.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "pnpm test src/agents/transport-stream-shared.test.ts"
Fixes#60113
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Fix Nostr allowFrom npub normalization by returning the decoded hex string from nostr-tools instead of iterating the hex string as bytes.
Proof:
- node scripts/run-vitest.mjs extensions/nostr/src/nostr-bus.test.ts
- PR CI green at head 7c3433435b
Co-authored-by: DocNR <danieljwyler@gmail.com>
Use chat.history metadata to hydrate TUI and web startup state without the extra sessions.list refresh, with guards for aliases, stale active rows, blank-session defaults, and lightweight TUI usage metadata.
When a configured Google provider/model row had no explicit
but had a baseUrl set, the fallback defaulted to openai-completions,
causing Gemini requests to route through the OpenAI Responses
transport instead of the native @google/genai transport.
Made resolveConfiguredProviderDefaultApi provider-aware: for the
google provider, the default API is now google-generative-ai.
Root cause: the generic fallback assumed any provider with a baseUrl
should use openai-completions, which is incorrect for Google's native
Gemini API.
Co-authored-by: xin <1052326311+xin@users.noreply.github.com>
Preserve long Feishu streaming replies by falling oversized finals back to chunked message/static-card delivery instead of closing through an over-limit streaming CardKit payload.
Keeps late-final suppression after a streaming card closes, and uses markdown-aware chunking for static card fallback replies.
Fixes#88631.
Co-authored-by: Ted Li <tl2493@columbia.edu>
Keep native subagent spawns with `lightContext=true` and resolved isolated context out of context-engine pre-spawn preparation so they remain lightweight.
The normal isolated and forked context-engine lifecycle stays intact, and docs now call out the lightweight isolated exception.
Fixes#81214
Fix JSONL file-log hostnames getting pinned to `unknown` when the first hostname read returns an empty value. The logger now retries empty hostname reads and caches the first non-empty value, keeping the top-level `hostname` and `_meta.hostname` fields aligned.
Fixes#87258.
Thanks @lonexreb for the fix.
Verification:
- `node scripts/run-vitest.mjs src/logging/logger-redaction-behavior.test.ts src/logger.test.ts`
- `node_modules/.bin/oxfmt --check --threads=1 src/logging/logger.ts src/logging/logger-redaction-behavior.test.ts`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `gh pr checks 88131 --watch=false`
Co-authored-by: lonexreb <reach2shubhankar@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Expose session status route context so agents can distinguish session origin, active live route, and persisted delivery route.
Add maintainer fixup to keep active route metadata on the real live run key when policy and run keys differ.
Thanks @nxmxbbd.
Closes#84544
Preserve the current container-related service opt-in environment when regenerating daemon service files, while continuing to drop stale or arbitrary `OPENCLAW_*` variables.
Verification:
- `git diff --check`
- `node scripts/run-vitest.mjs src/commands/daemon-install-helpers.test.ts -t "operator opt-in allowlist"`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --prompt "Review PR #82828 fixup for daemon service env preservation. Focus on whether the allowlist should include only current container opt-in env keys and whether tests cover stale/arbitrary OPENCLAW_* filtering."`
- GitHub CI on `2e4b7f7fccbc46541c9c0ac271b1c97f1a6aa071`
Co-authored-by: wAngByg <281221101+wAngByg@users.noreply.github.com>
Carry the canonical session UUID from the session store into interactive dispatch diagnostic lifecycle events, matching the cron path so downstream diagnostic consumers can join events back to the JSONL transcript id.
Guard native command redirects by only attaching the UUID when the lifecycle session key matches the session-store lookup key, avoiding a target UUID under a source conversation key.
Verification:
- `pnpm test src/auto-reply/reply/dispatch-from-config.test.ts -t "carries the session store UUID|does not stamp a command target"`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --prompt ...`
- synthetic merge-tree against current `origin/main`
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Address Codex review (P2 x3): replace the duplicate fs.access-based entry
checks in runPostUpgradeProbes with a call to
validatePackageExtensionEntriesForInstall so the doctor probe enforces the
same contract as plugin install/discovery:
- runtimeExtensions shape and length-mismatch validation
- plugin-root boundary enforcement (rejects absolute paths and ../ escapes)
- inferred dist/*.js peer for TypeScript entries; TS source-only entries
without compiled output are now flagged
Adds 4 regression tests covering the boundary-escape, dist-peer accept,
TS-source-only reject, and runtimeExtensions length-mismatch cases.
Refs: https://github.com/openclaw/openclaw/pull/79260#issuecomment-4403594002
Add a Doctor health contribution that checks free space on the partition containing the active OpenClaw state directory. Doctor now warns below 500 MB and reports critical below 100 MB so disk pressure is visible before config writes, session transcripts, or log rotation start failing.
The contribution reuses the shared `src/infra/disk-space.ts` probe, runs before state integrity, and is registered in the Doctor health conversion plan with focused coverage for thresholds, formatting, and note behavior.
PR: #59196
Proof: `pnpm test src/commands/doctor-disk-space.test.ts src/flows/doctor-health-conversion-plan.test.ts`; `git diff --check origin/main...HEAD`; `git merge-tree --write-tree origin/main refs/remotes/pr/59196`; GitHub CI run `26720861380`; Real behavior proof run `26720996848`.
Co-authored-by: alkor2000 <200923177@qq.com>
Forward prompt-submission owned session write publication into the embedded session lock controller so same-process announcement/completion writes can advance the requester fence while external edits still trigger takeover protection.
Adds regression coverage for a second controller publishing an owned announcement write and for preserving rejection of a later unowned edit.
Closes#88703.
Thanks @TurboTheTurtle.
Show existing Workboard card comments in the edit modal and allow operators to append a new comment through the existing `workboard.cards.comment` gateway method.
Refs #88592.
Verification:
- node scripts/run-vitest.mjs ui/src/ui/views/workboard.test.ts
- pnpm tsgo:test:ui
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
Co-authored-by: Ted Li <tl2493@columbia.edu>
Keep cron media generation detached while making cron runs wait for image/music/video completion before final closeout. Records async task IDs, falls back to the task registry for active run-scoped media work, handles timeout races, and scopes no-target generated-media delivery. Fixes#88001.
Guard the remaining Windows Testbox workflow ref logging against GitHub Actions template injection by moving `target_ref` through step env before PowerShell reads it.
Extend the local workflow check wrapper to run pinned `zizmor` across every workflow file, and keep Workflow Sanity's CI audit explicit with trusted-base pre-commit and zizmor configs for pull-request runs.
Thanks @WT-WSL for the original report and patch.
Co-authored-by: dev111-actor <captaintobb@outlook.com>
Split ACP manager session-flow ownership into focused helpers for initialization, status reads, cancellation, and startup identity reconciliation.
Verification:
- `node scripts/run-oxlint.mjs src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.initialize-session.ts src/acp/control-plane/manager.status.ts src/acp/control-plane/manager.cancel-session.ts src/acp/control-plane/manager.startup-identity-reconcile.ts src/acp/control-plane/manager.close-session.ts src/acp/control-plane/manager.turn-runner.ts src/acp/control-plane/manager.runtime-options-commands.ts src/acp/control-plane/manager.types.ts src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.initialize-session.test.ts src/acp/control-plane/manager.cancel-session.test.ts src/acp/control-plane/manager.startup-identity-reconcile.test.ts src/acp/control-plane/manager.runtime-config.test.ts`
- `pnpm tsgo:prod`
- `pnpm test src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.initialize-session.test.ts src/acp/control-plane/manager.cancel-session.test.ts src/acp/control-plane/manager.startup-identity-reconcile.test.ts src/acp/control-plane/manager.runtime-config.test.ts src/acp/control-plane/manager.runtime-handles.test.ts`
- `pnpm format:check src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.initialize-session.ts src/acp/control-plane/manager.status.ts src/acp/control-plane/manager.cancel-session.ts src/acp/control-plane/manager.startup-identity-reconcile.ts src/acp/control-plane/manager.close-session.ts src/acp/control-plane/manager.turn-runner.ts src/acp/control-plane/manager.runtime-options-commands.ts src/acp/control-plane/manager.types.ts src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.initialize-session.test.ts src/acp/control-plane/manager.cancel-session.test.ts src/acp/control-plane/manager.startup-identity-reconcile.test.ts src/acp/control-plane/manager.runtime-config.test.ts`
- `git diff --check`
- `pnpm check:test-types`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub PR checks for #88752 passed
Real behavior proof:
Behavior addressed: ACP manager session-flow ownership is split out of `AcpSessionManager` without changing initialization, status, cancel, startup identity reconciliation, close, turn, or runtime-option behavior.
Real environment tested: Local OpenClaw checkout, Node/pnpm repo toolchain, GitHub Actions PR CI.
Exact steps or command run after this patch: Focused ACP manager/runtime config/runtime handle tests plus prod/test type checks, lint, format check, diff check, autoreview, and PR CI.
Evidence after fix: All listed local commands passed, autoreview reported no accepted/actionable findings, and GitHub PR checks passed.
Observed result after fix: `manager.core.ts` is down to 612 LOC, with init/status/cancel/startup identity flows in focused modules and matching focused tests.
What was not tested: Live ACP backend session initialization/cancel/status against a real external ACP provider.
Adds optional `gateway.tailscale.serviceName` support for Tailscale Serve so the Gateway Control UI can be exposed through a named Tailscale Service while existing hostname-based Serve and Funnel behavior stays unchanged.
The implementation validates `svc:<dns-label>`, passes the Service name to `tailscale serve`, clears named Service config with `tailscale serve clear <service>` when resetOnExit runs, and uses the derived Service hostname in startup logs, status output, and pairing URLs.
Verification:
- node scripts/run-vitest.mjs src/infra/tailscale.test.ts src/gateway/server-tailscale.test.ts src/config/config.gateway-tailscale-bind.test.ts src/gateway/startup-auth.test.ts src/commands/status.scan.shared.test.ts src/pairing/setup-code.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "node scripts/run-vitest.mjs src/infra/tailscale.test.ts src/gateway/server-tailscale.test.ts src/config/config.gateway-tailscale-bind.test.ts src/gateway/startup-auth.test.ts src/commands/status.scan.shared.test.ts src/pairing/setup-code.test.ts"
- git diff --check
- git merge-tree --write-tree origin/main origin/pr/88691
Closes#88629.
Co-authored-by: Charles OpenClaw <charles-openclaw@9bcfae.inboxapi.ai>
Expose the existing virtual Communication > Notifications settings tab for Web Push controls, while keeping it out of the unscoped root settings view. Adds browser regression coverage for the scoped virtual tab.
Thanks @VladyslavLevchuk.
Co-authored-by: Vladyslav Levchuk <32742736+VladyslavLevchuk@users.noreply.github.com>
Extract ACP runtime-option command flows from `AcpSessionManager` into `manager.runtime-options-commands.ts`.
Verification:
- `pnpm format:fix src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.runtime-options-commands.ts`
- `node scripts/run-oxlint.mjs src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.runtime-options-commands.ts`
- `pnpm tsgo:prod`
- `pnpm test src/acp/control-plane/manager.runtime-config.test.ts src/acp/control-plane/manager.runtime-handles.test.ts src/acp/control-plane/manager.test.ts`
- `pnpm format:check src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.runtime-options-commands.ts`
- `git diff --check`
- `pnpm check:test-types`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
- GitHub PR checks for #88747 passed
Real behavior proof:
Behavior addressed: ACP runtime-option mutation ownership moved out of `AcpSessionManager` without changing set-mode, set-config-option, raw update, reset, persistence, or runtime-cache invalidation semantics.
Real environment tested: Local OpenClaw checkout, Node/pnpm repo toolchain, GitHub Actions PR CI.
Exact steps or command run after this patch: Focused ACP runtime config/handle/manager tests plus prod/test type checks, lint, format, diff check, autoreview, and PR CI.
Evidence after fix: All listed local commands passed, autoreview reported no accepted/actionable findings, and GitHub PR checks passed.
Observed result after fix: `manager.core.ts` is down to 885 LOC, with runtime-option command logic isolated in `manager.runtime-options-commands.ts`.
What was not tested: Live ACP backend mode/config option mutation against a real external ACP provider.
Prefer the clean channel command body when ACP decides whether an inbound message should bypass the agent loop for local OpenClaw commands.
This keeps envelope-wrapped channel text, such as WhatsApp display bodies, from hiding commands like /status when the channel already provided a normalized command body. The ACP runtime prefilter now uses the same command-text resolution as dispatch, and dispatch still requires registry-backed local commands before bypassing.
Co-authored-by: RoeeJ <RoeeJ@users.noreply.github.com>
Force required preflight context compaction before oversized turns can enter the agent runtime. Treat required preflight compaction as a hard gate: compact, skip only explicit harmless no-op reasons, or surface a visible recovery message when compaction cannot recover.
Fixes#87234.
Co-authored-by: ArthurNie <264332276+ArthurNie@users.noreply.github.com>
Refactor ACP close-session ownership by extracting the runtime close/recovery lifecycle into `manager.close-session.ts`.
Verification:
- `pnpm test src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.runtime-config.test.ts src/acp/control-plane/manager.runtime-handles.test.ts`
- `pnpm tsgo:prod`
- `pnpm check:test-types`
- `node scripts/run-oxlint.mjs src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.close-session.ts`
- `pnpm format:check src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.close-session.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
- GitHub PR checks for #88744 passed
Real behavior proof:
Behavior addressed: ACP close-session ownership moved out of `AcpSessionManager` without changing close/recovery behavior.
Real environment tested: Local OpenClaw checkout, Node/pnpm repo toolchain, GitHub Actions PR CI.
Exact steps or command run after this patch: Focused ACP manager tests covering close-session behavior, runtime config, and runtime handles, plus prod/test type checks, lint, format, diff check, autoreview, and PR CI.
Evidence after fix: All listed local commands passed, autoreview reported no accepted/actionable findings, and GitHub PR checks passed.
Observed result after fix: `manager.core.ts` dropped from 1149 LOC to 1038 LOC while close-session runtime lifecycle handling lives in `manager.close-session.ts`.
What was not tested: Live ACP backend close/recovery against a real external ACP provider.
Bounds skills watcher subscriptions and workspace snapshot-version state to active workspaces on the current `src/skills/runtime` implementation.
The fix keeps shared path watchers as the owner boundary, evicts idle workspace subscriptions after 1 hour without closing watchers still used by other workspaces, and clears per-workspace version keys only after preserving/advancing invalidation so cached skill snapshots cannot miss changes across teardown or re-enable.
Thanks @fede-kamel.
Fixes#77997.
Co-authored-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Refactor ACP turn execution ownership by extracting the backend attempt and cleanup loop into `manager.turn-runner.ts`.
Verification:
- `pnpm test src/acp/control-plane/manager.test.ts src/acp/control-plane/manager.turn-results.test.ts src/acp/control-plane/manager.failover.test.ts src/acp/control-plane/manager.runtime-handles.test.ts src/acp/control-plane/manager.runtime-config.test.ts`
- `pnpm tsgo:prod`
- `pnpm check:test-types`
- `node scripts/run-oxlint.mjs src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.turn-runner.ts`
- `pnpm format:check src/acp/control-plane/manager.core.ts src/acp/control-plane/manager.turn-runner.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
- GitHub PR checks for #88739 passed
Real behavior proof:
Behavior addressed: ACP turn execution ownership moved out of `AcpSessionManager` without changing runtime behavior.
Real environment tested: Local OpenClaw checkout, Node/pnpm repo toolchain, GitHub Actions PR CI.
Exact steps or command run after this patch: Focused ACP manager tests covering turn results, failover, runtime handles, runtime config, plus prod/test type checks, lint, format, diff check, autoreview, and PR CI.
Evidence after fix: All listed local commands passed, autoreview reported no accepted/actionable findings, and GitHub PR checks passed.
Observed result after fix: `manager.core.ts` dropped from 1495 LOC to 1149 LOC while turn execution lives in `manager.turn-runner.ts`.
What was not tested: Live ACP backend process recovery against a real external ACP provider.
Sanitize credential-shaped provider HTTP 401 failures in embedded-agent replies so chat users see a re-authentication hint instead of raw provider text such as `HTTP 401: "Invalid token"`.
The classifier now requires auth classification plus positive 401 evidence, and it stays narrow to credential-shaped failures so billing, scope, replay-invalid, schema, message-only auth, and plain 403 paths keep their existing behavior.
Fixes#56197. Thanks @lokamir.
Co-authored-by: jeffrey701 <jeffreyconradtucker@gmail.com>
Phase-signal store reads now recover only missing files and corrupt JSON. Nonrecoverable filesystem read failures propagate so dreaming aborts before overwriting existing phase-signal history with an empty replacement.
Fixes#77881.
Thanks @bennewell35.
Co-authored-by: bennewell35 <newelljben@gmail.com>
Extract ACP runtime resume/discard recovery helpers from `AcpSessionManager` into `manager.runtime-resume-state.ts`, and share the manager session-meta writer callback type from `manager.types.ts`. Keeps close-time fresh-session recovery, early-turn retry, persisted resume identifier clearing, and discard-persistent-state behavior intact while reducing `manager.core.ts` from 1655 LOC to 1495 LOC.
Proof: focused ACP manager runtime-handle/runtime-config/turn-result tests, prod + test type checks, narrow oxlint, format check, diff check, autoreview clean, PR CI green.
Bound DiscordEntityCache entries with a write-time expired-entry sweep and a default 5,000-entry cap while preserving current safe expiry timestamp normalization. This prevents high-cardinality Discord user/channel/guild/member fetches from retaining stale Map entries for the gateway lifetime.
Fixes#77975.
Thanks @fede-kamel.
Co-authored-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Guard group display-name generation behind group/channel classification so direct Telegram sessions fall back to their explicit or origin labels. Keep session-list search aligned with that visible fallback.
Fixes#55354.
Thanks @sebuh-infsol.
Summary:
- Add forced provider re-login support that clears cached auth profiles before running provider login again.
- Add provider-auth remediation guidance and a session-scoped skip cache for known-bad fallback auth attempts.
- Wire session ids through agent command, auto-reply, and embedded compaction fallback callers so the skip cache applies on real run paths.
- Fail closed when forced auth profile removal cannot update the profile store.
Verification:
- Local format, lint, diff-check, focused Vitest shards, and autoreview passed.
- PR CI, CodeQL Security High, and Critical Quality agent-runtime-boundary passed on head 1b4e9e753e.
Co-authored-by: Mert Basar <MertBasar0@users.noreply.github.com>
Fix approval fallback text so exec and plugin approval messages render a concrete request id in the chat copy-paste command instead of the literal <id> placeholder.
This makes the Reply with: /approve ... line directly usable for owners while keeping the existing approval resolver contract unchanged.
Proof:
- git diff --check origin/main...HEAD
- pnpm test src/infra/exec-approval-forwarder.test.ts src/infra/plugin-approval-forwarder.test.ts src/plugin-sdk/approval-renderers.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- CI run 26720052738 passed
Thanks @itsuzef.
Serialize QMD update and embed writes with one per-agent store lock so foreground memory search/index and gateway background QMD work do not write the same index.sqlite concurrently.
The embed path now waits for global embed capacity before taking the per-store lock, so queued embeds do not block same-agent foreground updates while no store write is active.
Fixes#66339
Thanks @openperf.
Co-authored-by: Chunyue Wang <16864032@qq.com>
Refresh pinned node:24-bookworm and node:24-bookworm-slim manifest-list digests across the root, smoke, and e2e Dockerfiles. Update digest pin assertions to cover the plugin-binding e2e Dockerfile.
Verified with live Docker digest inspection, targeted Dockerfile tests, root base-runtime build, install-sh smoke build, and plugin-binding e2e build.
Thanks @LibraHo.
Detect OpenClaw gateway units installed in the system systemd scope, including marker-owned custom unit names such as `openclaw.service`. Route status/restart/stop through the system manager when appropriate, and show non-root users the matching `sudo systemctl ...` command instead of falling back to unmanaged process signaling.
Fixes#87577.
Thanks @yetval.
Verification:
- `node scripts/run-vitest.mjs src/daemon/systemd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/daemon/inspect.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/status.gather.test.ts src/cli/daemon-cli/response.test.ts src/commands/doctor-gateway-daemon-flow.test.ts src/cli/update-cli/restart-helper.test.ts src/infra/outbound/message-action-runner.core-send.test.ts`
- AWS Crabbox `cbx_69f97dff5e5c`, run `run_a68431b3dad6`: exact SHA checkout, focused tests, real `/etc/systemd/system/openclaw.service` status/restart/stop proof.
Ref #84134.
Prefer real tool results over generated missing-result placeholders during transcript repair, including late results after later assistant turns and explicitly marked custom-text repair placeholders. Keep real error outputs such as aborted when they are not generated repair placeholders.
Thanks @Jerry-Xin.
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
Rewrite generated session transcript paths at the shared session-store merge boundary when a persisted session rolls from one session id to another. This prevents patches that carry a stale generated `sessionFile` from leaving a new logical session id attached to the old transcript file, while preserving custom transcript paths.
Refs #65564.
Proof:
- `node scripts/run-vitest.mjs src/config/sessions/sessions.test.ts`
- `node scripts/run-vitest.mjs src/agents/command/session-store.test.ts`
- `git diff --check origin/main...HEAD`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- CI run 26719583889 attempt 2
Co-authored-by: Sunjae Kim <sunjaekim@bigvalue.co.kr>
Remove Telegram runtime JSON sidecar read/write fallback for the prompt-context message cache. Keep legacy sidecar parsing for doctor import into SQLite plugin state and update docs/tests to match.
Fixes#85124.
Anthropic standard API keys no longer resolve as provider usage auth for `openclaw status --usage`, so valid inference keys are not sent to Anthropic's OAuth usage endpoint and surfaced as misleading invalid bearer-token errors.
The provider usage-auth SDK result now has an explicit handled/no-token shape so provider hooks can suppress generic fallback without widening the OAuth helper contract. Docs, Plugin SDK API baseline, and extension package-boundary cache inputs were updated with the new contract.
Thanks @zhangguiping-xydt.
Proof:
- node scripts/run-vitest.mjs src/infra/provider-usage.auth.normalizes-keys.test.ts src/infra/provider-usage.auth.plugin.test.ts extensions/anthropic/index.test.ts
- pnpm plugin-sdk:api:check
- pnpm plugin-sdk:check-exports
- git diff --check origin/main...HEAD
- pnpm docs:list
- pnpm run test:extensions:package-boundary:compile
- autoreview clean: no accepted/actionable findings
- PR CI rollup green: 131 success, 22 skipped, 1 neutral, 0 failures
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Validate context-engine assemble results at the shared harness boundary before embedded or Codex runners consume them.
Malformed plugins that return an object without a `messages` array now throw a descriptive engine-scoped error and use the existing runner fallback to pipeline messages, rather than poisoning session state and crashing prompt assembly on `.length`.
Proof:
- `node scripts/run-vitest.mjs src/agents/harness/context-engine-lifecycle.test.ts`
- `node scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/attempt.spawn-workspace.context-engine.test.ts`
- `pnpm exec oxfmt --check src/agents/harness/context-engine-lifecycle.ts src/agents/harness/context-engine-lifecycle.test.ts`
- `git diff --check origin/main...HEAD`
- GitHub CI on `5b6b7b1bf69b8f30329fdf749161a192d3d016fe`: https://github.com/openclaw/openclaw/actions/runs/26719202811
Thanks @Pluviobyte.
Fixes#75541
Plugin SDK subagent runs now register at the Gateway agent acceptance boundary so subagent_ended hooks fire without creating duplicate CLI task rows.
The registration stays best-effort: if the subagent registry cannot persist tracking state, the run still dispatches and falls back to the existing CLI task tracking path.
Closes#59164
Co-authored-by: Cornna <96944678+ymylive@users.noreply.github.com>
Count model stream diagnostic response bytes from snapshotless stream chunks, excluding accumulated partial snapshots on delta events. This avoids repeatedly serializing answer-so-far snapshots during streamed model calls and updates OTEL/docs wording for the new metric baseline.
Refs #86599.
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* refactor: move plugin state slices to sqlite
* fix: keep legacy plugin state migration out of runtime
* fix: add doctor migrations for plugin sqlite state
* fix: preserve teams feedback learning migration keys
* fix: merge teams legacy feedback learnings
* fix: guard doctor imports against plugin state caps
* fix: leave lossy teams learning filenames unmigrated
* fix: preserve teams feedback learning scope
* fix: load plugin doctor contracts from package dist
* fix: satisfy plugin state migration gates
Handle the Telegram isolated-polling spool recovery race where a stale `.processing` claim can disappear between discovery and the final rename back to pending. Recovery now treats `ENOENT` as benign and mirrors the existing duplicate-pending cleanup path for `EEXIST`, avoiding noisy drain-failure logs and spurious failure counters without changing claim ownership semantics.
Adds a regression test that removes the claim from inside `shouldRecover`, after recovery has discovered the entry and before the final rename path, so the old code would hit the reported `ENOENT` window.
Fixes#87847
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Expand Linux CA bundle auto-injection to recognize fnm, Volta, asdf, mise, n, nodenv, nodebrew, and nvs paths in addition to nvm. Adds regression coverage for the new version-manager path layouts.
Fixes#59494.
Thanks @alkor2000.
Co-authored-by: alkor2000 <200923177@qq.com>
Prevent streaming assistant text updates from reparsing the full accumulated reply for plain deltas, avoiding repeated work for small-model streams while preserving full cleanup for directives, media, and final events.
Also load the normal Control UI Vite config in the mock browser server so browser E2E uses the same workspace aliases as dev.
Thanks @vincentkoc.
Extend the CLI holiday tagline tables for Lunar New Year, Eid al-Fitr, Easter, Diwali, and Hanukkah through 2030 so those taglines do not silently disappear after 2027.
Maintainer fixup: corrected the 2030 Diwali row to October 25 and added explicit regression coverage for that date.
Verification:
- node scripts/run-vitest.mjs src/cli/tagline.test.ts
- Direct pickTagline() probe confirmed 2030-10-25 activates Diwali and 2030-10-26 does not.
Co-authored-by: alkor2000 <200923177@qq.com>
Refactor provider metadata lookup so hot paths consult the current process snapshot before falling back to a metadata load.
Centralize provider metadata lookup in the provider runtime and update the focused tests/mocks that exercise embedded-agent and provider loading paths.
Verification:
- node scripts/run-vitest.mjs src/plugins/providers.runtime.consult-current-snapshot.test.ts
- node scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/attempt.cwd-split.test.ts
- node scripts/run-vitest.mjs src/plugins/providers.test.ts
- autoreview --mode branch --base origin/main
- CPU profile loop: current-snapshot resolve 0.459 us/call vs warm direct metadata load 131.493 us/call
- GitHub CI on 728bd53510
Co-authored-by: masatohoshino <g515hoshino@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add durable memoryFlush failure metadata and lifecycle events so provider failures during memory flush no longer leave a session with no recorded recovery state.
After three consecutive non-abort flush failures, mark the current compaction cycle as exhausted so later messages can proceed without deleting transcript history. Successful flushes clear the failure metadata, and plugin session-entry slot reservations now protect the new fields.
Release-note: memoryFlush sessions can now fail open after repeated provider-side flush failures instead of retrying indefinitely before normal replies.
Refs #85645
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Fixes Codex/plugin-harness cold starts for exact static-catalog model ids such as openai/gpt-5.3-codex without adding a second resolver retry loop. The embedded runner now performs the normal provider-runtime attempt with agent discovery skipped, then consults the bundled static catalog before falling back to generic configured-provider synthesis when plugin harness owns transport.
The OpenAI static catalog row carries the Codex ChatGPT transport metadata, dynamic provider metadata still wins for runtime-owned models, and focused regression coverage exercises both paths.
Fixes#88510.
Co-authored-by: yetval <yetvald@gmail.com>
Show DeepSeek API-key account balance in status/auth-status usage surfaces by adding a summary-only provider usage snapshot path, a DeepSeek balance fetcher, SDK/docs coverage, and focused regression tests.
Maintainer verification accepted the additive provider-usage/status contract and the DeepSeek balance visibility boundary for authenticated status surfaces.
Proof:
- Live DeepSeek balance proof via 1Password-backed DEEPSEEK_API_KEY against https://api.deepseek.com/user/balance; key and balance amount redacted.
- GitHub CI run 26717953383 passed on the current head.
- Real behavior proof run 26718215605 passed after the PR body was refreshed.
- Local clean PR clone: git diff --check; node --max-old-space-size=8192 --import tsx scripts/generate-plugin-sdk-api-baseline.ts --check; node scripts/run-vitest.mjs run src/agents/bash-tools.exec.path.test.ts.
Co-authored-by: Alex Tang <tangli1987118@hotmail.com>
Co-authored-by: litang9 <141409885+litang9@users.noreply.github.com>
Treat the synthetic Codex app-server auth marker as a core non-secret marker so secrets audit does not flag it when bundled plugin discovery is disabled.\n\nVerified with focused model-auth marker tests, isolated secrets-audit CLI proof, autoreview, and green CI.\n\nThanks @vortexopenclaw.
Suppress WhatsApp typing indicators only for silent message-tool-only unmentioned group runs. Automatic visible replies and authorized group commands still show composing normally.
Fixes the autoreview regression risk by narrowing suppressTyping and adding coverage for both silent and visible group paths.
Proof:
- pnpm test src/auto-reply/reply/reply-utils.test.ts extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode local
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- CI run 26717880577 green
Thanks @Bluetegu.
Subscribe the iOS gateway chat transport to per-session transcript events so group chats update when other clients send messages. Constrain local user echo adoption to the optimistic row tied to the still-pending send run, so repeated same-content user messages from other clients append instead of replacing history.
Fixes#80231.
Co-authored-by: Yuval Dinodia <yetvald@gmail.com>
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Route Discord thread follow-up messages to plugin-owned bindings by the raw thread id while retaining parent channel fallback matching. This fixes `/codex bind` follow-ups in Discord threads being claimed by the parent OpenClaw route instead of the bound Codex session.
Verification:
- `node scripts/run-vitest.mjs extensions/discord/src/channel.conversation.test.ts src/hooks/message-hook-mappers.test.ts extensions/discord/src/monitor/message-handler.process.test.ts -t "prefers bound session keys|passes Discord thread parent only|routes Discord thread plugin-owned bindings|passes thread parent ids|thread binding"`
- `node scripts/run-vitest.mjs src/auto-reply/reply/dispatch-from-config.test.ts -t "routes Discord thread plugin-owned bindings by raw thread id"`
- `pnpm build`
- `pnpm lint --threads=8`
- `CI=true FORCE_COLOR=0 pnpm lint --threads=8`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
- GitHub: Real behavior proof, check-test-types, check-dependencies, check-prod-types, auto-reply dispatch shard, hooks shard, and extension package boundary passed on head 1e896d9835.
Known unrelated CI noise at merge: broad opengrep/test/lint CI failures are outside the touched Discord/session-binding surface and contradicted by focused local proof where applicable.
Co-authored-by: Hex <hex@openclaw.ai>
Add Claude Opus 4.8 to the GitHub Copilot static model catalog and default model IDs.
Updates provider manifest metadata and regression coverage so fallback/default discovery includes claude-opus-4.8.
PR: #88547
Co-authored-by: saju01 <saju@coderedcorp.com>
Clamps ANSI-aware terminal table cells before padding so width-2 graphemes cannot push borders out of alignment in width-1/narrow columns.
Fixes#88556.
Proof:
- node scripts/run-vitest.mjs run packages/terminal-core/src/ansi.test.ts packages/terminal-core/src/table.test.ts
- CI run 26717035619; check-dependencies red only for unrelated current-main deadcode issue ui/src/ui/browser-redact.ts, also red on main run 26717029674. checks-node-agentic-agents-core rerun failed in unrelated src/agents/bash-tools*.test.ts outside this PR diff.
Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
When dreaming narrative cleanup calls subagent.deleteSession() in the finally block and it throws, the store row can be left behind referencing a still-present transcript. The scrubber only pruned dreaming rows whose transcript was missing, so these orphans lingered in the recent sessions sidebar with no kind/status/endedAt and accumulated across restarts.
Reclaim a dreaming store row when its transcript is missing OR has aged past DREAMING_ORPHAN_MIN_AGE_MS, then leave the transcript unreferenced so the orphan-transcript pass archives it.
Fixes#88322
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Use the Google Chat thread resource as the ambient message-tool reply target so replies stay in the inbound thread. Normalize the current Google Chat space target and let plugin threading adapters explicitly suppress the generic message-id fallback when a provider needs a thread resource instead of a message resource.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Franco Viotti <franco-viotti@users.noreply.github.com>
Follow-up to #88658. Retries transient stale session-lock acquire failures when diagnostics show the old stale report disappeared, was replaced by a fresh valid lock, or was replaced by a fresh payload-less lock still inside the mtime/orphan grace window.
Preserves typed `SessionWriteLockStaleError` diagnostics for still-present live OpenClaw-owned stale locks.
Proof: 53 focused session-write-lock tests passed locally and in the agents-core CI shard; `pnpm tsgo:test:src`, touched-file oxlint, `git diff --check`, and autoreview passed locally. CI run 26716843811 has unrelated failures in UI deadcode/types and bash-tools tests; session-write-lock tests passed in that run.
Refs #87217.
Fix Discord DM pairing for PluralKit senders by storing the pairing identity with the same `pk:<member-id>` form used at inbound lookup time. Also recognizes both canonical direct DM session keys and account-scoped direct DM session keys as DM approval sessions.
Focused proof: `node scripts/run-vitest.mjs extensions/discord/src/approval-native.test.ts extensions/discord/src/monitor/dm-command-auth.test.ts extensions/discord/src/monitor/dm-command-decision.test.ts extensions/discord/src/monitor/message-handler.preflight.test.ts` passed with 4 files and 82 tests.
Closes#86332
Co-authored-by: Sanjays2402 <51058514+Sanjays2402@users.noreply.github.com>
Slack top-level channel mentions with replyToMode off now reply at the channel root instead of inheriting stale or auto-created thread targets.
Existing Slack thread replies and Slack assistant DM thread targets continue to preserve their thread target.
Thanks @lawrencetran.
Fix macOS menu bar status-item storms during rapid gateway connection churn by removing stale SwiftUI-vended status items before adopting replacements and debouncing transient control-channel states.
Surface: macOS menu bar app, `MenuBarExtra` status item ownership, `ControlChannel` UI-observed connection state.
Proof:
- `git diff --check origin/main...pr/82739`
- `swift test --package-path apps/macos --filter ControlChannelStateDebouncerTests`
- PR CI: preflight, security-fast, macos-node, macos-swift, dependency-guard, changed-path scan, real behavior proof, Socket checks
Co-authored-by: Alexander Falk <al@falk.us>
Fixes#88360.
Route Discord live-preview final replies containing targeted user or role mentions through fresh message delivery instead of edit finalization, preserving mention alias rewriting and notification behavior. Plain, broadcast-only, and mixed targeted-plus-broadcast replies keep the existing preview edit path.
Proof: CI run 26708866609 green for relevant lanes; Real behavior proof run 26708866194 successful; local git diff --check and git merge-tree clean.
Route implicit message_tool_only current-source sends through the internal source-reply sink for non-webchat transports, preserving the final reply payload path where usage decoration runs. Also keep reply payload metadata when appending usage text so transcript mirror text matches the delivered footer-bearing reply.
Recreated from PR #87425 because the fork branch is draft, dirty against main, and not maintainer-pushable.
Co-authored-by: Gio Della-Libera <giodl73@gmail.com>
fix(agents): preserve runtime tools in lean mode
Keep runtime-required tools, especially `message`, available when local-model lean filtering is enabled. This preserves `forceMessageTool`, `message_tool_only` source replies, explicit runtime allowlists, and schema projection without disabling lean filtering for ordinary denied tools.
Proof: focused Vitest passed 190 tests; `git diff --check origin/main...HEAD` passed; PR CI had no failing or pending checks.
fix(messages): use best-effort for implicit tool-only source replies
Preserve durable required-send semantics for explicit non-current targets while allowing current-source `message_tool_only` replies to be delivered through best-effort outbound sends. This fixes Slack source replies that otherwise fail when the adapter has no `reconcileUnknownSend` hook.
Fixes#84078.
Add an opt-in bash/zsh shell snapshot cache for host exec runs, consolidate shell helper ownership into src/agents/shell-utils.ts, document OPENCLAW_EXEC_SHELL_SNAPSHOT, and keep Windows config command execution on the bash resolver. Also removes a redundant Discord gateway close-code type branch that was blocking test type checks.
Report live-owned stale session locks as typed acquisition failures instead of auto-removing them, while preserving safe reclaim for dead/orphaned lock files. Propagate stale lock acquisition through embedded runner takeover handling, failover/cache/delivery classifiers, and QA retry detection.
Refs #87779
Fixes#88538. Carry the owning run sessionId through lifecycle events, skip stale persistence and sessions.changed projection when sessions.reset rotated the row, and register the persisted owning id across session-backed run paths. Also aligns per-agent subagent thinking typing with existing runtime/test usage.\n\nCo-authored-by: openperf <16864032@qq.com>
sessions.reset rotates a channel session to a fresh sessionId under the same
sessionKey, but an old in-flight run could still emit late start/end/error
lifecycle events. persistGatewaySessionLifecycleEvent resolved the row purely
by sessionKey, so those stale events overwrote the new row's status
(running/failed with hasActiveRun=false).
Stamp the owning run's sessionId onto lifecycle events in emitAgentEvent and
skip persistence when it differs from the current row's sessionId. The embedded
runner refreshes the run context's sessionId on every live-session rotation
(mid-run compaction), so a legitimately rotated run's terminal event still
matches the rotated row; only an external sessions.reset stays mismatched.
Matching and unknown-owner events are unaffected.
Fixes#88538
Fixes#74374.
Normalizes params.thinking false, disabled, and none to the existing off state for agent and auto-reply model selection. Thanks @yelog.
Known proof gap: build-artifacts is failing in an unrelated plugin prerelease plan assertion that expects an old Docker stats helper string; targeted tests, diff check, autoreview, and all touched-path checks pass.
Enforce OpenAI-compatible `tool_choice` contracts for Gateway HTTP Chat Completions and Responses client function tools.
- Add shared request normalization and post-run enforcement for required and pinned client function tool choices.
- Buffer streaming output until the tool-choice contract is satisfied, so failed runs do not leak partial assistant prose.
- Document the client-function-tool scope and add regression coverage for Chat/Responses success and failure cases.
Thanks @Lellansin for the contribution.
Proof: exact-head CI passed for `79fa0947360d307cf4ecffe713489cdf5db61093` in run `26714604449`; focused gateway tests passed locally.
Fixes the session transcript race where a newer assistant tool-call turn could force pending older tool calls to be written as synthetic missing-result entries while real parallel tool results were still in flight.
The guard no longer synthesizes at that racing boundary when synthetic repair is enabled, and transcript repair now moves late real results back beside their matching assistant tool-call turn before adding any placeholder. This keeps provider replay strict while preserving useful tool output.
Regression coverage: focused guard and transcript-repair tests for late parallel results.
Closes#88168.
Follow-up lock-lifetime report tracked in #88647.
Thanks @TurboTheTurtle for the fix and @jhartman00 for the report.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Release the embedded attempt session lock on manual aborts through the same best-effort abort cleanup path used by timeout aborts.
Proof: focused Vitest for abort/session-lock cleanup, `pnpm check:test-types`, oxfmt, `git diff --check`, branch autoreview, and full PR CI on 56fa5420d6.
Fixes#88600
Fixes#87462.
Timeout transport failures now record cooldowns against the attempted model when available. Model-scoped cooldown bypasses continue to respect profile-wide blocked/disabled windows, and timeout expiry selection stays per profile while rate-limit expiry keeps shared reset aggregation.
Verification:
- pnpm exec oxfmt --check --threads=1 src/agents/auth-profiles/usage-state.ts src/agents/auth-profiles/usage.test.ts src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts src/agents/auth-profiles.markauthprofilefailure.test.ts src/agents/embedded-agent-runner/run.ts
- pnpm check:test-types
- pnpm test src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts src/agents/auth-profiles/usage.test.ts src/agents/auth-profiles.markauthprofilefailure.test.ts src/agents/embedded-agent-runner/run.incomplete-turn.test.ts
- autoreview clean
- GitHub Actions green on PR head d64e2a4d2f
Bumps OpenClaw release metadata to 2026.5.31 across package manifests, app version files, plugin metadata, changelog headings, and generated shrinkwraps.
Verification:
- pnpm plugins:sync:check
- pnpm ios:version:check
- pnpm deps:shrinkwrap:check
- git diff --check
- stale 2026.5.30/build-code scan across changed files
- autoreview clean: no accepted/actionable findings
- PR CI green for real gates: Checks, security scans, dependency guard, app lanes, real behavior proof
Known non-code workflow issue:
- label workflow failed because this PR hits GitHub's 100-label issue cap before the size-label step.
Warn operators when message_tool_only produces unusually substantive private final text without a delivered source reply. Keeps short/NO_REPLY silence quiet, avoids logging response bodies, and distinguishes unrelated side effects from source-reply delivery.
* fix(tui): use middle truncation for paths and commands in tool display
Closes#87936
* fix(test): update channel-streaming test for middle truncation output
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* chore: retrigger CI (vitest env teardown flake)
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(tui): redact tool details before middle truncation
Apply redactToolDetail() to command and generic string text before
middle truncation so credential-like suffixes are masked while full
flag/key context is still available. Previously, truncation could
remove the --flag prefix while preserving the raw secret at the tail,
causing redaction patterns to miss the value.
Add regression tests for sk- prefixed tokens in commands and ghp_
tokens in generic string details.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(tui): skip history reload when final event has displayable output
On external/gateway runs, handleChatEvent fires void loadHistory() on
every final event. loadHistory() does clearAll() + rebuild from server
data, but the server may not have persisted the just-finished message
yet, causing the rendered final message to vanish.
Add a hasDisplayableFinal option to maybeRefreshHistoryForRun that skips
the destructive reload when the final text is already rendered locally.
This mirrors the existing local-run guard. Compute finalText before the
reload decision so the guard has the information it needs.
Closes#87922
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* retrigger proof check
Signed-off-by: Seb Tardif <sebtardif@ncf.ca>
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Signed-off-by: Seb Tardif <sebtardif@ncf.ca>
Refactor the subagent completion handoff path into the generic agent steering queue, preserving legacy persisted handoff lease fields by normalizing them into steering lease fields on restore.
Also allowlists the split cron run-log SQLite boundary in the Kysely guardrail after rebasing onto current main.
Refs #88407.
* fix(tasks): reclaim ACP zombie runs blocking gateway restart (#88205)
hasBackingSession treated an ACP task as backed whenever its persisted
session-store entry existed, so a crashed mid-turn ACP run left a
status=running record that survived the crash and wedged gateway
restart/update forever.
Gate ACP backing on in-process live-turn liveness instead of entry
existence, behind the existing authoritative-process flag (generalized
from cron-only) so a standalone maintenance CLI with an empty live-turn
map stays conservative and never reclaims. The liveness signal lives in a
core-internal active-turns registry (mirroring cron active-jobs) so it
stays off the SDK-exported AcpSessionManager surface. It is marked once
before the backend loop and cleared when the task is marked terminal, so
a slow init or backend failover cleanup cannot let the sweep reclaim a
still-live turn.
* fix(tasks): preserve cron operator JSON diagnostic reason
Split the merged runtime_not_authoritative reason back into the existing cron_runtime_not_authoritative (shipped, consumed by openclaw tasks maintenance --json operator scripts) and a new acp_runtime_not_authoritative for the ACP branch. Strengthen the cron non-authoritative test to lock the reason string contract.
* fix(tasks): clear ACP turn liveness on retry failures
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Auto-reply now uses the existing per-model model params thinking value before falling back to the global thinkingDefault, matching gateway/shared model selection behavior.\n\nVerified with targeted auto-reply and agents Vitest coverage plus formatting and diff checks.\n\nThanks @tynamite for the fix.
Preserve OpenAI-compatible replay reasoning when the selected custom or self-hosted model already has reasoning metadata enabled.
The transcript policy now treats existing model metadata as the replay contract instead of requiring a new provider config knob, and the OpenAI-compatible serializer preserves reasoning_content for those routes while keeping stock OpenAI, Gemma 4, and known non-replayable OpenRouter safeguards.
Fixes#88068.
Replaces #88071.
Treat pathless POSIX shell builtins (`:`, `cd`, `false`, `pwd`, `true`) as internally safe only during shell allowlist evaluation. This avoids approval prompts for chains like `cd /tmp && git status` when the executable segment is already allowlisted, without adding a `tools.exec.safeBuiltins` config knob.
Environment-mutating builtins (`export`, `unset`), code-evaluating builtins (`eval`, `source`, `.`), unknown commands, and direct argv execution remain approval-gated unless separately allowlisted.
Proof: `pnpm test src/infra/exec-safe-builtins.test.ts src/agents/bash-tools.exec.security-floor.test.ts -- --reporter=verbose`; `pnpm changed:lanes --json`; `pnpm check:no-conflict-markers`; `git diff --check origin/main...HEAD`. CI related failures were resolved on the final SHA; remaining `checks-node-core-runtime-media-ui` failure is unrelated to this PR.
Fixes#46056.
Thanks @kinjitakabe.
Co-authored-by: kevinkang-ai <273844887+kevinkang-ai@users.noreply.github.com>
Summary:
- The branch documents friendly browser tab references across docs, the browser skill, CLI help, and tool schema descriptions, and adds tests for target reference resolution and tab alias behavior.
- PR surface: Source +24, Tests +328, Docs +9. Total +361 across 21 files.
- Reproducibility: yes. for the documentation mismatch by source inspection: current main supports friendly ta ... schema/help surfaces still emphasize raw CDP target ids. Runtime behavior itself is not a new failing path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: refactor(browser): share tab reference CLI help
Validation:
- ClawSweeper review passed for head 118af80b0b.
- Required merge gates passed before the squash merge.
Prepared head SHA: 118af80b0b
Review: https://github.com/openclaw/openclaw/pull/88393#issuecomment-4583558133
Co-authored-by: FMLS <kfliuyang@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Fixes#88443.
Cooldown-only edits under auth.cooldowns now hot reload the active runtime config instead of scheduling a gateway restart. This avoids dropping active gateway work while preserving restart-required behavior for gateway.auth.* credential changes.
Verification:
- pnpm test src/gateway/config-reload.test.ts -- --reporter=verbose
- env -u OPENCLAW_TESTBOX pnpm check:changed
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --prompt 'Review PR 88474 after rebase. Focus on whether auth.cooldowns hot reload correctly refreshes active runtime config without weakening gateway auth/token restart behavior. Treat no-op vs hot reload semantics as central.'
- GitHub CI, Real behavior proof, CodeQL, Dependency Guard, OpenGrep PR Diff, and Workflow Sanity passed on 51232ff66c.
Thanks @IWhatsskill.
Retry live query embeddings on transient provider transport failures and split eligible batch embedding socket failures after bounded retries.
Fixes#71784Fixes#44166
Supersedes #44167
Co-authored-by: MrGeDiao <MrGeDiao@users.noreply.github.com>
Suppress BOOT.md/internal-runtime-context echoes in fallback boot sends.
Wrap boot prompts as internal runtime context, track the active boot prompt during boot runs, and sanitize message-tool visible payloads before dispatch so fallback models cannot deliver copied BOOT.md instructions or leak them through raw-params errors. Preserves media/presentation sends that still contain non-text payload content after sanitization.
Fixes#53732.
Co-authored-by: stainlu <stainlu@newtype-ai.org>
Allow media understanding providers to opt into synthetic non-secret auth for local or self-hosted no-auth audio/video execution.
This preserves configured env/profile/literal provider credentials first, keeps explicit profile failures hard-fail, and leaves unmarked remote providers fail-closed.
Fixes#74644.
Limit plugin metadata snapshots to the channel, provider, and startup surfaces that need them, while preserving unscoped fallback for incomplete index data and provider runtime resolution.
Refs #70533.
Refs #84628.
Co-authored-by: IWhatsskill <IWhatsskill@users.noreply.github.com>
Fixes#67423.
Resolve provider-entry apiKey fields that intentionally reference model auth profiles through centralized binding logic, so runtime auth and status labeling agree. Preserve env-first precedence, SecretRef handling, provider/baseUrl compatibility checks, and model auth-mode guards.
Verification:
- node scripts/run-vitest.mjs src/agents/model-auth.profiles.test.ts src/agents/model-auth-label.test.ts
- PATH=/tmp/openclaw-corepack-shim.XXXXXX:$PATH CI=true pnpm check:changed
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI run 26710260760 and related CodeQL/proof checks on f55dec154d
Co-authored-by: kinjitakabe <273844887+kinjitakabe@users.noreply.github.com>
Stabilizes Claude CLI reusable sessions when Claude token rotation causes transient token-shaped credential reads. Local Claude CLI OAuth and token credential encodings now share the same identity-only auth-epoch, while ref-backed token auth profiles ignore refreshed token material and plaintext token profiles remain epoch-sensitive on manual token replacement.
Fixes#74312.
Proof: focused local Vitest, autoreview, Testbox-through-Crabbox tbx_01ksyrcknbt743x32x6k1s95qw, and GitHub CI run 26709864094 all passed.
Co-authored-by: stainlu <stainlu@newtype-ai.org>
Deliver plugin-owned bound-thread replies even when the source room is configured for `message_tool` visible replies. Normal agent final text still stays private unless the agent calls `message(action=send)`.
Document the distinction in the group/channel docs and root routing policy, and keep ambient room-event plus unauthorized text-slash suppression covered by regression tests.
Fixes#87721.
Adds a report-only memory-core dreaming shadow-trial runner that writes inspectable artifacts without mutating durable memory. The public helper now stores default reports under daily directories with opaque content-hash filenames, so multiple same-day trials coexist without leaking candidate text into paths.
Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-memory.config.ts extensions/memory-core/src/dreaming-shadow-trial.test.ts --reporter=verbose --maxWorkers=1
- git diff --check
- pnpm exec oxfmt --check extensions/memory-core/src/dreaming-shadow-trial.ts extensions/memory-core/src/dreaming-shadow-trial.test.ts
- pnpm tsgo:extensions
- autoreview clean: no accepted/actionable findings
- GitHub CI run 26709794635 passed
- Real behavior proof run 26709798698 passed
- Dependency Guard run 26709794113 passed
Co-authored-by: Firas Alswihry <itzfiras@gmail.com>
Align diagnostic stuck-session recovery in-flight dedup with the runtime recovery key. The coordinator now dedups by logical session ref only, so a mid-flight generation bump cannot emit a phantom `session.recovery.requested` event that runtime recovery skips as already in flight.
Adds a regression test for the idle-queued stall path where a queued message bumps generation while recovery is pending.
Fixes#88010
Fixes#70746 by pairing nameless same-name tool results with the earliest unmatched Control UI tool card while preserving exact ID matches. Empty fallback results now count as consumed, so later results do not overwrite the first card.
Focused regression coverage covers sequential same-name calls and empty-result fallback pairing. Thanks @chinar-amrutkar.
Co-authored-by: Chinar Amrutkar <chinar.amrutkar@gmail.com>
## Summary
- Document scoped configured mention-pattern policy on the Groups page, including allow/deny mode semantics, supported conversation IDs, account-level precedence, and native-mention behavior.
- Add config UI help for `mentionPatterns.mode`, `allowIn`, and `denyIn` on Discord, Matrix, Slack, Telegram, and WhatsApp.
- Regenerate channel config/docs/plugin SDK metadata baselines for the new hint copy.
Refs #70864.
## Verification
- git diff --check
- pnpm format:docs:check
- pnpm docs:check-mdx
- pnpm docs:check-links
- pnpm config:channels:check
- pnpm config:docs:check
- pnpm plugin-sdk:api:check
- node scripts/run-vitest.mjs src/config/schema.hints.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode local
## Real behavior proof
Behavior addressed: Documentation and config UI metadata for scoped configured mention-pattern policy.
Real environment tested: Local OpenClaw checkout on macOS.
Exact steps or command run after this patch: The verification commands listed above.
Evidence after fix: Docs formatting, MDX, link audit, generated config/channel/API baselines, and config hint tests passed; autoreview reported no accepted/actionable findings.
Observed result after fix: The Groups page now explains how to scope `messages.groupChat.mentionPatterns` with `channels.<channel>.mentionPatterns`, and config metadata exposes field help for the supported channels.
What was not tested: Live Discord, Matrix, Slack, Telegram, or WhatsApp inbound messages; this PR is documentation/config metadata only and follows the already-landed runtime behavior from #70864.
* fix(agents): route media task hints below the system-prompt cache boundary
Per-turn image/video/music generation task hints were injected into the
static prependSystemContext slot, landing above the cache boundary inside the
cacheable prefix. The hints are present only on user/manual turns and vary
with active media tasks, so the cacheable prefix shifted turn-to-turn and
defeated Anthropic/OpenAI prompt caching (#85203).
Split the per-turn media hints out of the prepend resolver into
resolveAttemptMediaTaskSystemPromptAddition and route them below the boundary
via the existing prependSystemPromptAddition helper, matching how subagent and
context-engine system-prompt additions are already routed. The static plugin
prependSystemContext / appendSystemContext hook fields are unchanged and
remain in the cacheable prefix. Applied at both consumers (embedded agent
runner and CLI runner).
* fix(agents): keep media task hints below the cache boundary for hook systemPrompt overrides
A before_prompt_build hook that returns a full systemPrompt override replaces
the base prompt with marker-free text. Per-turn media-generation task hints
were then front-prepended into that marker-free prompt, which providers cache
as a single block, so the cached prefix still shifted turn-to-turn on the
override path (#85203).
Wrap the base with ensureSystemPromptCacheBoundary at both media-routing sites
(embedded agent runner and CLI runner) so a marker-free override gets an
appended boundary and the hint routes into the uncached suffix. The helper is
idempotent, so marker-bearing prompts are unchanged. The shared
prependSystemPromptAddition wrapper and the static prependSystemContext /
appendSystemContext hook fields are untouched.
* fix(agents): keep marker-free idle prompts cacheable below the boundary
A marker-free hook systemPrompt override only had the cache boundary
ensured on turns with an active media task. On idle turns the later
appendModelIdentitySystemPrompt landed above the absent boundary, so the
idle cached system prefix diverged from active turns and prompt caching
broke across active/idle transitions. Ensure the boundary regardless of
media state in both the embedded and CLI runners, and extend the
regression to cover the model-identity append across active->idle.
* fix(agents): scope cache-boundary ensure to the model-identity append
Ensuring the boundary unconditionally on media-idle turns appended a
boundary marker to empty raw/gateway system prompts (turning "" into a
marker-only prompt) and to prompts with nothing below the boundary.
Instead ensure the boundary only when a model identity line is actually
appended to a non-empty prompt, in both the embedded and CLI runners.
This still keeps the identity below the boundary for marker-free hook
systemPrompt overrides (the #85203 idle-cache regression) while leaving
empty and identity-less prompts untouched.
* test: refresh stale type and lint expectations
* test: stabilize CI timeout checks
* test: satisfy channel entry lint
* fix(agents): skip cache boundary for blank prompts
* fix(channels): keep draft flush timer referenced
* test(agents): tolerate failed exec timeout setup
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Provider-scoped configured regex mention patterns for Discord, Matrix, Slack, Telegram, and WhatsApp.
Native platform mentions keep their existing behavior, and unsupported channels do not opt into the new regex policy path. The new policy supports per-channel allow/deny routing through mentionPatterns.mode with allowIn and denyIn so group auto-reply regexes can be limited without broad global blast radius.
Refs #70864.
Supersedes #87200.
Thanks @patrick-slimelab.
Adds Xiaomi MiMo voicedesign TTS support by registering the v2.5 voicedesign model and omitting audio.voice for that model's prompt-driven voice design flow.
Also accepts generic TTS aliases modelId, speakerVoice, and speakerVoiceId for Xiaomi provider config and request overrides.
Fixes exec timeout classification so a process that exits after a missed timeout callback is still reported as timed out, using monotonic deadlines to avoid wall-clock skew.
Verification:
- node scripts/run-vitest.mjs extensions/xiaomi/speech-provider.test.ts
- node scripts/run-vitest.mjs src/process/supervisor/supervisor.test.ts
- node scripts/run-vitest.mjs src/agents/bash-tools.exec-foreground-failures.test.ts
- git diff --check
- autoreview --mode local
- live Xiaomi MiMo voicedesign call returned wav RIFF/WAVE output, 169004 bytes
- GitHub CI success on fb3018ef31: CI 26708919072, CodeQL Critical Quality 26708919082, CodeQL 26708919091, OpenGrep PR Diff 26708919089, Workflow Sanity 26708919083, Dependency Guard 26708918574, Real behavior proof 26708921767
Thanks @GimingRao.
Co-authored-by: Raoyu <2425198313@qq.com>
Co-authored-by: giming <53329020+GimingRao@users.noreply.github.com>
getTimeZoneOffsetMs built localAsUtc via Date.UTC() without the millisecond
argument, so for a sub-second instant the computed timezone offset was wrong by
that fraction. That corrupts resolvedMs and fails the exact-millisecond
re-validation in matchesOffsetlessIsoDateTimeParts, so parseOffsetlessIsoDateTimeInTimeZone
returned null for valid fractional input.
User impact: openclaw cron --at "<ISO>.<ms>" --tz <zone> was silently rejected
even though the parser's regex explicitly accepts fractional seconds (\.\d+).
Pass parts.millisecond (carried from utcMs via getUTCMilliseconds) into Date.UTC
so the offset is exact. Add fractional-second regression rows.
Co-authored-by: coder999999999 <coder999999999@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(infra): guard against overwriting corrupt target session store during migration
migrateLegacySessions reads the target agents/{id}/sessions/sessions.json
and merges it with the legacy sessions dir. When the target file is
corrupt, readSessionStoreJson5 swallows the parse error and returns
{store:{}, ok:false}, so the merge becomes legacy-only. The save gate
(legacyParsed.ok || targetParsed.ok) passes on legacyParsed.ok alone and
never checks targetParsed.ok, so the corrupt target is atomically
overwritten with the legacy-only store. Target-only session records (keys
with no legacy counterpart) are lost permanently and the corrupt file can
no longer be recovered by hand. Legacy corruption is already guarded
(warn + skip delete); target corruption was asymmetrically unprotected.
Skip the save (and the legacy delete) when the target store exists but is
unreadable, leaving the corrupt file and the legacy store both in place,
and push a warning mirroring the legacy-unreadable path. saveSessionStore
and readSessionStoreJson5 signatures are untouched.
AI-assisted: drafted with claude code (claude-opus-4-8).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(infra): report direct-chat session migration only after target save commits
Addresses ClawSweeper review on #88018. The `Migrated latest direct-chat session`
result.changes entry was pushed before the targetReadable guard, so the
corrupt-target skip path (which intentionally does not save) still reported a
session migration in doctor/startup logs. Defer that report into the
save-committed block (keeping its existing position before `Merged sessions
store`) and assert its absence in the corrupt-target regression test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(infra): add explicit corrupt session recovery
* fix(infra): keep legacy sessions retryable
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fix Control UI Talk consults so an empty final chat event no longer forces the no-text realtime tool result when a later source-reply or delivery-mirror final contains the answer displayed in the UI.
Also makes agent.wait use the chat-side terminal snapshot while a same-runId chat.send is active, so lifecycle completion cannot beat chat post-dispatch/source-reply delivery.
Adds regression coverage for delayed source replies, agent.wait failure/timeout handling, the wait-before-source-reply race, gateway wait ordering, and punctuation-only skill searches.
Fixes#85275.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Add bounded timeouts for Crabbox wrapper sanity probes so a stale or hung selected binary cannot block the wrapper indefinitely. The wrapper now maps timed-out sanity probes to a deterministic failure and keeps provider/help parsing behavior intact.
Also add regression coverage for a binary whose `--version` probe hangs while `run --help` still responds.
Co-authored-by: Evan Newman <evanjames010101@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(auto-reply): redact config show secrets
* fix(auto-reply): use schema redaction for config show
* fix(auto-reply): redact config set acknowledgements
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
WebChat now stores/restores composer draft and queued sends across refresh, scoped by gateway/session/agent. It skips in-flight/steered sends, restores after agent scope hydration, waits for fresh idle session proof before draining restored sends, and backfills visible chat history when the raw tail contains silent/context entries.
Refs #83344
Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
Fixes#86161.
Route Telegram media-message edits through the Telegram caption/reply-markup APIs instead of always calling `editMessageText`. Button-only edits now update reply markup, explicit captions use `editMessageCaption`, and text edits can fall back to caption edits when Telegram reports the message has no editable text.
Also documents the edit behavior, adds regression coverage, tightens timer-spy cleanup for the affected agents test lane, and removes a stale loader helper from the current base that broke core typecheck.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Remove isolate: true from the channel Vitest config and fix the leaking fake-timer/mock tests so the lane runs under the shared non-isolated runner. Verified with focused scoped-config/channel tests, the full channel Vitest config, git diff --check, and branch-mode autoreview.
Deliver same-session channel replies directly while preserving stale-reply guards.
The fix bypasses the announce decider only when the requester and target are the same source channel, carries reply baselines into fire-and-forget follow-up delivery, and keeps history reads best-effort so timeout-zero sends still dispatch. It also includes focused regression coverage for delayed same-session replies, stale snapshots, retry timer caps, and the current strict-null/package-boundary blockers fixed while preparing the PR.
Move Telegram plugin-local state from JSON sidecars into plugin-state SQLite. Keep legacy JSON handling in startup and doctor migration plans, with runtime state now reading and writing SQLite directly. Stabilize the channel Vitest lane by cleaning up typing timers and isolating that lane.
Adds a default-enabled SwiftPM Talk trait for OpenClawKit so chat-only consumers can opt out with traits: [] and avoid resolving ElevenLabsKit. Default traits preserve existing talk/TTS API and bundled app behavior; macOS CI now verifies the trait-off dependency graph and build.
Verification:
- CI at 85f00ebc04 passed macos-swift and Real behavior proof.
- Local Swift 6.3.2: trait-off dependency graph omitted ElevenLabsKit; full swift build with default traits disabled built through OpenClawChatUI; default dependency graph still included ElevenLabsKit; trait-off OpenClawKit target build passed.
- merge-tree against latest origin/main 4eba3e5d7d was clean.
- Current main already fails plugin-SDK declaration gates in unrelated TS files; reproduced locally with node scripts/run-tsgo.mjs -p tsconfig.plugin-sdk.dts.json --declaration true.
Thanks @mochiexists.
Co-authored-by: mochiexists <259077624+mochiexists@users.noreply.github.com>
Co-authored-by: atlascodesai <76924051+atlascodesai@users.noreply.github.com>
Keep Slack direct-message sessions stable while tracking routed Slack thread ids on active reply operations. Different top-level Slack DM threads from the same sender no longer steer into or block each other, while ordinary same-thread follow-ups and non-Slack direct-message behavior keep their existing semantics.
Verification:
- `git diff --check origin/main...FETCH_HEAD`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main --output /tmp/pr85904-autoreview.txt --json-output /tmp/pr85904-autoreview.json`
- GitHub CI green for head `6703e166545bcb96c1a50de93a42446212cca9a7`, including Real behavior proof and auto-reply reply routing/dispatch shards.
Co-authored-by: guanbear <123guan@gmail.com>
Fixes#88056.
Reload workspace skill commands for `/skill <name>` when directive resolution supplied only an empty placeholder list, so the generic skill wrapper can invoke the same command-visible skills as direct slash commands.
Keep stale-message cutoff and empty-config channel suppression ahead of skill discovery and tool dispatch so suppressed `/skill` messages cannot trigger side-effecting skill tools.
Co-authored-by: Ted Li <tl2493@columbia.edu>
Align Telegram proactive DM-topic outbound session routing with inbound reply routing.
The Telegram plugin now uses the chat-scoped DM-topic suffix for direct-topic outbound sessions, so cron/proactive sends and replies reuse the same session. Delivery metadata is kept as the numeric Telegram topic id so visible sends still target the correct private topic.
Refs #80212.
Thanks @brokemac79.
Verification:
- PR head d904115e4c
- GitHub CI/checks green on PR head; Real behavior proof passed; OpenGrep passed; CodeQL neutral/pass
- git diff --check origin/main...pr/88421 -- extensions/telegram/src/channel.ts extensions/telegram/src/session-route.test.ts
- git merge-tree $(git merge-base origin/main pr/88421) origin/main pr/88421
Fix stale heartbeat scheduler deferrals so disabled/non-retry skips and flood deferrals advance the due slot instead of rearming a 0 ms timer loop.
Fixes#79380.
Supersedes #79418.
Proof:
- pnpm test src/infra/heartbeat-runner.scheduler.test.ts -- --reporter=verbose
- pnpm check:changed via Testbox tbx_01ksxfavykc7qyve4ysnxg3smh
- autoreview clean
- GitHub CI green for 213003a854, including Real behavior proof
Add a bounded `chat.message.get` gateway method so Control UI can fetch one display-normalized transcript message by id when an assistant history preview was truncated. Keep `chat.history` lightweight, reject oversized/hidden/missing rows with explicit unavailable reasons, and wire the WebChat side reader to request full content only for visible truncated assistant messages.
Also refresh the generated Swift gateway protocol models and document the new assistant-message side-reader behavior.
Closes#84651.
Related #53242.
Co-authored-by: NianJiuZst <3235467914@qq.com>
Extract shared normalization/coercion helpers into private @openclaw/normalization-core workspace package while preserving existing plugin SDK helper subpaths.\n\nAlso keeps direct normalization-core imports internal, wires UI/build/loader resolution, and replaces the slow PR network CodeQL lane with a fast added-line boundary scan while retaining full CodeQL for scheduled/manual runs.\n\nVerification: local moved tests, plugin SDK boundary tests, extension loader tests, agents-support shard, UI build/test, build artifacts, lint, workflow guards, autoreview, and GitHub CI passed on PR head 963d893715.
Move Workboard durable data into a relational SQLite database and add extension doctor migration for .28 plugin-state rows. Preserve attachment lifecycle behavior, SQLite permissions/WAL settings, and scoped plugin migration access.
* feat(browser): add optional vision understanding to screenshot tool
* fix(browser): wrap vision output as external content, enforce maxBytes, forward auth profiles
* fix(browser): remove no-op scope/attachments config, drop profile pass-through lacking runtime support
* feat(media-understanding): add profile/preferredProfile to DescribeImageFileWithModelParams and forward to describeImage
* style(browser): add curly braces to satisfy eslint curly rule
* fix(browser): correct tools.browser.enabled help text to match actual behavior
* fix(browser): thread agentDir/workspaceDir from plugin tool context into browser vision
* refactor(browser): move vision config from tools.browser to browser.models
The browser plugin's vision configuration now lives on the top-level
`browser` config namespace (browser.models, browser.visionEnabled,
browser.visionPrompt, etc.) instead of `tools.browser`. This aligns
with the plugin's existing config location and avoids confusion between
tool-level and plugin-level settings.
- Remove tools.browser from ToolsSchema and ToolsConfig
- Add models/vision* fields to BrowserConfig and its zod schema
- Update getBrowserVisionConfig to read from cfg.browser
- Update schema help, labels, and quality test
- Update vision.test.ts to use new config shape
* docs(browser): add screenshot vision configuration section
Document the new browser.models config for automatic screenshot
description via vision models, enabling text-only main models to
reason about web page content.
* fix(browser): remove deliverable media markers from vision result, drop unused import
P1: Vision-success path no longer exposes the raw screenshot as
deliverable media (removes MEDIA: line and details.media.mediaUrl).
This prevents channel delivery from auto-sending sensitive page content
when the intended output is a text description.
P2: Remove unused ToolsMediaUnderstandingSchema import that would fail
noUnusedLocals typecheck.
* fix(browser): add command/args fields to browser models schema
The browser vision model schema uses .strict(), so CLI-type entries
with command/args were rejected by TypeScript. Add these fields to
align with MediaUnderstandingModelSchema.
* chore(browser): remove debug console.log statements
* fix(browser): harden screenshot vision result against MEDIA: directive injection and restore image sanitization on failure fallback
ClawSweeper #84247 review round 2:
P1 (security, high): neutralize line-start MEDIA: directives in vision descriptions
before wrapping with wrapExternalContent. The agent media extractor scans every
browser tool-result text block via splitMediaFromOutput which treats line-start
MEDIA: as a trusted local-media delivery directive, and browser is on the
trusted-media allowlist. Without neutralization, page or vision-provider output
containing 'MEDIA:/tmp/secret.png' could synthesize a channel-deliverable media
artifact from untrusted content. wrapExternalContent itself does not strip
line-start directives. Introduce neutralizeMediaDirectives in vision.ts that
prepends '[neutralized] ' to any line whose trimStart() begins with MEDIA:
(case-insensitive), defanging the parser anchor while keeping the original
text human-readable.
P2 (compatibility): pass resolveRuntimeImageSanitization() to imageResultFromFile
in the vision-failure catch fallback. The non-vision screenshot path already
forwards this option (d5cc0d53b7) so configured agents.defaults.imageMaxDimensionPx
takes effect. Without this fix, any provider timeout/error silently bypasses the
sanitization guard and returns a raw full-resolution screenshot.
Regression coverage:
- vision.test.ts: 6 unit cases for neutralizeMediaDirectives (no-op fast path,
mid-line MEDIA: untouched, line-start defanged, leading-whitespace defanged,
case-insensitive, multiple directives per blob).
- browser-tool.test.ts: 2 integration cases that drive the full screenshot
tool execute path:
- 'neutralizes MEDIA: directives in vision text and does not attach media'
asserts no line matches /^\s*MEDIA:/i in returned text, secret path text
is preserved verbatim, details.media is absent, and imageResultFromFile
is not called on the success path.
- 'preserves screenshot image sanitization on vision failure fallback'
mocks describeImageFileWithModel to reject and asserts the fallback
imageResultFromFile call receives imageSanitization: {maxDimensionPx:1600}
plus the 'browser screenshot vision failed' extraText.
* fix(browser): apply clawsweeper fallback media fix from PR #84247
* refactor: reuse media image understanding for browser screenshots
* refactor: use structured media delivery
* test: update music completion media instruction expectation
* fix: trim buffered reply directive padding
* test: refresh codex prompt snapshots for message media aliases
---------
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Add MCP server add/configure/login/reload flows plus config/runtime support for enablement, filters, timeouts, OAuth, TLS, and parallel execution hints. Update docs and tests for the expanded MCP operator surface.
Treat OpenAI-compatible streaming tool deltas as executable only when the final finish reason is `tool_calls`. This prevents malformed provider streams from triggering spurious tool execution while preserving normal tool-call responses.
Fixes#85161.
Verification:
- Local OpenAI-compatible SSE replay: spurious stop stream `finalToolCalls: 0`; valid tool-call stream `finalToolCalls: 1`.
- `pnpm test src/agents/openai-transport-stream.test.ts src/llm/providers/openai-completions.test.ts -- --reporter=verbose`
- PR CI green on `cdc2fc34753492c862cae99b37f8cf3761d9bbed`.
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
Preserve plugin-resolved cron delivery targets after target resolution so provider-looking canonical target prefixes are not stripped before outbound delivery.
Adds regression coverage for plugin canonical targets returned directly and via aliases, plus a guard that generic normalized fallback targets still strip the selected prefix.
Fixes#87905
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Surface gateway chat failures as visible assistant messages in the Control UI, with regression coverage and Crabbox/WebVNC proof.
(cherry picked from commit 31a46638ad)
Fixes#63558.
Adds a Dreaming-tab agent selector and propagates the selected agent through Dreaming status, diary, and diary actions while preserving default-agent fallback when agentId is omitted. Also keeps report Memory Palace cards in the Control UI wiki-preview flow and documents the optional Dreaming agentId gateway parameters.
Verification:
- GitHub CI run 26693682975 passed on 43a2b17243.
- CodeQL Critical Quality run 26693682971 passed.
- CodeQL / Security High run 26693682957 passed.
- Workflow Sanity run 26693682949 passed.
- OpenGrep PR Diff run 26693682947 passed.
- Dependency Guard run 26693682003 passed.
- Real behavior proof run 26693860539 passed.
- git diff --check origin/main...refs/remotes/origin/pr/78748 passed.
- git merge-tree --write-tree origin/main refs/remotes/origin/pr/78748 passed.
Thanks @stevenepalmer.
Co-authored-by: Steven Palmer <6134396+stevenepalmer@users.noreply.github.com>
Extracts serialized plaintext tool-call parsing, scrubbing, stream normalization, and standalone promotion into the private internal @openclaw/tool-call-repair package.
Provider wrappers and the embedded runner now share one repair path for standalone serialized tool calls, including adjacent text-block splits, while preserving exact argument bytes when already valid. The public plugin SDK payload module remains as the compatibility facade.
Verification:
- pnpm test src/plugin-sdk/provider-stream-shared.test.ts src/plugin-sdk/tool-payload.test.ts src/agents/embedded-agent-runner/run/attempt.tool-call-normalization.test.ts -- --reporter=verbose
- env -u OPENCLAW_TESTBOX pnpm check:changed
- PR CI: all reported checks green/skipped/neutral on ff0b3c0a5c
Refs #86924
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Preserve Slack Agents & Assistants DM root thread context for tool and subagent replies even when Slack omits or misreports `channel_type`, while leaving non-DM self-thread roots top-level.
Fixes#63659.
Thanks @zozo123.
Fixes#88214.
Control UI dashboard Recent sessions now follows the selected agent, preserves legacy main sessions under stale identity, keeps unknown sessions unscoped, and scopes agent/default session refreshes before the session-list limit. Completed run refreshes now use the run's original session/agent target, global New Chat creates under the selected agent, and the agent switcher preserves last known target sessions across scoped refreshes without resurrecting deleted or archived sessions while accepting newer out-of-scope live rows into the switch cache. Also fixes a current-main lint issue around trusted approval params.
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Classify release dependency ownership metadata so release evidence no longer reports current root dependencies as missing ownership metadata. Also recognizes command-explainer package-file lookups for tree-sitter-bash.
Verification: jq empty scripts/lib/dependency-ownership.json; node scripts/dependency-ownership-surface-report.mjs --check; node scripts/root-dependency-ownership-audit.mjs --check; targeted Vitest for root dependency ownership and ownership surface reports; git diff --check; autoreview clean; PR CI green including Real behavior proof.
* fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019)
When an Azure/OpenAI Responses session falls back to a non-Responses model
and later resumes a Responses model, sanitizeSessionHistory drops the
replayable reasoning (rs_*) item via downgradeOpenAIReasoningBlocks. The
paired assistant text block still carried its textSignature (the msg_* id),
so the transport replayed an assistant message item referencing msg_* with
no accompanying rs_* reasoning item. Azure Responses then rejected the next
turn with:
400 Item 'msg_...' provided without its required 'reasoning' item: 'rs_...'
permanently poisoning the session.
Fix:
- downgradeOpenAIReasoningBlocks now strips the textSignature from a turn's
text blocks whenever it drops a replayable reasoning item, so the msg_* id
and its rs_* reasoning are removed together. The transport then falls back
to a synthetic, unpaired id that Azure accepts.
- Because the synthetic fallback id is derived from the per-message msgIndex,
multiple id-less text blocks in one assistant turn (e.g. commentary +
final_answer) would collide on the same id. Make the fallback unique per
text block in both Responses conversion sites
(openai-transport-stream.ts and the shared llm provider
openai-responses-shared.ts).
Tests:
- sanitize-session-history: model-switch path drops the paired msg_* id.
- embedded-agent-helpers: downgrade strips paired text signature(s).
- reasoning-replay: multiple id-less text blocks get distinct item ids.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(responses): preserve phase metadata and guard malformed blocks (#88019)
Address PR review feedback on the orphaned msg_* replay fix:
- Preserve Responses phase metadata: dropping the paired msg_* id when its
rs_* reasoning is removed previously stripped the entire textSignature,
which also discarded the phase (commentary/final_answer). Phased text now
keeps a phase-only signature ({v:1,phase}) so commentary is not replayed
as user-visible output. Both parseTextSignature copies (shared provider and
embedded transport) now accept id-less phase-only signatures and fall back
to a synthetic id while preserving the phase.
- Guard malformed content blocks: the post-drop map no longer dereferences
contentBlock.type unconditionally, so a corrupted transcript with a
null/primitive block can still sanitize through a model switch.
Tests:
- sanitize-session-history: phase metadata is preserved while the paired id
is dropped on a model switch.
- reasoning-replay: id-less phase-only signatures get distinct synthetic ids
and retain their phase.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Payload-less session write-lock files now get a 30s grace for default/long acquire timeouts and cleanup sweeps, while short acquire timeouts keep 5s recovery. This avoids reclaiming a lock while the owner is suspended between exclusive create and metadata write.
Verified with:
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "node scripts/run-vitest.mjs src/agents/session-write-lock.test.ts"
- gh pr checks 80686 --repo openclaw/openclaw --watch=false
Thanks @wAngByg.
Extract web-content shared runtime helpers into packages/web-content-core, move the focused tests with the new package, and split quiet CI shards so the node matrix no longer stalls past the no-output watchdog.\n\nVerification: node scripts/run-vitest.mjs test/scripts/ci-node-test-plan.test.ts test/scripts/run-vitest.test.ts src/infra/restart.test.ts src/infra/os-summary.test.ts src/infra/gateway-processes.test.ts src/infra/inline-option-token.test.ts src/infra/map-size.test.ts src/infra/machine-name.test.ts src/commands/doctor-whatsapp-responsiveness.test.ts; autoreview clean; manual CI https://github.com/openclaw/openclaw/actions/runs/26693962844; dependency guard https://github.com/openclaw/openclaw/actions/runs/26693959937. Admin merge used because optional Mantis Telegram Desktop proof was cancelled after blocking merge outside this PR's required proof.
Bound MCP channel bridge pending Claude permission and approval maps with TTL sweep and close cleanup.
Also sweep before listing pending approvals so expired requests are not exposed between periodic ticks.
Fixes#71646.
Thanks @Feelw00.
Adds `openclaw sessions tail` as an operator-facing progress view over session trajectory events, with conservative redaction for prompt text, tool arguments, and tool result bodies. The command supports explicit session keys, store/agent scope, follow mode, relocated trajectory pointer files, and cursor-safe follow across bounded trajectory window rewrites.
Documents the new sessions tail CLI surface in `docs/cli/sessions.md`.
Fixes#83441.
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Skip browser lifecycle cleanup when root browser support or the browser plugin entry is disabled, and make the browser maintenance facade respect activation before cached surface use.
Also stabilize the resource-only MCP runtime test by waiting for the async rejection log that CI can observe late.
Verification:
- pnpm test src/plugin-sdk/browser-maintenance.test.ts src/browser-lifecycle-cleanup.test.ts src/auto-reply/reply/session.test.ts src/gateway/server.sessions.reset-cleanup.test.ts src/agents/auth-profiles/usage.test.ts
- pnpm test src/agents/agent-bundle-mcp-runtime.test.ts
- git diff --check
- pnpm build
- autoreview local: no accepted/actionable findings
- GitHub Actions: CI 26693713166, CodeQL 26693713159, CodeQL Critical Quality 26693713157, OpenGrep PR Diff 26693713125, Workflow Sanity 26693713149, Dependency Guard 26693712478
Co-authored-by: Nicolas Van Eenaeme <nicolas@poison.be>
Move MSTeams conversation and poll plugin-local stores to plugin-state SQLite. Legacy JSON stores import once without overwriting existing SQLite state; conversation and poll IDs are hashed for plugin-state keys; poll votes are sharded with bounded row-cap headroom and prune cleanup; MSTeams docs now describe SQLite storage. SSO and delegated token stores are unchanged. Verified with focused MSTeams tests, docs sanity, autoreview, Testbox check:changed, and green PR CI.
Deduplicate the browser lifecycle cleanup wrapper for embedded subagent completions while preserving retire and announce finalization for duplicate callers.\n\nAdds regression coverage for parallel completion callers and the held-first-cleanup duplicate-tail path.\n\nFixes #68668.\n\nCo-authored-by: Feelw00 <dhrtn1006@naver.com>
Repair invalid \u escapes during streaming JSON parsing without changing valid Unicode escapes. Split oversized node CI doctor/infra shards and fix the restart test mock deadlock so PR CI stays under the no-output threshold.\n\nCo-authored-by: Coder <83845889+coder999999999@users.noreply.github.com>
Move model catalog normalization and package-owned catalog schema/types into model-catalog-core while keeping public plugin SDK model catalog declarations on the existing SDK surface. Verified focused tests, package-boundary compile, full build, changed gate, declaration leak grep, CI, and autoreview.
Keep Codex app-server continuation turns alive after post-tool, raw assistant, and progress notifications, and reschedule continuation idle watches when shorter progress timeouts apply.
Add regression coverage for the plugin-sdk child_process mock helper deadlock that blocked CI shards on this PR.
Co-authored-by: abnershang <abner.shang@gmail.com>
Stop minimal cliStartup and gatewayWatch builds from copying generated plugin static assets they intentionally do not build.\n\nVerified with focused Vitest, autoreview, AWS Crabbox startup-memory proof, and AWS Crabbox changed gate run_bd9ea01e6a12 plus rebased changed gate run_bd9ea01e6a12.
* fix(export-html): guard all msg.content and result.content filter/iteration paths
Three call sites in the export HTML template called `.filter()` or iterated
with `for...of` directly on `msg.content` or `result.content` without first
checking `Array.isArray`. When a transcript message row carries a non-array
content value (null, undefined, or any scalar), those paths throw:
TypeError: msg.content.filter is not a function
Fix: normalize with `Array.isArray(x) ? x : []` before every unguarded
filter and iteration on `msg.content` (computeStats stats path and the
renderEntry assistant render loops) and `result.content` (renderToolCall
text/image accessors).
Regression test added: renderTemplate resolves without throwing for assistant
messages with null, undefined, string, and numeric content values.
Closes#88255
* fix(export-html): guard user message text extraction path against non-array content
The user-message render path in the export HTML template extracted text with
`content.filter(...)` without checking whether `content` is an array. A
persisted user message row with null, undefined, or any non-string scalar
content crashed during export with the same TypeError class as the assistant
path.
Fix: normalize the ternary so a non-string, non-array value falls through to
an empty string rather than calling `.filter` on it.
Regression test added for null, undefined, and numeric user message content.
Addresses feedback from ClawSweeper review on #88271.
* fix(export-html): preserve string content guards
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Move model catalog ref helpers into @openclaw/model-catalog-core/model-catalog-refs and update internal callers/package-boundary aliases. Also fix the timestamp predicate typing that blocked prod type checks on current main.
Fixes#37748.
Sort skill package archive entries by relative POSIX archive name so generated `.skill` bundles are reproducible regardless of filesystem traversal order.
Verification:
- `PYTHONDONTWRITEBYTECODE=1 python3 skills/skill-creator/scripts/test_package_skill.py`
- `git diff --check origin/main...HEAD`
- GitHub CI run 26690938925 on `43a0fdf7175f33a5c74bc7ff92723ebf5efc4df9`: all checks passed except repeated unrelated no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state` after visible tests passed.
Forward OpenAI-compatible stop sequences from gateway chat completions through the agent runner into provider transports.
The gateway now normalizes stop into sampling extras, agent transports pass it into the shared stream options, and OpenAI, Anthropic, Mistral, Google, and Vertex-backed simple providers map it to their native request fields. Provider/gateway/agent coverage plus Crabbox live gateway proof verify valid stop dispatch and invalid stop rejection.
Refs #87920
Show the remote node name in exec tool transparency details when an exec call targets `host=node`, while ignoring stray `node` values for gateway, sandbox, and auto-host calls.
Covers node-only, cwd+node, absent-node, and non-node-host regression cases in the tool display tests.
Fixes#77719.
Co-authored-by: JiataiWang <wangjiatai@proton.me>
Feishu `channels.feishu.streaming=true` now streams ordinary assistant replies through CardKit in auto mode, while keeping tool-summary delivery on the existing message path.
Also discards stale partial previews when final delivery intentionally suppresses text for voice media or duplicate final text, and preserves streamed partial text for regular media-only finals.
Verification:
- `node scripts/run-vitest.mjs run extensions/feishu/src/reply-dispatcher.test.ts`
- `pnpm tsgo:extensions`
- `pnpm test:extensions:package-boundary:compile`
- `pnpm exec oxfmt --check extensions/feishu/src/reply-dispatcher.ts extensions/feishu/src/reply-dispatcher.test.ts extensions/feishu/src/streaming-card.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub PR checks on run 26689677607 passed except repeated unrelated broad Vitest no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state`.
Co-authored-by: 传妈 <chuanmother@chuanMac-Mini.local>
Fixes#88218.
Preserves exact configured provider/model defaults before bare alias target reverse matches, while retaining slash-form aliases and auth-profile alias behavior.
Co-authored-by: Steven Palmer <palmer.e.steven@gmail.com>
Carry Discord reply typing feedback through preflight, queued dispatch, and cleanup so delayed accepted replies keep typing alive at the actual dispatch target without duplicate keepalives. Adds focused Discord queue/process policy coverage and stronger lifecycle invariant comments.
Prunes undefined Discord component and modal registry metadata before persisting it so SQLite-backed plugin state never receives JSON-incompatible undefined values. Adds direct regression coverage for undefined own properties on component, modal, and nested field entries.
Add actionable operator guidance when an unauthorized SIGUSR1 gateway restart is ignored because unmanaged restart is disabled.
The change is log-only: restart authorization and scheduling semantics are unchanged, and the existing run-loop test now asserts both the reason warning and the recovery hint.
Refs #79577
Refs #78110
Refs #82433
Co-authored-by: wAngByg <281221101+wAngByg@users.noreply.github.com>
Dedupe prompt-side inbound media note suffixes when sanitized MediaPath and MediaUrl render to the same value, while preserving genuinely distinct remote URLs.\n\nFixes #47587.\nThanks @MoerAI for the patch and @yzjJosh for the report.
Show the same Installing OpenClaw package progress line in the no-gum npm install fallback before redirecting npm output to the temp log.
Fixes#82305
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Adds focused coverage for task-domain view mapper DTO contracts, including summary cloning, task run/detail mapping, flow view/detail mapping, and implicit summary computation.
Test-only PR. Verified with git diff --check and PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false pnpm test src/tasks/task-domain-views.test.ts on the current-main merge result.
Thanks @leno23.
Co-authored-by: wuyangfan <yangfan.wu@succaiss.com>
Fixes#49517.
Updates the TUI command catalog so /new describes spawning an isolated session while /reset describes resetting the current session. Adds a focused regression test for the two descriptions.
Co-authored-by: KhanCold <119404710+KhanCold@users.noreply.github.com>
Adds a persisted collapse state for the Control UI Recent sessions sidebar group, including storage and browser coverage.
Also narrows gateway run miss cache expiry typing so the rebased branch stays clean against current main.
Closes#85510
Co-authored-by: NianJiuZst <3235467914@qq.com>
Route internal model catalog imports to the extracted @openclaw/model-catalog-core package and delete obsolete internal facades.
Keep public SDK declarations self-contained by wrapping core helpers at public boundaries instead of leaking private package imports.
Verification:
- pnpm test src/plugins/contracts/model-catalog-core-imports.test.ts src/plugins/sdk-alias.test.ts packages/model-catalog-core/src/configured-model-refs.test.ts packages/model-catalog-core/src/provider-model-id-normalize.test.ts packages/model-catalog-core/src/provider-model-id-normalization.test.ts src/config/config.model-ref-validation.test.ts src/agents/model-selection.test.ts src/plugin-sdk/provider-model-shared.test.ts -- --reporter=verbose
- pnpm check:test-types
- pnpm test:extensions:package-boundary:compile
- pnpm build
- rg "@openclaw/model-catalog-core" dist/plugin-sdk packages/plugin-sdk/dist -n --glob '*.d.ts' || true
- git diff --check
- autoreview clean after fix
CI note: merged with admin override because checks-node-agentic-commands-doctor and checks-node-core-runtime-infra-state failed twice with exit 143/no-output watchdog termination after prior passing test output, while relevant local proof and the rest of CI were green.
Fixes#88198.
Ignore top-level helper scripts in auto-discovered global/workspace extension roots so they do not become manifestless plugin candidates during config validation. Standalone plugin files remain supported when explicitly configured through `plugins.load.paths`, and docs now call out the supported path.
Verification:
- `node scripts/run-vitest.mjs src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `node scripts/run-oxlint.mjs src/plugins/discovery.ts src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `git diff --check`
- GitHub CI green at `93073bfa85ee294e644c623881ba59ba71d90975`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
Thanks @mushuiyu886 for the fix and @mmhzlrj for the report.
Pack newline-mode outbound paragraphs up to the configured text limit instead of sending one message per blank-line-separated paragraph. Preserves markdown fence guardrails and adds focused chunking plus outbound delivery regressions.\n\nVerified: autoreview clean; node scripts/run-vitest.mjs src/auto-reply/chunk.test.ts src/infra/outbound/deliver.test.ts; git diff --check origin/main...HEAD.\n\nThanks @kesslerio.
Fixes#66509.
QQBot now sends text-only tool progress immediately when partial streaming is enabled instead of buffering it until a fallback timer that is cleared by the final block. Immediate progress uses QQ plain-text sends so markdown-enabled accounts do not reinterpret media-like progress text, while streaming-off behavior remains final-only.
Thanks @gabrielduartesignart for the report.
Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* refactor: extract model catalog core package
* refactor: route model catalog imports through package boundary
* build: include model catalog in plugin sdk package dts
* fix: preserve static fallback model metadata
Classify the exact `ws` pre-handshake close-before-open error as a benign uncaught network exception so transient Feishu WebSocket cleanup does not crash the gateway process.
The classifier now keeps the upstream `ws` message as an exact contract and rejects broader prefixed WebSocket messages, with regression coverage for direct, wrapped, and non-exact cases.
Fixes#88257.
Thanks @akrimm702.
Co-authored-by: AI-HUB <144416483+akrimm702@users.noreply.github.com>
Completed WebChat stream segment bubbles now render without the active streaming animation after live output has moved on. The UI chat item contract now marks completed stream segments as non-streaming and the active stream as streaming, so the renderer applies the pulsing class only to live output.
Verified with:
- node scripts/run-vitest.mjs ui/src/ui/chat/build-chat-items.test.ts ui/src/ui/chat/grouped-render.test.ts ui/src/ui/views/chat.test.ts
- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui-stream-artifacts.tsbuildinfo
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
PR: #88225
Credit: @scotthuang
Refactor OpenAI provider identity so OpenAI remains the canonical provider for API-key and OAuth-backed flows while legacy openai-codex state is doctor/migration-only.
Keeps OpenAI Codex Responses as an API/transport class rather than a provider identity, moves auth aliases through providerAuthAliases, updates doctor repair sequencing for old auth/profile state, and refreshes tests/docs around the canonical OpenAI behavior.
Resolve raw plugin config environment references before plugin discovery and validation, while preserving the existing single-pass behavior for configs already loaded through config IO.
The loader now resolves raw config opt-ins with config.env vars included, bypasses active/cache reuse for that mode, and redacts plugin entry config from raw-mode cache keys so resolved secrets do not enter registry keys or reentry errors.
Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/loader.test.ts src/plugins/loader.runtime-registry.test.ts
- autoreview --mode branch --base origin/main
- pnpm check:changed on Blacksmith Testbox tbx_01ksw36bp7zygwxgq3jcsvjv3b / GitHub Actions run 26680322889
- PR CI green on facb77634e
Co-authored-by: Peter Lindsey <peter@lindsey.jp>
Adds first-class Xiaomi Token Plan provider support with regional onboarding/configuration, token-plan key prefix validation, runtime pricing/catalog metadata, and docs/test coverage.
Keeps Token Plan model catalog discovery runtime-owned so region-specific base URLs are required and the provider cannot silently fall back to the static SGP manifest catalog.
Fixes#86169.
Verification:
- node scripts/run-vitest.mjs src/plugins/provider-discovery.runtime.test.ts extensions/xiaomi/index.test.ts src/plugins/manifest-model-catalog.test.ts src/model-catalog/manifest-planner.test.ts
- git diff --check
- autoreview --mode local: clean, no accepted/actionable findings
- CI run 26678998539: all relevant checks passed; check-prod-types failed on unrelated browser unused-function issue already present on origin/main
Co-authored-by: NianJiuZst <3235467914@qq.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Keep Codex post-tool assistant/commentary progress and patch snapshot updates on the post-tool completion guard so long generated edits do not fall back to terminal idle handling. Enable Codex patch streaming events for native code mode and refresh exact prompt/config expectations.
Verification:
- pnpm prompt:snapshots:check
- pnpm test extensions/codex/src/app-server/run-attempt.turn-watches.test.ts extensions/codex/src/app-server/thread-lifecycle.test.ts extensions/codex/src/app-server/thread-lifecycle.binding.test.ts extensions/codex/src/app-server/side-question.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- git diff --check origin/main...HEAD
- exact-head CI run 26677938955
- Real behavior proof override run 26678097960
Thanks @keshavbotagent.
Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
Stop Codex app-server turns from projecting mirrored OpenClaw transcript history into prompt/model-input surfaces by default. Keep context-engine output on the rendered prompt/developer-instruction path and preserve mirrored history only for OpenClaw-side snapshots.
Move OpenClaw skills and the routed workspace-memory pointer out of native Codex turn user input and into turn-scoped collaboration developer instructions.
Preserve full MEMORY.md fallback prompt injection, delivery-hint rewrapping, lightweight cron exact prompts, and trajectory reporting for the rendered developer surface.
Co-authored-by: Beru <beru@lastguru.lv>
Fix Codex app-server native thread overflow recovery and CLI compaction fallback.
- rotate Codex native startup bindings when rollout token pressure leaves too little headroom
- keep byte-size rollout fuses ahead of rollout content reads
- clear stale resumed context-engine bindings only when the stored thread id still matches
- fall back to context-engine compaction when Codex owns/skips native compaction
Verification:
- node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-codex.config.ts extensions/codex/src/app-server/startup-binding.test.ts extensions/codex/src/app-server/run-attempt.context-engine.test.ts extensions/codex/src/app-server/session-binding.test.ts --reporter=verbose
- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts src/agents/command/cli-compaction.test.ts --reporter=verbose
- git diff --check origin/main...HEAD
- autoreview --mode branch --base origin/main: clean
- GitHub CI for 466bfbe78c: green
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
A claude-cli session whose JSONL transcript ends with an assistant
`tool_use` content block that was never answered by a `tool_result` user
message cannot resume — claude-cli will sit waiting for the missing
`tool_result`, hit its no-output watchdog, and the runtime kills it
with `reason=abort`. The dispatcher then sees an empty payload and emits
NO_REPLY, which to the user looks like the agent silently ignored their
message — same end-user symptom as the binding-flush amnesia bug, but a
different root cause.
The orphan can be left behind when:
- Gateway restarts mid-tool (brew upgrade, manual kickstart, OOM,
crash) — claude was waiting on a tool result that never arrived.
- `claude-live-session.ts` no-output watchdog fires while a tool is
actively running and OC kills the subprocess.
- The tool itself crashed or hung past its own deadline.
In all cases the resumed session is dead until the binding gets cleared,
because every subsequent resume hits the same trailing tool_use and the
same kill cycle. Observed in production on a personal OpenClaw gateway
(3d-engineer agent, 50-message-deep transcript ending in a Bash
`tool_use`; every Telegram message after the orphan landed silently
aborted at the 180s no-output mark).
Add `claudeCliSessionTranscriptHasOrphanedToolUse` to the helpers that
walks the JSONL, finds the last assistant message, and returns true if
any of its `tool_use` ids has no matching `tool_result` later in the
file. Wire into `prepareCliRunContext` as a second invalidator gate
alongside `missing-transcript`. The new `invalidatedReason:
"orphaned-tool-use"` follows the same path as missing-transcript: the
binding is dropped, this turn starts a fresh session, and the prior
context is reseeded into the new session via `RAW_TRANSCRIPT_RESEED`.
Detection only considers TRAILING orphans — an unanswered tool_use
deeper in history is inert because a later assistant message already
moved past it. Only the most recent assistant message's tool_use ids
matter for forward progress.
Probe runs only for claude-cli providers and only when the transcript-
content gate already passed, so we add no I/O on already-invalidated
sessions and no behavior change for non-claude providers.
AI-assisted: yes. Tooling: Claude Opus + claude-cli.
When a claude-cli turn produces a session id but the underlying claude
subprocess fails to flush an assistant-role record to its
~/.claude/projects/<cwd>/<sid>.jsonl transcript (e.g. mid-turn kill from
a concurrent fingerprint-mismatched turn, supervisor restart, internal
failure), buildCliRunResult was still persisting that session id into
cliSessionBinding. The next turn ran claudeCliSessionTranscriptHasContent,
didn't find the file, logged 'cli session reset: reason=missing-transcript',
and started a brand-new claude session with empty memory.
End-user symptom: agent forgets prior conversation between turns.
Gate the cliSessionBinding spread on the same predicate the next-turn
invalidator uses, evaluated at write time. Also clear agentMeta.sessionId
in the same case so the session-store fallback at command/session-store.ts
(which reads agentMeta.sessionId via setCliSessionId when the binding is
absent) doesn't re-persist the unflushed sid through a different field
path. The fallback is what makes the binding-only gate insufficient on
its own; both writes must drop together.
The gate only fires for claude-cli providers — other CLI providers don't
write to ~/.claude/projects, so probing them would always return false
and incorrectly strip valid binding metadata. isCliBindingFlushed now
takes the provider id and returns true unconditionally for non-claude-cli
sessions.
A bounded retry (0 / 50 / 150 ms) tolerates the brief gap between
claude-cli's stdio close and the OS making the JSONL line visible to
readers (cooperative fsync semantics on APFS, but not guaranteed under
stress).
The transcript-probe is exposed as an injectable dep
(setCliRunnerTestDeps / restoreCliRunnerTestDeps) mirroring the existing
pattern in src/agents/cli-runner/prepare.ts so isCliBindingFlushed is
testable without touching ~/.claude/projects.
AI-assisted: yes. Tooling: Claude Opus + claude-cli. Codex review caught
the fallback path and the missing provider gate before this hit upstream.
Real-Behavior-Proof: dist-side patch on M5 gateway; branch-build
follow-up pending — see PR body.
Move task run, delivery, and flow registry persistence onto the shared OpenClaw state SQLite database.
Summary:
- Store task runs, delivery state, and flow runs in state/openclaw.sqlite via the generated Kysely schema.
- Migrate shipped task sidecars into the shared state DB and archive old sidecars, including invalid-config/read-only CLI paths.
- Keep startup migration lightweight for read-only status/tasks paths while still detecting known legacy state markers and custom session stores.
Verification:
- .agents/skills/autoreview/scripts/autoreview --mode local: clean after final fix
- pnpm test src/tasks/task-registry.store.test.ts src/tasks/task-flow-registry.store.test.ts src/commands/doctor-state-migrations.test.ts -- --reporter=verbose
- pnpm test src/commands/doctor-state-migrations.test.ts src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-path-policy.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-startup-policy.test.ts src/cli/command-path-policy.test.ts src/cli/command-execution-startup.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/argv.test.ts src/cli/route.test.ts src/commands/doctor-config-preflight.state-migration.test.ts -- --reporter=verbose
- pnpm test src/tasks/task-flow-registry.store.test.ts -- --reporter=verbose
- pnpm test test/scripts/lint-suppressions.test.ts -- --reporter=verbose
- pnpm db:kysely:check
- pnpm lint:kysely
- git diff --check HEAD
- pnpm test:startup:memory
- PR CI green on 2f7d76f0d5
Preserve iMessage SMS reply routes for approval replies so a direct SMS /approve response can acknowledge and return results to the same SMS conversation.
Verification: gateway-only build, extension type checks, CI build-artifacts/check-prod-types/check-test-types/check-lint/check-additional-extension-package-boundary, and live prod iMessage SMS approval proof. checks-node-core-fast was waived by maintainer request after unrelated flaky failures in non-iMessage tests.
Adds Workboard orchestration statuses, dependency links, idempotent child creation, dispatch, and complete/block lifecycle operations backed by the plugin SQLite keyed store.
Persists tenant, skills, workspace, schedule, runtime, retry, dispatch, and handoff metadata in card records, with claim scoping and token redaction. Surfaces the new states and metadata in the Control UI, horizontal board layout, localized strings, and Workboard docs.
Verification:
- pnpm test extensions/workboard/src/store.test.ts extensions/workboard/src/tools.test.ts extensions/workboard/src/gateway.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/styles/workboard.test.ts ui/src/ui/views/workboard.test.ts -- --reporter=verbose
- pnpm ui:i18n:check
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main, followed by focused clean local autoreview loops for final fixes
- env -u OPENCLAW_TESTBOX pnpm check:changed
- git diff --check
Summary:
- The PR classifies selected embedded agent provider-denial error payloads through the shared failover matcher ... 1/current-ak auth matching, preserves guarded non-fallback cases, and covers fallback progression in tests.
- PR surface: Source +34, Tests +166. Total +200 across 5 files.
- Reproducibility: yes. Current main is source-reproducible: a non-GPT embedded result whose only signal is CE ... returns null from the classifier, and the fallback wrapper treats null classification as candidate success.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): classify embedded provider business denials for fallback
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8304…
Validation:
- ClawSweeper review passed for head e266beac93.
- Required merge gates passed before the squash merge.
Prepared head SHA: e266beac93
Review: https://github.com/openclaw/openclaw/pull/84814#issuecomment-4505010446
Co-authored-by: Stellar鱼 <2182712990@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Fixes#86820.
Preserve Codex OAuth-backed compaction by selecting and loading the Codex harness before resolving direct or queued compaction models, while keeping OpenAI-compatible custom base URLs on the OpenAI context config path. Also preserves persisted concrete harness pins so compaction does not hot-switch existing sessions just because an explicit Codex fallback exists.
Verification:
- node scripts/run-vitest.mjs src/agents/embedded-agent-runner/compact.hooks.test.ts src/agents/harness/selection.test.ts src/agents/harness/runtime-plugin.test.ts
- pnpm tsgo:prod
- pnpm check:test-types
- pnpm lint --threads=8
- git diff --check origin/main...HEAD
- git diff --check
- autoreview clean: no accepted/actionable findings reported; overall patch is correct (0.82)
- GitHub PR checks green on ac6f93de4a
Fix Codex app-server completion-stall recovery so replay-safe stdio completion-idle failures retry once, while progress/terminal turn-watch timeouts only surface timeout payloads.
Also preserve post-tool completion guards for scoped native response deltas and stabilize the oversized CONNECT timeout regression test picked up from latest main.
Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
Adds the shared SQLite state database base, moves plugin keyed state into it with doctor migration coverage, and keeps generated Kysely guardrails aligned. Proof: focused SQLite/plugin-state tests, db:kysely:check, lint:kysely, architecture/dependency guards, autoreview, and PR CI all clean.
Move compaction planning work to a bounded worker-thread path so large transcript planning no longer monopolizes the agent event loop. Extract pure planning helpers, sanitize worker inputs before structured clone, package the worker entrypoint, and keep synchronous fallback only for worker-unavailable cases.
Fixes#86358.
Fixes#87438.
Bound unset heartbeat run timeouts so background heartbeat turns no longer inherit the built-in 48-hour interactive agent default. Timeout precedence is explicit heartbeat timeout, explicit global agent timeout, then heartbeat cadence capped at 600 seconds.
Verification:
- git diff --check
- Testbox tbx_01kstna69zvznn4fq7zrqr04a1: corepack pnpm test src/infra/heartbeat-runner.model-override.test.ts -- --reporter=verbose passed 13 tests
- Direct node --import tsx runtime probe verified 300s, 600s, 60s, and 45s timeout precedence cases
- Autoreview clean
Known CI state:
- PR CI run 26661465248 has failures matching latest main CI run 26661386468 at a7820b2f54; failures are outside this six-file heartbeat/docs diff.
Keep session lock cleanup from removing live OpenClaw-owned locks solely because they are old. Cleanup now reports age-only stale locks without deleting them, while still removing dead, orphaned, recycled, malformed-old, and non-OpenClaw-owned locks.
Update doctor docs and regression coverage for the cleanup/repair contract.
Refs #87779
Notte exposes a CDP-compatible WebSocket gateway at
wss://us-prod.notte.cc/sessions/connect?token=<NOTTE_API_KEY> that
auto-creates a session on connect — the same shape OpenClaw's existing
"Direct WebSocket CDP providers" section was generically framed for
(per #31085).
Real behaviour proof (against wss://us-prod.notte.cc/sessions/connect):
$ openclaw browser --browser-profile notte open https://example.com
opened: https://example.com/
tab: t4
id: 7FE04AC44931A6E1C799DE4ABF0DC807
A screenshot captured against the same session is a 1254x1111 PNG of
the rendered example.com page.
Playwright connectOverCDP flow against the same URL (today):
connectOverCDP 695ms
context.newCDPSession(page) 169ms
session.send('Target.getTargetInfo') → targetId 87ms
page.goto('https://example.com') 631ms
total 1.8s
AI-assisted (Claude Opus 4.7). codex review --base origin/main returned
clean. See PR description for the full pre-flight checklist.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Forward initial image/file attachments when spawning ACP subagents through the existing sessions_spawn attachment opt-in. Remove the PR-only acpEnabled config split so ACP uses the same attachment gate as other runtimes.
Also fix the PR branch CI fallout: type the browser element CLI request mock and use Vitest env stubs in the Azure speech test to satisfy the changed-path security scan.
Verification:
- GitHub CI passed on f6ca26b160.
- Autoreview clean.
- Crabbox AWS live OpenAI proof passed: cbx_a576d49493fe / run_081dcc6c6a1b.
Thanks @zhangguiping-xydt.
Fix `sessions.json` persistence after compaction transcript rotation.
When the agent runtime rotates from the pre-compaction session transcript to the post-compaction transcript, post-run consumers now receive the effective OpenClaw session id and session file. Backend CLI session ids remain backend metadata and no longer overwrite the top-level OpenClaw session identity.
Refs #88040.
Thanks @1052326311.
Verification:
- `node scripts/run-vitest.mjs src/agents/agent-command.compaction-rotation.test.ts src/agents/agent-command.live-model-switch.test.ts src/agents/command/session-store.test.ts`
- Autoreview clean
- GitHub CI green on PR head `c3d3c77ddf675bbba0b9ba6681b030a2f69a898c`
Fix claude-cli transcript resume so session-id rotation and transcript flush timing do not drop valid resume state.
- Capture the latest claude-cli session_id from JSONL output.
- Resolve Claude project transcript paths through the shared canonical project-dir resolver.
- Probe transcript content from the actual CLI process cwd.
- Thanks @benjamin1492!
Persist GitHub Copilot SDK session ids in the plugin-state SQLite store so separate OpenClaw process turns can resume the same Copilot-side session when the compatibility fingerprint still matches.
The fingerprint covers provider/model/cwd, resolved agent id, resolved Copilot home, and auth identity. Plugin-state lookup/register/delete failures are non-fatal, stale rows are invalidated, and reset delete failures use an in-process tombstone so reset does not accidentally reuse a durable binding.
Also routes the QQBot token POST through the plugin SDK SSRF guard with capture disabled for the secret-bearing request, preserving the current token lifetime validation from main.
Verification: focused Copilot and QQBot Vitest suites, raw channel fetch guard, autoreview clean, Blacksmith Testbox pnpm check:changed tbx_01kst9fwjmsfzwaxqatszcbf40, live local Copilot two-turn smoke with the same SDK session id persisted in SQLite.
Refs #88064
Summary:
- The PR changes plugin auto-enable materialization so an explicit empty `plugins.allow` stays empty while non-empty restrictive allowlists are still extended, and adds a regression test.
- PR surface: Source +3, Tests +17. Total +20 across 2 files.
- Reproducibility: yes. Source inspection of current main shows an empty array reaches `ensurePluginAllowlisted`, and the linked report gives a concrete `doctor --fix` config path that matches that code.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head c06837f5dd.
- Required merge gates passed before the squash merge.
Prepared head SHA: c06837f5dd
Review: https://github.com/openclaw/openclaw/pull/87883#issuecomment-4570537738
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Active Memory recall now runs on its own queue lane instead of sharing the parent prompt-build lane.\n\nValidation:\n- git diff --check\n- node scripts/run-vitest.mjs extensions/active-memory/index.test.ts -t "runs recall on a dedicated active-memory lane"\n- fresh local gateway smoke with Active Memory + Memory Core + loopback OpenAI-compatible model: HTTP 200, active-memory start/done, recall elapsedMs=209\n\nFixes #79026.\nRelated: #72015.
Summary:
- The PR updates Codex doctor route repair to preserve explicit non-default `agentRuntime` pins across agent model maps and provider policies, adds regression coverage, and tightens a live-gateway test helper type guard.
- PR surface: Source +240, Tests +574. Total +814 across 3 files.
- Reproducibility: yes. The source path is clear from current main's model-map merge behavior and the PR's bef ... beRepairCodexRoutes` with the reported config, though this read-only review did not execute the test suite.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(doctor): preserve explicit non-default agentRuntime pin during le…
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8414…
Validation:
- ClawSweeper review passed for head c142ec1ef8.
- Required merge gates passed before the squash merge.
Prepared head SHA: c142ec1ef8
Review: https://github.com/openclaw/openclaw/pull/84362#issuecomment-4493152445
Co-authored-by: David Huang <nxmxbbd@gmail.com>
Co-authored-by: Nex <nex@dbitstec.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Add a general typed tool-progress contract so long-running non-exec tools can emit public channel progress without overloading model-facing tool content.
`web_fetch` now uses the generic delayed progress helper: it shows `Fetching page content...` only when the fetch is still pending after five seconds, clears the timer on completion/abort, passes the abort signal into guarded fetch, and avoids provider fallback or cached success after cancellation. The subscriber path accepts only explicit `visibility: "channel"` and `privacy: "public"` progress metadata, while untyped tool partials and exec output keep their existing behavior.
Docs now explain typed progress, delayed producer examples, and the `web_fetch` timing behavior.
Proof: `pnpm test src/agents/tools/web-tools.fetch.test.ts src/agents/embedded-agent-subscribe.handlers.tools.test.ts -- --run`; `pnpm docs:check-mdx`; changed-file `pnpm exec oxlint ...`; `git diff --check`; autoreview clean.
Match text slash command names case-insensitively across the reset/new fallback paths and the shared registry/control detection contract while preserving command argument casing.
Add regression coverage for uppercase and mixed-case reset/new commands plus registered non-reset commands such as `/STATUS`, `/Model`, `/T`, and `/COMPACT`.
Co-authored-by: zhangtong26 <zhangtong26@xiaomi.com>
Co-authored-by: Lanzhi <lizhan3@xiaomi.com>
Remove stale Telegram-only wording from the reasoning stream acknowledgement and docs so channel-neutral behavior is reflected.
Fixes#68305.
Co-authored-by: Lanzhi <lizhan3@xiaomi.com>
Load `docker-compose.override.yml` when ClawDock builds its explicit Docker Compose file list, preserving standard Compose override behavior while keeping `docker-compose.extra.yml` as the final OpenClaw overlay.
Update Docker docs so manual Compose users include the same override order, and keep the regression test for the generated `_clawdock_compose` arguments.
Fixes#49909.
Thanks @spacegeologist.
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Preserve npm install selectors while recording resolved npm provenance for plugin and hook install/update records. Active `record.spec` stays the requested selector unless explicitly pinned, while resolved npm fields remain available for audit and diagnostics.
Adds focused coverage for hook-pack npm fallback provenance after the maintainer review found that path worth pinning down.
Co-authored-by: Phil <99397913+GitHoubi@users.noreply.github.com>
Forward Zalo quote-reply metadata from zca-js data.quote into the existing ReplyToId, ReplyToBody, and ReplyToIsQuote context keys so agents can correlate quoted replies with prior bot messages.
Adds parser and monitor regression coverage for quote extraction and context projection.
Fixes#86851.
Thanks @tanshanshan.
Remove unreachable optional chaining from four Discord message-handler-family runtime error calls.
This aligns the code with the required RuntimeEnv.error contract while leaving production behavior unchanged for valid runtimes. Maintainer-updated PR proof clarifies that shared queue reporter hooks still treat malformed runtime reporter failures as best-effort.
Clean up completed exec tool-call abort listeners so normal foreground completion and background-yield no longer retain the exec run/session context through AbortSignal listener state.
The listener cleanup now lives beside the exec listener registration and runs when the foreground process settles, rejects, or the tool returns a background running result. Existing abort/timeout/background behavior remains owned by the process supervisor and process registry.
Verification:
- gh pr checks 83022
- gh api repos/openclaw/openclaw/commits/fe86528ecb2043b6febef5c2eec53f9124be5543/check-runs
- git merge-tree --write-tree origin/main refs/remotes/pr/83022
- git diff --check origin/main...refs/remotes/pr/83022
- node AbortSignal add/remove listener probe
Thanks @c19354837.
Co-authored-by: Ninty <c19354837@hotmail.com>
Fixes#66479.
Workspace skills whose SKILL.md starts with a UTF-8 BOM now keep their shared markdown frontmatter metadata, so they remain discoverable through skills list. The fix strips one leading BOM at the parser boundary and adds parser plus workspace discovery regression coverage.
Thanks @jbetala7 for the fix.
Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
Route Microsoft Teams attachment downloads through the shared SSRF guarded fetch path so DNS validation is pinned into the dispatcher used for the actual request.
Keep Teams auth fallback and allowlisted HTTPS Authorization redirect behavior while failing closed for custom fetch hooks that cannot accept dispatcher injection.
Verification:
- CI=1 OPENCLAW_VITEST_MAX_WORKERS=1 timeout 300 node scripts/run-vitest.mjs run extensions/msteams/src/attachments/shared.test.ts extensions/msteams/src/attachments/bot-framework.test.ts src/infra/net/fetch-guard.ssrf.test.ts
- gh pr checks 87567 --repo openclaw/openclaw --watch=false
PR: #87567
Fix cron local-model preflight fallback handling so scheduled runs try configured fallback candidates before skipping when the local primary is unavailable.
Verification:
- GitHub CI on PR head fe884dab90: passing required CI checks.
- Local focused cron/model fallback tests passed earlier for the touched surface.
- Local merge-wrapper build and check passed on the prepared candidate.
- Local full pnpm test reported unrelated failures outside this PR's touched files; touched files are limited to cron docs, src/agents/model-fallback.ts, and src/cron/isolated-agent/*.
Co-authored-by: chen-zhang-cs-code <chenzhangcode@163.com>
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
Remove the chatType === 'direct' guard from
shouldAllowQuietChannelOwnedProgressCallbacks so that channel-owned native
progress callbacks (onToolStart, onItemEvent, onPlanUpdate,
onApprovalEvent, onCommandOutput, onPatchSummary, onCompactionStart/End)
are forwarded in group and group-channel sessions when verbose is off.
Previously the guard required chatType === 'direct', which meant that
/verbose off would suppress all progress callbacks in group sessions
while direct sessions continued to relay them. Message-level tool
summary suppression is handled separately; native channel relay hooks
should not be gated on chat type.
Closes#87612
Cache single-row gateway session child indexes without hiding live subagent registry changes.
Summary:
- Reuses store-derived child-session candidates for repeated single-row session loads.
- Keeps runtime subagent registry reads live per row so moved child sessions do not stay attached to stale parents.
- Versions the session-store cache and includes that version in the single-row cache key so same-object store rewrites cannot reuse stale child candidates.
- Adds focused regression coverage for cache reuse, live registry refresh, and same-object session-store writes.
Verification:
- git diff --check
- pnpm tsgo:prod
- pnpm test src/gateway/session-utils.single-row-cache.test.ts src/gateway/session-utils.subagent.test.ts -- --reporter=verbose
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI run 26620265206: passing
- Azure Crabbox cbx_a58389e50f49: single-row-loads 13.622240 ms before vs 1.869456 ms after, 7.29x speedup, 86.3% reduction
* feat: add Claude Opus 4.8 support
* fix: omit Vertex Opus sampling overrides
* fix: preserve Opus adaptive thinking levels
* fix: clamp Anthropic max effort support
* fix: use sha256 for QA mock call ids
* fix: type Anthropic transport test model metadata
* test: update PDF model default for Opus 4.8
Summary:
- This PR adds an internal gateway active-run projection flag, clears it during terminal lifecycle handling be ... ons.list on that flag, adds gateway regression coverage, and tightens memory-wiki confidence normalization.
- PR surface: Source +29, Tests +131. Total +160 across 7 files.
- Reproducibility: yes. Source inspection shows current main can broadcast terminal sessions.changed before ch ... the abort-controller entry, and the before/after recording supports the visible stuck In progress symptom.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): preserve chat retry guard after terminal state
- PR branch already contained follow-up commit before automerge: fix(gateway): clear completed session active runs
Validation:
- ClawSweeper review passed for head 9b132bdc2b.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9b132bdc2b
Review: https://github.com/openclaw/openclaw/pull/87810#issuecomment-4569094800
Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Adds opt-in Discord progress-draft commentary for assistant preambles while keeping commentary hidden by default and final delivery unchanged.
Keeps commentary config Discord-specific, strips directive tags/NO_REPLY, and clears stale commentary rows without stopping the active draft stream.
Thanks @bryanpearson.
Co-authored-by: bryanpearson <bryanmpearson@gmail.com>
Preserve OpenClaw-owned embedded system prompts after active tool selection in both normal embedded attempts and compaction. Adds an exact base prompt path on AgentSession that keeps active tool prompt metadata current for extension hooks.
Fixes#87807.
Verification:
- mise exec node@24.16.0 -- node scripts/run-vitest.mjs src/agents/sessions/sdk.test.ts src/agents/embedded-agent-runner/system-prompt.test.ts src/agents/embedded-agent-runner/run/attempt.spawn-workspace.context-engine.test.ts src/agents/embedded-agent-runner/compact.hooks.test.ts --reporter=dot
- mise exec node@24.16.0 -- pnpm tsgo:core
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
Thanks @shakkernerd.
Handle exec-backed Gateway SecretRefs in doctor, lint, and health probing without executing providers by default.
- Add `openclaw doctor --allow-exec` for explicit SecretRef execution during lint/doctor checks.
- Skip only the active exec-backed gateway probe path and avoid local service diagnostics for remote-only skipped health.
- Keep env-winning and dormant fallback credentials probeable, stabilize related tests, and remove a stale live-shard fixture left by the moving base.
Verification:
- `node scripts/run-vitest.mjs src/commands/doctor-gateway-auth-token.test.ts src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts src/gateway/credentials.test.ts src/gateway/probe-auth.test.ts src/commands/doctor-gateway-daemon-flow.test.ts test/scripts/test-live-shard.test.ts --reporter=verbose`
- `mise x node@24.13.0 -- pnpm prompt:snapshots:check`
- `pnpm tsgo:prod`
- `pnpm build`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- Crabbox AWS live config proof: `run_f44a4d9dae4e`
- GitHub CI: green on final head `88d24abdbf9529a59d75d1d5e04eac74bbbbc267` after rerunning a stale in-progress Security High workflow.
Co-authored-by: Merlin <258679497+funmerlin@users.noreply.github.com>
Fixes#87132.
Default Usage now requests all configured agents with `agentScope: "all"`, while selecting a specific agent sends `agentId` consistently to both session usage and cost usage calls. The gateway now supports explicit all-agent session usage, aggregates all-agent cost summaries across configured agents, and keeps scoped cache entries separate. Legacy gateway fallbacks remain for older `agentId` / `agentScope` support, with protocol docs/schema and Swift generated models updated.
Verification:
- `node scripts/run-vitest.mjs ui/src/ui/controllers/usage.node.test.ts ui/src/ui/app-render-usage-tab.test.ts ui/src/ui/views/usage.test.ts --reporter=dot`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway-methods.config.ts src/gateway/server-methods/usage.test.ts src/gateway/server-methods/usage.cost-usage-cache.test.ts src/gateway/server-methods/usage.sessions-usage.test.ts --reporter=dot`
- `pnpm check:test-types`
- `pnpm protocol:check`
- targeted `node scripts/run-oxlint.mjs ...`
- `git diff --check`
- autoreview clean after Swift compatibility fix
- PR CI green at head `d67156a3c552c4f9c8b6edf8516b6242bf5cdd26`
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
Keep Codex reasoning updates as accumulated snapshots and mark the stream payload so channel consumers can distinguish snapshots from deltas.
This prevents Discord and Teams progress previews from duplicating accumulated reasoning text while preserving delta-style reasoning for legacy producers.
Refs #86708
Thanks @SebTardif.
Co-authored-by: OpenAI Codex <codex@openai.com>
Scope jiti filesystem transform caches for OpenClaw plugin loaders by package version and package.json install metadata so stale transforms cannot survive upgrades or package reinstalls.
Covers the central plugin module loader and the plugin SDK root alias CJS loader, while preserving jiti filesystem-cache env opt-outs and the TMPDIR cwd guard.
Verification: CI run 26601117143 passed; Real behavior proof run 26601445285 passed; CodeQL selected checks passed in run 26601117126; CodeQL Critical Quality plugin-boundary and plugin-sdk-package-contract passed in run 26601117074; OpenGrep PR diff passed in run 26601117137.
Refs: https://github.com/openclaw/openclaw/pull/87745
Thanks @fuller-stack-dev.
Route Codex app-server report-mode PreToolUse plugin approval requirements through the matching app-server approval request instead of failing closed. Shares duplicate in-flight approvals, preserves block/rewrite fail-closed behavior, and keeps generic plugin allow-always scoped to one Codex request. Supersedes #86978; thanks @clawSean for the original docs clarification.
Compact promoted short-term memory snippets before writing them into MEMORY.md, while keeping the full rehydrated snippet in recall state for ranking/provenance. Adds the deep-dreaming config surface and docs, with the default promoted snippet cap set to 160 estimated tokens.
Verification:
- git diff --check
- fnm exec --using v24.13.0 node scripts/run-vitest.mjs run extensions/memory-core/src/short-term-promotion.test.ts extensions/memory-core/src/dreaming.test.ts src/memory-host-sdk/dreaming.test.ts
- GitHub CI run 26605272497
- CodeQL security run 26605272404
Co-authored-by: AMARA <amara@eyeinthesky.pl>
Server-side cron job list filtering now applies schedule-kind and last-run-status filters before pagination, and the UI only sends table filters for the cron table view.
Fixes#9455.
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
* fix(msteams): rebase SDK migration onto current main
Reapply the msteams SDK migration (originally on feat/msteams-sdk-migration)
on top of upstream/main, resolving conflicts with parallel msteams work that
landed upstream during our session.
What got applied vs decisions made:
CLEANLY APPLIED (3-way patch):
- monitor.ts, monitor-handler.ts, polls.ts, reply-stream-controller.ts/.test.ts,
reply-dispatcher.ts, attachments/download.ts, monitor.lifecycle.test.ts,
monitor-handler/message-handler.ts, monitor-handler.types.ts, etc.
- streaming-message.ts + .test.ts deletions
WHOLESALE TAKE FROM ORIGINAL BRANCH (partial 3-way left broken cross-refs):
- sdk.ts, sdk.test.ts, messenger.ts, feedback-reflection.ts,
send-context.ts, send.test.ts
KEPT UPSTREAM (deferred for separate cleanup):
- extensions/msteams/package.json (still has jsonwebtoken/jwks-rsa per
Peter's b3bc60ae25 incremental approach)
- src/plugins/contracts/package-manifest.contract.test.ts (consistent with
package.json)
- pnpm-lock.yaml (avoids lockfile churn; pnpm install --frozen-lockfile clean)
ADAPTED:
- Dockerfile matrix-sdk-crypto check now wraps upstream's new retry-loop in
the if-matrix-bundled gate
KNOWN TEST FAILURES (need eyes — see PR comment):
- attachments.test.ts: 1 fail (pre-existing — warn meta arg shape changed in
our migration but test wasn't updated)
- reply-dispatcher.test.ts: 6 fails (pre-existing — tests mock old
TeamsHttpStream, not updated for our ctx.stream rewrite)
- send.test.ts: 4 fails (NEW from merge — upstream's send.ts changed media
loading; our mocks need updating or take upstream's send.test.ts wholesale)
UPSTREAM COMMITS POTENTIALLY MISSED (in wholesale-take files):
- 08c4af0ddf fix(msteams): accept conversation id allowlists
- e1840b8581 fix(msteams): bind global audience tokens to app id
- Channels turn-kernel refactor (ffe67e9cdc / 1ead1b2d18 / 9a9cd0c0ab) —
may be partially preserved in cleanly-patched files
Static checks pass: pnpm check:changed is green (typecheck, lint, contract
tests, import cycles, etc.). Manual testing required before merge.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(msteams): preserve thread routing for channel and group-chat replies
- monitor.ts: adaptSdkContext now uses ctx.reply() for channel and groupChat
conversations (so the SDK threads outbound activities to the inbound's
replyToId/serviceUrl) and ctx.send() only for personal DMs (where
reply()'s blockquote-prepend is ugly).
- messenger.ts: sendProactively passes resolvedThreadId on the non-thread
fallback path so channel @mentions that fall through outbound.ts -> send.ts
still land in the original thread instead of top-level.
Live-validated: channel @mention -> bot replies in thread, threaded reply
-> bot replies in same thread, no top-level leakage.
* fix(msteams): tag outbound SDK calls with OpenClaw User-Agent
- user-agent.ts: add buildOpenClawUserAgentFragment() that returns just
'OpenClaw/<version>'. The SDK's Client.clone merges this with its own
'teams.ts[apps]/<sdk-version>' identifier — passing the full buildUserAgent()
here would double-print the SDK token.
- sdk.ts: pass the fragment via AppOptions.client.headers['User-Agent'] so
the Teams backend can identify OpenClaw traffic for usage telemetry.
Final UA looks like 'OpenClaw/<openclaw-version> teams.ts[apps]/<sdk-version>'.
* fix(msteams): handle StreamCancelledError when user presses Stop mid-stream
The new SDK throws StreamCancelledError synchronously from stream.emit/update
when the user pressed Stop in Teams: Teams replies 403 to the next chunk
update, the SDK flips _canceled, and any subsequent emit() throws. The old
custom TeamsHttpStream either swallowed cancel or didn't expose this exception
type, so the migration inherited an SDK behavior the original code didn't have
to handle.
Symptom on 2026-05-05: pressing Stop during a streaming reply caused an
unhandled promise rejection that crashed the Node 24 process. Docker restarted
the gateway about two minutes after each Stop click. Two related bugs surfaced
once the crash was caught: the would-be block fallback re-delivered the full
text as a second message (duplicate after Stop), and the typing-keepalive kept
pulsing in Teams for the rest of the agent run because nothing told it to
stop.
reply-stream-controller.ts:
- Wrap stream.update / stream.emit / stream.close in try/catch that swallows
StreamCancelledError (matched by .name to dodge tsgo's SDK re-export
resolution quirk). Latch a wasCanceled flag so subsequent calls
short-circuit even if stream.canceled is stale.
- preparePayload() returns undefined when the stream was canceled — the
streamed prefix is already visible to the user, so dropping the payload
prevents a duplicate block message from overriding the cancel intent.
reply-dispatcher.ts:
- Typing-keepalive gate now also checks streamController.wasCanceled() so
typing pulses stop firing once Stop is observed. Otherwise the bot keeps
pulsing for the rest of the (uncancellable) agent run.
reply-stream-controller.test.ts:
- 6 new regression tests cover: cancel-during-emit (the crash scenario),
cancel-during-update, cancel-during-finalize, non-cancel error propagation,
post-cancel inactivity, and dropped-payload-on-cancel.
Live-validated: long streaming reply + Stop mid-stream -> stream freezes,
no duplicate message, no zombie typing, container stays healthy.
* fix(msteams): allow Bearer-token retry on Skype CDN attachment downloads
Teams puts inline DM images and clipboard-pasted images on
*.asm.skype.com URLs (e.g. us-api.asm.skype.com/v1/objects/<id>/views/imgo).
The download path in attachments/download.ts already does a plain GET first
and falls back to a Bearer-token retry on 401/403 — but the retry was gated
on the URL being in DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST. asm.skype.com hosts
were in DEFAULT_MEDIA_HOST_ALLOWLIST (download permitted) but not in the
auth-host list, so a 401 plain-GET response skipped the retry and surfaced
as a missing image to the agent.
Add asm.skype.com and ams.skype.com to the auth allowlist so openclaw
attempts the Bearer-token retry consistently, matching how it treats the
other CDN/Bot-Framework hosts already in the list.
Note: this does not unblock all clipboard-pasted DM images — for at least
some tenants asm.skype.com rejects the Bot Framework token (returns 401
even with auth). Routing those URLs through <serviceUrl>/v3/attachments/...
the way #62219 already handles HTML-wrapped attachments is a separate
follow-up. The +button 'Upload from this device' path works today because
Teams generates an attachment with an HTML wrapper that triggers the
existing BF v3 attachments fallback in monitor-handler/inbound-media.ts.
* fix(msteams): align docker-compose msteams port default with plugin default
The plugin defaults webhook.port to 3978 (the Bot Framework standard used in
Microsoft samples) and listens on whatever the operator sets there. The
docker-compose.yml port mapping was exposing ${OPENCLAW_MSTEAMS_PORT:-3000}:3000
which only works for operators who explicitly set webhook.port to 3000.
Default-config users would have the plugin listening on 3978 inside the
container while compose forwarded 3000, causing connection refused.
Realign to ${OPENCLAW_MSTEAMS_PORT:-3978}:3978 so a default-config docker
compose up Just Works with Teams. Operators wanting a custom port override
both webhook.port in openclaw.json and OPENCLAW_MSTEAMS_PORT env var.
* fix(msteams): post-rebase reconciliation with main
Three follow-ups after rebasing the SDK migration onto current main:
- reply-dispatcher.ts: rename createChannelReplyPipeline to its post-rebase
identifier createChannelMessageReplyPipeline (the plugin-sdk barrel renamed
it during the 1454-commit rebase window).
- reply-dispatcher.ts: tighten the typing-keepalive onStartError signature to
(err: unknown) to satisfy upstream's stricter type checks.
- messenger.ts: drop the unconditional thread suffix on the bottom proactive
fallback. The previous behavior threaded all top-level proactive sends when
the stored ref had a threadId, which contradicts replyStyle='top-level'
semantics (and breaks the new upstream test). Threading on the proactive
path is preserved where it matters — the onRevoked branch within
replyStyle==='thread' still passes resolvedThreadId, which is the original
#55198 fix path.
- attachments.test.ts: update the warn-call assertion to match the migration's
inline message format (host=... error=...) — the structured meta object was
being dropped by the logger formatter pre-migration.
* feat(msteams): port streaming preview/progress features to ctx.stream
While the SDK migration was open, upstream landed preview/progress/draft
streaming features built on the OLD custom TeamsHttpStream class (which the
migration deletes). This commit ports the user-visible parts of those
features onto the new ctx.stream substrate so the migration doesn't lose
ground:
- pickInformativeStatusText: reads custom labels from
msteams.streaming.progressDraft config via resolveChannelProgressDraftLabel.
Falls back to the plugin-sdk default rotation. Pre-rebase used a hardcoded
4-string array.
- streamMode resolution: "partial" (default, per-token streaming),
"progress" (no tokens; preview card carries informative label that updates
as tools run), or "block" (no native streaming). Mode is read from
cfg.channels.msteams.streaming.preview.
- progress-draft gate: createChannelProgressDraftGate gates informative
updates so the rotating label only starts firing once meaningful work has
begun (avoids flicker before the first tool call).
- noteProgressWork() / pushProgressLine(): public methods on the controller
for callers (typing keepalive ticks, tool-event callbacks) to signal work.
pushProgressLine appends tool names as bullets above the rotating label
when streaming.previewToolProgress is enabled. Wiring these into actual
tool events is a separate follow-up.
- preparePayload progress-mode path: when stream is active but no tokens
streamed (progress mode) and a final text payload arrives, emit the text
into the stream so the preview card transitions in place to the final
reply on close().
reply-dispatcher: pass log + msteamsConfig + a stable progressSeed
(${accountId}:${conversation.id}) to createTeamsReplyStreamController so the
informative-label rotation is consistent across reconnects.
What's NOT ported and why:
- Live-edit-via-replaceInformativeWithFinal: the SDK's HttpStream natively
accumulates emitted text + entities + channelData and flushes ONE final
activity at close() using the same activity id as the preview. So the
separate "replace informative with final" call from upstream is
unnecessary — we get live-finalization for free via the SDK's design.
- pushProgressLine triggers from tool events: needs reply-pipeline-side
callbacks the new SDK migration didn't surface yet. Follow-up.
Tests: existing 22 reply-stream-controller tests still pass (the new
behaviors are additive).
* feat(msteams): wire pipeline tool events to streaming progress + fix test debt
Two follow-ups from yesterday's stopping point:
1. Wire pipeline events into the stream controller's progress-draft surface.
reply-dispatcher's replyOptions now exposes onReasoningStream, onToolStart,
onItemEvent, onPlanUpdate, onApprovalEvent, onCommandOutput callbacks that
format each event via the channel-streaming helpers and route through
streamController.pushProgressLine(). Mirrors the discord adapter's wiring.
Also:
- resolveChannelStreamingPreviewToolProgress + ...SuppressDefaultTool... so
the dispatcher exposes suppressDefaultToolProgressMessages on its
replyOptions when progress mode is on.
- Switch disableBlockStreaming resolution to the channel-streaming helpers
(resolveChannelPreviewStreamMode + resolveChannelStreamingBlockEnabled)
so streaming.mode='block' and streaming.block.enabled=true are honored
alongside the legacy blockStreaming boolean.
2. Fix the test debt that the rebase exposed:
- reply-dispatcher.test.ts: drop the streamInstances + TeamsHttpStream
mock pattern (file deleted by migration); replace with a streamMock
provided via context.stream that mirrors the SDK's IStreamer shape
(update/emit/close/canceled). Update assertions on sendInformativeUpdate
-> stream.update, stream.update -> stream.emit. Drop the
resumes-typing-between-segments test (no equivalent in the new
ctx.stream model — the SDK's HttpStream doesn't have a 'between
segments' notion; close ends the stream).
- send.test.ts: fix two stale mock targets — loadOutboundMediaFromUrl
comes from openclaw/plugin-sdk/outbound-media (not /msteams), and
resolveMarkdownTableMode comes from openclaw/plugin-sdk/markdown-table-runtime
(not /config-runtime). The previous mock paths were no-ops post-migration.
All 854 msteams tests now pass (was 17 failing in 4 files yesterday).
* fix(msteams): SDK streaming delta + use app.reply for proactive thread sends
Two narrow regressions exposed by the @microsoft/teams.apps migration:
- The SDK's HttpStream.emit appends each chunk to its internal buffer
(`this.text += activity.text`), but the channel reply pipeline emits
cumulative text on each chunk. Forwarding cumulative text into an
appending sink produced "chunk1 + chunk1chunk2 + chunk1chunk2chunk3..."
duplication for streamed (DM) replies. Track the emitted prefix length
in the stream controller and only forward the new tail.
- Replace the manual `${convId};messageid=${msgId}` URL construction in
the proactive thread fallback with `app.reply()`, which builds the
threaded conversation id via the SDK's own toThreadedConversationId
helper. Mechanically equivalent today; removes coupling to Teams' URL
format and tracks any future SDK changes.
Also adds the `reply` method to the structural MSTeamsApp type so the
refactor typechecks without casts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(msteams): bump @microsoft/teams.api and teams.apps to 2.0.10
2.0.10 adds support for the AAD v1 token issuer that the Bot Framework
JWT validator needs. The minor version bump pulls teams.cards / common /
graph along to 2.0.10 too.
Add `@microsoft/teams.*` to `minimumReleaseAgeExclude` in
pnpm-workspace.yaml because 2.0.10 was published <48h ago and the default
`minimumReleaseAge: 2880` (~2 days) would otherwise reject it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* revert(msteams): remove asm.skype.com auth-host allowlist additions
These hosts were added in dfc169d31d for inline DM image auth-retry, but
the commit's own footnote acknowledges it doesn't actually unblock
clipboard-pasted images (asm.skype.com rejects Bot Framework tokens in
at least some tenants). The change is unrelated to the SDK migration and
the user-visible bug it claimed to fix isn't fixed; lifting it out keeps
this PR focused on the migration. Will land as a separate PR if the
auth-allowlist consistency improvement is wanted on its own.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(msteams): typed ExpressAdapter helper, drop unknown-cast pyramid
The monitor's SDK bootstrap had an awkward chain:
httpServerAdapter: new (
(await import("@microsoft/teams.apps")) as unknown as {
ExpressAdapter: new (app: unknown) => unknown;
}
).ExpressAdapter(expressApp) as never,
Three casts (`unknown`, structural shape literal, `never`) were a
defensive workaround from when the SDK's hashed d.ts files tripped up
tsgo. With the SDK's exports now resolving cleanly, the same import can
be done with full types.
- Extend the lazy `loadSdkModules()` cache to include `ExpressAdapter`
alongside `App` so the dynamic import is shared.
- Add `createMSTeamsExpressAdapter(serverOrApp)` helper in `sdk.ts` that
encapsulates the lazy import and returns a properly-typed adapter
instance.
- Replace `httpServerAdapter`'s structural shape on `CreateMSTeamsAppOptions`
with the SDK's own `IHttpServerAdapter` interface (re-exported from
`@microsoft/teams.apps`).
The call site in `monitor.ts` becomes a single typed call with no `any`,
no `unknown`, no `as never`. The lazy-load behavior is preserved: nothing
imports `@microsoft/teams.apps` at module load time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(msteams): unbreak tsgo:extensions on the ExpressAdapter helper
CI's check-prod-types failed because the previous commit's typed helper
used `typeof import("@microsoft/teams.apps").ExpressAdapter`, which
tsc/tsgo's NodeNext resolution can't follow through the SDK's chained
`export *` barrel:
@microsoft/teams.apps/dist/index.d.ts:
export * from "./http"; // folder with index.d.ts
export * from "./app"; // single .d.ts file
The folder re-export drops `ExpressAdapter` and `IHttpServerAdapter` from
the namespace shape under `tsconfig.extensions.json` (passes under the
per-extension `tsconfig.json` because of inherited `paths`). Same root
cause as why we already model `MSTeamsApp` structurally (line 47 comment).
Switch the ExpressAdapter side to the same structural-shape pattern:
- Define `MSTeamsHttpServerAdapter` and `MSTeamsExpressAdapterCtor` locally.
- Cast `m.ExpressAdapter` once inside `loadSdkModules` (the runtime export
is fine; only the type surface is hidden).
- `httpServerAdapter` on `CreateMSTeamsAppOptions` and the return type of
`createMSTeamsExpressAdapter` use the local structural type.
Net result: the call site in `monitor.ts` stays the cast-free single line
the previous commit landed; the one remaining cast is confined to the
SDK-loading helper with an explanatory comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(msteams): drop unused jsonwebtoken/jwks-rsa deps
The SDK migration removed all `import "jsonwebtoken"` / `import "jwks-rsa"`
from source code (the SDK does JWT validation internally now), but the
package.json entries and the matching `package-manifest.contract.test.ts`
expectation were left orphaned. Drop both:
- `extensions/msteams/package.json`: remove `jsonwebtoken` (^9), `jwks-rsa`
(^4) from `dependencies` and `@types/jsonwebtoken` from `devDependencies`.
- `src/plugins/contracts/package-manifest.contract.test.ts`: remove the
two entries from msteams's `pluginLocalRuntimeDeps` expectation.
- `monitor.lifecycle.test.ts`: extend the `./sdk.js` mock with the
`createMSTeamsExpressAdapter` export added in the typed-helper cleanup,
so the lifecycle suite still mounts after the deps drop.
Lockfile regenerates accordingly. All msteams tests (865) pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(msteams): drop unused @microsoft/teams.api direct dep
CI's deadcode:dependencies (knip) flagged @microsoft/teams.api as
unused in extensions/msteams. The plugin source uses structural type
aliases (MSTeamsActivityParams, MSTeamsActivityLike, etc.) to dodge
tsgo resolution bugs with teams.api's hashed d.ts files, so it never
imports teams.api directly. The package is brought in transitively
via @microsoft/teams.apps; the only other reference is
probe.test.ts's vi.mock("@microsoft/teams.api"), which works on the
import-path string and doesn't require a direct dep declaration.
Lockfile regenerates accordingly. tsgo:extensions, knip, and all
865 msteams tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(msteams): clear three CI gate failures (lint, contract, deprecated config API)
Three CI checks flagged on the latest run; all three are msteams-local
and unrelated to one another:
- **check-lint** / **check-additional-extension-bundled**:
`oxlint` flagged a redundant `as string[]` assertion in
`reply-dispatcher.ts:431`. The preceding `every((s: unknown) => typeof
s === "string")` already narrows the array type, so the cast does
nothing. Drop it.
- **checks-fast-contracts-plugins-c**: the
`package-manifest.contract.test.ts` `pluginLocalRuntimeDeps` for
msteams still expected `@microsoft/teams.api`, but the deadcode
cleanup commit (8f4050f51a) dropped it from
`extensions/msteams/package.json`. Remove it from the contract test
too — `teams.api` is only present transitively via `teams.apps`,
which is the reason knip flagged it.
- **check-additional-runtime-topology-architecture**: the deprecated
internal config API guard caught `messenger.ts:223` calling
`getMSTeamsRuntime().config.loadConfig()`. Switch to
`config.current()` to match the pattern used by phone-control,
synology-chat, and matrix.
Pre-existing failures on this run that are NOT msteams-related and not
caused by this PR: `check-test-types` (errors in
`src/agents/openai-transport-stream.test.ts` and
`pi-embedded-runner/openai-stream-wrappers.test.ts`) and `macos-swift`
(`hoistAwait` in `MacNodeRuntime.swift`). Leaving those for upstream.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(msteams): cast config.current() return to OpenClawConfig
The previous commit switched `messenger.ts:223` from the deprecated
`config.loadConfig()` to `config.current()` to satisfy the architecture
guard, but `config.current()` returns a deeply-readonly type that's not
assignable to the `Partial<OpenClawConfig>` parameter
`resolveMarkdownTableMode` expects (a mutable type from the SDK
contract). Phone-control, synology-chat, and matrix all cast at this
seam — adopt the same pattern.
Verified locally: tsgo:core, tsgo:extensions, check:architecture, and
test:extensions:package-boundary:compile all pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(msteams): address PR review — pre-auth body limit, allowlist log level, /api/messages forwarder, narrow release-age exclude
Four narrow fixes from the PR review (BradGroux + clawsweeper bot +
galiniliev's plan), each its own concern:
- **pre-auth-body-limit** (monitor.ts) — install
`express.json({ limit: DEFAULT_WEBHOOK_MAX_BODY_BYTES })` before the
bearer-presence gate and SDK route. Express memoizes the parsed body
on the request, so the SDK's later `json()` becomes a no-op and our
limit applies before any handler parses bodies. Closes the gap where
a `Bearer garbage`-shaped attacker could force unbounded JSON parsing
before token validation.
- **allowlist-error-logging** (monitor.ts) — restore main's `runtime.error`
level for the `msteams resolve failed` catch (was downgraded to
`runtime.log` mid-merge). Graph allowlist resolution failures are
security-relevant; they need to surface to operators.
- **legacy-messages-route** (monitor.ts) — when `webhook.path` is set
to a custom value, also accept POSTs on the legacy `/api/messages`
path with a one-time deprecation warning, then re-enter the Express
middleware chain on the configured path. Keeps existing Azure Bot
registrations working through the transition. Cast-free
(`expressApp(req, res, next)` works because `Application extends
IRouter extends RequestHandler`).
- **release-age-scope** (pnpm-workspace.yaml) — narrow
`@microsoft/teams.*` glob to the single direct dep
`@microsoft/teams.apps`. Future scoped packages no longer get a
freshness-guard pass.
Tests + checks: msteams suite (867), tsgo:core, tsgo:extensions,
tsgo:test, lint:extensions, check:architecture, knip --dependencies,
package-manifest contract, all green.
Still pending from the review (separate commits):
- auth-coverage-tests (Brad #1 + comment) — tests proving the SDK accepts
`aud=<bot app id>` and rejects `aud=api.botframework.com`.
- invoke-response-handling (Brad #2, codex P2) — file-consent invoke ack
must return through the SDK invoke handler, not `ctx.sendActivity`.
- stream-failure-fallback (codex P2, galin F5) — `streamFailed` latch so
partial streams fall back to block delivery on non-cancel errors.
- serviceurl-routing (Brad #4, codex P2) — proposed rebuttal pending
empirical confirmation that `smba.trafficmanager.net/teams` routes to
non-default-region conversations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(msteams): lock SDK auth contract — aud + v1/v2 issuer coverage
Adds extensions/msteams/src/auth-coverage.test.ts driving ServiceTokenValidator
and createEntraTokenValidator directly with jose-minted RS256 tokens against an
in-memory JWKS (via JwksClient.prototype patch). Locks in the three contract
cases @BradGroux flagged on #76262: aud=<bot app id> accepted, aud=api.botframework.com
rejected even when appid/azp match, and v1/v2 issuers accepted for allowed tenant
(disallowed tenant rejected).
Drops a stale ambient module declaration in src/types/microsoft-teams-sdk.d.ts
that was shadowing the SDK's real jwt-validator types with a long-renamed
createServiceTokenValidator surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): route file-consent invokes through typed app.on, drop broken invokeResponse send
Brad #2 / codex #4 on PR #76262 — `ctx.sendActivity({ type: "invokeResponse", ... })`
no longer reaches Teams as an HTTP InvokeResponse on the new SDK; it becomes
an outbound Bot Framework activity instead. Move file-consent accept/decline
to typed `app.on("file.consent.accept|decline", ...)` handlers. The SDK's
typed-route layer wraps a void return into `{ status: 200 }`
(`app.process.js:130`), so the manual ack disappears.
While in here, type `MSTeamsApp.on` properly. Borrowing the SDK's `App.on`
directly fails because that function carries a `this: App<TPlugin>`
constraint our structural alias can't satisfy, so we model an equivalent
generic over `IRoutes` with route-specific overloads (`card.action`,
`file.consent.*`, `activity`). The overloads work around a tsgo bug — the
`@microsoft/teams.api` `Activity` discriminated union collapses to `any`,
turning `ActivityRoutes` into a `[string]: RouteHandler<X, void>` index
signature that swallows every typed `Out` not already void-compatible
(card.action returns `AdaptiveCardActionResponse`; the others happen to
include `void`). Real tsc resolves cleanly. Linked upstream:
https://github.com/microsoft/typescript-go/issues/1057.
Other cleanups:
- Cast-free call sites for `adaptSdkContext` (now returns
`MSTeamsTurnContext` instead of `unknown`).
- card.action error responses include `innerHttpError` per the SDK's
`HttpError` shape requirement.
- Activity catch-all also skips `fileConsent/invoke` now that it's
typed-routed (parallel to the existing `adaptiveCard/action` skip).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): route SSO sign-in invokes through typed app.on, drop broken invokeResponse send
Brad #2 / codex #4 on PR #76262, SSO half. Continue the typed-route migration:
`signin/tokenExchange` and `signin/verifyState` now register via
`app.on("signin.token-exchange" | "signin.verify-state", ...)`. Per the
SDK's router, registering a user route with the same name as a system
route removes the system default — so the SDK's built-in handlers (which
would call `api.users.token.exchange` themselves and emit a `signin` event
nobody currently subscribes to) are silenced, and only ours runs. The SDK
wraps a void return into the HTTP 200 InvokeResponse, so the legacy
`ctx.sendActivity({ type: "invokeResponse", ... })` ack — broken on the new
SDK because it becomes an outbound BF activity instead of the HTTP
response — is gone.
The handler body is extracted from the activity-catch-all dispatch in
`monitor-handler.ts` to a new `signin-invoke.ts`, parallel to
`file-consent-invoke.ts`. `isSigninInvokeAuthorized` is now exported from
`monitor-handler.ts` so the new handler can reuse it. The activity
catch-all skips the SSO invoke names alongside the existing skips for
`adaptiveCard/action` and `fileConsent/invoke`.
`MSTeamsAppOn` overloads now cover the two SSO routes with their typed
ctx (`ISignInTokenExchangeInvokeActivity` / `ISignInVerifyStateInvokeActivity`).
Tests in `monitor-handler.sso.test.ts` were rewritten to call the
extracted handler directly — the `registered.run(ctx)` shape no longer
covers SSO, and the `expect(ctx.sendActivity).toHaveBeenCalledWith({ type:
"invokeResponse" })` assertions were dropped to match the new contract
(the SDK ack happens via the typed-route return value).
Note on overlap with #77784 (Stefan Stüben, Microsoft): that PR is doing
a much bigger SSO rework (sign-in card / sign-in-link / six-digit-code
fallbacks plus a `ctx.auth` plumbed to plugin tools). This change is
the small migration-correctness fix and is structured so #77784's SSO
body changes drop into the typed-route registrations cleanly on rebase.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): route message-submit (feedback) invokes through typed app.on
Last invoke off the activity catch-all dispatch. `message/submitAction`
(thumbs up/down on AI-generated messages) now registers via
`app.on("message.submit", ...)`. Same shape as file-consent and SSO:
handler body extracted to a new `feedback-invoke.ts`, the SDK wraps a
void return into the HTTP 200 InvokeResponse, the broken
`ctx.sendActivity({ type: "invokeResponse", ... })` line is gone, and
the activity catch-all skips this invoke name alongside the others.
`isFeedbackInvokeAuthorized` is exported from `monitor-handler.ts` so
`feedback-invoke.ts` can reuse it. Tests in
`monitor-handler.feedback-authz.test.ts` were rewritten to call the
extracted handler directly — the old `handler.run(ctx)` shape no longer
intercepts feedback, and `originalRun` was removed because the typed
route is the dispatch point now.
`MSTeamsAppOn` overload added with the typed
`IMessageSubmitActionInvokeActivity` ctx, slotted between the SSO
overloads and the `activity` catch-all so `activity` stays last.
This leaves only `message`, `conversationUpdate`, and `messageReaction`
flowing through `app.on("activity", ...)` → `handler.run`. Promoting
those is the path to deleting the catch-all entirely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): fall back to block delivery when partial-mode stream fails mid-flight
codex #5 / Galin F5 on PR #76262. `reply-stream-controller.ts` previously
re-threw any non-cancel error from `stream.emit` during partial streaming
and from `stream.emit`/`stream.close` during finalize. Combined with
`preparePayload` suppressing block delivery once `tokensEmitted` was
true, that meant a network blip or API error mid-stream produced a
truncated reply with no recovery — the user saw the prefix that made it
through and nothing else.
Add a `streamFailed` latch parallel to `canceledLocally` / `tokensEmitted`:
- `onPartialReply`: catch non-cancel errors, set `streamFailed = true`,
log a warn, don't propagate (the pipeline must keep running so
`preparePayload` can decide).
- `preparePayload`: when `tokensEmitted && streamFailed`, fall through to
block delivery instead of suppressing. The user may see a duplicate
(streamed prefix + full block reply); intentional — matches the
pre-migration `TeamsHttpStream.hasContent` recovery and is better than
truncated-only.
- `finalize`: same latch + warn on non-cancel close failure, swallow
rather than throw. The streamed content already reached the user; the
closing activity (AI-Generated marker, feedback channelData) is the
only loss, not worth blowing up the dispatcher.
- `isStreamActive` returns false once the stream has failed.
New tests cover crash-mid-stream after tokens were emitted (assert block
delivery payload is returned), happy-path no-duplicate behavior (assert
`preparePayload` still suppresses when nothing failed), and finalize
close-failure (assert no throw). The pre-existing "re-throws non-cancel"
test was inverted to assert non-throwing latch behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): declare @microsoft/teams.api as a runtime dependency
Type-only `import("@microsoft/teams.api/dist/...").TypeName` references
in `sdk.ts` (added when typed `MSTeamsApp.on` overloads were introduced)
are picked up by the `extension-runtime-dependencies` contract test as
genuine runtime imports. Declaring `@microsoft/teams.api` as a direct
dep makes the contract pass; the package was already coming in
transitively via `@microsoft/teams.apps`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(msteams): keep SSO on SDK signin routes
* test(msteams): avoid redundant signin handler assertion
* docs(msteams): clarify Teams cloud support
* fix(msteams): use current SDK string helper
* fix(msteams): gate SDK invoke side effects
* test(msteams): avoid implicit any in lifecycle tests
* fix(msteams): preserve SDK user agent and matrix check
* fix(msteams): expose SDK common dependency
* fix(msteams): use SDK user agent merge
* fix(msteams): fall back when stream close no-ops
* chore(msteams): drop unrelated merge artifacts
* chore(msteams): restore unrelated main files
* chore(msteams): restore unrelated main files
* chore(msteams): restore unrelated main files
* test(msteams): type stream close mock result
* fix(msteams): configure Teams cloud service URL
* chore(msteams): refresh shrinkwrap
* chore(deps): refresh shrinkwrap locks
* chore(ci): rerun guards after main sync
* chore(deps): refresh shrinkwrap for node 24
* chore(config): refresh docs baseline
* fix(msteams): preserve Teams SDK proactive references
* fix(msteams): harden SDK proactive sends
* fix(msteams): align service url contract
* test: fix bonjour beacon type narrowing
* fix(msteams): ignore ambient service url
* fix(msteams): fall through submit invokes
* test: align shrinkwrap override policy with Teams SDK deps
* fix(msteams): ack invoke routes promptly
* fix(msteams): support china cloud boundaries
* test: sync PR with current CI gates
* test: isolate channel setup registry metadata
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Recover Codex compaction paths when a stale app-server thread binding returns an unstructured `thread not found` failure. The raw missing-thread response now shares the same recovery behavior as structured missing/stale binding failures for preflight, queued compaction, and CLI fallback.
Fixes#87736.
Co-authored-by: Paul Frederiksen <paul@paulfrederiksen.com>
Summary:
- The PR reorders embedded attempt cleanup to release the session write lock before session/MCP/LSP teardown, treats sessions_yield cleanup as abort-like for flush timing, and adds focused regression tests.
- PR surface: Source +14, Tests +71. Total +85 across 3 files.
- Reproducibility: yes. Source inspection shows current main releases the cleanup lock only after runtime tear ... R body’s terminal proof exercises the same ordering with production cleanup and filesystem lock primitives.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Merge branch 'main' into fix/session-lock-release-before-teardown
Validation:
- ClawSweeper review passed for head 178192fa0e.
- Required merge gates passed before the squash merge.
Prepared head SHA: 178192fa0e
Review: https://github.com/openclaw/openclaw/pull/87747#issuecomment-4566994280
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Generated-media completions now use the existing idempotent direct-media fallback when active requester wake has already failed and the requester-agent handoff hits a session write-lock-shaped no-response error. Generic requester-agent handoff errors still fail visibly instead of direct-sending after an unknown side effect.
Release-note context: fixes a message-delivery loss path for generated images, music, and video where the artifact had been created but the final handoff could be reported as failed after a session write lock.
Verification:
- GitHub CI run 26601111985 passed at b0be994332.
- Blacksmith Testbox through Crabbox tbx_01ksr2jtt3fnz0zqvwmqq513h7 covered the exact lock fallback and qa-channel generated-media smoke.
- git diff --check origin/main...refs/remotes/pull/87741/head passed before merge.
Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
Reuses the current plugin metadata snapshot in facade activation checks when the resolved boundary config matches, avoiding repeated manifest registry loads on the facade path.
Falls back to manifest registry loading when the current snapshot is missing or belongs to a different config/environment. Adds regression coverage for snapshot mismatch, snapshot reuse, and Windows path normalization.
Co-authored-by: 郑苏波 (Super Zheng) <superzheng@tencent.com>
Bound aggregate tool-result history at the provider prompt boundary without rewriting persisted session entries.
Provider-visible prompt history now trims older aggregate tool results before newer evidence, while canonical session history, slash/extension command handlers, and context-engine afterTurn snapshots stay unmodified.
Co-authored-by: luyifan <al3060388206@gmail.com>
* fix(nvidia): load featured model catalog
Co-authored-by: CaptainTimon <CaptainTimon@users.noreply.github.com>
* fix(nvidia): widen catalog fetch timeout
* fix(nvidia): cover catalog registration
* fix(picker): include provider catalog loader
* fix(nvidia): guard featured catalog fetch
* fix(nvidia): sync bundled catalog with live API
Replace minimaxai/minimax-m2.5 (MiniMax M2.5) with minimaxai/minimax-m2.7 (Minimax M2.7) and z-ai/glm5 (GLM-5) with z-ai/glm-5.1 (GLM 5.1) in the bundled fallback catalog to match NVIDIA's public featured-models endpoint.
Update docs table and all extension test expectations.
* fix(nvidia): retain shipped catalog refs
* fix(picker): keep alias catalog rows
* fix(nvidia): restore live catalog priority
---------
Co-authored-by: CaptainTimon <CaptainTimon@users.noreply.github.com>
Summary:
- The PR changes three TUI final chat-event early returns to call `tui.requestRender(true)` and adds focused event-handler assertions for those branches.
- PR surface: Source 0, Tests +25. Total +25 across 2 files.
- Reproducibility: yes. Current main and the latest release still have the three unforced final-event repaint calls, and the linked source PR includes PTY terminal proof showing the changed behavior after the patch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(tui): force repaint final chat events
Validation:
- ClawSweeper review passed for head 570dc3af86.
- Required merge gates passed before the squash merge.
Prepared head SHA: 570dc3af86
Review: https://github.com/openclaw/openclaw/pull/87423#issuecomment-4558845936
Co-authored-by: Ted Li <tl2493@columbia.edu>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Narrow the abort-settle timeout helper to the env keys it reads and keep the dynamic live-model hook unit test from loading provider normalization/runtime plugins.\n\nProof: focused Vitest for live-model-dynamic-candidates, oxfmt/oxlint/diff checks, autoreview clean, AWS Crabbox run_8a485e593c2e corepack pnpm check:changed exit 0, and PR CI green.
Summary:
- The PR updates the bundled MiniMax music provider to request streaming hex responses, decode SSE/audio bodie ... while preserving JSON/url fallbacks, and adds provider tests for streaming, fallback, and timeout behavior.
- PR surface: Source +148, Tests +152. Total +300 across 2 files.
- Reproducibility: yes. by source inspection and live proof, though I did not run a fresh live reproduction. C ... s provider fallback, and the source PR reports a 130s live MiniMax provider run succeeding after the patch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(minimax): stream music generation responses
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8456…
Validation:
- ClawSweeper review passed for head 806b0b40f2.
- Required merge gates passed before the squash merge.
Prepared head SHA: 806b0b40f2
Review: https://github.com/openclaw/openclaw/pull/84764#issuecomment-4504175527
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Render Slack progress-mode updates as native task-card progress blocks, with bounded Slack chunk text and stable fallback behavior.
Also deep-merge Slack account streaming objects over top-level defaults while preserving legacy scalar account overrides, and keep the plugin SDK fetch runtime import path from evaluating guarded-fetch dispatcher code.
Verification:
- pnpm test extensions/slack/src/progress-blocks.test.ts extensions/slack/src/accounts.test.ts src/plugin-sdk/fetch-runtime.test.ts
- pnpm lint --threads=8
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub PR checks green on #87748 at 4803e98820
Refs #82258
Co-authored-by: Simon van Laak <32648751+simonvanlaak@users.noreply.github.com>
Support grouped skill folders while keeping skill invocation flat via frontmatter names.
Includes bounded nested SKILL.md discovery, refresh/watch coverage for grouped folders, plugin symlink containment, and docs for grouped skill organization.
Verification:
- Node 24 targeted skill discovery and refresh tests passed locally.
- Docs checks passed locally and in CI.
- Autoreview clean.
- Crabbox live OpenAI proof showed nested foo/bar skills listed and visible in the agent system prompt.
- CI run 26595118581 passed.
Summary:
- The branch preserves current Claude Haiku 4.5 refs in the Anthropic resolver and doctor migration, repoints the bare `haiku` family alias to `claude-haiku-4-5`, and updates regression tests.
- PR surface: Source +5, Tests +21. Total +26 across 4 files.
- Reproducibility: yes. Current main source maps the bare `haiku` alias and explicit Haiku 4.5 migration path ... de-sonnet-4-6`; the PR body also supplies before/after terminal proof for the resolver and migration tests.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 64429e23b3.
- Required merge gates passed before the squash merge.
Prepared head SHA: 64429e23b3
Review: https://github.com/openclaw/openclaw/pull/87719#issuecomment-4566419633
Co-authored-by: alkor2000 <200923177@qq.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Cap Dreaming short-term recall stores so repeated recall recording, repair, and promotion application cannot grow the JSON artifact without bound.
The fix keeps full normalized snippets for recall identity and contamination checks before truncating persisted snippets, exposes the new overflow audit code through the SDK facade, and adds regression coverage for recording, repair, promotion rehydration, and deterministic retention ties.
Fixes#87095.
Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/memory-core/src/short-term-promotion.test.ts src/commands/doctor-memory-search.test.ts src/plugin-sdk/memory-core-engine-runtime.test.ts
- pnpm tsgo:prod
- pnpm check:test-types
- pnpm lint --threads=8
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- PR CI run 26594527697: unrelated current-main failures only in checks-node-agentic-plugin-sdk and checks-node-agentic-agents; same failures reproduced on main run 26594198639.
Co-authored-by: ai-hpc <mail.speedy.hpc@hotmail.com>
Wrap Ollama native streams with the shared plain-text tool-call compatibility wrapper so local/plain-text tool requests are delivered as structured toolCall events when matching tools are available.
Verified with live local Ollama proof, focused Testbox Vitest, Testbox check:changed, and autoreview.
Summary:
- The branch filters OpenClaw CLI image-cache paths out of prompt image-reference detection and adds parser/helper regression tests.
- PR surface: Source +17, Tests +65. Total +82 across 3 files.
- Reproducibility: yes. source-level reproduction is high confidence: current main still scans replayed prompt ... ectImageReferences and has no cache-path exclusion before loadPromptRefImages can reload stale image paths.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(images): skip CLI image cache refs
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8750…
Validation:
- ClawSweeper review passed for head dfe0408df8.
- Required merge gates passed before the squash merge.
Prepared head SHA: dfe0408df8
Review: https://github.com/openclaw/openclaw/pull/87523#issuecomment-4560945125
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR changes the Control UI chat session picker blur handler to skip empty-query search application and adds a regression test that picker options remain clickable after an empty search blur.
- PR surface: Source +4, Tests +52. Total +56 across 2 files.
- Reproducibility: yes. The issue steps, before recording, and current-main source path all point to the same ... r clearing picker state before click delivery; I did not rerun a live browser repro in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ui): preserve session picker on empty search blur
Validation:
- ClawSweeper review passed for head bb14687756.
- Required merge gates passed before the squash merge.
Prepared head SHA: bb14687756
Review: https://github.com/openclaw/openclaw/pull/87682#issuecomment-4565441074
Co-authored-by: Ryan Weng <14496969+ryan4559@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Surface inbound bundle-MCP structuredContent as the model-visible result when present so agents can read Codex MCP threadId values and continue with codex-reply. Preserve non-structured content behavior, preserve the empty-result fallback, and keep details.structuredContent for internal consumers.
Also remove an unused secrets path helper that was breaking the latest prod-type gate on main.
Fixes#87511.
Verification:
- node scripts/run-vitest.mjs src/agents/agent-bundle-mcp-tools.materialize.test.ts
- pnpm exec oxfmt --check src/secrets/path-utils.ts src/agents/agent-bundle-mcp-materialize.ts src/agents/agent-bundle-mcp-tools.materialize.test.ts
- pnpm tsgo:prod
- local check-guards shard commands
- live Codex MCP smoke with codex__codex and codex__codex-reply same-thread continuation
- autoreview clean
- CI run 26587222874 green
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Fix replay handling for voice-call webhooks so duplicate signed requests do not mint or expose realtime stream tokens.
- Return token-free Twilio replay TwiML before realtime setup shortcuts.
- Cache bounded non-Twilio first responses for idempotent replay XML while skipping duplicate side effects.
- Cover Twilio realtime replay and Plivo replay behavior with regression tests.
- Remove an unused secrets path helper that was tripping latest-main prod type CI.
Fixes#87497.
Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
Fixes#87016.
Empty preflight compaction recovery now resets stale token snapshots immediately, preserves valid legacy transcript rows during cleanup, and avoids re-persisting stale context-budget or compaction metadata after a successful retry.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Add read-only MCP visibility to `tools.effective` by projecting MCP tools only after a session catalog has already been warmed by an agent turn. Keep the gateway additive: no `tools.effective.refresh`, no forced MCP startup, and no behavior change for MCP loading.
Verification:
- `git diff --check origin/main..HEAD`
- `node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts --reporter=verbose src/agents/tools-effective-inventory.test.ts`
- GitHub checks green on `a8a7f8442adb216f60da24d50118374a15c62e06`, including `Real behavior proof`, `check-guards`, `check-prod-types`, `check-test-types`, `build-artifacts`, `Critical Quality (gateway-runtime-boundary)`, and `Critical Quality (network-runtime-boundary)`.
Co-authored-by: David Huang <nxmxbbd@gmail.com>
The anthropic-transport-stream was overwriting thinkingSignature on each
signature_delta event instead of appending. Since Anthropic sends the
thinking block signature across multiple streaming chunks, only the last
chunk survived. The truncated signature was persisted to session JSONL,
causing all subsequent replay attempts to fail with HTTP 400:
thinking or redacted_thinking blocks in the latest assistant message
cannot be modified
This permanently bricked sessions with no user recovery path.
Fix: accumulate signature_delta values by concatenating instead of
overwriting, matching the correct implementation in the LLM provider
layer (src/llm/providers/anthropic.ts:629-634).
Includes real-scenario proof against live Anthropic API validating that
correct signatures replay successfully while truncated signatures are
rejected.
Fixes#87574
Refs #80625, #85781, #87475
* fix(agents): preserve reasoning_content replay across DeepSeek tier suffixes
OpenCode Zen exposes DeepSeek V4 as `deepseek-v4-flash-free`, which keeps the upstream DeepSeek thinking-mode contract that requires `reasoning_content` to be passed back on follow-up requests. The existing replay allowlist only matched the bare ids (`deepseek-v4-flash`, `kimi-k2-thinking`, ...), so the tier-suffixed id missed every candidate and the sanitizer stripped `reasoning_content` from the assistant turn. DeepSeek then rejected the second API call with HTTP 400 and the session deadlocked.
Strip the well-known tier suffixes (`-free`, `-paid`, `-trial`) when generating allowlist candidates so the base model id matches and the reasoning replay survives. Existing matching for prefixed / colon-suffixed routes is unchanged.
Fixes#87575
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(agents): avoid spread-rebuild when iterating allowlist candidates
oxlint flagged the [...candidates] spread as an unnecessary array copy. Use an explicit baseCount loop bound instead so we still iterate the original entries while pushing tier-stripped variants onto the same array.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(opencode): add live DeepSeek replay probe
* test(opencode): avoid forced tool choice in live replay
---------
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fixes#58012.
Applies strict9 replay tool call id sanitization to OpenRouter Mistral-family model routes, including unprefixed Mistral/Codestral/Devstral aliases, while preserving existing passthrough behavior for Gemini and other OpenRouter-backed routes.
Adds focused unit coverage plus a live OpenRouter model catalog test so new Mistral-family routes are checked against the replay policy. Also keeps the current core lint gate green by switching the tool schema cache key sort to a non-mutating sorted array.
Co-authored-by: Pluviobyte <Pluviobyte@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Preserve explicit gateway service identity when package/update refreshes the managed service environment. This keeps caller-selected systemd units ahead of stale persisted service env and applies the same precedence to launchd labels and Windows task names during service-state inspection.
Fixes#87490
Verification:
- node scripts/run-vitest.mjs src/daemon/service-env.test.ts src/daemon/service.test.ts src/cli/update-cli.test.ts src/cli/update-cli/restart-helper.test.ts src/cli/daemon-cli/install.test.ts src/daemon/systemd.test.ts
- git diff --check origin/main...pr/87556
- Crabbox AWS Linux systemd install/refresh proof: run_f3374bd610f7, lease cbx_754e69eb6c3a, provider aws, target linux
- autoreview --mode branch --base origin/main: clean, no accepted/actionable findings
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Summary:
- Replace the legacy iOS shell with Pro Command, Chat, Agents, and Settings tabs.
- Wire iOS chat/session/settings/diagnostics and realtime Talk flows through gateway-backed APIs.
- Add gateway/session and shared chat coverage for the new iOS flow.
Verification:
- git diff --check
- node scripts/run-vitest.mjs src/gateway/server.sessions.create.test.ts src/gateway/talk-realtime-relay.test.ts
- swift test --filter ChatViewModelTests (apps/shared/OpenClawKit)
- xcodebuild build for Nimrod's iPhone succeeded; install succeeded; launch was blocked because the phone was locked
Known follow-up:
- Preserve traceLevel in sessions.create parent runtime inheritance and keep the changelog credit in the follow-up patch.
Increase the code-mode wait-timeout test timeout so CI shard load does not trip the worker startup guard before the test reaches the intended pending-tool wait path.
Reduce repeated gateway warning noise in startup/auth retry paths while preserving credential mismatch and rate-limit audit visibility.
Also hardens empty embedded-assistant retry handling by carrying lifecycle state through the missing-assistant guard, and keeps the relevant regression coverage in gateway and agent tests.
Wire QA fallback models into live gateway config, fix Slack allowlist-block coverage, and keep WhatsApp live artifacts useful while redacting raw credential metadata.\n\nVerification: focused QA Vitest; autoreview clean; AWS Crabbox pnpm check:changed run_0207de7d47aa; QA-Lab branch-defined transport run 26565521272 with Matrix transport 56/56 and Slack/Discord/Telegram/parity clear. WhatsApp remains blocked by stale shared Convex WhatsApp Web credentials returning Baileys 401 before scenarios.
* fix(telegram): enable TCP keepalive on getUpdates connections to prevent NAT timeout stalls
Long-polling connections to api.telegram.org stay idle for up to the
getUpdates timeout (~900 s). Most home/office NAT tables expire idle TCP
entries after 60–1800 s (commonly ~1000 s). When the NAT entry is
silently dropped the connection hangs rather than returning an error,
leaving the grammY runner stuck until the 90 s stall watchdog fires and
forces a restart cycle.
Fix: unconditionally set `keepAlive: true` and
`keepAliveInitialDelay: 30_000` (30 s) on the undici Agent `connect`
options built in `buildTelegramConnectOptions`. OS-level TCP keepalive
probes sent every ~75 s (OS default) will:
1. Refresh the NAT table entry before it expires.
2. Surface dead connections immediately with ETIMEDOUT instead of
hanging forever.
The `return Object.keys(connect).length > 0 ? connect : null` guard is
also removed; `connect` is now always non-empty so it always returns the
object.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 92e454c0614256201cdf6f0f73c7897d006616d4)
* fix(telegram): stop self-flagging disconnected on poll-cycle start; widen channel connect grace to 300s
(cherry picked from commit 1ca963a05dac0d9d605e9a15dc97fced9cf7725e)
* fix(telegram): catch hung polling startups that preserve inherited connected:true
The widened 300s channel connect grace and the removal of connected:false from
notePollingStart left a path where a polling restart could hang forever
looking healthy. notePollingStart clears lastConnectedAt, lastEventAt, and
lastTransportActivityAt but deliberately omits connected, so server-channels'
patch-merge inherits a connected:true from the previous lifecycle. After grace,
evaluateChannelHealth's stale-socket branch requires lastTransportActivityAt
to be non-null and the connected:false branch is masked, so the channel sits
healthy with no first getUpdates.
Add a post-grace branch to evaluateChannelHealth that flags polling channels
as stale-socket when connected:true is paired with null lastConnectedAt and
null lastTransportActivityAt and a non-null lastStartAt. Scoped to mode:polling
so webhook channels and channels without continuous transport tracking are
not falsely flagged. Align TELEGRAM_POLLING_CONNECT_GRACE_MS in the Telegram
status diagnostic with DEFAULT_CHANNEL_CONNECT_GRACE_MS so openclaw channels
status agrees with the shared health monitor on the grace window. Refresh
the notePollingStart comment to point at the new evaluateChannelHealth branch.
Addresses clawsweeper review on #83304 (P1 connect-grace startup-hang, P2
diagnostic grace drift). Tests cover the new flagged path, the in-grace happy
path, and the prior-successful-connect happy path.
* fix(telegram): clear polling connected state on startup
* fix(gateway): add defense-in-depth health-policy branch for hung polling startups
Defense in depth on top of 87db46c576's notePollingStart connected:false fix.
The primary path (notePollingStart writes connected:false explicitly so
evaluateChannelHealth's existing connected===false branch catches a hung
restart) is unchanged. This adds a defensive post-grace branch that catches
the same hang via a different signature -- inherited connected:true paired
with null lastConnectedAt and null lastTransportActivityAt -- in case a
future code path forgets to clear the inherited connected flag on lifecycle
start. Scoped to mode:polling so webhook channels and channels without
continuous transport tracking are not falsely flagged.
Also bump lastStartAt: Date.now() - 121_000 to 301_000 in the spool-handler
timeout test added by upstream #83505 so it falls past the widened 300s
TELEGRAM_POLLING_CONNECT_GRACE_MS suppression window (mirroring the same
fixup already applied to the two adjacent polling-startup tests).
* revert(telegram,gateway): keep connect grace at 120s
Drop the 120s -> 300s widening from this PR after maintainer feedback that
the extra grace masks real startup bugs. The defense-in-depth checks added
in earlier commits (notePollingStart clearing inherited connected state,
the stale-socket policy branch, the per-snapshot startup grace test) all
work fine at 120s and remain valuable on their own.
Reverts in:
- src/gateway/channel-health-policy.ts: DEFAULT_CHANNEL_CONNECT_GRACE_MS 300 -> 120
- extensions/telegram/src/status-issues.ts: TELEGRAM_POLLING_CONNECT_GRACE_MS 300 -> 120
- extensions/telegram/src/status.test.ts: lastStartAt 301_000 -> 121_000 (3 cases)
The new channel-health-policy.test.ts cases use explicit channelConnectGraceMs:
10_000 in the policy, so they are unaffected by the default constant change.
* fix(telegram): narrow polling keepalive fix
---------
Co-authored-by: Yibei Ou <yibeiou@Yibeis-Mac-mini.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Harden QQBot direct media URL uploads by downloading through the local SSRF guard before QQ upload, disabling redirects, bounding fetch/setup and body reads, and routing downloaded buffers through the existing one-shot/chunked size gate.
Co-authored-by: Agustin Rivera <agustin@rivera-web.com>
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
Preserve pending agent-job error diagnostics as non-terminal timeout snapshots so the retry grace path can still recover when the lifecycle later starts and completes.
Local proof:
- node scripts/run-vitest.mjs packages/sdk/src/index.test.ts src/gateway/server-methods/server-methods.test.ts src/gateway/server.chat.gateway-server-chat.test.ts src/agents/run-wait.test.ts src/agents/openclaw-tools.sessions.test.ts
- node scripts/run-oxlint.mjs packages/sdk/src/client.ts packages/sdk/src/index.test.ts src/gateway/server-methods/agent-job.ts src/gateway/server-methods/agent.ts src/gateway/server-methods/agent-wait-dedupe.ts src/agents/run-wait.ts src/agents/tools/sessions-send-tool.ts src/gateway/server-methods/server-methods.test.ts src/gateway/server.chat.gateway-server-chat.test.ts src/agents/run-wait.test.ts src/agents/openclaw-tools.sessions.test.ts
- autoreview --mode local: no accepted/actionable findings
- CI run 26536599850: success
Co-authored-by: Martin Garramon <martin@yulicreative.ai>
Include second-level precision in inbound metadata and auto-reply envelope timestamps, matching the timestamp helper contract used by providers and channel adapters.
Docs now show the weekday plus seconds form in date-time and timezone examples.
Verification:
- node scripts/run-vitest.mjs src/auto-reply/envelope.test.ts src/auto-reply/reply/inbound-meta.test.ts
- pnpm docs:list >/tmp/openclaw-docs-list-87360.log
- git diff --check origin/main...HEAD
- pnpm format:docs:check
- pnpm lint:docs
- pnpm lint:extensions:bundled
- pnpm lint
- PR CI green on 495bb6c10fFixes#87257
Co-authored-by: GarlicGo <582149912@qq.com>
Expire browser-origin Control UI/WebChat device tokens when shared gateway auth rotates by tagging those tokens with the shared-auth generation and enforcing it during verification.
Preserve the issuer tag when a shared-auth-derived device token reconnects through a non-browser client, so reconnect rotation cannot turn it into an untagged long-lived token.
Proof:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/gateway/server.shared-auth-rotation.test.ts src/infra/device-pairing.test.ts src/gateway/control-ui.http.test.ts
- GitHub CI run 26535632102: relevant build/runtime/test-type checks green; inherited lint reds match origin/main.
- GitHub CodeQL Critical Quality run 26535631610: network-runtime-boundary green.
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
Fixes repeated Tool Search catalog registration for unchanged effective tool sets by reusing a fingerprinted catalog snapshot across embedded-agent run cleanup.
The reusable catalog is guarded by catalog-affecting fields, parameters, and executable identity, and reuse now rebinds the current run/session refs before returning. Embedded-agent prep logging only suppresses the catalog line when reuse actually happened.
Verification:
- pnpm test src/agents/tool-search.test.ts -- --reporter=verbose
- pnpm check:changed, Testbox tbx_01ksney4f00wgk9n39yv7jsh4m
- Real behavior proof, GitHub Actions run 26534896284
- CI rerun for unrelated model-picker timeout passed, GitHub Actions run 26534489215
- autoreview clean: no accepted/actionable findings
Closes#86887
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Avoids a self-wait in embedded agent session event hooks by skipping the queue drain only for hooks running inside the current session event processing chain. Detached or external hook work still drains the queue before taking the session write lock.
Verification:
- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents-embedded-agent.config.ts src/agents/embedded-agent-runner/run/attempt.session-lock.test.ts
- node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/agents/embedded-agent-runner/run/attempt.session-lock.test.ts src/agents/embedded-agent-runner/run/attempt.session-lock.ts --threads=8
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI: https://github.com/openclaw/openclaw/actions/runs/26533883763
Thanks @luoyanglang.
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Make plugin-state enforce the plugin-wide live-row fuse by evicting only from the namespace currently being written, preserving sibling namespace rows and still failing atomically when the current namespace cannot free enough rows.
Raise the plugin-wide cap to 6,000 rows, keep Telegram's persistent message-cache namespace at 3,000 entries, and document the updated SDK runtime contract. Harden legacy plugin-state import so capacity pressure cannot archive a source after losing imported keys, with focused regression coverage for Telegram-shaped namespaces and migration rollback.
Also restore the Docker runtime-assets preflight step in full release validation so release workflow contract tests stay aligned.
Verification: focused plugin-state, migration, Telegram, workflow-contract, lint, deprecated-API, diff-check, Blacksmith Testbox, CI, CodeQL, Workflow Sanity, OpenGrep, and autoreview all passed on PR head fee021cfa6.
Co-authored-by: Keshav's Bot <keshavbotagent@gmail.com>
Use read-only Telegram account inspection for prompt-time channel actions, inline buttons, and reaction guidance so unresolved SecretRef tokens retain configured non-secret behavior before runtime snapshot hydration.
Match runtime Telegram account lookup for normalized config keys and multi-account fallback guards, while keeping sends/actions on the existing strict credential resolution path.
Fixes#75433.
Co-authored-by: Shubhankar Tripathy <reach2shubhankar@gmail.com>
Fixes #87331.\n\nPersist Codex native hook relay generations for real app-server resumes, keep a bounded legacy-binding grace path, and rotate generation on fresh-thread fallback so stale hook commands stay rejected.\n\nCo-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Document that automation should pipe `models auth paste-token` credentials over stdin instead of passing token material in argv, keeping the existing secret-handling path explicit in the CLI docs.
Also include accepted auth-profile credential types in invalid-profile warning logs so malformed local auth stores are easier to repair.
Fixes#63042.
Thanks @liaoandi.
Clarify the Codex Computer Use docs around inferred opt-in, read-only status checks, and marketplace root versus marketplace JSON path setup.
The docs now match current source-backed behavior: autoInstall opts Computer Use in, status does not mutate plugin setup, and marketplacePath is for a local marketplace JSON file while source registers a marketplace root.
Verification:
- pnpm docs:list
- GitHub CI check-docs passed
- Real behavior proof passed via maintainer proof override for this docs-only PR
Thanks @bdjben.
Co-authored-by: Benjamin Badejo <ben@benbadejo.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
Split the diffs viewer Shiki language pack into an external publishable plugin.
The diffs plugin keeps the default curated syntax set, while the new @openclaw/diffs-language-pack package carries the extended Shiki languages for npm and ClawHub distribution. The install metadata includes the external ClawHub spec, and the curated C# alias set keeps both c# and cs supported without the language pack.
Co-authored-by: Dallin Romney <dallinromney@gmail.com>
Fix non-interactive and wizard onboarding reruns so existing agent lists and bindings are preserved unless the user explicitly resets config.
Isolate legacy `plugins.installs` migration into its own write so the config size-drop allowance cannot mask unrelated config loss, while preserving new or repaired install records for the final plugin-index commit. Also keep shrinkwrap generation pinned to pnpm-locked transitive patch versions only when the dependency edge still allows that version, and isolate the tooling Vitest shard that mutates process state.
Fixes#84692.
Replaces #84748.
Co-authored-by: yetval <yetvald@gmail.com>
Suppress reasoning-prefixed silent replies before outbound delivery while preserving substantive replies that merely end with the silent token.\n\nFixes #66701.\n\nThanks @zuoanCo for the PR and @Cavadus for the report.\n\nProof: focused Vitest and pnpm check:changed passed on Testbox-through-Crabbox tbx_01ksmvfw0gk9xwh10ra1cyhzfw; CI passed for head a014eb0d91.
Fixes#87226.
Preserve the already-applied `openai` to `openai-codex` Codex runtime promotion when the persisted selection is canonical `openai` with the same model, while keeping explicit runtime provider changes switchable.
Verification:
- `node scripts/run-vitest.mjs src/agents/live-model-switch.test.ts`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `pnpm check:changed` via Testbox `tbx_01ksmr59zdaqj3617w8w53xv4t` / Actions run `26512418770`
- Real behavior proof override gate: Actions run `26513059970`
Co-authored-by: Peter Lindsey <peter@lindsey.jp>
Keeps plain `openclaw status` on a bounded fast path while preserving local status metadata. The default text scan now avoids network update fetches, live channel checks, setup fallback work, and unbounded session hydration; deep/all status keeps the fuller behavior.
Behavior addressed: default status latency from update, channel, setup, and session scans
Real environment tested: GitHub Actions on PR head 98f589a35df74a7abb8327984d0103bb9f31af3e; local focused lint; autoreview
Exact steps or command run after this patch: CI workflow 26510790999; CodeQL workflow 26510790924; CodeQL Critical Quality workflow 26510791058; OpenGrep workflow 26510791138; autoreview branch against origin/main
Evidence after fix: all current-SHA workflows completed successfully; autoreview clean; local focused core oxlint passed on touched status files
Observed result after fix: default status hydrates only visible recent sessions, keeps local update metadata, and shows intentionally skipped SecretRef credentials as unknown instead of warning
What was not tested: live provider/channel roundtrip
Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
Route Telegram sendMessage action replies through durable outbound delivery so completed agent responses remain retryable when the gateway send path times out.
Verified with focused Telegram/outbound tests, extension test typecheck, prepare build/check/full test gates, and green CI rerun for head 20b45687e1.
Move vLLM Qwen thinking control onto configured model compat metadata and carry it through catalog/model-selection/runtime thinking contexts.
Also migrate legacy provider/default request params in doctor and keep Pi/runtime model rows buildable with explicit reasoning defaults.
Thanks @rendrag-git.
Co-authored-by: rendrag-git <253747599+rendrag-git@users.noreply.github.com>
Summary:
- The PR moves the runtime `HEARTBEAT.md` bootstrap template into `src/agents/templates`, keeps docs templates ... or other workspace files, adds a legacy heartbeat-template doctor repair, and updates package guards/tests.
- PR surface: Source +281, Tests +283, Docs +11, Config +1, Other 0. Total +576 across 15 files.
- Reproducibility: yes. from source inspection: current main loads `HEARTBEAT.md` from the docs template, and ... pty heartbeat file non-empty to the runtime. I did not run a live heartbeat repro in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(doctor): recognize heartbeat docs boilerplate
- PR branch already contained follow-up commit before automerge: fix(agents): update heartbeat workspace test
- PR branch already contained follow-up commit before automerge: fix(doctor): tighten heartbeat template repair
Validation:
- ClawSweeper review passed for head e34e85864c.
- Required merge gates passed before the squash merge.
Prepared head SHA: e34e85864c
Review: https://github.com/openclaw/openclaw/pull/85416#issuecomment-4519851630
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Carry over #82973 and fix#81281 by preserving explicit cacheRetention for OpenAI-compatible completions providers that opt into prompt-cache-key support.
The change keeps explicit cacheRetention suppressed for OpenAI-compatible providers without compat.supportsPromptCacheKey, adds regression coverage for both paths, and updates prompt-caching docs for prompt_cache_key / prompt_cache_retention behavior.
Fixes#81281.
Supersedes #82973.
Co-authored-by: lonexreb <reach2shubhankar@gmail.com>
Fix runtime context placement so hidden runtime context is model-visible before the active user turn without persisting as a visible/session message.
Verification:
- git diff --check origin/main...origin/pr/86995-merge
- gh pr checks 86995 --repo openclaw/openclaw --watch=false
- gh run rerun 26493979156 --repo openclaw/openclaw --failed
- gh run watch 26493979156 --repo openclaw/openclaw --exit-status
- CodeQL run 26493979156 attempt 2, Security High (mcp-process-tool-boundary) job 78066719467 passed
Preserve replayability for direct Anthropic sessions whose stored assistant thinking blocks have empty or blank signatures after a newer user turn. Older invalid thinking-only assistant turns are replaced with the existing omitted-reasoning placeholder so the turn shape survives provider replay.
Also keep active tool-use continuations safe: when an assistant tool call is followed by tool results, preserve the latest assistant thinking block so signed-thinking providers can replay the current tool turn unchanged.
Proof:
- node scripts/run-vitest.mjs src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/pi-embedded-runner/thinking.test.ts test/scripts/openclaw-e2e-instance.test.ts
- pnpm check:changed via Blacksmith Testbox through Crabbox, tbx_01ksmfypqet50et92vdm5mmv5v, run https://github.com/openclaw/openclaw/actions/runs/26505947008
- Live Anthropic Messages replay accepted the OpenClaw-sanitized active tool-turn history with a real thinking signature.
- PR CI on 37c2e72d82 completed successfully for relevant checks.
Fixes#86886.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Forward cache-read token counts through the OpenAI-compatible chat-completions usage shape as prompt_tokens_details.cached_tokens so clients can price cached turns correctly.
Align internal gateway usage typing with the expanded wire shape.
Thanks @caz0075.
Preserve existing `agents.list` and top-level `bindings` during ordinary onboarding reruns so rerunning `openclaw onboard` cannot silently wipe configured agents or routing bindings.
Keep config size-drop allowances scoped to explicit reset/import/plugin-install migration flows, validate binding agent ids with normalized agent ids, and add doctor repair coverage for dangling bindings that is still best-effort around malformed agent lists.
Closes#84692.
Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Closes#87181.
Direct Anthropic Messages requests now send bare Claude model ids even when OpenClaw stores them with the `anthropic/` provider prefix. Anthropic-compatible proxy and custom endpoint routes keep slash-bearing model ids unchanged so configured proxy models do not regress.
Also preserves the original parse error as `cause` in the JSONL request tail helper to keep the current CI lint gate green.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
* fix(deepinfra): load all DeepInfra models when user wants to browse them during onboarding
* docs(deepinfra): align TTS default
* fix(deepinfra): refresh video fallbacks
* fix(deepinfra): share credential-aware catalog discovery
* test(deepinfra): narrow catalog regression types
* test(deepinfra): keep catalog narrowing across callback
* fix(deepinfra): preserve default model in live catalog
* fix(deepinfra): align default model pricing
* fix(deepinfra): keep pixverse as video default
* docs(deepinfra): match video fallback default
* fix(deepinfra): honor config api keys for live catalog
* test(e2e): wait for watchdog stdio close
* test(media): align live harness provider expectation
* fix(deepinfra): always augment custom catalogs
* test(e2e): resolve watchdog commands before spawning
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Validates forced plugin harness support for the requested provider/model before pinning Codex or any other plugin harness. This prevents an explicitly forced Codex runtime from accepting unsupported OpenAI-like providers through a hardcoded bypass while preserving implicit PI fallback and CLI runtime alias passthrough.
Regression coverage covers forced Codex rejection for unsupported openai/openai-codex support, Codex provider support declarations, CLI attempt routing, pi-embedded auth/profile forwarding fakes, Testbox scenario probes, and live Docker Codex plugin E2E.
Thanks @cathrynlavery.
Keep macOS Homebrew setup lazy so users with supported Node and Git can install without admin/Homebrew, while still installing Homebrew before macOS Node or Git package installs.
Updates installer docs and adds focused install.sh coverage for the lazy Git path. Also aligns the live-media provider expectation with current main so built-artifact checks stay green.
Fixes#83232
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(agents): suppress Write/Edit failed warning on response-timeout false-failure (#55424)
Reporter sees '⚠️ Write failed' / '⚠️ Edit failed' warnings on Feishu (and other channels) even though the file was 100% saved successfully (8 of 8 verified writes succeeded; warning shown for all 8). Source path: tool-mutation records lastToolError.timedOut=true with a fileTarget when a write/edit tool ack reply times out after the disk mutation has already completed, then resolveToolErrorWarningPolicy goes through the default mutating-tool branch and emits the misleading failure summary.
Add a narrow gate inside resolveToolErrorWarningPolicy that suppresses the warning only when both lastToolError.timedOut is true AND lastToolError.fileTarget is defined. fileTarget is set by tool-mutation.ts only for the write/edit family (FILE_MUTATING_TOOL_NAMES), so this branch never matches exec/message/cron/gateway mutating-tool timeouts where the disk-write idempotency reasoning does not apply. Real file failures (no timeout) and timeouts without recorded fileTarget keep their visible warnings.
* fix: recover completed write timeouts safely
* fix: bound write timeout recovery precheck
* fix: type write recovery precheck fallback
* test: complete write recovery result mock
* test: isolate e2e timeout fixture shims
* test: stabilize e2e timeout fixture path
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Clarify that OpenAI Realtime voice is billed through OpenAI Platform credits, not Codex/ChatGPT subscription quota, for Voice Call and Control UI Talk.
Document the direct Platform API key path, the `openai-codex` OAuth client-secret path, the quota symptom, and the Platform billing fix. Keep the changelog note crediting @lonexreb.
Closes#76498.
Co-authored-by: lonexreb <reach2shubhankar@gmail.com>
Keep the Codex app-server full attempt watchdog armed after a terminal turn notification is queued, so a wedged notification projector cannot leave a run stuck indefinitely.
Proof:
- `git diff --check origin/main...HEAD`
- `node scripts/run-oxlint.mjs extensions/codex/src/app-server/run-attempt.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `node scripts/run-vitest.mjs run extensions/codex/src/app-server/run-attempt.test.ts --testNamePattern "keeps the attempt watchdog armed"` passed in PR proof (`1 passed | 232 skipped`)
- `OPENCLAW_TESTBOX=1 pnpm check:changed` passed in `tbx_01kskyg44ej461k574jee8ffjc`
- CI required checks green after `build-artifacts` rerun job `78031279635` passed
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Fix Claude CLI skill prompt handling so native skill plugin materialization is prepared before prompt suppression, with the prompt fallback preserved when plugin args are unavailable. Also keeps direct prepared-run callers covered by an execute-time fallback.
Fixes#87063.
Co-authored-by: uday <udaymanish.thumma@gmail.com>
Regression test for the binary stall fix: when rawResponseItem/completed
arrives with a non-assistant type (e.g. "reasoning") and all tracked
items have completed, the completion idle watch must stay armed so the
stall is caught in 60s, not 30 minutes.
Refs openclaw/openclaw#87071
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the codex binary emits rawResponseItem/completed and all tracked
items have completed (activeTurnItemIds empty, no active requests), the
binary should deliver turn/completed imminently. Previously, a
rawResponseItem/completed that didn't qualify as a post-tool assistant
completion would actively disarm the completion idle watch, leaving only
the 30-minute terminal timeout to catch a stalled binary. This caused
turns to hang for up to 30 minutes when the OpenAI Responses API fails
to deliver response.completed to the binary.
Now, rawResponseItem/completed with no active items arms the 60s
completion idle watch and is excluded from the disarm path, so stalled
binaries are detected in 60s instead of 30 minutes.
Refs openclaw/openclaw#87071
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restart stale local node-host processes when they reconnect to a newer gateway with a released-version mismatch, so launchd/systemd can restart them with updated code instead of leaving old dynamic imports alive.
Adds gateway mismatch detail propagation, node-host terminal pause handling, and regression coverage for the GatewayClient reconnect-pause path.
Verification:
- node scripts/run-vitest.mjs run src/gateway/client.test.ts -t 'CLIENT_VERSION_MISMATCH' --reporter=verbose
- node scripts/run-vitest.mjs run src/gateway/server.node-version-mismatch.test.ts src/node-host/runner.credentials.test.ts src/gateway/client.test.ts --reporter=verbose
- /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode local
- Crabbox AWS run_292dcbfd78d9: focused GatewayClient mismatch regression plus server/node-host mismatch tests passed
Co-authored-by: scotthuang <scotthuang@tencent.com>
Persist trailing `/model ...@profile` suffixes through the gateway session patch path so documented per-session credential pinning reaches the session entry. Strip the suffix before model resolution so bare allowlisted model IDs still infer their configured provider, and mark same-model profile-only changes as pending live model switches.
Closes#87099.
Verification:
- `npx oxfmt --check src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts`
- `node scripts/run-vitest.mjs src/gateway/sessions-patch.test.ts src/sessions/model-overrides.test.ts`
- `npx oxlint src/sessions/model-overrides.ts src/sessions/model-overrides.test.ts src/gateway/sessions-patch.ts src/gateway/sessions-patch.test.ts`
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- `gh pr checks 87123 --watch --fail-fast`
Co-authored-by: xin zhuang <65798732+1052326311@users.noreply.github.com>
Fix Codex OAuth-backed OpenAI compaction routing by separating the configured provider from the runtime auth provider, preserving same-provider fallback auth, and keeping OpenAI context policy lookup intact. Also preserves the original cause when sessions.send reports A2A fallback failure. Fixes#86373.
Summary:
- Enforces /allowlist config and pairing-store writes against the real command origin plus the selected target.
- Adds regressions for disabled Telegram-origin commands targeting an enabled Discord allowlist.
Verification:
- node scripts/run-vitest.mjs src/auto-reply/reply/commands-allowlist.test.ts
- pnpm check:changed via Blacksmith Testbox tbx_01ksm06e82dnpxmnj00hrt6xzd
- autoreview --mode local clean, no accepted/actionable findings
- GitHub PR checks green on 42a38d2b00Closes#72360.
Thanks @coygeek.
Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
Co-authored-by: opencode <opencode@users.noreply.github.com>
Remove the hidden 15s default from reply-run idle waits so visible user turns do not inherit cleanup-settle behavior while waiting behind an active same-session reply operation.
Keep the 15s timeout explicit for queued follow-up retry/defer paths and interrupt/reset cleanup waits, and add reply-admission regressions for both visible and queued follow-up behavior. Also preserve the original cause on a nearby sessions-send fallback error to keep current lint green after rebasing onto main.
Thanks @keshavbotagent.
Co-authored-by: Keshav's Bot <keshavbotagent@gmail.com>
Fix run-scoped sessions_send active-run fallback handling.
- surface active queue rejection plus durable fallback admission failures instead of returning accepted too early
- return fallback run/session metadata so normal A2A announcement waits on the fallback run
- retry active steering without transcript-commit waiting when the active runtime does not support it
Thanks @TurboTheTurtle.
Verification:
- node scripts/run-vitest.mjs src/agents/openclaw-tools.sessions.test.ts
- pnpm check:test-types
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
The Windows Gateway daemon crashes (or rather is killed by Task Scheduler) every time the laptop unplugs from AC power. Reporter on Windows 10 22H2 documented a 100% failure rate.
Root cause: `activateScheduledTask` in `src/daemon/schtasks.ts` used `schtasks /Create` with CLI flags (`/SC ONLOGON /RL LIMITED /TR ...`). That CLI surface cannot set `<DisallowStartIfOnBatteries>` or `<StopIfGoingOnBatteries>`, so the task inherits the Task Scheduler defaults (both `true`), which prevent the task from starting on battery and stop it when AC power is lost mid-run.
This change switches `/Create` to `/Create /XML <tempfile>` and emits a Task Scheduler XML payload that mirrors the prior CLI flags (ONLOGON trigger, LeastPrivilege run level, InteractiveToken logon when a `taskUser` is resolved, single-instance policy, no idle restrictions, exec action wired to the existing `gateway.cmd` / `gateway.vbs` launcher) AND sets:
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
The XML is written as UTF-16 LE with a BOM, which is what `schtasks /XML` expects on all Windows locales. The temp file is cleaned up in a `finally` block.
The same XML re-apply is also issued from `updateExistingScheduledTask` after the existing `/Change /TR` call, so users upgrading from older versions inherit the new battery flags on the next gateway install/refresh instead of staying broken until a full uninstall+reinstall.
This follows clawsweeper's direction on #59299: "Land a narrow Windows Scheduled Task settings repair that lets the Gateway task start and continue on battery while preserving the current Startup-folder fallback, hidden launcher, quoting, and update behavior."
Preserved unchanged:
- Startup-folder fallback when `/Create` is denied or times out
- Hidden launcher (.vbs) selection via `OPENCLAW_WINDOWS_TASK_HIDDEN_LAUNCHER`
- `quoteSchtasksArg` quoting strategy for the script launch path
- `/Change` update path semantics (still updates `/TR` first)
- All `runScheduledTaskOrThrow` and fallback launch behavior downstream
Verification:
- `node scripts/run-vitest.mjs src/daemon/schtasks.install.test.ts` — 12 passed (incl. 2 new battery-flag regression tests)
- `node scripts/run-vitest.mjs src/daemon/schtasks.test.ts src/daemon/schtasks.startup-fallback.test.ts src/daemon/schtasks.stop.test.ts src/daemon/schtasks-exec.test.ts` — 54 passed (sibling daemon coverage)
- `pnpm tsgo:core` — passed (production typecheck)
Closes#59299
Derive explicit source-reply command turns from authorized control-command bodies when legacy command source metadata is missing.
Preserve native/text structured command semantics, keep unauthorized native commands and structured normal command bodies on plugin-owned fallback paths, and pass bot username normalization through the derived detection.
Co-authored-by: Alex Knight <aknight@atlassian.com>
Bounds nonessential installer finalization probes so npm prefix and daemon-status checks warn and fall back instead of hanging setup.
Thanks @giodl73-repo!
Behavior addressed: doctor hooks model validation now loads the model catalog read-only, so lint/doctor can warn without writable catalog side effects.
Real environment tested: local temp merged tree on current origin/main.
Exact steps or command run after this patch: node scripts/run-vitest.mjs src/flows/doctor-core-checks.test.ts src/flows/doctor-health-contributions.test.ts --reporter=dot; ./node_modules/.bin/oxfmt --check --threads=1 src/flows/doctor-core-checks.ts src/flows/doctor-health-contributions.ts src/flows/doctor-core-checks.test.ts src/flows/doctor-health-contributions.test.ts; ./node_modules/.bin/oxlint src/flows/doctor-core-checks.ts src/flows/doctor-health-contributions.ts src/flows/doctor-core-checks.test.ts src/flows/doctor-health-contributions.test.ts; git diff --check origin/main <merged-tree>
Evidence after fix: 2 test files passed, 30 tests passed; oxfmt passed; oxlint passed; diff check passed.
Observed result after fix: hooks.gmail.model doctor paths call loadModelCatalog with readOnly true in both structured and legacy health surfaces.
What was not tested: GitHub Actions run details could not be refreshed because the Actions API was rate-limited; gh reported no required checks for the branch.
Thanks @giodl73-repo.
Co-authored-by: Gio Della-Libera <giodl73@gmail.com>
Keep Windows node service stop/restart/status from treating the gateway listener port as node-owned runtime evidence. Node Scheduled Task and Startup fallback paths now match the installed node host command line before reporting or terminating a node runtime, so WSL2 gateway loopback connectivity is not disturbed by node lifecycle commands.
Fixes#85289.
Verification:
- node scripts/run-vitest.mjs src/daemon/schtasks.startup-fallback.test.ts src/daemon/schtasks.stop.test.ts
- git diff --check
Co-authored-by: Gio Della-Libera <giodl73@gmail.com>
Stage remote iMessage attachments before media understanding so the image pipeline receives local remote-cache paths instead of raw macOS Messages paths.
Fixes#87089
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Fix stale `subagent_announce` history hydration after `/new` by filtering pre-session-start announce/user reply pairs before `chat.history` projection.
Maintainer fixups added:
- require the adjacent assistant reply to carry a pre-session timestamp before dropping it
- preserve record timestamps for oversized transcript placeholders
- run the filter after Claude CLI history import and support imported timestamp/text fallback
- overread one local transcript message only as boundary context so limit-window edges do not leak stale assistant replies
Verification:
- `git diff --check`
- `node scripts/run-vitest.mjs src/gateway/server-methods/server-methods.test.ts src/gateway/session-utils.fs.test.ts src/gateway/session-history-state.test.ts src/gateway/cli-session-history.test.ts src/gateway/server.chat.gateway-server-chat-b.test.ts` -> 11 files, 463 tests passed
- `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main` -> clean, no accepted/actionable findings
Thanks @openperf.
Fix gateway/chat timeout abort propagation so timed-out runs do not cascade through fallbacks. Preserve provider timeout errors when the gateway abort signal did not fire, and keep timeout stop reasons in async gateway agent results. Includes regression coverage for chat, follow-up, memory flush, fallback classification, and gateway agent timeout results. Fixes#83962.
* fix(plugin-sdk): use Function.name to find onDiagnosticEvent export
normalizeDiagnosticEventsModule hardcodes `mod.r` as the fallback alias
for onDiagnosticEvent, but the bundler reassigns export aliases across
builds. On 2026.5.25-beta.1, `r` is emitFailoverEvent — calling it as
onDiagnosticEvent returns a non-function, so the combo unsubscribe
closure throws TypeError on every gateway stop.
Replace the hardcoded letter with Function.name introspection. JS
functions retain their original .name regardless of export aliasing,
so this survives bundler alias changes.
Fixes#87082
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(plugin-sdk): cover diagnostic event alias shifts
* fix(plugin-sdk): harden diagnostic alias cleanup
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Recover idle queued sessions whose diagnostic activity retained stale ownerless model or tool calls by classifying them as recoverable session.stuck after the usual recovery gates. Yield the event loop before stale session-lock process inspection so sync process lookup cannot monopolize lock contention paths.
Docs now describe the widened session.stuck telemetry contract for recoverable stale bookkeeping, including ownerless activity. Thanks @samuelsoaress.
Refs #84903.
Co-authored-by: samuelsoaress <samuelsoares177778@gmail.com>
Summary:
- Resolve inbound media references through the shared media-reference path before workspace-relative handling.
- Reuse the same sandbox rewrite for Pi native images and sandbox media bridge paths.
- Add regression coverage for managed inbound images, sandbox-staged media references, and invalid media IDs.
- Fix current lint by using non-mutating cpuprofile sorting.
Verification:
- node scripts/run-vitest.mjs src/media/media-reference.test.ts src/agents/sandbox-media-paths.test.ts src/agents/pi-embedded-runner/run/images.test.ts src/agents/tools/image-tool.test.ts src/media/web-media.test.ts src/agents/tools/pdf-tool.test.ts src/agents/tools/image-generate-tool.test.ts src/agents/tools/video-generate-tool.test.ts src/agents/tools/music-generate-tool.test.ts
- node scripts/run-oxlint-shards.mjs --threads=8
- git diff --check
- /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI rollup passed for eceea707a7Fixes#87024.
Supersedes #87055; thanks @TurboTheTurtle for the report and initial fix direction.
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Release the embedded attempt session lock before sessions_yield abort cleanup waits for session events and rewrites yielded-parent artifacts.
This keeps the existing bounded settle wait while preventing child completion callbacks from contending on the coarse parent transcript lock.
Adds focused session-lock lifecycle coverage.
Refactor memory close provider draining so providers created during shutdown are closed through the same bounded retry path.
Co-authored-by: spacegeologist <zheng.zuo0@gmail.com>
Honor the selected session agent's thinkingDefault for ingress agent runs before global fallback.
Also keep session store cache object-clone writes parse-free while matching persisted JSON shape when cloning values.
Fixes#86669
Co-authored-by: ai-hpc <mail.speedy.hpc@hotmail.com>
Guarantee MCP stdio child cleanup during Gateway shutdown by sending a synchronous SIGKILL when the child survives the existing stdin and SIGTERM waits. This prevents SIGTERM-ignoring local MCP processes from outliving the Gateway when killProcessTree's unref'd SIGKILL timer would otherwise lose the shutdown race.
Fixes#86412.
Verification:
- GitHub CI green on relevant agent/runtime, lint/type, CodeQL/security, OpenGrep, and Real behavior proof checks.
- Real behavior proof: https://github.com/openclaw/openclaw/actions/runs/26430512156/job/77802651894
- Maintainer manual review: no blocking findings.
Thanks @openperf.
Co-authored-by: openperf <16864032@qq.com>
Fix cron delivery previews for no-delivery jobs that still provide explicit message-tool targets.
- Reuse one cron delivery-plan explicit-target predicate across preview and isolated-agent runtime paths.
- Treat numeric threadId 0 as an explicit delivery target.
- Avoid fail-closed wording for unresolved message-tool-only targets.
Thanks @Alix-007 for the fix.
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
Copy plugin-provided skills from their validated real target into sandbox workspaces while keeping prompt-visible skill paths sandbox-local.
Adds regression coverage for symlinked plugin skills, multiple plugin skill roots, escaped symlink targets, and sandbox prompt paths that must not leak host plugin-skill locations.
Refs #86190
Remove the proposed public `maxReseedHistoryChars` config surface and scale Claude CLI reseed history automatically from the resolved context tier instead.
Claude CLI 200K-context runs now keep a 64K-character reseed slice, 1M Opus/Sonnet runs use the bounded 256KiB cap, and non-Claude CLI backends keep the existing 12KiB default. This preserves the intended long-context behavior without adding another config option.
Verification:
- `node scripts/run-vitest.mjs src/agents/cli-runner/session-history.test.ts src/agents/cli-runner/prepare.test.ts`
- `node scripts/run-vitest.mjs src/agents/cli-runner/prepare.test.ts -t "automatic Claude CLI cap"`
- `node scripts/run-oxlint.mjs src/agents/cli-runner/prepare.ts src/agents/cli-runner/prepare.test.ts src/agents/cli-runner/session-history.ts src/agents/cli-runner/session-history.test.ts src/config/types.agent-defaults.ts src/config/zod-schema.core.ts`
- `pnpm check:changed` via Testbox `tbx_01kska2twjxb925xft9dj82hvb`
- GitHub PR checks green
Closes#83985
Co-authored-by: Abdel Gomez-Perez <nabdel07@icloud.com>
Generate the public config JSON Schema from accepted input shapes so transform-backed fields remain renderable in the Control UI. Keep transform output schemas representable with explicit string pipes, align analyzer metadata handling, and cover the generated schema plus browser-safe UI render shapes.
Co-authored-by: Altay <altay@hey.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Keep the Logs page from rendering competing outer page and inner log-stream scrollbars. The Logs route now opts into an explicit content class for desktop fill-height layout, while mobile keeps the single-page scroll behavior with the capped log panel.
Also adds regression coverage for the route class and CSS ownership selectors.
Co-authored-by: Brian potter <brian@potterdigital.com>
Preserve native slash-command laziness while allowing `/skill` to load workspace skill commands asynchronously when needed. The loaded command list is reused for downstream native skill dispatch so valid `/skill <name>` calls do not get misclassified as unknown.
Verification:
- git diff --check
- fnm exec --using v24.15.0 -- pnpm changed:lanes --json
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub CI rollup success for c0d778d512
Co-authored-by: Keshav's Bot <keshavbotagent@gmail.com>
Fixes#86007.
Release note: Windows gateway install/update now ignores a persisted OPENCLAW_WRAPPER when it points back at the generated gateway.cmd task script, preventing recursive gateway startup while keeping valid wrapper installs intact.
Credit: thanks @luoyanglang for the fix and proof.
* fix(gateway): reject RPCs from invalidated device-token clients during rotation/revoke race
device.token.rotate, device.token.revoke and device.pair.remove all
respond 200 OK to the admin, then schedule disconnectClientsForDevice
via queueMicrotask so the response can flush before the socket close.
That microtask window plus the absence of a per-RPC re-check for
device-token auth (unlike shared-auth, which gets checked at
message-handler.ts:1444-1458) created a race: an attacker with RPCs
already pipelined in the WS socket buffer could land a few more
authenticated operations with the rotated/revoked token before the
socket actually closed.
Fix: add a cheap in-memory 'invalidated' flag on GatewayWsClient and
mark it synchronously *before* responding in the three handlers. Add
a mirror check at the start of the per-RPC dispatch that force-closes
the client if the flag is set, regardless of whether socket.close()
has taken effect yet. Disconnect still happens via queueMicrotask so
the admin's rotate/revoke response flushes normally.
Introduces context.invalidateClientsForDevice(deviceId, opts) as a
sync companion to the existing disconnectClientsForDevice. Also
defense-in-depth: disconnectClientsForDevice now sets the flag too,
so any other caller of the hard-disconnect path gets the per-RPC
gate for free.
* test(gateway): use vi.mocked instead of direct Mock casts in devices tests
check-test-types failed on the PR because direct 'as ReturnType<typeof vi.fn>' casts from RespondFn (or the optional context methods) don't structurally overlap with the Mock type — Mock has mockImplementation/mockReturnValue that RespondFn lacks, so strict tsgo rejects the conversion. vi.mocked() is the intended helper for reinterpreting an already-mocked function, and drops through to the Mock surface cleanly.
* test(gateway): align tests with upstream type/shape changes after rebase
After rebasing onto upstream main, two test surfaces drifted:
1. GatewayRequestContextParams gained two required fields upstream
(getRuntimeConfig, broadcastVoiceWakeRoutingChanged). The
makeContextParams test helper was missing them, so every consumer
tripped tsgo with a missing-field error. Add both as vi.fn()
stubs.
2. revokeDeviceToken's return shape changed upstream from a bare
entry record to a discriminated union {ok: true, entry: ...} | {ok:
false, reason}. The new device.token.revoke synchronous-invalidate
test still mocked the old shape, so the production handler took the
!revoked.ok branch and never reached the invalidateClientsForDevice
call the test asserted. Update the mock to the new union shape.
Also fix three new Set([...] as never) sites in server-request-
context.test.ts that produced Set<unknown> rather than Set<never>.
Move the cast outside the Set constructor so the literal stays
inferred while the wrapper is type-erased to never, which is
assignable to the Partial<GatewayRequestContextParams> clients field.
* fix(gateway): export GatewayRequestContextParams for test access
* fix(ci): resolve check-test-types and lint failures from PR #70707 branch
- server-request-context.test.ts: hasConnectedMobileNode → hasConnectedTalkNode
(field renamed in server-request-context.ts but test fixture not updated)
- status.summary.redaction.test.ts: add configuredModel/selectedModel/
modelSelectionReason to createRecentSessionRow fixture
(SessionStatus gained these fields in a13468320c; test was not updated)
- video-generation-providers.live.test.ts: replace empty {} fallbacks in
conditional spreads with undefined (oxlint 1.65.0, 5 occurrences)
- music-generation-providers.live.test.ts: same fix for 4 occurrences
Remaining CI failures (FsSafeError/Python helper, media tests, Windows ACL,
session-memory hooks) are pre-existing infra failures unrelated to this PR.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): add missing GatewayRequestContextParams fields to test fixture
chatDeltaLastBroadcastText, agentDeltaSentAt, and bufferedAgentEvents are
required fields in GatewayRequestContextParams but were absent from the
makeContextParams fixture, causing TS2322 in check-test-types.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix(gateway): serialize credential invalidating RPCs
---------
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Apply diagnostics.otel.flushIntervalMs to OpenTelemetry trace batching so short-lived Windows and QA runs do not lose late lifecycle/model spans. Also make the OTel QA smoke wait for required telemetry and print bounded failure diagnostics.
Keep model browse/list visibility consistent with runtime-normalized allowlist entries while keeping unrestricted default browse off plugin/runtime hydration. Add regression coverage for catalog visibility, `/models` browse data, and the replay sanitizer mock isolation that made the agents shard order-sensitive.
Verification:
- pnpm test src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/model-catalog-visibility.test.ts src/auto-reply/reply/commands-models.test.ts src/auto-reply/reply/model-selection.test.ts src/agents/model-selection.plugin-runtime.test.ts -- --reporter=verbose
- OPENCLAW_VITEST_MAX_WORKERS=2 pnpm exec node scripts/test-projects.mjs test/vitest/vitest.agents-core.config.ts
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub Actions CI run 26476126784
* fix(telegram): preserve command slots for aliases
* fix: report Telegram alias command overflow
* fix: preserve Telegram alias menu order
* docs: drop release-owned changelog entry
---------
Co-authored-by: wuyangfan <yangfan.wu@succaiss.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Ensure deferred context-engine maintenance rejects cleanly when the gateway command queue is draining, including coalesced active-run requests. This prevents budget compaction from treating an unscheduled deferred maintenance run as successful and leaving the context engine alive.
Verification:
- pnpm exec oxfmt --check --threads=1 src/process/command-queue.ts src/agents/pi-embedded-runner/compact.queued.ts src/agents/pi-embedded-runner/context-engine-maintenance.ts src/agents/pi-embedded-runner/context-engine-maintenance.test.ts
- pnpm test src/auto-reply/reply/agent-runner-memory.test.ts src/agents/pi-embedded-runner/compact.hooks.test.ts src/agents/pi-embedded-runner/context-engine-maintenance.test.ts src/tasks/task-flow-registry.store.test.ts src/auto-reply/reply/commands-compact.test.ts src/agents/pi-embedded-runner/compact-reasons.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub Actions CI run 26475226442: relevant Node/Linux, lint, type, security, CodeQL, OpenGrep, Socket, Real behavior proof, and build jobs passed; Windows job failed before tests due current runner image Node 22.19.0 vs required 24.x, matching current main infra failure.
Fixes#86814.
Reclaims stale plugin lock files only when the previous owner is provably gone or the recorded process start time proves PID reuse. Timestamp age alone now stays fail-closed for PID-owned locks, preserving mutual exclusion for long-running writers while still allowing pidless expired locks to expire.
Verification:
- pnpm test src/infra/stale-lock-file.test.ts src/plugin-sdk/file-lock.test.ts
- pnpm tool-display:check
- git diff --check
- autoreview --mode branch --base origin/main
Known CI note: check-guards failed in deps:shrinkwrap:check because npm resolved newer AWS transitive versions than pnpm-lock.yaml contains; no package or lock files are changed in this PR.
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
Remove the transcript redaction path for sessions_spawn arguments and inline attachments. OpenClaw transcripts are local trusted-operator state, and streamTo/resumeSessionId are runtime routing fields that must not be rewritten before replay or dispatch.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Runtime-injected web_search provider config from plugins.entries.<plugin>.config.webSearch now stays available to provider execution without being validated as user-authored legacy tools.web.search.<provider> config.
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Preserve legacy numeric stable git tags while excluding named semver prerelease tags from stable git channel detection and status display.
Thanks @goldmar.
Memoize owner process argv lookups per PID during `cleanStaleLockFiles`, and yield between lock entries so startup cleanup does not monopolize the event loop while inspecting many session locks.
This keeps lock classification semantics unchanged while avoiding repeated synchronous process-args reads for lock clusters owned by the same PID, especially the Windows PowerShell path.
Fixes#86509.
Verification:
- `git diff --check origin/main...HEAD`
- focused TSX harness against the current-main merge result: `session-lock memo regression harness passed`
Thanks @openperf.
Co-authored-by: openperf <16864032@qq.com>
Project newer external OpenClaw chat history into resumed Codex app-server threads when the saved binding is older than user-visible transcript messages, while filtering Codex-owned mirror records on consecutive resumes.
Thanks @TurboTheTurtle!
Keep Codex app-server turn timeouts within the Codex runtime boundary so they interrupt the active turn without retiring the shared app-server client, poisoning auth-profile cooldowns, or falling through to generic provider/model fallback.
Preserve concrete non-timeout provider failures for auth-profile rotation and fallback, and add regression coverage for prompt-stage timeouts, assistant idle timeouts, auth-profile cooldowns, and app-server timeout handling.
Thanks @pashpashpash.
Fixes#74061.
Stages absolute final-reply MEDIA paths that already live under the agent workspace before sandbox path translation runs, so Telegram/local delivery can attach generated workspace media instead of dropping it as Media failed. Outside-workspace host-local paths remain blocked, and host-read HTML stays denied pending separate security-boundary review.
Verification:
- git diff --check origin/main...refs/remotes/pull/86531
- git merge-tree --write-tree origin/main refs/remotes/pull/86531
- reviewed src/auto-reply/reply/reply-media-paths.ts, src/media/web-media.ts, and focused tests
Co-authored-by: mjamiv <74088820+mjamiv@users.noreply.github.com>
Remove the Telegram DM thread reply policy config and use Telegram bot capability as the single source of truth for DM topic session splitting.
DM messages with message_thread_id now split into thread-scoped sessions only when Telegram getMe reports has_topics_enabled for the bot. Doctor removes retired dm.threadReplies and direct.*.threadReplies keys, docs explain the upgrade behavior, and startup keeps cached bot info as a non-auth fallback when a fresh probe fails.
Refs #86513.
Thanks @alexph-dev.
Verification:
- pnpm docs:list
- pnpm exec oxfmt --check --threads=1 extensions/telegram/src/channel.ts extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/doctor-contract.ts extensions/telegram/src/doctor.test.ts
- git diff --check
- node scripts/run-vitest.mjs extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/doctor.test.ts extensions/telegram/src/bot/helpers.test.ts extensions/telegram/src/bot-message-context.dm-threads.test.ts extensions/telegram/src/config-schema.test.ts
- pnpm config:channels:check
- pnpm config:docs:check
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub Actions: CI 26468039803, Workflow Sanity 26468040057, OpenGrep 26468039472, Real behavior proof 26468036483, CodeQL 26468039466, CodeQL Critical Quality 26468039473
Known CI caveat: checks-windows-node-test failed before tests because Windows runner setup left Node 22.19.0 active while the job requested Node 24.x; the same setup failure is present on current main CI run 26468063947.
Reworks the Codex app-server native thread reuse guard so OpenClaw no longer adds a user-facing token config. Token clearing now prefers Codex's reported model context window, falls back to a high internal recovery fuse, and preserves context-engine thread-bootstrap reuse while keeping byte guard behavior intact.
Verification:
- `fnm exec --using v24.15.0 -- node scripts/run-vitest.mjs run extensions/codex/src/app-server/run-attempt.test.ts extensions/codex/src/app-server/run-attempt.context-engine.test.ts --reporter=dot --pool=forks --no-file-parallelism`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode local --base origin/main`
- Testbox `check:changed`: `tbx_01ksjm1hy7mfrc5bebzyckqdew`, GitHub Actions run https://github.com/openclaw/openclaw/actions/runs/26463150977, exit 0
- PR CI green after rerunning unrelated `checks-node-agentic-agents` flake and stuck OpenGrep scan
Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
* fix: validate wide-area dns domains
* addressing codex review
* fix(dns-cli): throw explicit DNS-name error on invalid --domain
resolveWideAreaDiscoveryDomain catches the validation error from
normalizeWideAreaDomain and returns null, so dns setup --domain foo/bar
fell through to the "No wide-area domain configured" branch instead of
surfacing the invalid-domain diagnostic. Validate explicit CLI/config
input directly so the user-facing setup command reports the actual
problem; preserve the resolver's silent env-fallback semantics for the
background callers that depend on graceful degradation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(gateway): lock in graceful degrade on invalid wide-area config
Drive startGatewayDiscovery through the real resolveWideAreaDiscoveryDomain
with wideAreaDiscoveryDomain: "foo/bar" so the test exercises the actual
swallow-and-return-null path. Asserts the operator-facing warning is
logged, writeWideAreaGatewayZone is never called, and startup completes
without throwing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(gateway): type resolveWideAreaDiscoveryDomain mock to match real signature
vi.fn(() => "openclaw.internal.") inferred the mock as `() => string`, so
mockImplementationOnce(realResolver) tripped tsgo:core:test with TS2345.
Apply the same vi.fn<typeof ...>(...) pattern the file already uses for
writeWideAreaGatewayZone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(changelog): note dns validation fix
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Agustin Rivera <agustin@rivera-web.com>
Updates Discord voice Opus callers to the published libopus-wasm 0.1.0 API, pins the Discord plugin dependency and lockfiles to that release, keeps the package freshness exception version-scoped, treats expected Discord receive-stream premature closes as normal stream ends, and includes routed OpenClaw transcript roots for local PR transcript discovery.\n\nProof: npm view libopus-wasm@0.1.0; pnpm install --lockfile-only --filter @openclaw/discord; Node encode/decode smoke with pkg 0.1.0 decoded=3840; node scripts/run-vitest.mjs extensions/discord/src/voice/audio.test.ts extensions/discord/src/voice/receive-recovery.test.ts; git diff --check; autoreview clean; live tmux gateway on e0fa3e3 joined Discord voice and processed realtime audio without decoder.decode or Premature close warning spam.
Guard loadUsage in the Control UI overview secondary refresh so stale overview loads do not start the expensive usage.cost RPC after the user has navigated away. Active overview usage loading is preserved.
Fixes#86392.
Thanks @Marvinthebored for the report, live gateway proof, and patch.
Verification:
- CI=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=120000 fnm exec --using v24.15.0 -- node scripts/run-vitest.mjs run ui/src/ui/app-settings.refresh-active-tab.node.test.ts --reporter=dot --pool=forks --no-file-parallelism
- GitHub PR checks green on d52d8d10da, including Real behavior proof and checks-node-core-ui.
Co-authored-by: Marvinthebored <262704729+Marvinthebored@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Move meeting notes into core transcripts, remove the bundled meeting-notes plugin/API, and require explicit transcripts.enabled before exposing the recording-capable tool.
Fix outbound message actions so structured attachments[] media participates in existing sandbox, local-root, and hydration checks. Single-attachment actions select structured attachments only when no top-level or plugin media source wins, while send collects all structured attachments. Proof: git diff --check; pnpm tsgo:core && pnpm tsgo:test:src; direct selector/hydration probe; autoreview clean.
Tag authorized Mattermost typed text-slash control commands with CommandSource: text so existing explicit-command source-reply delivery bypasses message_tool_only suppression for /new, /reset, ACP reset, and soft-reset acknowledgement replies.
Remove the normal PR changelog edit flagged by review and keep release-note context in the PR body/squash message. Tighten the regression test to exercise the leading-space Mattermost text-post path used to bypass native slash handling and assert the normalized command body.
Local proof: node scripts/run-vitest.mjs extensions/mattermost/src/mattermost/monitor.inbound-system-event.test.ts src/auto-reply/command-turn-context.test.ts src/auto-reply/reply/source-reply-delivery-mode.test.ts src/auto-reply/reply/commands-reset-hooks.test.ts; git diff --check origin/main..HEAD; oxfmt check; autoreview clean.
CI: PR run 26443271650 passed relevant checks. Ignored check-test-types failure because the exact same extensions/codex/src/app-server/run-attempt.test.ts TS2345 failure is already present on main run 26442926352 at the PR base.
Fixes#86664.
* fix(imessage): send group media via attachment command
* fix(imessage): preserve media rpc fallback
---------
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Summary:
- The PR updates diagnostics to mark streamed model chunks as run progress, keeps silent model calls abortable after the stuck-session timeout, and adds regression coverage for stream progress and recovery behavior.
- PR surface: Source +54, Tests +229. Total +283 across 6 files.
- Reproducibility: yes. at source level: current main tracks model-call start/end activity but streamed chunks ... covery keys on stale lastProgressAgeMs. I did not run a live local-provider repro in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(diagnostics): track model stream progress
- PR branch already contained follow-up commit before automerge: test(diagnostics): cover silent local model aborts
- PR branch already contained follow-up commit before automerge: fix(diagnostics): skip stream progress when disabled
Validation:
- ClawSweeper review passed for head fcc74d9869.
- Required merge gates passed before the squash merge.
Prepared head SHA: fcc74d9869
Review: https://github.com/openclaw/openclaw/pull/86757#issuecomment-4540111930
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- The PR adds runtime-only external OAuth provenance to auth-profile stores, updates save/merge/read paths to ... e profiles in active snapshots while filtering disk persistence, and expands auth-profile regression tests.
- PR surface: Source +381, Tests +974. Total +1355 across 8 files.
- Reproducibility: yes. from source: current main writes the disk-filtered localStore into an existing runtime ... tches the reported credential drop path. I did not run a failing current-main repro in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Preserve runtime external auth snapshots
Validation:
- ClawSweeper review passed for head a73074ed45.
- Required merge gates passed before the squash merge.
Prepared head SHA: a73074ed45
Review: https://github.com/openclaw/openclaw/pull/85558#issuecomment-4523577269
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR preserves provider-facing embedded-runner prompt errors when cleanup detects session takeover, keeps the takeover signal fatal for fallback, and adds focused regressions.
- PR surface: Source +52, Tests +92. Total +144 across 5 files.
- Reproducibility: yes. Source inspection shows current main can let cleanup takeover replace a prior prompt/p ... rror and can normalize a provider-looking takeover wrapper before fallback sees it as coordination failure.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(embedded-runner): preserve takeover during fallback
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8405…
Validation:
- ClawSweeper review passed for head 050c779cfa.
- Required merge gates passed before the squash merge.
Prepared head SHA: 050c779cfa
Review: https://github.com/openclaw/openclaw/pull/84321#issuecomment-4492087335
Co-authored-by: abnershang <abner.shang@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* refactor: use Rastermill for image processing
* docs: clarify autoreview heartbeat patience
* refactor: use simplified rastermill api
* fix: preserve rastermill media safety boundaries
* build: update rastermill api pin
* build: use published rastermill package
Summary:
- Adds `plugins/synthetic-auth.runtime` as an explicit tsdown dist entry and adds a regression test tying PI model-discovery synthetic-auth imports to that stable entry.
- PR surface: Tests +22, Other +1. Total +23 across 2 files.
- Reproducibility: yes. as a source-reproducible package-build path: current main imports synthetic-auth from ... y. The PR proof covers emitted production `dist/` imports, though it did not run a live scheduled cron job.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(build): pin synthetic auth runtime dist entry
Validation:
- ClawSweeper review passed for head cb99947919.
- Required merge gates passed before the squash merge.
Prepared head SHA: cb99947919
Review: https://github.com/openclaw/openclaw/pull/86714#issuecomment-4538919657
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR changes DeepSeek provider tool-schema normalization to convert multi-value string const unions into flat string enums, with regression coverage for pure, nullable, and single-const union cases.
- PR surface: Source +27, Tests +84. Total +111 across 2 files.
- Reproducibility: yes. source-level reproduction is high confidence: current main selects only the first non-null anyOf/oneOf variant, and the linked source PR proof shows before/after output for that exact schema shape.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(plugin-sdk): preserve string-const unions as flat enum for deepse…
Validation:
- ClawSweeper review passed for head 310d95e327.
- Required merge gates passed before the squash merge.
Prepared head SHA: 310d95e327
Review: https://github.com/openclaw/openclaw/pull/86712#issuecomment-4538892244
Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Move immutable session-store snapshot cloning/freezing off the write path and rebuild snapshots lazily on read. Resolve runtime external auth profiles once per auth-profile save instead of once per OAuth profile.
Proof: oxfmt targeted files; pnpm tsgo:core; pnpm check:test-types; node scripts/run-vitest.mjs src/config/sessions.cache.test.ts src/agents/auth-profiles.store.save.test.ts src/agents/auth-profiles/external-oauth.test.ts; autoreview clean.
Route invalid-config recovery output for source-only installed plugin packages to plugin packaging guidance instead of openclaw doctor --fix.
Validated with focused config/CLI/gateway/plugin tests, autoreview, Crabbox/Testbox E2E tbx_01ksgr80tnvvc13kv6t126yv78, and green PR CI on 3b3ce73d0f.
Thanks @brokemac79.
Reuse a lazy model manifest context across configured model resolution so common static defaults do not trigger manifest metadata loads, while keeping plugin-owned normalization available when aliases, provider rows, or OpenRouter compat paths need it.
Preserves exact alias behavior, auth-profile-suffixed alias behavior, provider inference from manifest-normalized configured refs, and existing plugin/runtime cache lifecycle rules.
Co-authored-by: Alyana <alyana@lumina.local>
Use the effective runtime/model context when computing overflow recovery reserveTokensFloor hints, including uncataloged runtime refs, stale session windows, and heartbeat fallback cases.
Verification:
- pnpm test src/auto-reply/reply/agent-runner-execution.test.ts
- autoreview clean on final focused fixup; prior accepted findings addressed before push.
- CI passed on head e25b3e84f4 after rerunning cancelled jobs: preflight, critical quality network-runtime-boundary, security high, checks, Real behavior proof.
Co-authored-by: tanshanshan <tanshanshan@users.noreply.github.com>
Forward OpenAI-compatible frequency_penalty, presence_penalty, and seed params through the gateway/chat-completions path while keeping Responses untouched.
Verification:
- pnpm test src/gateway/openai-http.test.ts src/agents/pi-embedded-runner/extra-params.sampling.test.ts src/agents/openai-transport-stream.test.ts
- CI passed on head 9abb9466d9 after rerunning cancelled jobs: preflight, critical quality network-runtime-boundary, security high, checks, docs, Real behavior proof.
Co-authored-by: lellansin <lellansin@gmail.com>
Cache configured model cost indexes for repeated session usage cost lookups while preserving in-place config mutation behavior via value-fingerprint invalidation. Raw pricing lookups now skip manifest model-id normalization as well as runtime/plugin normalization, keeping direct cost lookup off plugin metadata hot paths.
Verification:
- node scripts/run-vitest.mjs src/utils/usage-format.test.ts
- pnpm exec oxfmt --check src/utils/usage-format.ts src/utils/usage-format.test.ts
- pnpm lint --threads=8
- pnpm tsgo:core
- autoreview --mode local
- PR CI green on head 15c1e25d95
Cap retained compaction checkpoint snapshots by total bytes per session while preserving the existing count cap.
The gateway now stats retained checkpoint snapshots inside the session-store writer before trimming, deletes older trimmed checkpoint files, and keeps the newest checkpoint available. Regression coverage uses real sparse checkpoint files to prove byte-budget cleanup.
Closes#84822.
Summary
- Bound Memory Wiki compile-time page summary reads through the existing concurrency helper.
- Preserve deterministic result ordering before title sort and keep the helper in stop-on-error mode.
- Replaces #84458 because the fork branch does not allow maintainer edits and the contributor changelog entry needed removal.
Behavior addressed: Memory Wiki compile no longer starts one page-summary read per page without a bound.
Real environment tested: Local macOS source checkout, Node/pnpm repo environment.
Exact steps or command run after this patch: pnpm test extensions/memory-wiki/src/compile.test.ts; pnpm exec oxfmt --check --threads=1 extensions/memory-wiki/src/compile.ts extensions/memory-wiki/src/compile.test.ts; .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --no-web-search --prompt "Review PR #84458 after maintainer fixup. Focus on memory-wiki compile page summary read concurrency, runTasksWithConcurrency result/error handling, ordering preservation, and test reliability."
Evidence after fix: compile.test.ts passed 10 tests; oxfmt reported clean; autoreview reported no accepted/actionable findings.
Observed result after fix: Page reads are executed through runTasksWithConcurrency with errorMode stop, successful results are consumed in input-index order, and the existing summary title sort remains deterministic.
What was not tested: Full repository suite.
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Behavior addressed: Unknown CLI command roots now error consistently even when --help or --version is appended, while legitimate built-in help fast paths still render normally.
Real environment tested: Local OpenClaw source checkout plus GitHub workflow run-level status.
Exact steps or command run after this patch: pnpm test src/cli/run-main.exit.test.ts src/cli/argv.test.ts src/cli/argv-invocation.test.ts; pnpm exec oxfmt --check --threads=1 src/cli/run-main.ts src/cli/run-main.exit.test.ts; autoreview --mode branch --base origin/main --no-web-search.
Evidence after fix: Focused CLI test shards passed 178 tests; formatter clean; autoreview reported no accepted/actionable findings; GitHub CI run 26422344121 and CodeQL Critical Quality run 26422344090 completed successfully.
Observed result after fix: `openclaw foo --help` and `openclaw foo --version` reject before proxy/program startup, while known help fast paths remain ahead of the unknown-root guard.
What was not tested: Full local build; contributor PR body already supplied build/CLI command proof before rebase.
Co-authored-by: YB0y <brianandez6@gmail.com>
Behavior addressed: The codex-cli metadata branch no longer calls process.exit(0) immediately after writing stdout, and it still emits exactly one unsupported-backend JSON object.
Real environment tested: Local OpenClaw source checkout on macOS with Node/tsx.
Exact steps or command run after this patch: pnpm test test/scripts/print-cli-backend-live-metadata.test.ts test/scripts/docker-build-helper.test.ts; node --import tsx scripts/print-cli-backend-live-metadata.ts codex-cli | python3 -c 'import sys,json; print(json.load(sys.stdin)["provider"])'; autoreview --mode branch --base origin/main --no-web-search.
Evidence after fix: Focused tooling test shard passed 2 files / 23 tests; direct pipe parse printed codex-cli; autoreview reported no accepted/actionable findings; PR status rollup was clean.
Observed result after fix: stdout is parseable as a single JSON payload and the normal metadata path is skipped for codex-cli.
What was not tested: Live provider metadata paths beyond the focused existing test coverage.
Co-authored-by: Iftekhar Uddin <ifuddin3@gmail.com>
Behavior addressed: Native Codex app-server threads now disable Codex's built-in personality on thread/start, thread/resume, turn/start, bound conversation turns, and /btw side-thread forks so OpenClaw agent workspace identity stays authoritative.
Real environment tested: Local OpenClaw source checkout plus GitHub CI on PR #85891.
Exact steps or command run after this patch: pnpm test extensions/codex/src/app-server/thread-lifecycle.test.ts extensions/codex/src/app-server/side-question.test.ts extensions/codex/src/conversation-binding.test.ts extensions/codex/src/app-server/schema-normalization-runtime-contract.test.ts; pnpm check:docs; pnpm prompt:snapshots:check; OPENCLAW_ADDITIONAL_BOUNDARY_SHARD=1/4 OPENCLAW_ADDITIONAL_BOUNDARY_CONCURRENCY=4 node scripts/run-additional-boundary-checks.mjs.
Evidence after fix: Focused Codex test shard passed 4 files / 79 tests; docs check passed; prompt snapshots are current; CI passed all code/quality checks, with only Real behavior proof failing as unrelated proof-bot gating for this non-channel change.
Observed result after fix: App-server request snapshots and unit tests include personality: "none" on native Codex start/resume/turn/fork paths.
What was not tested: A live Codex app-server model run was not executed.
Co-authored-by: Beru <beru@lastguru.lv>
renewInterval is not cleared on re-entry to startGmailWatcher,
leaking the previous timer. Each config reload adds another
interval that fires independently.
Clear existing watcher state before starting a new one.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Bump USAGE_COST_CACHE_VERSION 3->4 so a warm .usage-cost-cache.json written by a
pre-change build is rebuilt instead of serving stale complete-$0 totals after
upgrade (the new missing-cost branch otherwise only runs when a file is rescanned).
Add a regression test asserting an older-version cache is treated as stale for an
unpriced session.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address review: distinguish unknown pricing from an intentional free price. A
turn's all-zero cost is treated as unknown (counted toward missingCostEntries)
only when the operator did NOT explicitly configure the model's price under
models.providers -- i.e. the zero is a generated-catalog default (codex/gpt-5.x),
not a deliberate $0. Operator-configured zero-cost models keep reporting a
complete $0.
Adds resolveConfiguredModelCost() to read config-only pricing, and regression
tests for both paths (unconfigured unknown -> missing; configured free -> $0).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Only treat an unpriced (all-zero) model's turn as missing when it has no
trustworthy recorded cost (recorded cost is 0 or absent). A turn carrying a
real positive recorded cost is preserved, fixing a regression where priced
fixtures without explicit pricing config lost their recorded cost.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Models that ship an all-zero cost block (e.g. codex gpt-5.5, whose Codex
backend exposes no per-token price) made usage-cost report totalCost: 0 with
missingCostEntries: 0 -- a confident, complete $0 -- so every budget/spike
safeguard keyed off totalCost was silently blind to real pay-per-token spend.
scanTranscriptFile now treats a resolved cost config with no positive per-token
rate (and no tiered pricing) as "pricing unknown": for turns that burned tokens
it drops the transport's fabricated $0 and surfaces the turn as a missing-cost
entry, mirroring the existing tiered-pricing override. Models with positive or
tiered pricing and zero-token entries are unaffected.
Verified on a real OpenClaw 2026.5.20 host (default openai/gpt-5.5, api_key):
1,780,235 tokens that previously reported missingCostEntries 0 now report 32.
Related: #85858
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary:
- The PR updates `src/agents/identity-file.ts` to normalize backtick-wrapped IDENTITY.md labels and values, and adds parser/merge regression tests in `src/agents/identity-file.test.ts`.
- PR surface: Source +8, Tests +28. Total +36 across 2 files.
- Reproducibility: yes. source-reproducible with high confidence: current main strips `*` and `_` but not back ... e unnormalized string. I did not run tests because this review was required to keep the checkout read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): strip markdown code spans from IDENTITY.md values and la…
Validation:
- ClawSweeper review passed for head 30c43defd6.
- Required merge gates passed before the squash merge.
Prepared head SHA: 30c43defd6
Review: https://github.com/openclaw/openclaw/pull/86647#issuecomment-4537456646
Co-authored-by: nayrosk <105997554+nayrosk@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR extracts the CJK-aware memory tokenizer into a shared helper, routes dreaming dedupe through it, preserves MMR re-exports, and adds regression coverage for CJK and empty-token cases.
- PR surface: Source +15, Tests +96. Total +111 across 5 files.
- Reproducibility: yes. Current main has an ASCII-only tokenizeSnippet path in dreaming dedupe, and the source ... ction source bytes for the CJK failure modes; I did not run tests locally because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(memory-core): use Array.toSorted for #80613 lint fix
- PR branch already contained follow-up commit before automerge: fix(memory-core): preserve dedupe identity when both snippets tokeniz…
- PR branch already contained follow-up commit before automerge: fix(memory-core): rename __testing to testing in CJK regression tests…
- PR branch already contained follow-up commit before automerge: fix(memory-core): use CJK-aware tokenizer for dreaming dedupe (#80613)
Validation:
- ClawSweeper review passed for head ca9c02734c.
- Required merge gates passed before the squash merge.
Prepared head SHA: ca9c02734c
Review: https://github.com/openclaw/openclaw/pull/86645#issuecomment-4537414471
Co-authored-by: MoerAI <friendnt@g.skku.edu>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Behavior addressed: Embedded PI compaction retry now drains block replies again after the retry wait resolves, so retry-generated replies are not left behind while preserving aggregate-timeout fallback behavior.
Real environment tested: local OpenClaw focused Pi runner test shard plus contributor local live-output proof in the PR body.
Exact steps or command run after this patch: pnpm test src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts src/agents/pi-embedded-runner/run/compaction-retry-aggregate-timeout.test.ts; .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
Evidence after fix: 2 test files passed, 55 tests passed; final autoreview clean with no accepted/actionable findings.
Observed result after fix: the runner flushes before the compaction wait, waits for compaction retry, then performs a second idempotent flush when the wait resolves without timing out.
What was not tested: fresh external-channel live retry by this agent; PR retains contributor live-output proof for the delayed channel adapter path.
Thanks @spacegeologist.
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Behavior addressed: Telegram direct-message turns no longer drop an earlier overlapping normal reply, while authorized aborts and explicit/native/plugin/skill command turns still supersede active reply work.
Real environment tested: local OpenClaw focused Telegram test shard plus existing contributor Telegram screenshot/log proof in the PR body.
Exact steps or command run after this patch: pnpm test extensions/telegram/src/telegram-reply-fence.test.ts extensions/telegram/src/bot-message-dispatch.test.ts; .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
Evidence after fix: 2 test files passed, 93 tests passed; final autoreview clean with no accepted/actionable findings.
Observed result after fix: overlapping normal Telegram DMs use non-interrupting reply fences and both final replies remain deliverable; direct /stop, authorized built-in commands, and explicit text/native command turns still supersede.
What was not tested: fresh live Telegram Desktop rerun by this agent; PR retains contributor screenshot/log proof and the Real behavior proof bot remains red despite proof labels.
Thanks @neeravmakwana.
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Keep isolated cron announce delivery owned by runner fallback while leaving agent-initiated message sends optional. `delivery.mode: none` no longer forces message delivery, announce delivery skips fallback only after a verified same-target message-tool send, and prompt allowlist checks now match runtime tool policy normalization/group expansion.
Verified with focused cron tests, `check:changed`, autoreview, and PR CI on 7ab77bad97.
Thanks @bryanpearson.
Co-authored-by: bryanpearson <bryanmpearson@gmail.com>
Fix Gemini cached-content GenerateContent payloads so cached requests no longer resend request-level systemInstruction, tools, or toolConfig.
Covers explicit cachedContent and managed cacheRetention prompt caching; fixes#84919.
Proof: Real behavior proof passed on PR head 198a42bbc6 after live Gemini repro/fix evidence was added to the PR body. Focused tests and check:changed were already green.
Thanks @neeravmakwana.
Adds regression coverage for agents.defaults.agentRuntime schema acceptance and invalid-config doctor fix reachability.
The runtime behavior fix already landed on main in 5b9be2cdb1c01a2896783c52f5f0654c5f22a249; this PR locks the expected behavior with focused tests.
Closes#72872
Precompute FIR resample kernels for common voice sample-rate conversions to avoid per-sample trigonometry while preserving output for tested ratios.\n\nVerification: node scripts/run-vitest.mjs extensions/voice-call/src/telephony-audio.test.ts; pnpm tsgo:core; autoreview --mode commit --commit HEAD; PR CI green.
Fix isolated cron delivery so agent-default derivation keeps using the paired runtime config snapshot, preserving resolved channel credentials such as Discord SecretRefs. Fixes#86545.
Add inline comment explaining that compileSafeRegex rejects patterns
with nested repetition (ReDoS risk) and returns null. Rejected patterns
are silently skipped; the plugin will not match via that pattern but
other patterns and prefixes still apply.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Replace raw `new RegExp(patternSource, "u")` in
`resolveModelSupportMatchKind` with the existing
`compileSafeRegex()` guard from `src/security/safe-regex.ts`.
A malicious or careless plugin manifest pattern like `(a+)+$`
causes catastrophic backtracking (ReDoS) against non-matching model
IDs. `compileSafeRegex` detects nested repetition and returns null,
which the caller now treats as a non-match (equivalent to the
previous catch-continue for invalid regex).
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Replace string containment check with direct field assertions:
- oversized.role is 'assistant'
- __openclaw.id is 'oversized-child' (exact match)
- parentId extraction proven by record inclusion in active tree
5/5 oversized transcript tests pass.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
extractJsonStringFieldPrefix and extractJsonNullableStringFieldPrefix
interpolate the `field` parameter into `new RegExp(...)` without
escaping. All current callers pass hardcoded strings ("id",
"parentId", "type", "role"), but the function signature accepts
any string. A future caller passing a field containing regex
metacharacters (e.g. "foo.bar") would match unintended patterns.
Wrap the interpolation with escapeRegExp() from src/shared/regexp.ts
so metacharacters are treated literally.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
When the gateway process is orphaned after a systemd service restart,
the parent's journal pipe closes and every write to stdout/stderr returns
EPIPE. The previous handler swallowed it with a bare return, so background
loops (config file watcher, etc.) kept firing and the process spun at
100% CPU indefinitely.
Exit cleanly with code 0 instead — a process whose own output streams
are broken has nowhere to log and no reason to keep running.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/docs-spellcheck.sh uses set -u and constructs args=( ... "${write_flag[@]}" ), where write_flag may be an empty array. On bash 3.2 (still the default /bin/bash on macOS), referencing an empty array under set -u raises an unbound variable error. Newer bash (>= 4.4) handles this expression correctly, which is why the script ships green on Linux CI runners.
Switch to the bash 3.2-safe parameter expansion ${write_flag[@]+"${write_flag[@]}"}: it expands to nothing when the array is empty and to the array contents otherwise, preserving --write behavior unchanged.
Also fixes overrideable -> overridable in docs/reference/test.md, which the now-running spellcheck surfaces.
Repro:
bash scripts/docs-spellcheck.sh # was: write_flag[@]: unbound variable, exit 1
bash scripts/docs-spellcheck.sh # now: codespell runs to completion
Summary:
- The PR replaces Feishu presentation/action card fallback rendering with a shared JSON 2.0 button/behaviors renderer, updates native card sanitization, and expands Feishu channel/outbound tests.
- PR surface: Source +118, Tests +223. Total +341 across 5 files.
- Reproducibility: yes. source-reproducible: current main renders Feishu presentation button blocks through ma ... help` fallback. I did not run local tests because this review was required to keep the checkout read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(feishu): render native presentation buttons
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8601…
Validation:
- ClawSweeper review passed for head 36d6a36323.
- Required merge gates passed before the squash merge.
Prepared head SHA: 36d6a36323
Review: https://github.com/openclaw/openclaw/pull/86588#issuecomment-4536092569
Co-authored-by: NianJiuZst <3235467914@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Refactor diagnostic queued/state/processed emission into a shared helper used by dispatch and isolated cron turns.
Preserve dispatch processed-event behavior, cron queue-depth symmetry, and final cron session-id adoption while adding focused helper coverage and reviewer comments for the non-obvious invariants.
Fixes Dependabot alert #118 for GHSA-q8mj-m7cp-5q26 by updating the workspace qs override from 6.14.2 to 6.15.2 and regenerating root and plugin shrinkwrap files.
Runtime surface: transitive qs consumers through Express, Slack, Feishu, Teams, ACP, and MCP paths.
Prefer the active Claude CLI OAuth auth label when the configured Anthropic model resolves through an equivalent Claude CLI runtime alias, so `/status` no longer reports an unused env API-key label.
Also adds regression coverage for both text and message status renderers, plus the maintainer changelog entry.
Closes#80184.
Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
Normalize Google Gemini 3.1 Flash Lite routing to the GA model id and keep the retired preview spelling as a compatibility alias. Align default alias docs, FAQ guidance, and deprecated-model manifest recommendations with the GA id.
Fixes#86151.
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
Address clawsweeper P2: cron isolated-agent lifecycle (message.queued,
session.state, message.processed) now mirrors the dispatch path and
respects the diagnostics.enabled master toggle. Added regression test
for the disabled-config path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(doctor): skip restart prompt when gateway is healthy after recent restart
`openclaw doctor` unconditionally prompted "Restart gateway service now?"
with default=Yes whenever the gateway was running, even if it had just
restarted via SIGUSR1 after an update. This caused restart loops on macOS
where the prompt raced with launchctl KeepAlive.
Changes:
- Probe gateway health before the restart prompt when a restart handoff
exists (deep doctor mode). If healthy, skip the prompt entirely.
- Change `initialValue` from `true` to `false` as a safety net so users
don't accidentally confirm a restart by pressing Enter.
- Update existing test that expected a single `readGatewayRestartHandoffSync`
call (now called twice: diagnostic display + health-probe check).
Fixes#86518
* fix(doctor): correct GatewayRestartHandoff mock types in tests
Add explicit literal types + satisfies constraint so the mock handoff
objects match the exact GatewayRestartHandoff type expected by the
type-check CI.
* fix(doctor): apply recent-restart skip to normal doctor flow
* test(doctor): align normal-flow handoff expectation
* chore: add doctor restart prompt changelog
---------
Co-authored-by: OpenClaw Contributor <openclaw-contributor@example.com>
Co-authored-by: liaoyl830 <267396060+liaoyl830@users.noreply.github.com>
Co-authored-by: sallyom <somalley@redhat.com>
* fix(agents): warn on Claude permission overrides under YOLO
* fix: narrow Claude audit backend guard
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(agents): answer Claude live control_request can_use_tool via exec policy
Claude CLI emits stream-json control_request frames with subtype
can_use_tool when it wants to use a native tool. The Claude live-session
bridge previously dropped these frames, leaving Claude waiting for a
control_response until the 180/600s no-output timeout fired (see #80819).
Resolve the effective OpenClaw exec policy (per-agent tools.exec -> global
tools.exec -> allowlist/on-miss defaults) once at session-start time and
thread it through fingerprinting and the session record. When a
can_use_tool request arrives:
- Allow native Bash when the resolved policy is security=full, ask=off
(matching the bypassPermissions semantics OpenClaw already documents).
- Otherwise deny with a message that names the resolved policy and
points the agent at OpenClaw MCP tools.
Unsupported control_request subtypes get a structured error response
instead of a silent no-op, and stray control_response frames are
silently dropped. Adds spawn-test coverage for both allow and deny paths.
Fixes#80819
* fix(agents): align Claude live control_request policy with backend defaults
Resolve the effective exec policy through the same defaults that
extensions/anthropic/cli-shared.ts:isOpenClawRequestedYolo and
src/agents/exec-defaults.ts:resolveExecDefaults already use (security
?? "full", ask ?? "off") instead of falling back to a hand-rolled
allowlist/on-miss default that disagreed with the rest of the codebase.
Without this, a default-config OpenClaw deployment launches Claude with
--permission-mode bypassPermissions but the bridge would still deny
Bash control_requests, re-creating the #80819 stall for the very
default-config case the issue reports.
Also thread the effective Claude permission mode into the policy
decision. Prefer the operator's explicit --permission-mode in argv,
falling back to what normalizeClaudePermissionArgs would have inserted
for an un-overridden launch. Native Bash is auto-allowed only when the
effective mode is bypassPermissions AND tools.exec resolves to
full/no-ask, so explicit raw-arg overrides like --permission-mode
default or acceptEdits broaden Claude's native prompting and are
honored by routing through deny.
Adds a no-config regression test (default deployment allows Bash, no
stall) and a permission-mode-override test (tools.exec full/off plus
explicit --permission-mode default in raw args denies). Existing
allow/deny tests continue to pass via the synthesized-mode fallback.
* fix(agents): honor effective exec policy for Claude live Bash
---------
Co-authored-by: Guillaume Thirry <g.thirry@gmail.com>
* fix(sessions): stop doctor OOM on large session stores and reclaim stale store temps
`openclaw doctor` loaded the full sessions.json via loadSessionStore with the
default cache-write plus return clone, materializing a multi-hundred-MB
monolithic store several times and exhausting the heap (#56827). The read-only
doctor checks (state integrity, heartbeat target, codex route scan) now load
with { skipCache: true, clone: false } so the store is materialized once.
Orphaned session-store atomic-write temps were also never reclaimed: the store
write went through the generic atomic writer, staging a shared
.fs-safe-replace.<pid>.<uuid>.tmp not identifiable as a store temp. Give the
store write a store-specific tempPrefix so its temps stage as
sessions.json.<pid>.<uuid>.tmp, classify them (isSessionStoreTempArtifactName),
and reclaim stale ones via the disk-budget sweep and the unreferenced-artifact
prune on a short staleness window so in-flight temps are preserved.
Fixes#56827
* docs(changelog): note large session store doctor fix
* test(qa): preserve WhatsApp RTT source literal
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- This PR adds an Ollama Kimi-cloud visible-content sanitizer for streamed and final assistant replies, updates stream handling and regression tests, and adds a changelog entry.
- PR surface: Source +183, Tests +473, Docs +1. Total +657 across 7 files.
- Reproducibility: yes. from source and the linked report: current main appends Ollama `message.content` direc ... payload described in the issue would be shown. I did not run a live vendor repro in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ollama): sanitize kimi inline reasoning in stream events
- PR branch already contained follow-up commit before automerge: fix(ollama): buffer kimi cloud stream reasoning
- PR branch already contained follow-up commit before automerge: fix(ollama): cover kimi inline boundary variants
- PR branch already contained follow-up commit before automerge: fix(ollama): preserve text start partial state
- PR branch already contained follow-up commit before automerge: fix(ollama): bound kimi stream sanitizer hold
- PR branch already contained follow-up commit before automerge: fix(ollama): keep kimi sanitizer deltas append-only
Validation:
- ClawSweeper review passed for head b709229157.
- Required merge gates passed before the squash merge.
Prepared head SHA: b709229157
Review: https://github.com/openclaw/openclaw/pull/86515#issuecomment-4534945393
Co-authored-by: Jason O'Neal <jason.allen.oneal@gmail.com>
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- This PR changes the shared block reply coalescer/pipeline so compatible buffered visible text is merged into a following media payload, adds focused regression tests, and records a Discord changelog fix.
- PR surface: Source +50, Tests +175, Docs +1. Total +226 across 6 files.
- Reproducibility: yes. Current main has a clear source reproduction path: media enqueue forces a text flush and then sends the media payload separately, and the PR adds focused tests for the corrected merge path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: route streamed media through reply coalescer
- PR branch already contained follow-up commit before automerge: fix(discord): merge media captions into one message
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8648…
Validation:
- ClawSweeper review passed for head ceafbeaf3c.
- Required merge gates passed before the squash merge.
Prepared head SHA: ceafbeaf3c
Review: https://github.com/openclaw/openclaw/pull/86487#issuecomment-4534402219
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* fix(memory): prevent silent vector index degradation when embedding provider temporarily unavailable
Two related bugs cause complete loss of semantic vector data:
1. Promise cache deadlock in ensureProviderInitialized():
When the embedding provider (e.g. local MLX server on port 8123) is
temporarily unreachable at Gateway startup, loadProviderResult() throws
and providerInitPromise becomes a permanently-cached Rejected Promise.
The block only clears it on success (providerInitialized=true),
so the stale rejection blocks all future init attempts until Gateway restart.
2. Silent fts-only overwrite in runSync():
With the provider stuck at null, shouldRunFullMemoryReindex() compares
the stored meta.model (e.g. 'jina-embeddings-v5-text-small') against the
runtime provider model, and since provider is null, falls through to the
'meta.model !== fts-only' check — returning true. This triggers a full
reindex where every file is written as fts-only, silently erasing all
existing 11k+ semantic vectors.
Fix 1: Clear providerInitPromise in the catch block so the next call can
retry initialization (self-healing when the provider comes back online).
Fix 2: Guard runSync() — if requestedProvider is set and not 'none', but
the runtime provider is null, throw an error instead of silently degrading
to fts-only. This protects existing vector data by failing loudly.
Tested on production: 11,715 chunks + 1024-dim vectors fully preserved
after Gateway restart with the fix applied. The guard correctly blocks
sync when MLX is offline and allows normal operation when it recovers.
* fix: use this.settings.provider instead of private requestedProvider
The guard clause in runSync() was referencing this.requestedProvider
which is a private property on the MemoryIndexManager subclass and not
accessible from MemoryManagerSyncOps. Use this.settings.provider
instead, which is the same value and is accessible via the protected
abstract settings property.
* fix(memory): narrow degradation guard to only protect existing semantic indexes
The previous guard was too broad — it blocked sync for ALL non-none
provider configurations when provider was null, including the default
'auto' path where users without embedding credentials legitimately
build FTS-only indexes.
Narrow the guard to only abort when:
1. provider is null (embedding unavailable)
2. existing index metadata has a semantic model (not 'fts-only')
3. settings.provider is configured and not 'none'
This preserves the legitimate FTS-only fallback for auto/no-provider
users while still protecting existing semantic vector indexes from
silent degradation.
Reported-by: ClawSweeper (PR #85704 review)
* test: cover memory semantic index outage guard
* fix: protect semantic memory index fallback paths
* test: update memory sync harnesses
---------
Co-authored-by: Bo Yan <yaaboo-gif@users.noreply.github.com>
Co-authored-by: Yan Bo <yanbo@Mac.lan>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- The branch replaces QQBot's hardcoded outbound response watchdog with a resolver based on existing agent/provider `timeoutSeconds` settings, adds regression tests, and updates the changelog.
- PR surface: Source +113, Tests +116, Docs +1. Total +230 across 5 files.
- Reproducibility: yes. at source level: current main and the latest release use a hardcoded 300000 ms QQBot o ... s an 1800s provider timeout. I did not run the reporter's live QQBot/Ollama setup in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(qqbot): cover slow provider response watchdog
- PR branch already contained follow-up commit before automerge: fix(qqbot): derive outbound watchdog from configured timeouts (#85267)
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8527…
Validation:
- ClawSweeper review passed for head 7bd829292a.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7bd829292a
Review: https://github.com/openclaw/openclaw/pull/86500#issuecomment-4534669816
Co-authored-by: SymbolStar <symbolstar@users.noreply.github.com>
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- Adds a scoped ModelStudio/DashScope OpenAI-compatible guard for chat payloads with no non-empty user or assi ... turn, shared turn-detection helper coverage, prompt-skip handling, regression tests, and a changelog entry.
- PR surface: Source +83, Tests +298, Docs +1. Total +382 across 10 files.
- Reproducibility: yes. source-reproducible for the OpenClaw-side malformed payload shape: current main has no ... he exact qwen-long/qwen3-coder-plus provider error was not reproduced with the available DashScope account.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: make OpenAI payload guard content-aware
- PR branch already contained follow-up commit before automerge: fix: scope openai payload turn guard
- PR branch already contained follow-up commit before automerge: Guard OpenAI chat payload turns
Validation:
- ClawSweeper review passed for head e16a3fe9f2.
- Required merge gates passed before the squash merge.
Prepared head SHA: e16a3fe9f2
Review: https://github.com/openclaw/openclaw/pull/86497#issuecomment-4534668405
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Reverts the diagnostic queue-pressure suppression of non-terminal session tool mirrors from PR 84846 while keeping PR 86503 recipient dedupe intact. Session-only Control UI subscribers keep receiving tool lifecycle mirrors; overlapping run and session subscribers still receive one canonical run-scoped frame. Verification: focused gateway and diagnostic tests, diff check, changed check, and autoreview all passed.
* fix(agents): release embedded-attempt session lock on every exit path
The embedded run controller acquires its session write lock eagerly at
creation and released it only inside the post-run cleanup block. An
exception thrown in post-prompt processing skipped that block, so the lock
leaked to the live gateway process until the watchdog reclaimed it and
later requests to the session failed with SessionWriteLockTimeoutError.
Add an idempotent dispose() to the lock controller and call it from the
run's outer finally so the eagerly-held lock is released on every exit
path. Normal/aborted/timed-out runs still hand the lock to
acquireForCleanup first, so dispose() is a no-op then (no double release).
Fixes#86014
* fix: keep session lock teardown comment lean
* docs(changelog): note embedded session lock fix
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Dedupe gateway tool-event fanout so connections subscribed by both run and session receive the canonical run-scoped agent event only, while session-only subscribers keep the compatibility session.tool mirror.\n\nVerification:\n- node scripts/run-vitest.mjs src/gateway/server-chat.agent-events.test.ts\n- git diff --check\n- env -u OPENCLAW_TESTBOX pnpm check:changed\n- .agents/skills/autoreview/scripts/autoreview --mode local
Summary:
- The PR expands security audit, CLI docs, and tests so `hooks.token` reuse of active Gateway token/password auth is reported while password-mode Gateway startup remains compatible.
- PR surface: Source +178, Tests +311, Docs +14. Total +503 across 14 files.
- Reproducibility: yes. from source inspection: current main forwards a bearer token as both token and passwor ... ecause this review was read-only, but the linked issue and code path make the reproduction high confidence.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cr-fmi-hook-ingress-token-unlocks-password-mode-gateway-auth): ap…
- PR branch already contained follow-up commit before automerge: fix: include trusted proxy password in hooks token reuse check
- PR branch already contained follow-up commit before automerge: fix(gateway): audit hooks password reuse without blocking startup
- PR branch already contained follow-up commit before automerge: fix: Hook ingress token unlocks password-mode gateway auth
Validation:
- ClawSweeper review passed for head 7c796b22ec.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7c796b22ec
Review: https://github.com/openclaw/openclaw/pull/86453#issuecomment-4533831028
Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: jesse-merhi
* fix(diagnostics): reclaim wedged session lanes with a stale leaked active run
A group session lane could wedge permanently (#85639): an embedded run that dies
abnormally leaves a stale ACTIVE_EMBEDDED_RUNS handle, so the diagnostic heartbeat
classifies the lane stale_session_state (recoveryEligible without allowActiveAbort)
while stuck-session recovery reads the leaked isEmbeddedPiRunActive flag and skips
with active_reply_work — a tautology that keeps the lane forever. The age-based
escape never fires because ageMs (last-activity) resets on every incoming queued
message.
Make the active-run skip a liveness check: before keeping the lane, consult the
run's real forward-progress age (lastProgressAgeMs, not refreshed by incoming
messages). If a run flagged active has made no forward progress past the resolved
diagnostics.stuckSessionAbortMs threshold (threaded through the recovery request;
falls back to a 5-minute floor) with queued work waiting, treat it as a
leaked/dead handle and reclaim it (abort + drain + force-clear) instead of
skipping. A genuinely progressing run, or one within an operator-raised
threshold, is kept.
Fixes#85639
* test(diagnostics): cover stale active run recovery
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- The PR adds HEIC/HEIF-to-JPEG normalization before media-understanding image description providers run, with regression tests and a changelog entry.
- PR surface: Source +58, Tests +82, Docs +1. Total +141 across 6 files.
- Reproducibility: yes. at source level: current main forwards HEIC buffers to `describeImage` without normali ... ody includes a red HEIC regression test before the patch. I did not execute tests in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(media-understanding): normalize HEIC before image descriptions
Validation:
- ClawSweeper review passed for head ed34620bd7.
- Required merge gates passed before the squash merge.
Prepared head SHA: ed34620bd7
Review: https://github.com/openclaw/openclaw/pull/86037#issuecomment-4528578874
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
- Rotate OpenAI Realtime voice sessions on provider max-duration events without surfacing the expected expiry as a Discord voice error.
- Add lifecycle logging for Realtime rotation/reconnect and regression coverage for max-duration reconnect.
- Allowlist the existing Control UI chunking helper for the optional Knip unused-file guard so the dependency shard stays green on the current base.
Catch non-ENOENT load failures inside maybeRepairLegacyCronStore so an
unreadable ~/.openclaw/cron/jobs.json (e.g. root-owned 0600 inside
Docker) no longer aborts the rest of the doctor health checks. The
scheduler-side loadCronStore keeps its strict throw-on-read-failure
contract.
Closes#86102
Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
After config.patch writes new values to openclaw.json, a subsequent
SIGUSR1 in-process restart could overwrite them with a stale snapshot.
Root cause: run-loop's onIteration hook resets lanes and task registry,
but leaves the runtimeConfigSnapshot intact. loadConfig() then returns
the old snapshot via loadPinnedRuntimeConfig() instead of re-reading disk.
Fix: clearRuntimeConfigSnapshot() in the restart iteration hook so the
next startup reads fresh config from disk.
Refs #86350
Summary:
- The PR routes local GGUF memory embeddings through a bundled worker sidecar, adds structured degradation and fallback handling, updates memory tests/build output, and keeps the local config contract unchanged.
- PR surface: Source +831, Tests +503, Docs +1, Other +2. Total +1337 across 23 files.
- Reproducibility: Do we have a high-confidence way to reproduce the issue? Source and report evidence are str ... cludes native crash logs; the exact Metal teardown abort was not reproduced in this review or the PR proof.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(memory): keep local embedding config unchanged
- PR branch already contained follow-up commit before automerge: fix(memory): type local embedding degradation
- PR branch already contained follow-up commit before automerge: fix(memory): refresh keywords after embedding fallback
- PR branch already contained follow-up commit before automerge: fix(memory): keep worker errors internal
- PR branch already contained follow-up commit before automerge: test: satisfy memory provider lifecycle harnesses
- PR branch already contained follow-up commit before automerge: fix: harden local embedding worker fallback
Validation:
- ClawSweeper review passed for head 1d1fe41c4e.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1d1fe41c4e
Review: https://github.com/openclaw/openclaw/pull/85348#issuecomment-4518516047
Co-authored-by: Onur Solmaz <onur@Onurs-MacBook-Pro.local>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
* fix(memory-core): filter REM dreaming candidates to light-staged entries
REM dreaming re-ingested the full short-term recall store independently,
ignoring which entries were staged by the light sleep phase. Because the
confidence formula heavily weights accumulated averageScore (45%) and
recallStrength (25%), old high-recall entries permanently dominated
freshly staged candidates. The intended light→REM→deep pipeline was
broken: light correctly staged current material, but REM selected a
different set entirely, so lightHits never paired with remHits for deep
ranking.
Fix: in runRemDreaming(), read the phase-signals store for keys with
lightHits > 0 and filter entries to that set before passing to
previewRemDreaming(). When no light-staged keys exist (light disabled
or first run), fall back to the full entry set for backward
compatibility.
Added readLightStagedKeys() to short-term-promotion.ts as a clean
export for reading the light-staged key set from the phase signal store.
Closes#86249
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(memory-core): keep REM staging pending
* fix(memory-core): mark REM-considered staged entries
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(telegram): propagate forum topic names into agent context
The topic-name-cache already tracks forum topic names via
forum_topic_created/edited/closed events in bot-message-context, but
this metadata was not surfaced in two key paths:
1. The native-command handler (bot-native-commands.ts) builds the agent
context payload with IsForum but never looked up the cached topic
name. Now it resolves the topic name from the cache and includes
TopicName in the context, giving agents awareness of which forum
topic they are responding in.
2. The action runtime (action-runtime.ts) executes createForumTopic and
editForumTopic actions but never persisted the resulting topic
metadata back to the cache. Now both actions write the topic name
(and optional icon metadata) to the cache after success, ensuring
subsequent messages in those topics can resolve the name.
Closes#86024
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(telegram): scope forum topic cache updates
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Move the plain-text tool-call promotion wrapper out of the public provider stream SDK helper and into a private local-only bundled-provider runtime seam.
Replays #84749 because the contributor fork branch became conflicted and was no longer maintainer-writable.
Co-authored-by: TeodoroRodrigo <rodrigoteodoro.90@gmail.com>
* fix(scripts): include ui:build in build-all full and ciArtifacts profiles
Closes#85206.
scripts/build-all.mjs only ran ui:build via a separate `pnpm ui:build`
command. Because `pnpm build` invokes tsdown which removes `dist/`,
a backend rebuild silently deletes any previously generated
dist/control-ui assets, leaving the gateway to serve the
"Control UI assets not found" message at startup. Documentation and
startup auto-repair masked the bug at the worst possible time
(LaunchAgent readiness / remote recovery) instead of guaranteeing the
build artifact contract.
This change adds ui:build as a build-all step after
copy-export-html-templates and before write-build-info, and includes
it in the full and ciArtifacts profiles. Minimal backend dev profiles
(gatewayWatch, cliStartup) keep their existing fast-loop step lists
and do not run ui:build.
Regression coverage:
- ciArtifacts step list assertion updated to match the new ordering.
- Three new resolveBuildAllSteps assertions: ui:build is in full and
ciArtifacts and runs after tsdown/runtime-postbuild-stamp and before
write-build-info; ui:build is excluded from gatewayWatch/cliStartup;
ui:build cache outputs declare dist/control-ui.
* fix(scripts): leave ui:build uncached so dist/control-ui never restores stale build IDs
ClawSweeper review on #86010 flagged that the original ui:build cache only
hashed ui/, scripts/ui.js, and scripts/lib/copy-assets.ts, but
ui/vite.config.ts also reads package.json plus git HEAD and the
OPENCLAW_CONTROL_UI_BUILD_ID/OPENCLAW_VERSION env vars to embed a build ID
into the app and service worker. A file-input cache signature cannot
exactly invalidate those metadata sources, so a warm build-all hit could
restore a previously generated dist/control-ui after tsdown clears dist
and ship stale service-worker/app cache metadata.
Leaving the step uncached keeps the contract simple: every pnpm build
re-runs Vite, which is fast for the Control UI bundle and matches the
existing behavior of every other un-cached build-all step. Backend-only
profiles (gatewayWatch, cliStartup) are still unchanged.
Tests:
- Updated the ui:build cache assertion to require step.cache to be
undefined and explain the metadata-input reason.
- Existing presence/order/exclusion assertions for ui:build are unchanged
and still cover the full and ciArtifacts profile contract.
* fix(scripts): keep ui build fallback pnpm-free
---------
Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
enqueueSession injects sessionQueuePriority into its enqueue opts so
user-facing work (trigger=user/manual → foreground) jumps ahead of
background work (trigger=cron/heartbeat/memory/overflow → background)
in the session lane.
enqueueGlobal was passing opts through unchanged, so priority resolved
to "normal" for both lanes. Since the heavy embeddedRun body
(workspace-sandbox, core-plugin-tools, bootstrap-context, bundle-tools,
system-prompt, session-resource-loader, agent-session, stream-setup)
runs inside enqueueGlobal, the global-lane queue was effectively FIFO
between user chat and cron — defeating the priority intent on the path
where it matters most.
Inject sessionQueuePriority into enqueueGlobal the same way it's
injected into enqueueSession.
Observed in production: a 3m48s user chat on a hibernation-wake
storm at 2026-05-24T04:19:09Z, where 11 overdue cron jobs + 16
overdue agent heartbeats entered the global lane simultaneously
on hibernation resume. The chat enqueued with trigger=user landed
at the back of a 27-entry FIFO queue at priority 0 instead of
preempting at priority 1 (foreground). 62 s of the 228 s wall-clock
was waiting in that queue.
Summary:
- This PR forwards Codex app-server source reply delivery mode into active run handling, adds a focused regression test, and adds a changelog entry.
- PR surface: Source +1, Tests +38, Docs +1. Total +40 across 3 files.
- Reproducibility: yes. Source inspection shows the shared active-run queue rejects `message_tool_only` replies when the active handle lacks that mode, and current main's Codex app-server handle omits it.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(codex): preserve source reply mode for active runs
Validation:
- ClawSweeper review passed for head d8fac59d8f.
- Required merge gates passed before the squash merge.
Prepared head SHA: d8fac59d8f
Review: https://github.com/openclaw/openclaw/pull/86325#issuecomment-4531516197
Co-authored-by: Fermin Quant <ferminquant@hotmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds a commitments-store writer helper, wraps load-modify-save mutators and expiry cleanup with a per-path queue plus `withFileLock`, adds three concurrency regressions, and updates the changelog.
- PR surface: Source +153, Tests +61, Docs +1. Total +215 across 4 files.
- Reproducibility: yes. Source inspection on current main shows the unqueued load-modify-save mutation path, a ... inked proof log shows the Promise.all repro changing from 20/20 lost writes before the patch to 0/20 after.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(commitments): serialize load-modify-save with in-process queue + …
Validation:
- ClawSweeper review passed for head a349f41ccf.
- Required merge gates passed before the squash merge.
Prepared head SHA: a349f41ccf
Review: https://github.com/openclaw/openclaw/pull/86326#issuecomment-4531553610
Co-authored-by: ai-hpc <mail.speedy.hpc@hotmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Route normal [telegram][diag] polling diagnostics through runtime.log while keeping non-diag Telegram warnings/errors and offset persistence failures on runtime.error.
Verification:
- node scripts/run-vitest.mjs extensions/telegram/src/monitor.test.ts (34 passed)
- git diff --check
- CI run 26378692736 passed on 979c6f31a4Fixes#82957
Repair explicit anchorless iMessage watch payloads by GUID before debounce/routing, and drop unrecoverable payloads fail-closed instead of routing them as sender DMs.
Closes#84470.
Refs #84503.
Thanks @zhangguiping-xydt and @zqchris.
Fix Google Vertex production ADC mode support by routing explicit google-vertex models to the Vertex transport and relying on google-auth-library for request-time ADC resolution.
Verification:
- pnpm install --frozen-lockfile
- pnpm test extensions/google/transport-stream.test.ts extensions/google/index.test.ts src/config/zod-schema.models.test.ts src/agents/pi-embedded-runner/model.inline-provider.test.ts -- --reporter=verbose
- pnpm check:changed
- GitHub PR checks green on c4b7cad4df
- Live ADC smoke reached Google Vertex auth/transport and failed only because the configured redacted project has the Vertex AI API disabled
Co-authored-by: Damian Finol <damian@felixpago.com>
* fix: clean up browser MCP subprocess tree
* fix: clean up windows browser mcp tree before close
* fix(browser): repair chrome mcp cleanup rebase
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(compaction): preserve partial summary on mid-chain chunk failure
When summarizing multiple chunks, if a chunk fails after at least one
chunk has already succeeded, return the partial summary instead of
propagating the error and losing all summarization progress.
Abort and timeout errors still propagate immediately. First-chunk
failures still rethrow so the existing fallback path runs.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(compaction): use content array for assistant messages to match updated AgentMessage type
* fix(compaction): use as-unknown-as-AgentMessage cast for assistant test fixtures
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
maybeRecoverSuspiciousConfigRead unconditionally recorded
lastObservedSuspiciousSignature in health state even when
restoredFromBackup was false (copyFile failed). The guard at
resolveConfigReadRecoveryContext then prevented the same
signature from ever being retried, permanently accepting the
suspicious config on every subsequent launch.
Only record the dedup signature when the backup restore
actually succeeded.
* fix: avoid false telegram pairing prompts
* docs: add telegram pairing changelog
* refactor(telegram): share pairing-store gating and align isGroup check
Extract loadTelegramPairingStoreIfNeeded so the text-fragment flush path
and resolveTelegramGroupAllowFromContext share one implementation, and
align the isGroup derivation in the flush path with the
'group || supergroup' form used elsewhere in bot-handlers.runtime.ts.
Note on transient-vs-known errors: readChannelAllowFromStore already
translates missing-file (ENOENT) and JSON parse failures to an empty
allowlist internally, so the only errors that escape into the new
silent-drop path are unexpected I/O failures (EMFILE/EACCES/EIO/...) —
unpaired senders still get a pairing challenge as expected.
* fix(telegram): skip pairing-store read when commands.allowFrom already authorizes the sender
Native command auth resolves group/dm allow context (which may read the
pairing store) before checking commands.allowFrom. On DMs with
dmPolicy: "pairing", a transient pairing-store I/O failure was therefore
dropping commands from senders explicitly authorized by
commands.allowFrom.telegram.
Add a skipPairingStoreRead hint on resolveTelegramGroupAllowFromContext /
loadTelegramPairingStoreIfNeeded, precompute the command authorization
once at chat scope before the context call, and pass the hint when that
pre-check already authorizes the sender. The post-context command auth
check still owns the topic-scoped decision.
Regression covers a DM /status from a sender allowed by
commands.allowFrom.telegram with dmPolicy: "pairing" and a rejecting
readChannelAllowFromStore mock.
* fix(telegram): satisfy test-types on harness readChannelAllowFromStore
CI check-test-types failed because the harness now stores a loose
AnyAsyncMock for readChannelAllowFromStore but TelegramNativeCommandDeps
requires the precise typeof readChannelAllowFromStore signature. Cast at
the telegramDeps assignment so harness callers can keep passing any
vi.fn(...) (including ones that reject) without type pollution at the
call site.
* feat(telegram): reply with a retry hint when pairing-store read fails transiently
Wrap unexpected pairing-store I/O errors (EACCES, EMFILE, ...) in a
typed TelegramPairingStoreReadError and surface them through
handleInboundMessageLike with a friendly "please try again" reply that
matches the media-failure precedent at bot-handlers.runtime.ts:1893.
Beats silent drop: paired senders see why their message wasn't
processed, and unpaired senders who happen to send a DM during a
transient store outage retry naturally and get the correct pairing
prompt once the store recovers.
Verified live against @paxicoto_bot with chmod 000 on
~/.openclaw/credentials/telegram-default-allowFrom.json after touching
mtime to bypass the stat-pinned cache.
Summary:
- The PR updates the Unix installers to avoid emitting npm `--before` when raw npm config contains `min-releas ... records a changelog fix, and widens an internal model-catalog test helper type to accept sync auth checks.
- PR surface: Source +1, Tests +421, Docs +1, Other +150. Total +573 across 7 files.
- Reproducibility: yes. The linked report at https://github.com/openclaw/openclaw/issues/84743 gives an isolat ... exclusivity, and current main still has the source path that can generate the conflicting `--before` flag.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(installer): avoid before with npm release-age configs
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8549…
Validation:
- ClawSweeper review passed for head fb0762f468.
- Required merge gates passed before the squash merge.
Prepared head SHA: fb0762f468
Review: https://github.com/openclaw/openclaw/pull/85491#issuecomment-4522229812
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* perf(plugins): thread metadata snapshot and discovery through hot paths
With the snapshot memo now actually hitting, route the snapshot's
manifestRegistry and discovery through the helper chains that already
had fast paths for them. Eliminates redundant per-call rebuilds at
two big amplifiers.
- Provider resolve paths (resolvePluginProviders /
isPluginProvidersLoadInFlight / resolveOwningPluginIdsForProvider /
resolveExternalAuthProfilesWithPlugins) self-service a snapshot once
at the public entry, then thread it as a separate required arg
through resolvePluginProviderLoadBase,
resolveExplicitProviderOwnerPluginIds, and the setup/runtime load
state helpers. Inner reads change from
'params.pluginMetadataSnapshot?.x' to 'snapshot.x', no more
enrichedParams clone. loadPluginManifestRegistryForInstalledIndex
fires drop ~685 -> ~10 per cold start.
- Bundled-channel / auto-enable chain accepts an optional
PluginDiscoveryResult. discoverOpenClawPlugins is fired once during
snapshot building (resolveInstalledPluginIndexRegistry already
produced it internally; now bubbled up through
loadInstalledPluginIndexWithDiscovery, PluginRegistrySnapshotResult,
and onto PluginMetadataSnapshot.discovery). load-context reads
metadataSnapshot.discovery and passes it through
applyPluginAutoEnable, so the bundled-channel cascade
(collectConfiguredChannelIds, listBundledChannelIdsWith*,
listPotentialConfiguredChannelPresenceSignals) short-circuits
instead of each leaf re-firing discovery. Persisted-cache path is
unchanged: no discovery on the snapshot, downstream chain handles
its own fallback (pre-PR behavior on that path).
* test(plugins): isolate snapshot memo across tests that mock manifest registry
The snapshot memo is now process-scoped and effective (~98% hit rate).
Three test files were depending on cache misses (because the broken
cache returned them) — each test would set up its own
loadPluginManifestRegistry mock and expect a fresh derive. With the
cache fixed, an earlier test's mocked registry now leaks into later
tests in the same file.
- io.write-config.test.ts: afterEach now clears the snapshot memo so
the 'demo' plugin mocked in the first test does not survive into
'keeps shipped plugin install config records when index migration
fails', which expects an empty registry to surface the 'plugin not
found: demo' warning.
- gateway/model-pricing-cache.ts: resetGatewayModelPricingCacheForTest
also clears the memo. Tests in model-pricing-cache.test.ts assert
loadPluginManifestRegistryForInstalledIndex was called; the memo
hit otherwise skips the call.
- providers.test.ts: vi.doMock loadPluginMetadataSnapshot to wrap the
existing loadPluginManifestRegistryMock fixture. The plumbing
commit added an auto-fetch fall-through in
resolveOwningPluginIdsForProvider; without the mock, providers
tests hit real disk reads and return empty registries (which is
what surfaced as 9 unrelated-looking failures in the prior CI
run).
* fix(plugins): preserve setup.cliBackends owner matching in provider scan
resolveOwningPluginIdsForProvider now also checks plugin.setup?.cliBackends.
The pre-PR no-registry fallback used resolvePluginContributionOwners which
includes both top-level cliBackends and setup.cliBackends; the PR's manifest
scan replacement was missing the setup case.
* fix(plugins): inherit active registry workspaceDir before loading metadata snapshot
isPluginProvidersLoadInFlight and resolvePluginProviders now resolve
env and workspaceDir once at the entry point (falling back to
getActivePluginRegistryWorkspaceDir) and pass them into both
loadPluginMetadataSnapshot and resolvePluginProviderLoadBase. Pre-fix
the snapshot used params.workspaceDir raw while the load base inherited
the active workspace, so workspace-scoped provider plugins could be
absent from the snapshot manifest registry even though owner resolution
expected them.
Regression test asserts the snapshot mock receives the active
workspaceDir when the caller omits it.
* perf(gateway): thread discovery into applyPluginAutoEnable call sites
Every gateway applyPluginAutoEnable call now passes the snapshot's
PluginDiscoveryResult so the bundled-channel cascade (collectConfiguredChannelIds
→ listBundledChannelIdsWith* → listPotentialConfiguredChannelPresenceSignals)
short-circuits instead of each leaf re-firing discovery.
Startup-time sites pull discovery from the snapshot/lookup-table they already
hold:
- server-plugin-bootstrap.ts (pluginLookUpTable)
- server-startup-plugins.ts (pluginMetadataSnapshot)
- server-startup-config.ts (pluginMetadataSnapshot)
- server-plugins.ts (pluginLookUpTable, both call sites)
Per-RPC sites (server.impl getRuntimeConfig callback, server-methods/channels
status + start handlers, server-methods/send) source discovery via
getCurrentPluginMetadataSnapshot using the runtime config to validate
compatibility. Falls through to the original slow path when the snapshot is
absent or incompatible.
Summary:
- The branch adds a 1500 ms internal timeout to bundled MCP `tools/list` catalog discovery, adds slow and hung stdio MCP regression tests, and records the fix in `CHANGELOG.md`.
- PR surface: Source +2, Tests +216, Docs +1. Total +219 across 3 files.
- Reproducibility: yes. The current-main source path is high confidence: bundled MCP connects successfully, then calls `client.listTools` without request options, and the upstream SDK defaults that request to 60000 ms.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(mcp): use internal tools list timeout
- PR branch already contained follow-up commit before automerge: fix(mcp): bound tools/list during catalog discovery
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8506…
Validation:
- ClawSweeper review passed for head bbbfb9f059.
- Required merge gates passed before the squash merge.
Prepared head SHA: bbbfb9f059
Review: https://github.com/openclaw/openclaw/pull/85063#issuecomment-4511554739
Co-authored-by: nxmxbbd <32288+nxmxbbd@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* feat(imessage): support thumb approval reactions
Mirrors openclaw#85477 (WhatsApp) for the iMessage channel. iMessage can now
deliver exec/plugin approval prompts via the existing imsg/BlueBubbles
transport and resolve approvals from 👍 (allow-once) / 👎 (deny) tapbacks.
Allow-always remains on the manual /approve <id> allow-always fallback.
What changed:
- New approval surfaces under extensions/imessage/src/:
approval-auth.ts, approval-resolver.ts, approval-reactions.ts,
approval-handler.runtime.ts, approval-native.ts (+ tests for each).
- channel.ts wires base.approvalCapability to the new iMessage capability.
- send.ts appends the 👍/👎 hint to outbound /approve prompts and registers
the reaction binding (keyed by accountId + chat_guid/chat_identifier/
chat_id/handle + messageId) after a successful send.
- monitor/monitor-provider.ts resolves approval reactions ahead of the
normal inbound decision pipeline so resolution bypasses
reactionNotifications gating and runs its own actor authorization.
- runtime.ts now exports getIMessageRuntime / getOptionalIMessageRuntime so
approval-reactions can open a persistent keyed store for binding state
across gateway restarts.
What did NOT change:
- Core approval surfaces in src/gateway/server-methods/* and src/infra/*
remain channel-agnostic; the channels.imessage.allowFrom field already
exists and is reused as the approver list for reactions.
- Other channels and the manual /approve sender-authorized path are
untouched.
* fix(imessage): address codex review findings on thumb approvals
Addresses 15 findings from the multi-angle codex review:
Critical (correctness / blocking):
- Register CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY in the iMessage
monitor so the gateway can actually deliver native approval prompts via
approval-handler.runtime.ts (it was dead code without the context lease).
- DM tapback approvals never resolved because send keyed by handle while
inbound preferred chat_guid. Register and look up under EVERY available
conversation key (chat_guid / chat_identifier / chat_id / handle); inbound
probes them all and accepts the first hit.
- Reaction binding now requires the bridge's GUID string (rejecting numeric
ROWIDs) so the binding key matches inbound reacted_to_guid.
- Outbound regex now requires both a canonical `ID: <approvalId>` header AND
a matching `/approve <id> <decision>` line, so non-approval messages that
legitimately mention /approve syntax no longer get a phantom reaction
binding (and can no longer resolve a colliding live approval).
- Drop is_from_me reaction events so cross-device echoes of the operator's
own tap cannot self-approve when their handle is in allowFrom.
High (operability / cleanup):
- Non-ApprovalNotFound errors now log at warn via the runtime child logger
(no longer hidden behind OPENCLAW_LOG_LEVEL=debug).
- In-memory binding is cleared on successful resolve so a toggle 👍→👎 (or
chat.db replay) does not refire and emit a misleading 'expired approval'
log line. Removed tapbacks are also owned by the shortcut and not surfaced
as noisy reaction system events.
- Move resolveIMessageReactionContext (and its helpers) to a slim
monitor/reaction-context.ts so approval-reactions.ts no longer transitively
pulls monitor/inbound-processing.ts (14+ heavy runtime modules) into the
hot channel.ts entrypoint per extensions/CLAUDE.md.
Medium (consistency / future-proofing):
- Native runtime exec pending payload now passes agentId, ask, and
sessionKey through buildExecApprovalPendingReplyPayload so the two
delivery routes produce identical operator-visible prompts.
- Both delivery paths now use addIMessageApprovalReactionHintToText (single
insertion point after ID:) so the hint cannot be double-emitted by the
native runtime path bypassing the idempotency guard.
- Extract replaceApprovalIdPlaceholder into a shared approval-text.ts that
escapes `$` in the replacement string so an approvalId containing
`$&`/`$1`-`$9`/`$$` cannot interpolate into the outbound text.
- In-memory Map now stores TTL alongside each entry and prunes expired
bindings on each register so the gateway no longer accumulates an
unbounded reaction-target Map.
- bindPending refuses to bind when accountId is missing or the approval is
already expired, with explicit error logs instead of silent no-ops.
- Reject chat_id=0 as a synthetic key value (chat.db ROWIDs start at 1).
- Drop dead getIMessageRuntime export — only the optional accessor is used.
Documentation:
- docs/channels/imessage.md gains an 'Approval reactions (👍 / 👎)' accordion
documenting the reaction emoji map, allowFrom approver requirement, the
/approve <id> allow-always manual fallback, and the deliberate change to
/approve command authorization for users with non-empty allowFrom.
- CHANGELOG.md entry added under 2026.5.24.
Tests: 411 iMessage tests pass (was 406). Added explicit coverage for the
DM key-mismatch fix, the regex-tightening fix, the is_from_me guard, the
clear-on-success behavior, and the approval-id `$` escape.
* test(imessage): match WhatsApp approval-native test coverage
Backfills the nine cases from extensions/whatsapp/src/approval-native.test.ts
that weren't mirrored in iMessage:
- target-mode exec + plugin prompt rendering with the canonical hint
- target-mode availability when no iMessage target matches
- agentFilter / sessionFilter applied to native handling
- account-scoped target enabled/disabled per account
- shouldSuppressForwardingFallback session-origin exact-match cases
- shouldSuppressForwardingFallback off when native cannot bind (locks down
the targets-only forwarding path the Lobster live deploy exercised)
- both-mode explicit + unscoped target suppression
- group-origin tapback approvals require explicit approvers
Tests: extensions/imessage/src/approval-native.test.ts 21 passed (was 11).
Total iMessage approval-specific cases now 49 (was 40).
* fix(imessage): preserve service-prefixed direct handles as approvers
ClawSweeper P1 review finding on #85952. normalizeIMessageApproverId was
calling looksLikeIMessageExplicitTargetId() to reject conversation-target
prefixes, but that helper also matches the imessage:/sms:/auto: service
prefixes — which are valid direct-handle forms. Any allowFrom entry like
'imessage:+15551230000' dropped to undefined, leaving approvers empty,
which:
- silently denied reaction resolution ('reactions require explicit
approvers'), and
- let text /approve fall back to implicit same-chat authorization.
Fix: normalize first via normalizeIMessageHandle (strips the service
prefix), then reject only chat_id:/chat_guid:/chat_identifier:
conversation-target shapes that remain after normalization.
Tests:
- approval-auth.test.ts: assert the resolved approver list contains the
normalized handle, plus the corollary that a non-matching sender is
explicitly rejected (no longer masked by the implicit-same-chat
fallback). Add a separate case covering chat_id/chat_guid/
chat_identifier rejection (with and without a service prefix).
- approval-reactions.test.ts: reaction resolution end-to-end with a
service-prefixed allowFrom entry — proves resolveIMessageApproval is
called rather than silently denied.
Focused suite: 48 passed (was 47).
* test(imessage): satisfy strict buildPendingPayload signature in render tests
CI check:test-types caught that the render.exec/render.plugin
buildPendingPayload calls were passing accountId (not in the type
signature). The signature is { cfg, request, target, nowMs }. Replace
accountId with target on the four render-test sites so the strict
test-types pass matches the SDK contract:
- it('renders thumbs-only reaction hints in exec approval prompts')
- it('renders thumbs-only reaction hints in plugin approval prompts ...')
- it('renders target-mode exec prompts with concrete thumbs-only ...')
- it('renders target-mode plugin prompts with concrete thumbs-only ...')
Verified locally with pnpm check:test-types (tsgo:core:test +
tsgo:extensions:test). 49 approval-specific tests still pass.
* fix(imessage): probe every tapback GUID form for approval lookup
ClawSweeper P1 review finding on #85952. readApprovalReactionEvent was
only using reaction.targetGuid (the first/normalized form), but
resolveIMessageReactionContext produces reaction.targetGuids = [normalized,
raw] for both `abc-123` and `p:0/abc-123` forms. If the imsg bridge
returned 'p:0/<guid>' from send() and send.ts registered the binding under
that prefixed key, the inbound resolver probing only the unprefixed form
would miss and the tapback would silently fall through.
Fix:
- Surface every GUID candidate in IMessageApprovalReactionEvent
(messageIdCandidates).
- maybeResolveIMessageApprovalReaction now probes each candidate in
precedence order; first hit wins.
- On success / ApprovalNotFoundError, clear the binding under all
candidate keys so toggle/replay does not refire.
Tests: extensions/imessage/src/approval-reactions.test.ts gains a
'resolves a reaction when the binding was registered under a p:0/…
prefixed GUID and the tapback surfaces both forms' regression case;
22/22 reaction tests pass. Full iMessage suite: 424/424.
* fix(imessage): native approval binding requires GUID, not numeric id
ClawSweeper third P1 review finding on #85952. approval-handler.runtime.ts
deliverPending was using result.messageId as the approval-reaction binding
key, but that field can be a numeric ROWID coerced to a string ('12345')
when the imsg bridge returns only message_id. Inbound tapbacks carry
reacted_to_guid which is always a GUID, so a numeric-id binding can never
match.
Fix mirrors the send.ts forwarding-path treatment:
- IMessageSendResult now exposes a separate guid?: string field, populated
from the same resolveOutboundMessageGuid helper send.ts already uses for
the forwarding-path binding. The generic messageId field is unchanged so
reply-cache, echo-cache, and receipt-building paths still see the
broadest id form.
- deliverPending now binds against result.guid; when it's undefined (numeric
ROWID or 'ok'/'unknown' placeholders), the function returns null instead
of binding against an id the inbound tapback can't possibly match.
Tests: approval-handler.runtime.test.ts gets a deliverPending GUID-only
binding describe block with three regression cases (numeric ROWID refused,
GUID accepted, ok/unknown placeholders refused). vi.mock isolates
sendMessageIMessage so the cases run synchronously without spawning imsg.
11 tests pass across handler.runtime + send specs.
---------
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Summary:
- The branch updates OpenRouter dynamic model capability parsing to prefer `top_provider.context_length`, bump ... sk cache version, adds regression coverage and a changelog entry, and adds script helper declaration files.
- Reproducibility: yes. from source and live catalog evidence rather than an authenticated inference turn. Cur ... catalog currently reports a smaller endpoint-specific `top_provider.context_length` for the reported model.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(openrouter): use endpoint context limits
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8594…
Validation:
- ClawSweeper review passed for head 76fcc362d2.
- Required merge gates passed before the squash merge.
Prepared head SHA: 76fcc362d2
Review: https://github.com/openclaw/openclaw/pull/86041#issuecomment-4528646655
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR changes dev-channel git updates to fetch branches with `--no-tags`, adds targeted fetching for explicit dev tag refs, updates update-runner tests, and adds a changelog entry.
- Reproducibility: yes. Current main source shows dev updates still run a broad tag fetch, and the PR body sup ... al local bare-remote moved-tag reproducer showing that command fails before the branch update can continue.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(update): avoid broad tag fetches for dev updates
Validation:
- ClawSweeper review passed for head 733680b1bc.
- Required merge gates passed before the squash merge.
Prepared head SHA: 733680b1bc
Review: https://github.com/openclaw/openclaw/pull/84737#issuecomment-4503692161
Co-authored-by: Ruben Cuevas <hi@rubencu.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
The agentToAgent allow-pattern matcher converted user wildcards like
`*a*b*c*` into `^.*a.*b.*c.*$` via RegExp. Multiple overlapping
`.*` groups cause O(n^k) polynomial backtracking against non-matching
input, where k is the number of wildcards.
Replace the regex path with a segment-based glob matcher that splits on
`*` and checks prefix/suffix/interior segments in order. The new
matcher runs in O(n*k) worst case and eliminates the regex engine
entirely from this path.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(minimax): normalize OAuth token expiry to absolute millisecond timestamp
MiniMax returns expired_in from the token endpoint as a relative duration
in seconds (standard OAuth expires_in semantics), but the auth profile
store's hasUsableOAuthCredential() expects an absolute millisecond
timestamp. Without conversion the token appears perpetually expired,
triggering a slow OAuth refresh network call to api.minimaxi.com on
every request — the root cause of the 30-50s auth-stage delay.
Fixes#83449.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(minimax): cover oauth expiry normalization
* fix: polish minimax oauth expiry normalization (#83480) (thanks @NianJiuZst)
* fix: update minimax raw fetch allowlist (#83480)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- The branch updates gateway boot startup handling to use an `agent:<id>:boot` session, suppress prompt persis ... that boot mapping after the run, and adds focused gateway boot regression coverage plus a changelog entry.
- Reproducibility: yes. there is a high-confidence source reproduction path: current main passes the generated ... idence of repeated persisted boot prompts. I did not execute the gateway scenario in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Fix boot-md test lint
- PR branch already contained follow-up commit before automerge: Isolate boot-md startup sessions
Validation:
- ClawSweeper review passed for head 5d5338c2d9.
- Required merge gates passed before the squash merge.
Prepared head SHA: 5d5338c2d9
Review: https://github.com/openclaw/openclaw/pull/85919#issuecomment-4527318708
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Clamp proxy-like OpenAI Chat Completions output caps against the estimated final outbound request payload after compatibility transforms. This prevents strict local/API-compatible servers from rejecting requests whose prompt already consumes part of the effective context window, while avoiding over-clamping dropped replay turns.
Co-authored-by: rendrag-git <253747599+rendrag-git@users.noreply.github.com>
Honor configured restart drain budgets for embedded runs and avoid a second active-work drain after forced deferral timeout restarts.
Includes maintainer changelog entry.
* fix(ui): handle empty strings with minLength constraint in config save
Fixes#85831
When saving config in Control UI, required string fields with minLength
constraint (e.g., z.string().min(1)) were sent as empty strings instead
of being unset. This prevented schema defaults from applying.
Solution: coerce empty strings with minLength > 0 to undefined, allowing
schema defaults to take effect during validation.
Added 5 unit tests covering edge cases.
* fix(types): add minLength and maxLength to JsonSchema type
Keep successful Codex native hook relays alive through a bounded grace window so late hook callbacks still reach OpenClaw enforcement, while interrupted, aborted, timed-out, and failed turns unregister immediately.\n\nCo-authored-by: Kaspre <kaspre@gmail.com>
Summary:
- The PR adds the Chrome DevTools MCP `--no-usage-statistics` default launch arg, honors explicit profile usage-statistics `mcpArgs`, adds regression tests, and adds a changelog entry.
- Reproducibility: yes. source-reproducible: current main builds Chrome MCP launch args without the upstream o ... etry is initialized. I did not run a fresh failing current-main process leak loop in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Disable Chrome MCP telemetry watchdog by default
Validation:
- ClawSweeper review passed for head 68249b1f58.
- Required merge gates passed before the squash merge.
Prepared head SHA: 68249b1f58
Review: https://github.com/openclaw/openclaw/pull/85886#issuecomment-4526997996
Co-authored-by: Rohit <rohitjavvadi2@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Restore the describeImageWithModel default token budget to the helper-level 4096-token default instead of forcing 512 before resolution.
Add regression coverage for the default and for smaller model caps, and record the user-facing fix in the changelog.
Co-authored-by: scotthuang <scotthuang@tencent.com>
* fix(doctor): repair stale contextWindow for DeepSeek V4 Flash
Problem:
- Older releases configured deepseek-v4-flash with contextWindow: 200000
- Official DeepSeek V4 Flash context window is 1,000,000 (1M)
- Users switching from smaller models see incorrect progress bar (e.g.,
50% instead of 10%) because stale config value overrides catalog
Fix:
- Add 'models.providers.*.models.*.contextWindow-stale' migration
- Detects deepseek-v4-flash models with 200K contextWindow
- Repairs to 1M to match catalog default
- Handles both bare and provider-prefixed model IDs
- 7 unit tests covering repair, passthrough, edge cases
Fixes: #85834
* fix(doctor): preserve custom DeepSeek context windows
* fix(doctor): detect stale DeepSeek context windows
* fix(doctor): scope DeepSeek context repair
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(gateway): broadcast error to UI when chat.send fails synchronously
* test(gateway): verify broadcastChatError is called on chat.send error
* test(gateway): import GatewayRequestContext from local server-methods barrel
Fixes the chat error-broadcast regression test so it can resolve its
type import. The previous `../types.js` path does not exist in the
gateway tree; the shared types are re-exported from
`src/gateway/server-methods/types.ts`, so the test must use `./types.js`.
Addresses ClawSweeper review on PR #85815.
---------
Co-authored-by: scotthuang <scotthuang@tencent.com>
createAuthProvider swallowed addUserForToken rejections in a .catch()
that only logged, so getClient returned and cached a ChatClient backed
by a RefreshingAuthProvider with no bound user. The failure surfaced
later as an opaque auth error on first send instead of failing fast.
Re-throw in the catch so getClient rejects and does not cache the broken
client. Adds regression tests for the rejection and the no-cache behavior.
Fixes#83853
Summary:
- The PR skips agent-harness compaction preflight for provider-owned or configured CLI runtime sessions, adds claude-cli regression coverage, includes a changelog entry, and applies small test/type cleanups.
- Reproducibility: yes. at source level. Current main still routes provider-owned `claude-cli` runtime compaction preflight through harness selection, where `claude-cli` is not a registered embedded harness.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix#84857: skip CLI runtime harness preflight during compaction
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8487…
Validation:
- ClawSweeper review passed for head 1dd8a88d21.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1dd8a88d21
Review: https://github.com/openclaw/openclaw/pull/85862#issuecomment-4526794976
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* fix(session-lock): enforce maxHoldMs in shouldReclaim during lock acquisition
- Adds optional maxHoldMs parameter to inspectLockPayload
- Inspect now marks locks as stale when held longer than maxHoldMs
- Passes maxHoldMs through inspectLockPayloadForSession
- acquireSessionWriteLock's shouldReclaim callback now passes maxHoldMs
This ensures that when a live process holds a lock for longer than
maxHoldMs (default 5min), other processes can reclaim it during
acquisition — matching the watchdog's existing enforcement.
Previously shouldReclaim only used staleMs (30min default), meaning
a lock held for 10+ minutes by a live PID would never be reclaimable,
causing 60s timeout failures and gateway freezes.
Closes#85762
* fix(session-lock): add dead-PID fast-path before retry loop
Adds a fast-path check at the top of acquireSessionWriteLock:
if the lock file's owner PID is dead, remove it immediately
before entering the retry loop. This saves up to timeoutMs (60s)
of futile waiting when the previous lock holder has died.
The shouldReclaim callback already handles this case, but only
iteratively through the retry loop. The fast-path eliminates
that unnecessary delay.
* fix(session-lock): enforce max hold during acquisition
* fix(session-lock): revalidate max hold safely
* fix(session-lock): honor holder max-hold policy
* fix(session-lock): keep cleanup from reclaiming live holders
* fix(session-lock): remove stale locks only when unchanged
* fix(session-lock): skip self-held max-hold reclaim
* fix(ci): refresh gateway protocol checks
---------
Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(cli-runner): keep recent tail when reseed history exceeds maxHistoryChars
`buildCliSessionHistoryPrompt` was prefix-slicing the rendered history,
dropping the most recent assistant turns from the reseed prompt. After
#80934 made the Claude-CLI reseed default-on, every Claude-CLI user is
exposed to this on session_expired when the rendered transcript exceeds
12288 chars. The truncation marker landed mid-word in real reproductions.
Fix:
- Tail-slice (keep the recent suffix, drop the older prefix)
- Pin the compaction summary as a prefix when present, only cap the
post-summary transcript (loadCliSessionReseedMessages deliberately
places the summary first)
- When the summary alone exceeds maxHistoryChars, head-slice the summary
itself to honor the cap; drop the post-summary tail in that case
- Move the truncation marker to the lead since what follows is the
recent tail, not what was dropped
Closes#83157
* fix(cli-runner): retain recent tail with oversize summaries
* fix(cli-runner): cap summary block plus marker against maxHistoryChars
ClawSweeper P2 on #83117 flagged that when `summaryRendered.length` is
less than `maxHistoryChars` but `summaryBlock.length` (summary + `\n\n`
separator) meets or exceeds it, the `remainingBudget <= 0` arm of
`buildCliSessionHistoryPrompt` appends the truncation marker after the
already-full summary block. A 199-char rendered summary under a 200-char
cap produced a 257-char history block — defeating the cap that prevents
reseeding fresh CLI sessions with unexpectedly huge prompts.
Fix the budget edge by truncating the summary in this branch as well so
`summary + separator + marker` stays within `maxHistoryChars`. The tail
still drops (the summary alone consumes the budget) and the marker still
leads its own line so the prompt announces what was discarded. Mirrors
the existing oversize-summary branch's pattern of head-slicing the
summary against an explicit budget that reserves marker + separator.
Add a focused regression in `session-history.test.ts` covering exactly
the gap the finding called out: `summaryRendered.length < maxHistoryChars`
with a non-empty post-summary tail. Asserts the rendered history block
stays within `maxHistoryChars` and the truncation marker is present.
* fix(cli-runner): keep tail for near-cap summaries
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The auto-reply "delivery failed" log path passes a raw Error
under the `err` field. tslog's default JSON serialization
renders bare Error instances as `{}` because Error own data
properties are non-enumerable. Every delivery failure in
production therefore logs `err: {}`, forcing operators to
guess the underlying Baileys error from timestamp alone.
Convert Error to `{ type, message, stack }` plus own-enumerable
properties at the log site, so Boom-style subclass diagnostics
(output.statusCode, data) and custom OutboundDeliveryError
fields (stage, results) survive. Non-Error rejection values
pass through unchanged.
Tests cover Error, Error subclass (Boom-style), string
rejection, and object rejection paths.
AI-assisted: Claude Code (Opus 4.7) authored, codex review
locally addressed.
Strict OpenAI-compatible servers (vLLM, LocalAI, llama.cpp, LM Studio) and
current OpenAI itself reject requests containing tools: []. Strip the empty
tools array (and the orphan tool_choice) from outbound chat-completions
payloads when usesExplicitProxyLikeEndpoint is true. Native OpenAI/Azure/
OpenRouter routes are byte-identical.
Supersedes #70790 at the canonical payload builder seam so the gateway,
embedded runner, and public plugin-SDK consumers (zai/xiaomi/deepseek) all
benefit.
* codex: honor verbose in group dispatch
* codex: address group verbose review findings
Record the final local review pass for the group /verbose PR.
Codex review against origin/main completed clean after tightening the shared group progress gate, keeping public plugin hook types stable, preserving ACP hidden tool boundaries, and adding regressions for live verbose gating and progress-callback suppression.
* codex: require explicit group verbose progress
Normal group tool/progress summaries now require an explicit session verbose override instead of inherited agent verbose defaults.
This addresses the PR review concern that existing verboseDefault configurations could expose group progress after upgrade. DMs and forum-topic behavior continue to use the effective verbose state, while normal groups use the live explicit session verbose state set by /verbose on|full|off.
* codex: document Slack group verbose caveat
* fix(channels): simplify verbose progress gating
* docs(changelog): note verbose channel fix
* fix(channels): preserve quiet default for group progress
* fix(channels): keep verbose error policy dynamic
* fix(channels): default verbose progress off everywhere
* fix(channels): keep followup verbose default quiet
* fix(channels): latch visible tool-error progress
* fix(channels): track failed verbose progress events
* fix(channels): latch delivered tool errors
* fix(channels): prevent progress opt-out bypass
* fix(channels): isolate followup error warning state
* fix(channels): keep full verbose followup warnings
* fix(channels): latch tool errors after visible progress
* fix(channels): require visible followup failure progress
* fix(channels): refresh followup verbose state
* fix(channels): honor live verbose for error details
* test(channels): expect live verbose off warning mode
* fix(channels): preserve static tool error suppression semantics
* fix(channels): bypass acp for colon verbose commands
* fix(channels): narrow dynamic tool warning override
* fix(channels): gate compaction notices on live verbose
* fix(channels): suppress quiet followup compaction callbacks
* fix(channels): suppress tts for hidden tool summaries
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- The PR removes forced consult diagnostics from Discord and phone-call realtime consult payloads, adds private debug logs and regression tests, and records the fix in the changelog.
- Reproducibility: yes. by source inspection. Current main builds the forced Discord consult message with the ... gent_consult` diagnostic string, and the phone-call fallback passes the same diagnostic as consult context.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(discord): log forced consult fallback reason
- PR branch already contained follow-up commit before automerge: fix(discord): keep forced voice consult diagnostics private
Validation:
- ClawSweeper review passed for head c1592530c6.
- Required merge gates passed before the squash merge.
Prepared head SHA: c1592530c6
Review: https://github.com/openclaw/openclaw/pull/84411#issuecomment-4494164784
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Expose a path-free estimated context budget status on session entries and gateway session rows, render it in status when fresh provider usage is unavailable, and clear stale estimates across reset, refresh, compaction, and session-rotation boundaries.
Verification: focused local Vitest covered session persistence, status rendering, gateway rows, model resets, compaction, and session rotation; GitHub CI passed on clean head cad199e43d.
Refs #80594, #54996, #77992, #84490, #83177, #43009, #83526, #8635.
* fix: harden package URL downloads
Guard package acceptance URL downloads with HTTPS-only validation, no embedded credentials, private/special-use DNS and IP rejection, manual redirect checks, bounded timeout/size limits, pinned lookup, and atomic temp-file writes. Add tooling tests for unsafe URLs, redirect validation, size limits, and successful writes.
* fix: cancel redirect response bodies before closing dispatcher
ClawSweeper P2: the redirect branch in openPackageDownloadResponse cleared
the timeout and awaited dispatcher.close() without first cancelling
response.body. Undici's close() is graceful — it waits for in-flight
requests to complete — so a malicious redirect with a slow/never-ending
body could hang the hardened downloader.
Fix: call response.body?.cancel() before dispatcher.close() to abort the
redirect body immediately.
Test: add a regression test that uses a ReadableStream with an indefinite
interval to simulate a hanging body, and asserts cancel() was called.
Refs: clawsweeper review on PR #85512
* test: harden redirect body cancellation race in regression test
Guard the ReadableStream controller.enqueue() call with a cancelled
flag and try/catch to prevent ERR_INVALID_STATE when the interval
fires after cancel() closes the controller.
* fix: cancel final response body before closing dispatcher in downloadUrl
ClawSweeper P2: the HTTP-error and declared-oversize early-exit paths
in downloadUrl threw before consuming or canceling response.body. The
finally block then cleared the timeout and awaited graceful
dispatcher.close() with the body still open, allowing a slow/never-ending
response to hang release tooling.
Fix: add response.body?.cancel() in the finally block before
dispatcher.close().
Tests: add two regressions:
- HTTP 500 with slow body: asserts cancel() called before dispatcher close
- Declared content-length oversize with slow body: same assertion
* fix: add trusted package URL source policy
* fix: keep package URL resolver dependency-free
* test: cover encoded IPv6 package URL bypasses
* docs: sync package acceptance source overview
* docs: restore release doc formatting
* docs: sync package acceptance trusted-url source
* test: cover dotted IPv4 embedded IPv6 package URLs
* fix: parse dotted IPv4 embedded in IPv6 package URLs
* test: isolate anthropic pruning defaults
* test: move anthropic dated model coverage
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(exec-approvals): add .catch() to expiry delivery fire-and-forget
When exec-approval expiry fires, deliverToTargets is called as a
fire-and-forget promise with no .catch(). If delivery fails, the
unhandled rejection swallows the error and the notification is lost.
Add .catch() with log.warn to match the ackDelivery error handling
pattern. Keep pending.delete() before the await (the entry is expired
regardless of delivery success).
Closes#83113
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(approvals): label expiry delivery errors by kind
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(doctor): skip empty entries and memoize routes in plugin session repairs
runPluginSessionStateDoctorRepairs called resolveConfiguredDoctorSessionStateRoute
once per session-store key, even for entries that carry no plugin route state
fields. On stores with many CLI sessions (observed ~800 entries), each call
takes ~1.5s due to resolveAgentHarnessPolicy walking config and provider
metadata, so the doctor's state-integrity contribution hangs for minutes
and the surrounding 'openclaw doctor' run effectively never completes.
scanEntryForOwner can only produce repair/manual-review findings when the
entry exposes one of the fields covered by entryMayContainPluginSessionRouteState
(providerOverride/modelOverride/agentHarnessId/cliSessionBindings/etc.), so
the route resolution for empty entries was pure waste. The route itself is
also a function of agentId (sessionKey is only used to derive agentId), so
sessions sharing an agent can reuse one resolved route.
Filter the store by entryMayContainPluginSessionRouteState before resolving,
and memoize resolveConfiguredDoctorSessionStateRoute by agentId within the
remaining entries. On the repro store this drops the contribution from
'never completes' to <100ms.
Adds a guard test that builds a 200-entry store with 2 route-state-carrying
entries and asserts (a) the repair fires exactly once on the codex owner
and (b) the run completes in under 2s (pre-fix would take >5 minutes).
* fix(doctor): skip manifest model-id normalization in plugin session repairs
After the previous filter+memoize fix, runPluginSessionStateDoctorRepairs was
still ~38s on a 230-entry store because every scanned entry calls parseModelRef
on its runtime model. That implicitly enters manifest-driven model-id
normalization via normalizeStaticProviderModelId, which calls
loadPluginMetadataSnapshot when no current snapshot is bound to process state.
loadPluginMetadataSnapshot is filesystem-heavy and is only memoized when a
'current' snapshot is bound (it is not, during doctor), so each parseModelRef
call paid ~40ms of fresh plugin-metadata loading. 672 calls × ~40ms = ~27s
of doctor wall-clock, all of it useless for doctor's purposes: the scan only
needs the normalized provider id of the configured runtime/route to compare
against an owner's providerIds, never the manifest-normalized model id.
Pass allowManifestNormalization: false alongside the existing
allowPluginNormalization: false on all three parseModelRef call sites in
this file. normalizeStaticProviderModelId short-circuits to
normalizeBuiltInProviderModelId when allowManifestNormalization is false,
which is what doctor wants here.
On the same 230-entry store doctor:state-integrity drops from ~38s to ~2.4s
and total openclaw doctor wall-clock drops from ~91s to ~56s.
Consume the existing { text, changed } signal from
stripInlineDirectiveTagsForDisplay so unchanged text-parts keep their
references and the original message is returned when nothing was
stripped. Avoids spurious downstream rerenders/diff churn for consumers
relying on reference equality, and keeps the public SDK helper's text
output and message shape stable.
Fixes#37589.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
openai-codex-responses can return turns where usage.output > 0 but
assistantTexts is empty (hidden reasoning tokens only). The empty
response retry guard only covered openai-completions, anthropic-messages,
and Ollama, so these turns passed through as successful completions
with no content delivered to the user.
Add the full openai-responses API family (openai-responses,
openai-codex-responses, azure-openai-responses, and their transport
variants) to RETRY_GUARD_MODEL_APIS so the empty response and
reasoning-only retry paths can fire for these providers.
Closes#85364
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(status): show configured cost for aws-sdk models
Decouple status cost display from provider auth mode so explicit model pricing is used for Bedrock and other non-api-key providers. Include cache read/write tokens in the status cost estimate and cover the behavior with regression tests.
* fix: show configured response usage costs
* docs: align configured cost visibility
* fix(status): keep usage tokens mode cost-free
---------
Co-authored-by: ItsOtherMauridian <165866613+ItsOtherMauridian@users.noreply.github.com>
Co-authored-by: ItsOtherMauridian <itsothermauridian@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
When onboarding Microsoft Foundry-hosted DeepSeek-V4 models (Pro/Flash),
the onboarding wizard assigned api: 'openai-completions' because
usesFoundryResponsesByDefault() only matched GPT/o-series models.
These V4 models require the Responses API (openai-responses) to work
correctly against the Foundry endpoint. Without this fix, all calls fail
with 'provider rejected the request schema or tool payload'.
Fix: Add 'deepseek-v4' prefix to usesFoundryResponsesByDefault() so only
the verified V4 family defaults to openai-responses. Older DeepSeek
families (e.g., V3) remain on openai-completions until proven compatible.
Closes: DeepSeek V4 models deployed via Microsoft Foundry onboarding
failing immediately due to wrong API adapter.
Co-authored-by: Roslin <rmj010203@gmail.com>
Defer Gateway channel startup until after readiness, remove startup model prewarm, and move model catalog data onto manifest/static paths so startup no longer loads broad provider runtimes.
Verification:
- focused gateway/catalog/auth/QA Vitest runs
- autoreview clean
- Blacksmith Testbox-through-Crabbox tbx_01ksahn65rsrsqz3q1qyxwf929: pnpm check:changed, exit 0
- PR CI green on ee2b631c72
* fix(gateway): normalize explicit state dir overrides at startup
* test(gateway): simplify state-dir startup coverage
* test: fix state dir startup coverage
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Route cron announce topic target parsing through channel plugin target parsers instead of Telegram-specific cron core code. Keep supported Telegram topic forms in the Telegram plugin and document the channel-owned shorthand.
* fix(bootstrap): guard bootstrap name checks against undefined names
Add optional chaining to isAgentsBootstrapFile and isAgentsBootstrapName
to prevent TypeError: Cannot read properties of undefined (reading 'toLowerCase')
when bootstrap file entries have undefined name properties.
This crash was observed in 2026.5.20 where a workspace bootstrap file entry
with an undefined name caused every incoming message to fail during bootstrap
context building, completely blocking all agent replies.
Fixes#85523
* test(agents): cover unnamed bootstrap truncation entries
* test(agents): keep bootstrap truncation fixture typed
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
`waitForever()` is a public library export used by long-running embeds to
block until the host process is asked to exit. It called `interval.unref()`
on the keep-alive timer, which removes the timer from Node's active-handle
set. With no other ref'd handles, `await waitForever()` exits the process
in ~3ms with exit code 13 ("unsettled top-level await") instead of waiting.
Drop the `.unref()` so the interval actually keeps the loop alive, and
update the existing unit test (and comment) to lock in the new contract.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix(cli-output): ignore cumulative usage from result events in stream-json parser
Claude-cli's stream-json result event reports cumulative cache_read across
all tool sub-calls, not the per-call value. The parser was overwriting the
last assistant-event usage with this inflated sum, causing sessionEntry.totalTokens
to climb 6-13x on tool-heavy turns and trip the preemptive-compaction gate.
Fix: skip reading usage from result events in createCliJsonlStreamingParser,
keeping the last per-call usage from assistant events instead.
Fixes#85573
* fix(agents): keep Claude result usage as fallback
* fix(agents): read Claude assistant stream usage
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fixes#83883.
In `secrets configure`, the one-way-migration irreversibility warning was
computed from `opts.apply` (the original --apply flag) rather than
`shouldApply`. On the interactive path the user confirms "Apply this plan
now?", which sets shouldApply=true while opts.apply stays false, so the
warning was silently skipped and the irreversible plaintext migration was
applied without the second confirmation.
Derive the guard from shouldApply so the irreversibility warning fires on
both the --apply path and the interactive-confirm path. Adds regression
tests covering the interactive path (warning shown; declining it cancels
the apply).
* fix(agents/harness): pass CLI runtime aliases through to PI in selectAgentHarnessDecision
When a model defines `agentRuntime.id` as a CLI runtime alias
(`claude-cli`, `google-gemini-cli`) or a configured `cliBackends` id, the
explicit-non-`auto` branch of `selectAgentHarnessDecision` previously
threw `MissingAgentHarnessError` because the alias has no agent harness
plugin counterpart. Model dispatch is unaffected (the CLI-runtime
short-circuit in `assertModelFallbackCandidateHarnessAvailable` runs
first), but every non-dispatch caller — delivery-mirror metadata
lookups, lane preflight, channel projection — surfaces the throw. On
Slack `[[reply_to:]]` deliveries the warning text gets substituted into
the assistant message synthesized as `provider: openclaw,
model: gateway-injected`, poisoning the thread.
Mirror the existing implicit-codex escape hatch in the same function:
when the runtime is a CLI alias (`isCliRuntimeAlias`) or a configured
CLI backend (`isCliProvider`), return PI with the new
`selectedReason: "cli_runtime_passthrough_pi"`. Actual CLI dispatch is
already routed by callers that consult model runtime policy, so PI here
is just a transcript-composition placeholder — non-CLI typos still
throw as before.
Refs #85582.
* fix(agents): validate CLI harness aliases by provider
* fix(agents): keep custom CLI harness ids fail-closed
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* docs(auth): document named OAuth profile logins
* feat(auth): support --profile-id in models auth login
* docs: note named model login profiles
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Restores WebChat image uploads to the media-understanding flow without one-turn model overrides.
- removes image-model override plumbing from the reply run
- stages WebChat images as MediaPaths for enrichment
- avoids replaying already-understood images to text-only reply models while preserving undescribed images
Co-authored-by: NianJiuZst <3235467914@qq.com>
* feat(anthropic): migrate 1M context from beta to GA
Anthropic has graduated the 1M context window from beta to GA.
This commit:
- Stops injecting the context-1m-2025-08-07 beta header when
context1m: true is configured
- Removes the OAuth token skip logic that was needed because
Anthropic previously rejected the context-1m beta with OAuth auth
(OAuth now supports 1M natively)
- Strips the legacy beta header from user-configured anthropicBeta
arrays to prevent sending a stale header
- Removes the now-unused isAnthropic1MModel helper,
ANTHROPIC_1M_MODEL_PREFIXES constant, and logger import from
the stream wrappers
The context1m config param continues to be respected for context
window sizing in context.ts — only the beta header injection is
removed.
Closes#45550 (Phase 1)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(anthropic): migrate 1M context handling to GA
* fix(clownfish): address review for ghcrawl-156721-autonomous-smoke (1)
* fix(anthropic): restrict ga 1m context models
* docs(anthropic): align ga 1m context guidance
* fix(anthropic): normalize ga 1m model metadata
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(twitch): preserve newer message handler during cleanup
Fixes#83888.
`TwitchClientManager.onMessage` returns a cleanup closure that called
`messageHandlers.delete(key)` unconditionally. When a second onMessage()
for the same account replaced the handler, running the earlier cleanup
deleted the newer handler, leaving the account with no handler and
silently dropping all inbound messages.
Guard the delete with a referential check so the cleanup only removes
the handler it registered. Adds regression tests covering both the
stale-cleanup case (newer handler must survive) and the normal case
(current handler is still removed).
* fix(twitch): distinguish handler registrations
* fix(signal): avoid dangling test export name
* test(meeting-notes): use public sdk imports
* test(sdk): classify meeting-notes subpath
* fix(discord): keep channel entrypoint imports narrow
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Use the passive backend Gateway client for implicit local logs reads, and route Linux follow-mode local RPC failures to a bounded/redacted active systemd journal fallback instead of stale configured-file logs.
Fixes#83656Fixes#66841
Summary:
- The branch adds a config-aware tool auth helper, routes image/PDF/media generation preflight and list selection through it, threads `workspaceDir`, and adds focused regression tests plus a changelog entry.
- Reproducibility: yes. by source inspection. Current main gates affected media/PDF/generation preflight paths on env/profile auth while the runtime auth contract already accepts usable `models.providers.*.apiKey`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(tools): fall back to config apiKey in capability preflight
- PR branch already contained follow-up commit before automerge: fix(tools): honor config apiKey in media tool preflight
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8557…
Validation:
- ClawSweeper review passed for head b8c9242d77.
- Required merge gates passed before the squash merge.
Prepared head SHA: b8c9242d77
Review: https://github.com/openclaw/openclaw/pull/85570#issuecomment-4523770355
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Summary:
- Adds an optional archive-error callback for session transcript archiving, wires `/new` reset rotation to log previous-transcript archive failures, adds regression coverage, and updates the changelog.
- Reproducibility: yes. source-reproducible. Current main catches and ignores `archiveFileOnDisk` failures ins ... and the source PR proof exercises the same rename failure boundary with a real filesystem permission error.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 9d5f4c0c70.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9d5f4c0c70
Review: https://github.com/openclaw/openclaw/pull/85586#issuecomment-4523917139
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* fix(qmd): normalize direct file collection paths
Port fix from PR #65212 to new package location.
When a QMD custom collection path config entry points directly to a file
instead of a directory, normalize into:
- path = parent directory
- pattern = exact filename
This ensures direct file targets are handled correctly regardless of any
user-supplied glob pattern.
Original commit: 3570aa55a7 (fix/flow-runs-legacy-migration)
* fix(qmd): escape direct file collection patterns
* fix(qmd): escape direct file collection masks
* fix(ui): run ui script through junction paths
* test(ui): make junction direct-execution test portable
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- This PR routes bare `openclaw` to classic onboarding for missing, empty, or metadata-only configs; keeps aut ... cs/changelog/tests; and narrows a Docker E2E boundary-check exception for an existing source-checkout lane.
- Reproducibility: not applicable. this is a feature/default-routing PR rather than a bug report. The branch p ... ill includes a fresh-state terminal run reaching `OpenClaw setup` and tests for the relevant config states.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat: start onboarding for fresh CLI installs
Validation:
- ClawSweeper review passed for head f4b2572f2e.
- Required merge gates passed before the squash merge.
Prepared head SHA: f4b2572f2e
Review: https://github.com/openclaw/openclaw/pull/85519#issuecomment-4522938004
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Prepack npm GitHub/git source update specs into temporary tarballs before the staged global npm install. Extends coverage to hosted GitHub HTTPS URLs without a `.git` suffix.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
The CONNECT handler pipes clientSocket and upstreamSocket together but
only registers an error handler on upstreamSocket. If the client
disconnects abruptly (ECONNRESET), the unhandled error event on
clientSocket causes the Node process to crash.
Add a clientSocket error handler that logs the event and destroys the
upstream socket. Also change clientSocket.end() to clientSocket.destroy()
in the upstream error handler since destroy() is more appropriate for
error cleanup of piped sockets.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix(agents): handle parallel tool call deltas in openai-completions stream
The OpenAI completions streaming parser tracked only a single
`currentBlock` for tool calls and ignored `toolCall.index`. When the
API sends multiple `delta.tool_calls` entries (e.g., parallel tool
call scaffolding from kimi-for-coding), the parser created a new
block for every entry with a differing `id`, spawning phantom tool
calls with empty names and misrouting arguments.
Replace single-block tracking with Maps keyed by `index` and `id`,
matching the correct logic already present in the bundled
`@earendil-works/pi-ai` dependency. This ensures parallel and
interleaved tool call deltas accumulate to the correct block.
Fixes phantom "unknown" tool calls and empty arguments on
parameterized tools for providers that emit multiple tool_call
indices in streaming deltas.
* fix(agents): finalize tool-call blocks in place to keep maps live
ClawSweeper review [P1]: finishCurrentBlock() and finishAllToolCallBlocks()
were creating new block objects and replacing them in output.content,
but toolCallBlocksByIndex / toolCallBlocksById still pointed at the old
objects. Later deltas for those indices would mutate detached blocks,
causing argument loss and incorrect contentIndex in stream events.
Fix by finalizing arguments in place on the existing block objects.
Add regression test for parallel tool calls with split indices:
- two tool-call slots introduced in one chunk
- argument deltas arriving for each index in subsequent chunks
* fix(agents): keep byte counters out of emitted tool-call blocks
ClawSweeper review [P2]: partialArgsBytes was being stored directly on
the tool-call block objects pushed into output.content, exposing parser
scratch state to emitted stream events and final transcripts.
Replace the inline field with a WeakMap keyed by block object, keeping
byte tracking internal to the parser without polluting the public block
shape.
* refactor(agents): extract ToolCallBlock type for map declarations
ClawSweeper review [P1]: NonNullable<typeof currentBlock> at the map
declaration point was unreliable because currentBlock is initialized to
null and flow-narrowed. Define a local ToolCallBlock alias and use it
for toolCallBlocksByIndex, toolCallBlocksById, and toolCallBlockBytes
to give the maps a precise, stable type.
* fix(agents): iterate typed tool-call map in finishAllToolCallBlocks
ClawSweeper review [P1]: output.content elements are typed as
Record<string, unknown>, so block.partialArgs remained unknown even
after checking block.type === "toolCall". Latest CI failed strict
type checking at parseStreamingJson(block.partialArgs).
Fix by iterating toolCallBlocksByIndex.values() instead — the Map
values are already typed as ToolCallBlock, so partialArgs is known
to be a string and parseStreamingJson compiles cleanly.
- Restart the shared Codex app-server client when native server-side compaction times out.
- Retry native compaction once on the fresh app-server while preserving stale-thread cleanup only for `thread not found`.
- Add regression coverage and changelog entry for the preflight compaction recovery path.
Verification:
- `pnpm test extensions/codex/src/app-server/compact.test.ts`
- `env -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN pnpm check:changed`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
CI note: `build-artifacts` is red due inherited latest-main workflow/test drift, reproduced locally outside this PR diff and tracked in the pre-merge PR comment.
* fix(security): escape entry.id in HTML export to prevent attribute XSS
Apply escapeHtmlAttr to entry.id in renderEntry and renderCopyLinkButton
to prevent attribute injection via crafted entry IDs in HTML exports.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* chore: remove proof helper scripts from branch
ClawSweeper P2: committed proof scripts can provide false-positive
validation. Proof output is in the PR body instead.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
---------
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
When the Slack adapter's startup auth.test call fails (bad token,
transient error, etc.), the bot user id silently stays empty for the
life of the process. The downstream explicit-bot mention check is
`botUserId && mentionedUserIds.includes(botUserId)`, which always
returns false when botUserId is empty. The result is that explicit
<@bot> mentions are silently classified as non-mentions with no log
trace explaining why.
Changes:
- provider.ts: stop swallowing auth.test failures; emit a warn log at
boot so the degraded state is observable. Empty user_id is treated
as a failure too.
- prepare.ts + subteam-mentions.ts: export the existing normalizeSlackId
helper and apply it to both sides of the explicit-bot equality check
(and to the mentioned-ids list). Real Slack ids are already uppercase,
so this is a no-op on healthy traffic, but it locks the invariant down
and removes the asymmetry between collected ids and the ctx bot id.
- prepare.test.ts: add two regression tests pinning the exact symptom:
positive case (botUserId set -> explicit_bot), negative case
(botUserId='' -> not explicit_bot, mention_source not explicit_bot).
🤖 AI-assisted.
Co-authored-by: in-liberty420 <in-liberty420@users.noreply.github.com>
Replace empty .catch(() => {}) on two failDelivery calls with
log.warn() so delivery queue mark-failed errors leave a diagnostic
trail instead of being silently discarded.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
`parseSlashCommandActionArgs` used a naive `startsWith` against the
configured slash prefix. When a skill name shares a prefix with a
built-in command (e.g. a skill named `config-check` vs the built-in
`/config`), the longer name was captured by the shorter built-in
handler and surfaced as an invalid action:
⚠️ /config is disabled. Set commands.config=true to enable.
Any skill whose name starts with a built-in command prefix
(`config-*`, `debug-*`, `models-*`, etc.) was unreachable via slash
invocation from any channel.
Fix: after the prefix match, require that the next character is
whitespace, a colon, or end-of-string. Otherwise the prefix
collided with a longer command name and we return `no-match` so the
longer handler — or the skill router — gets a chance to claim it.
Adds a regression test file `commands-slash-parse.test.ts` covering:
- `/config-check <args>` returns null (the reported case)
- `/configfoo` (no separator) returns null
- `/modelsy` returns null for the `/models` prefix
- `/config:json` still matches (colon is a valid boundary)
- `/config show enabled` still parses cleanly (whitespace boundary)
- empty body still returns the default action
Fixes#84572.
Co-authored-by: infracore <infracore@users.noreply.github.com>
* fix(tui): dismiss watchdog notice when response actually arrives
The streaming watchdog renders 'This response is taking longer than
expected. Send another message to continue.' after 30s without a chat
delta. If a delta or final then arrives — common for runs that are slow
but not stuck — the notice stays in the log alongside the recovered
response and contradicts what the user sees.
Track the notice by runId in the chat log via a new `addPendingSystem`
+ `dismissPendingSystem` pair (mirroring the existing pendingUsers
pattern) and dismiss it from `handleChatEvent` whenever any further chat
event for that run is processed. The watchdog's internal cleanup
(`activeChatRunId` reset, status idle, history reload) is unchanged.
Refs #67052, #69081 (closed). Prior attempt #69026 raised the threshold
and suppressed the notice entirely; this is the narrower fix that keeps
the warning useful for genuinely stuck runs.
* fix(tui): adapt pending notice to repeatable system entries
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The SIGTERM handler's fire-and-forget IIFE can reject if the graceful
drain or tunnel-teardown throws. Without a catch, this becomes an
unhandled promise rejection. Add .catch() that logs the error and
falls back to a hard stop request. Same treatment for SIGUSR1.
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
* fix: release cron runtime state after isolated runs
After an isolated cron/subagent run completes, the prepared context retains
references to the full in-memory session store and the registered agent run
context. Over many runs, these retained objects accumulate -- heap snapshots
showed ~2.0 GiB from ~113k copies of the skill prompt string flowing through
skillsSnapshot.prompt -> session entry -> cronSession.store -> cron run context.
Changes:
- Add disposeCronRunContext() to runCronIsolatedAgentTurn's finally block
- Calls clearAgentRunContext(sessionId) to remove the run context from the
global agent-events map
- Nulls cronSession.store to release the in-memory session registry copy
- Export clearAgentRunContext from run-execution.runtime.ts barrel
- The disposal is shallow O(1) -- no deep traversal, no hot-path disk writes
- Session persistence is unaffected (on-disk sessions.json is untouched)
The finally block guarantees cleanup on both success and error paths,
including timeout/abort scenarios.
Includes unit tests for clearAgentRunContext, store disposal, and
sweepStaleRunContexts.
* fix: remove duplicate storePath property in test fixture
* fix: remove unused clearAgentRunContext import from run-executor
* fix(cron): use initial sessionId for disposeCronRunContext in finally block
finalizeCronRun calls adoptCronRunSessionMetadata() which can rotate
sessionEntry.sessionId before the finally block runs. Capturing the
sessionId before the try block ensures clearAgentRunContext clears the
correct registered context instead of the potentially-rotated one.
Also removes unused imports (vi, beforeEach) from the runtime cleanup test.
* chore: trigger CI re-check for proof gate
* chore: retrigger CI proof gate
* test(cron): prove isolated run cleanup path
* fix(cron): keep shared run contexts active
* test(cron): avoid spreading typed-never fixture
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(exec): parse nested approval metadata in followups
(cherry picked from commit 10ff9b318e77cda3d65f40d59bbab0f4a3f59da8)
* docs(changelog): note exec approval nested-paren parser fix
* fix(exec): sanitize denied-reason literals in (...)-delimited approval messages
The exec-approval followup wire format is `Exec denied (gateway id=..., <deniedReason>): cmd`. The producer at `src/agents/bash-tools.exec-host-gateway.ts:606` was emitting `approval-timeout (allowlist-miss)`, which embedded literal parens inside the metadata segment and broke the metadata/body boundary for naive parsers. Switch the literal to a colon-separated form (`approval-timeout: allowlist-miss`) so the surrounding `(...)` delimiter stays unambiguous.
The Gateway node-event surface at `src/gateway/server-node-events.ts:734` interpolates an untrusted `obj.reason` into the same `Exec denied (node=..., <reason>)` format. Strip parens from that field before interpolation so a buggy or hostile node payload cannot smuggle metadata into the body slot.
The robust nested-paren parser already in `src/agents/exec-approval-result.ts` stays as defense in depth. Extend `exec-approval-result.test.ts` to cover the canonical colon-separated `deniedReason` and confirm `formatExecDeniedUserMessage` still maps it to the timeout copy.
* fix(exec): require gateway/node metadata source to reject spoofed approval wrappers
The exec-approval result parser previously accepted any string starting with
"Exec denied (..." or "Exec finished (..." as a structured approval wrapper.
Generic command stdout that happened to start with these tokens would be
classified as kind: "denied" or "finished", letting a tool's output spoof a
resolved-approval event in pi-embedded-subscribe.handlers.tools.ts:1173.
Reported by Aisle as CWE-841 (Improper Enforcement of Behavioral Workflow),
medium severity. The fix validates that the parenthesized metadata starts with
either "gateway id=" or "node=" — both prefixes are emitted by the legitimate
approval generators (bash-tools.exec-host-gateway.ts, bash-tools.exec-host-node.ts,
gateway/server-node-events.ts) and are unlikely to appear in arbitrary command
output. Inputs that fail this check now return kind: "other", which all callers
already handle as a no-op.
* fix(exec): keep sandbox_blocked classification for raw exec-denied messages
After the spoof-guard tightening of parseExecApprovalResultText, inputs that
lack a gateway/node-sourced metadata prefix (such as the synthetic
"exec denied (allowlist-miss):" string used in classifier tests) no longer
return kind: "denied" and therefore no longer trigger formatExecDeniedUserMessage,
so isSandboxBlockedErrorMessage stopped recognising them.
Add a direct \bexec denied\s*\( alternative to SANDBOX_BLOCKED_RE so the
classifier still treats any raw "exec denied (" prefix as sandbox-blocked,
independent of whether the parser accepts the surrounding wrapper. This keeps
classifyProviderRuntimeFailureKind's existing behavior for unstructured exec-
denied messages.
Add documentation for the dynamicAgentCreation feature used to create
isolated agents per Feishu/Lark user. Covers:
- dynamicAgentCreation configuration fields (enabled, workspaceTemplate,
agentDirTemplate, maxAgents)
- Automatic agent/workspace creation flow
- Session isolation with dmScope
- Template variables ({agentId}, {userId})
- Verification steps and example deployment
Refs: feature available since OpenClaw 2026.4.25+
Co-authored-by: li <li@lideMac-mini.local>
* docs(channels/slack,telegram): document ackReactionScope and its DM-excluding default
The Slack and Telegram channel docs documented `ackReaction` but not
`ackReactionScope`, even though the scope (defaulting to
`group-mentions`) silently excludes DMs. People who set `ackReaction`
and expect to see an emoji on DMs are surprised when nothing fires.
This adds:
- The resolution order for `ackReactionScope` (per-account → channel →
`messages.ackReactionScope` → default `group-mentions`).
- The full list of scope values (`all`, `direct`, `group-all`,
`group-mentions`, `off`/`none`).
- A Note callout flagging that the default does not react in DMs and
that `messages.ackReactionScope` requires a gateway restart to take
effect.
- A short JSON example for the common case (`ackReactionScope: "all"`).
Mirrors the structure already used in `docs/channels/matrix.md`.
Found while configuring Slack DMs to show `👀` ack reactions and
discovering that the docs covered the emoji but not the scope gate. AI-assisted.
* fixup: scope is messages-only for Slack & Telegram (not per-account)
Reviewer correctly noted that the Slack and Telegram runtimes only read
`cfg.messages?.ackReactionScope` and the per-account/per-channel
`ackReactionScope` keys don't exist in those schemas (only Discord and
Matrix support them). Drop the misleading resolution-order bullets and
document `messages.ackReactionScope` only.
Verified against:
- extensions/slack/src/monitor/provider.ts:243
- extensions/telegram/src/bot-core.ts:262
- src/config/types.slack.ts (no ackReactionScope in account schema)
- src/config/types.telegram.ts (no ackReactionScope in account schema)
Keeps the DM-default gotcha, the full enum, and the gateway-restart note,
which were the original value of the PR.
---------
Co-authored-by: Dr. Claw <drclaw-iq@users.noreply.github.com>
Recreated from #85108 because the original branch could not be updated by maintainers.
Preserves current-main pnpm install hardening while switching workflow pnpm setup to packageManager, and adds exact version-scoped release-age exclusions for already-locked packages that pnpm 11.2.2 audits during install.
Co-authored-by: Altay <altay@hey.com>
Fixes#5369.
Preserve fresh session-store state when the agent handler observes a stale cached session entry, including model/provider overrides, send policy, delivery metadata, lifecycle timestamps, and fresh session rotations.
Co-authored-by: CodeReclaimers <github@codereclaimers.com>
Fixes the embedded attempt session write-lock watchdog so the fallback max hold time follows the resolved compaction timeout plus the existing lock grace window, instead of inheriting the full run timeout.
Adds regression coverage for the helper and settled-compaction lock lifecycle, plus a changelog entry thanking @luoyanglang.
Verification:
- `pnpm test src/agents/session-write-lock.test.ts src/agents/pi-embedded-runner/run/attempt.test.ts src/agents/pi-embedded-runner/run/attempt.session-lock.test.ts`
- `pnpm check:changed` via Blacksmith Testbox `tbx_01ks8b6vn8se5cg1dfn3te3g47` / https://github.com/openclaw/openclaw/actions/runs/26301988670
- Autoreview clean: `/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- PR CI green on `79e8c5f1a637981d263c0268bf5666967ff4e778`: https://github.com/openclaw/openclaw/actions/runs/26302152844 and https://github.com/openclaw/openclaw/actions/runs/26302152798
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Summary:
- Document that MEDIA directives must be plain-text line-start metadata.
Verification:
- Source check: src/media/parse.ts only recognizes lines whose trimmed start begins with MEDIA: and skips fenced code blocks.
- PR CI: check-docs succeeded.
Summary:
- The PR moves gateway provider auth-state prewarm into cancelable post-ready gateway lifetime work, uses current runtime config for delayed warms, and adds related gateway/provider-auth tests plus a changelog entry.
- Reproducibility: no. high-confidence runtime reproduction was run in this review. Source inspection shows th ... th on current main, and the source PR supplies live after-fix proof for the focused startup-ordering slice.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): defer provider auth prewarm after startup
Validation:
- ClawSweeper review passed for head 31ea4288e3.
- Required merge gates passed before the squash merge.
Prepared head SHA: 31ea4288e3
Review: https://github.com/openclaw/openclaw/pull/85369#issuecomment-4519123491
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- The PR teaches `openclaw devices approve <requestId>` to approve a compatible same-device replacement request during local fallback and adds focused CLI, infra, and changelog coverage.
- Reproducibility: yes. Source inspection shows current main rejects the gateway's replacement requestId as a ... adds focused infra and CLI tests for the churn path; I did not run tests because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs: note device approval recovery
Validation:
- ClawSweeper review passed for head 1d2f2e9b2f.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1d2f2e9b2f
Review: https://github.com/openclaw/openclaw/pull/85342#issuecomment-4518449317
Co-authored-by: masonxhuang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
normalizeAllowedModelRef() and the resolved override ref interpolated
${provider}/${model} after normalizeModelRef(), so a provider-qualified
model id like openrouter/gpt-5.4-mini surfaced as
openrouter/openrouter/gpt-5.4-mini in the allowlist set and policy
denial message, masking the actionable model ref.
Route both sites through modelKey() (src/agents/model-ref-shared.ts)
so the provider segment is collapsed when the model id already starts
with it. Add regression tests covering allowlist hit and denial paths
for the OpenRouter shape.
Fixes#84887
* fix(gateway): include openclaw bin in service PATH
* fix(doctor): accept expected service PATH
* docs(changelog): mention managed service PATH bin fix
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Summary:
- Honor per-model api/baseUrl overrides during custom provider auth hook lookup and transport selection.
- Keep models-add metadata safeguards intact and add focused auth/model resolver regression coverage.
- Add maintainer changelog credit for @huveewomg.
Verification:
- git diff --check
- GitHub CI green on 277629e992
- GitHub CodeQL green on 277629e992
- GitHub CodeQL Critical Quality green on 277629e992
- GitHub Real behavior proof green on 277629e992
- Local focused Vitest was stopped after 8 minutes on a busy host without producing a result; PR CI supplied the final proof.
Co-authored-by: huveewomg <wongrenthou1265@gmail.com>
* fix(gateway): eager-load lifecycle runtime to survive in-place upgrades
After a package-swap update (e.g. via update.run), dist/ chunk hashes
rotate while the gateway is still running. The SIGUSR1 listener's first
dynamic import of the lifecycle runtime module then throws
ERR_MODULE_NOT_FOUND inside its async IIFE, silently rejects, and leaves
restart.ts's emittedRestartToken permanently unconsumed. From that point
every scheduleGatewaySigusr1Restart() — including the one update.run
schedules for itself — returns { coalesced: true } without scheduling
anything, and the gateway never restarts until manually kickstarted.
Fix:
1. Eagerly resolve the lifecycle runtime module as the first statement
of runGatewayLoop, before any signal listener is installed. lifecycle.runtime
is a 36-line re-export hub, so loading it once pulls the entire restart
/ respawn / queue / sentinel / handoff graph into memory, immune to
later disk rotation. If the module is missing at startup, fail fast
with a loud error so the supervisor can recover instead of running
half-broken.
2. Defense in depth: catch SIGUSR1 IIFE rejections and call
markGatewaySigusr1RestartHandled() via the eagerly captured reference,
so a transient listener failure doesn't permanently stick the restart
token.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(changelog): mention lifecycle restart eager load
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Summary:
- The branch replaces the Crabbox wrapper's hardcoded provider allow-list with help-output parsing, preserves current aliases and a known help omission, adds wrapper tests, and updates the changelog.
- Reproducibility: yes. source-reproducible: current main only rejects selected providers that are already in ... rovider names can bypass wrapper validation. I did not run the PR branch because this review was read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: refactor(crabbox): parse provider list from binary help instead of ha…
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8530…
Validation:
- ClawSweeper review passed for head c99388d92a.
- Required merge gates passed before the squash merge.
Prepared head SHA: c99388d92a
Review: https://github.com/openclaw/openclaw/pull/85302#issuecomment-4517730136
Co-authored-by: masonxhuang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Limit sub-agent bootstrap context to AGENTS.md and TOOLS.md without adding a new config surface. Preserve the existing cron minimal bootstrap behavior.
Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
Close child ACP runtimes during parent reset/delete through a shared direct-child session lookup, covering spawnedBy and parentSessionKey lineage across combined agent stores.
Also adds focused regression coverage for direct child discovery, non-ACP/unrelated negatives, reset cleanup, delete cleanup, cross-store children, and concurrent stuck-child cleanup.
Co-authored-by: openperf <16864032@qq.com>
Summary:
- The branch adds a Google provider thinking-policy resolver and opt-in profile flag, updates shared thinking validation and cron/proof-policy tests, and adjusts ClawSweeper proof parsing.
- Reproducibility: yes. source-reproducible: current main applies the generic off-only profile before provider ... figured thinking through that resolver. I did not execute a live systemd cron run in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: preserve Google Gemini 3 cron thinking
Validation:
- ClawSweeper review passed for head a6cd2e826e.
- Required merge gates passed before the squash merge.
Prepared head SHA: a6cd2e826e
Review: https://github.com/openclaw/openclaw/pull/85300#issuecomment-4517662575
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Keep derived plugin metadata snapshots out of the process memo/current snapshot cache so newly added plugins under derived discovery paths are found without restart.
The deriveIdHint function already strips -provider from unscoped
package names (@openclaw/anthropic-provider -> anthropic) but does
not strip -plugin (@openclaw/xai-plugin -> xai-plugin instead of
xai). This causes ~30 spurious 'plugin id mismatch' warnings on
gateway startup for built-in plugins whose package names end in
-plugin.
Closes#85048
* fix(gemini): strip sub-second precision from web_search time_range_filter
Gemini's google_search.time_range_filter rejects any non-zero fractional
seconds with "[FIELD_INVALID] Granularity of nano is not supported", even
though the underlying google.protobuf.Timestamp type accepts 0/3/6/9
fractional digits per its public spec. The grounding endpoint enforces a
stricter rule than the underlying type.
Date.prototype.toISOString() always emits millisecond precision, so every
freshness call (and any date_after/date_before call hitting the "now"
fallback for endTime) failed with the above 400 after #66498's fix shipped
in 2026.5.19.
Introduce toGeminiTimeRangeTimestamp() which strips the fractional-second
component before serializing, and route all four timeRangeFilter timestamp
sites through it. isoDateExclusiveEnd happens to produce all-zero
fractional today (so Gemini accepts it), but routing it through the helper
keeps the contract uniform and resilient to future changes.
Why this slipped past the original CI: the existing freshness test used
vi.setSystemTime(new Date("2026-04-15T12:00:00Z")), which always
serializes back as ".000Z" — the one fractional form Gemini happens to
accept. Wall-clock new Date() in production always has non-zero ms. The
new test uses setSystemTime(new Date("2026-04-15T12:00:00.123Z")) to
exercise the realistic case.
Verified empirically against the live Gemini REST API:
".123Z" → 400 "Granularity of nano is not supported"
".000Z" → grounded content (the one fractional form accepted)
"Z" → grounded content
Fixes#85061.
* test(gemini): use realistic non-zero ms in existing freshness test
The original test set the fake clock to a moment with zero fractional
seconds, so toISOString() produced ".000Z" — the one fractional form
Gemini's google_search.time_range_filter happens to accept. Wall-clock
new Date() in production produces non-zero ms, which Gemini rejects.
Bumping the fake time to .123Z makes the existing test exercise the
realistic case alongside the dedicated regression test.
---------
Co-authored-by: Noah R <Noerr@users.noreply.github.com>
Summary:
- The PR changes generated-media duplicate guards, completion delivery fallback behavior, transcript write-lock reuse, task-registry fresh owner reads, docs, changelog, and regression coverage.
- Reproducibility: yes. with source and artifact evidence rather than a local rerun: current main completes me ... e task and one successful video task after the patch. I did not run tests because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: dedupe media completion delivery
- PR branch already contained follow-up commit before automerge: fix: avoid music provider lookup for explicit models
- PR branch already contained follow-up commit before automerge: fix: narrow detached media task handles
- PR branch already contained follow-up commit before automerge: fix: close media completion review gaps
- PR branch already contained follow-up commit before automerge: fix: tolerate media delivery mirrors during session lock
- PR branch already contained follow-up commit before automerge: Fix media completion duplicate delivery
Validation:
- ClawSweeper review passed for head f83e3bf143.
- Required merge gates passed before the squash merge.
Prepared head SHA: f83e3bf143
Review: https://github.com/openclaw/openclaw/pull/84006#issuecomment-4484835103
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Surface local post-challenge connect assembly failures immediately instead of waiting for the Gateway CLI wrapper timeout.\n\nCo-authored-by: samzong <samzong.lu@gmail.com>
Summary:
- The branch passes runtime config into the model config write helper, updates `openclaw models set` to resolve aliases source-first then runtime-fallback, and adds regression tests plus a changelog entry.
- Reproducibility: yes. I did not execute the CLI in this read-only review, but the current-main source path a ... ing against source config while runtime defaults can be the only place the displayed `sonnet` alias exists.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(models): preserve authored aliases for set
- PR branch already contained follow-up commit before automerge: fix(models): resolve set aliases from runtime config [AI-assisted]
Validation:
- ClawSweeper review passed for head 29138ac5d0.
- Required merge gates passed before the squash merge.
Prepared head SHA: 29138ac5d0
Review: https://github.com/openclaw/openclaw/pull/83262#issuecomment-4472495568
Co-authored-by: JARVIS-Glasses <284122573+JARVIS-Glasses@users.noreply.github.com>
Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
The watcher fired constantly because the gateway itself rewrites
auth-profiles.json frequently (cooldown ticks, usage stats, OAuth
refresh, markAuthProfileFailure). Each self-write triggered chokidar
which cleared the prepared auth map and scheduled an ~8 s rewarm,
a feedback loop that defeated the caching the rest of the PR added.
Drop the watcher entirely. Self-heal still covers the stale-TRUE
direction via the markAuthProfileFailure hook. Stale-FALSE (user adds
auth externally and the gateway hasn't observed any request through
that profile yet) reverts to the pre-PR behavior: reload config or
restart gateway to pick it up. Known limitation.
Summary:
- The PR rejects Codex app-server command overrides that embed Node/package-manager inline arguments, adds matching doctor diagnostics, regression tests, and a changelog entry.
- Reproducibility: yes. for the scoped malformed override path: current main passes the combined command strin ... ix resolver/doctor live output. I did not establish a live Windows npm-global managed-startup reproduction.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Validate Codex app-server command overrides
Validation:
- ClawSweeper review passed for head 966bcd6617.
- Required merge gates passed before the squash merge.
Prepared head SHA: 966bcd6617
Review: https://github.com/openclaw/openclaw/pull/84417#issuecomment-4494295224
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Remove the chat picker recency/current-agent filters while preserving the bounded configured-agent refresh, and add the changelog credit for @amknight.
Summary:
- The PR removes the auto-reply compaction-failure session reset hook, adds preserved-session recovery guidance for overflow/compaction failure paths, and updates focused tests, docs, and the changelog.
- Reproducibility: yes. at source level with high confidence. Current main routes both embedded overflow paylo ... resetSessionAfterCompactionFailure, and the PR body includes before/after terminal proof of those branches.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(auto-reply): drop dead compaction reset hook
- PR branch already contained follow-up commit before automerge: fix(auto-reply): preserve sessions after compaction failures
Validation:
- ClawSweeper review passed for head 193d3c0fdd.
- Required merge gates passed before the squash merge.
Prepared head SHA: 193d3c0fdd
Review: https://github.com/openclaw/openclaw/pull/70479#issuecomment-4325128777
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Addresses three ClawSweeper findings on the fs-watcher commit:
- [P1] auth-profile watcher now handles chokidar 'error' events (logs +
closes once) mirroring the gateway config-reload pattern. Without
this, an unhandled error from chokidar can crash the gateway.
- [P2] auth-profile watcher handle is pushed into postReadySidecars so
stopPostReadySidecarsAfterCloseStarted closes it on gateway shutdown.
- [P2] auth-failure and file-change invalidation paths now schedule a
background rewarm (with a 'reason=' log line). Without this, the next
/models call after an invalidation paid the slow per-provider path
until the next reload. The warmer's existing generation counter
handles concurrent rewarms safely.
Adds a chokidar watcher on every configured agent's auth-profiles.json.
Any change fires clearCurrentProviderAuthState so the next model-listing
call recomputes against the on-disk auth state. Closes the stale-FALSE
direction (user adds auth via codex login, hand-edit, etc.) that the
auth-failure hook can't catch on its own.
When markAuthProfileFailure observes an auth failure at request time
(token rotated, OAuth revoke, etc.), fire a hook that clears the
prepared provider-auth map so the next model-listing call recomputes
against the real auth state. Single mutable hook slot wired up at
gateway startup; no TTL or polling.
Addresses ClawSweeper's P1 freshness finding on #85125 without
reintroducing the TTL.
Summary:
- The PR changes shared, Feishu, Mattermost, Microsoft Teams, and WhatsApp inbound debounce predicates so bare abort text bypasses debounce, then adds focused tests and a changelog entry.
- Reproducibility: yes. source-level. Current main sends bare `stop`, `abort`, and `wait` through a `hasContro ... ()` debounce gate, while the existing abort-aware detector and trigger set already recognize those phrases.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(channels): bypass debounce for bare abort triggers [AI-assisted]
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8334…
Validation:
- ClawSweeper review passed for head c96bf84270.
- Required merge gates passed before the squash merge.
Prepared head SHA: c96bf84270
Review: https://github.com/openclaw/openclaw/pull/83348#issuecomment-4473176095
Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch adds an abort-aware dispatcher-idle wait after successful same-channel and direct ACP block replies, plus regression tests and a changelog entry.
- Reproducibility: yes. Current main source shows the same-channel block callback queues dispatcher delivery w ... spatcher idle, and the PR body supplies before/after diagnostic output for the tool-start ordering failure.
Automerge notes:
- PR branch already contained follow-up commit before automerge: [AI-assisted] fix(reply): wait for block replies before tools
Validation:
- ClawSweeper review passed for head 32576209a2.
- Required merge gates passed before the squash merge.
Prepared head SHA: 32576209a2
Review: https://github.com/openclaw/openclaw/pull/83722#issuecomment-4480639845
Co-authored-by: JARVIS-Glasses <284122573+JARVIS-Glasses@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Harden the Codex app-server native execution bridge for OpenClaw sandboxed runs. The change keeps core sandbox policy in OpenClaw while exposing the process, filesystem, and HTTP relay behavior Codex needs inside a scoped exec server.
The large exec-server/test files were split into focused modules before landing, and the PR was rebased onto current main with focused tests, Testbox changed checks, CI, and Codex autoreview green.
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Summary:
- The PR adds shared blocked-liveness normalization, applies it to agent.wait, gateway dedupe, subagent registry, and announcement paths, and adds regression tests plus a changelog entry.
- Reproducibility: yes. from source inspection: current main accepts blocked lifecycle/wait metadata as ok thr ... gateway wait and registry completion paths. I did not run a live provider overflow in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): normalize blocked wait completions
- PR branch already contained follow-up commit before automerge: fix(agents): surface blocked subagent completions
Validation:
- ClawSweeper review passed for head 224785c8a6.
- Required merge gates passed before the squash merge.
Prepared head SHA: 224785c8a6
Review: https://github.com/openclaw/openclaw/pull/80886#issuecomment-4427552621
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Adds installRecords to PluginLoadOptions and PluginRuntimeLoadContext so
callers that already hold a PluginMetadataSnapshot can pass the snapshot's
in-memory records instead of forcing each downstream loader to re-read
installs.json. resolvePluginRuntimeLoadContext extracts the records from
the snapshot via extractPluginInstallRecordsFromInstalledPluginIndex,
buildPluginRuntimeLoadOptionsFromValues forwards them, and the setup +
runtime provider load paths in providers.runtime.ts pass them through
from params.pluginMetadataSnapshot. resolvePluginLoadCacheContext uses
the threaded records (falling back to the sync read) and
loader-provenance now uses params.installRecords ?? sync-read instead of
always reading and overlaying.
Log structured details when Discord persistent component registry state falls back after a store failure.
- Format Error name, message, stack, and cause metadata at the Discord registry warning call site.
- Forward plugin runtime logger metadata to the underlying child logger.
- Add focused regression coverage for the Discord fallback warning and runtime logging adapter.
- Add changelog credit for @100menotu001.
Fixes#84185.
Co-authored-by: OpenClaw Contributor <100menotu001@users.noreply.github.com>
Co-authored-by: Craig <froelich@craigs.mac.studio.froho>
Summary:
- The PR adds a bundled-channel load-error formatter, wires it into the bundled-channel warning paths, adds focused tests, and updates the changelog.
- Reproducibility: yes. source-level: current main logs bundled-channel load failures with bare `formatErrorMe ... cause`. The contributor's terminal proof demonstrates the same wrapped-error shape before and after the PR.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(channels): walk error cause chain to detect missing bundled modules
- PR branch already contained follow-up commit before automerge: docs(changelog): add Unreleased Fixes entry
- PR branch already contained follow-up commit before automerge: Merge remote-tracking branch 'origin/main' into fix/bundled-channel-l…
- PR branch already contained follow-up commit before automerge: Merge branch 'main' into fix/bundled-channel-load-doctor-hint
Validation:
- ClawSweeper review passed for head 416a8a2e77.
- Required merge gates passed before the squash merge.
Prepared head SHA: 416a8a2e77
Review: https://github.com/openclaw/openclaw/pull/76974#issuecomment-4367336485
Co-authored-by: BSG2000 <github@hsu.hamburg>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: BSG2000 <BSG2000@users.noreply.github.com>
Co-authored-by: BSG2000 <thomas.krohnfuss@stud.th-luebeck.de>
Co-authored-by: Thomas Krohnfuß <BSG2000@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Preserve `reusable` for portable message presentation buttons and carry it through Discord component registration so repeatable callbacks stay available after a successful interaction.
Also keeps `reusable` through legacy presentation-to-interactive conversion and documents the user-visible change in the changelog.
Verification:
- `pnpm test src/interactive/payload.test.ts extensions/discord/src/shared-interactive.test.ts extensions/discord/src/components.test.ts -- --reporter=verbose`
- `git diff --check`
- `AUTOREVIEW_AUTO_TESTS=0 .agents/skills/autoreview/scripts/autoreview --mode local`
- PR CI at `52f25221b3e01f3255d8df37df73d0357ab7410b`: all completed checks green/skipped/neutral except pending CodeQL `Security High (mcp-process-tool-boundary)` at time auto-merge was armed.
Co-authored-by: OpenClaw Contributor <100menotu001@users.noreply.github.com>
Summary:
- The branch teaches Ollama discovery to use resolved `discoveryApiKey` values for non-local cloud providers, preserves local marker auth, and adds focused provider-discovery regressions plus a changelog entry.
- Reproducibility: yes. from source inspection: current main can return the `OLLAMA_API_KEY` marker instead of ... ential for documented Ollama Cloud config. I did not run executable tests because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: ci: allowlist qa lab fixtures
- PR branch already contained follow-up commit before automerge: Fix Ollama cloud API key discovery
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8503…
Validation:
- ClawSweeper review passed for head cb6b658819.
- Required merge gates passed before the squash merge.
Prepared head SHA: cb6b658819
Review: https://github.com/openclaw/openclaw/pull/85091#issuecomment-4512647237
Co-authored-by: Anup Sharma <anupnewsmail@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
The auto-migration introduced in #83312 only fires when a credential is loaded
via a path that reads its sidecar tokens. The OAuth refresh manager's internal
loader does (so direct CLI inference works and self-heals on first refresh).
The embedded runner's secrets-runtime loaders did not:
- loadAuthProfileStoreForSecretsRuntime
- loadAuthProfileStoreWithoutExternalProfiles
- ensureAuthProfileStoreWithoutExternalProfiles
All three opted out of sidecar resolution. So for an upgraded user with a
legacy oauthRef-backed openai-codex profile, the credential loaded with no
access/refresh material, evaluateStoredCredentialEligibility marked it
ineligible, resolveAuthProfileOrder filtered it out, and resolveApiKeyForProvider
threw "No API key found for provider 'openai-codex'" before the OAuth manager
(and its migration path) was ever consulted. CLI worked, Telegram/cron/embedded
turns broke — only doctor-or-bust would fix it.
Flip the three embedded loaders to default resolveLegacyOAuthSidecars to true
(matching loadStoredOAuthRefreshStore). The existing #83312 refresh-and-rewrite
then fires on the first embedded turn for these users and persists tokens
inline, removing the legacy sidecar from disk on the next doctor pass.
Cherry-picked and squashed from PR #84752 (commits 85f36e8d2b and
4624e34c06). Comments noting local-fork bookkeeping stripped per repo policy.
Co-authored-by: Will <totalsolutionspm@gmail.com>
P1 (auth-profile logout): invalidateModelAuthStatusCache now also clears
the prepared provider-auth map, and the models.auth.logout handler fires
a rewarm against the current config. Without this, removing a provider's
auth profiles left the warmed 'true' answer in the map until restart,
so /models and pickers kept advertising the removed provider.
P1 (plugin-reload ordering): the previous version fired the rewarm
inline with the clear, before plan.reloadPlugins() ran. The warmer
reads plugin metadata and synthetic-auth hooks, so it published the
pre-reload runtime's answers. Moved the rewarm to fire after the
plugin-reload block completes, so it reads the new plugin runtime.
The early clear still happens upfront so callers don't keep seeing the
pre-reload answer during the reload window.
ClawSweeper P1 + P2 findings on the prior review-fix commit.
- [P1] hasAuthForModelProvider now also checks workspaceDir against the
warm's snapshot value. The warmer uses resolveDefaultAgentWorkspaceDir,
but per-agent picker calls (buildModelsProviderData →
resolveVisibleModelCatalog → createProviderAuthChecker) thread an
agent-specific workspaceDir, and provider env/synthetic-auth
resolution depends on it. Without this check the picker for agent B
would silently reuse agent A's warmed answer.
- [P1] warmCurrentProviderAuthState now claims a generation counter at
the start of its work and only publishes the new state if the
generation hasn't been bumped (by a concurrent clear or another
warm). Closes the race where a slow startup warm could overwrite a
newer reload-driven rewarm with stale data.
- [P2] Reload handler now also clears and rewarms the prepared map
when plugins.* config paths change. Provider auth can come from
plugin env vars and plugin synthetic-auth wiring, so plugin hot
reloads must invalidate the auth state too — not just model config
paths.
Test: new case asserting a non-default workspaceDir caller bypasses the
prepared map and falls through to compute.
Two fixes flagged by ClawSweeper.
P1 — hasAuthForModelProvider now only short-circuits via the prepared
map when the caller's scope matches the warmer's (broad discovery, no
agentDir/env/store override). Read-only gateway model lists pass
runtimeAuthDiscovery: false, which the visibility helper maps to
discoverExternalCliAuth: false and allowPluginSyntheticAuth: false; the
prepared broad answer was previously masking that narrower intent. Now
those callers fall through to compute the narrow answer.
P2 — server-reload-handlers now also schedules a rewarm right after
clearing the prepared state on model-config reload, so long-lived
gateways don't regress to per-call discovery between reload and the
next restart.
Test: extends model-provider-auth.test.ts with a scope-narrowing case
asserting the prepared answer is bypassed when the caller passes
discoverExternalCliAuth: false / allowPluginSyntheticAuth: false.
Asserts hasAuthForModelProvider returns the warmed answer for providers
in the prepared map and skips the compute path, and that
clearCurrentProviderAuthState restores fall-through to compute.
Eliminates the per-call auth-filter loop that every /models invocation
(Discord/Telegram pickers, CLI, status commands) was paying — 30 unique
providers × ~600 ms each of plugin-runtime / external-CLI / auth-profile
discovery, done fresh on every call (~20 s per call).
warmCurrentProviderAuthState builds a provider->boolean map once at
gateway startup against a single AuthProfileStore scoped to every
candidate provider, and hasAuthForModelProvider consults the prepared
map first and short-circuits. The map is invalidated on config reload
alongside resetModelCatalogCache so the next read after a relevant
config change rewarms.
Per /models: ~20,569 ms → ~5 ms (~4,100×).
One-time startup warm cost: ~49 s (cold catalog + auth sweep), logged
via gateway log.info on completion.
knip's deadcode-unused-files check ignores fixtures matching **/*.fixture.ts
(dot before "fixture"). The codex lifecycle fixtures landed in bbf3eec786
as auth-profile-fixture.ts and codex-plugin-fixture.ts (hyphen), so knip
flagged them as unexpected unused files and CI's check-dependencies job
has been failing on main since then. Rename to auth-profile.fixture.ts
and codex-plugin.fixture.ts and update the lifecycle test, the fixture
cross-import, and the six qa/scenarios markdown files that reference
them by path and qaImport specifier.
Summary:
- The branch scopes config-time Google Gemini preview model normalization to Google providers or nested `google/` proxy suffixes, adds model-picker regression coverage, and adds a changelog entry.
- Reproducibility: yes. by source inspection. Current main sends every provider suffix through the Google prev ... i-3-flash` deterministically becomes `litellm/gemini-3-flash-preview`; I did not run a live cron preflight.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(config): scope Google preview model normalization to Google provi…
- PR branch already contained follow-up commit before automerge: fix#84745: scope Google preview model normalization to Google provid…
- PR branch already contained follow-up commit before automerge: fix#84745: preserve proxy Google model normalization
Validation:
- ClawSweeper review passed for head c59163c809.
- Required merge gates passed before the squash merge.
Prepared head SHA: c59163c809
Review: https://github.com/openclaw/openclaw/pull/84762#issuecomment-4504169062
Co-authored-by: zhang-guiping <zhang.guiping@xydigit.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
OAuth credentials that loaded without their sidecar material (no access, no
refresh) would still enter the refresh path inside the per-profile lock,
where the adapter call is bounded by OAUTH_REFRESH_CALL_TIMEOUT_MS (120s).
That made the eventual "No API key found for provider" surface to the user
only after a long stall, even though the resolver had no usable material to
attempt with.
Short-circuit doRefreshOAuthTokenWithLock to return null when there is no
refresh token to use, after the in-lock main-store adoption and external
bootstrap-credential checks have already had a chance to recover.
Thanks @romneyda.
Summary:
- The PR wraps the async JSON file readers in `src/infra/json-files.ts` with bounded retries for fs-safe `File changed during read` races, adds regression tests, and adds a changelog entry.
- Reproducibility: yes. Source inspection shows fs-safe throws `File changed during read`, current main re-exp ... R proof includes before/after gateway logs; I did not run a new live race harness in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(json): preserve strict reader types (Promise<T> for readJson/read…
- PR branch already contained follow-up commit before automerge: test(json): add retry-success and retry-exhaustion coverage
- PR branch already contained follow-up commit before automerge: fix(json): resolve lint warnings (prefer-exponentiation-operator, cur…
- PR branch already contained follow-up commit before automerge: fix(json): retry on transient File changed during read race condition
Validation:
- ClawSweeper review passed for head 00602a1c03.
- Required merge gates passed before the squash merge.
Prepared head SHA: 00602a1c03
Review: https://github.com/openclaw/openclaw/pull/85029#issuecomment-4510494668
Co-authored-by: samson1357924 <98934496+samson1357924@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This replacement PR adds inbound delivery diagnostic events, gateway status counters and warnings, transport ... ut, Prometheus/OpenTelemetry metrics, docs, changelog, and regression coverage for gateway delivery health.
- Reproducibility: no. high-confidence live reproduction of the original Feishu failure was run here. Source i ... ch/turn telemetry, and the source PR supplies after-fix live output for the connected WebChat gateway path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(types): restore PR conflict resolution type checks
Validation:
- ClawSweeper review passed for head 6ffe08a9c7.
- Required merge gates passed before the squash merge.
Prepared head SHA: 6ffe08a9c7
Review: https://github.com/openclaw/openclaw/pull/85016#issuecomment-4510224436
Co-authored-by: Andi Liao <liaoandi95@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds Docker/OrbStack host aliases to Ollama local-auth classification, keeps those aliases out of loopback-only discovery suppression, adds regression tests, and updates the changelog.
- Reproducibility: yes. The linked report gives a concrete v2026.5.19 config and error, and current main source shows host.orb.internal is not classified as local for ollama-local marker auth.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ollama): allow Orb host local auth
Validation:
- ClawSweeper review passed for head cb82dcf522.
- Required merge gates passed before the squash merge.
Prepared head SHA: cb82dcf522
Review: https://github.com/openclaw/openclaw/pull/84999#issuecomment-4509786332
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- The branch clears WebChat local run and stream state when terminal session reconciliation completes the acti ... session events, adjusts deferred history/queue flushing, adds regression tests, and updates the changelog.
- Reproducibility: yes. with high confidence from source inspection and PR evidence. Current main can apply a ... PR body, recording, and regression shape show the stale WebChat typing state being cleared by this branch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: harden webchat session run reconciliation
Validation:
- ClawSweeper review passed for head 89cca8dd01.
- Required merge gates passed before the squash merge.
Prepared head SHA: 89cca8dd01
Review: https://github.com/openclaw/openclaw/pull/84565#issuecomment-4498262223
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: jesse-merhi
Add the missing changelog entry for the landed Web Push VAPID subject fix and refresh the config docs baseline hash to match the Node 24 check environment.
Summary:
- The PR preserves native Ollama tool-call IDs through ingest and replay, opts native Ollama out of strict replay ID sanitization, and adds focused regression tests plus a changelog entry.
- Reproducibility: yes. Current main drops native Ollama tool-call IDs on ingest and replay and applies strict ... PR discussion includes a maintainer-side before/after probe that reproduced the source-level failure path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ollama): keep native tool ids through replay
Validation:
- ClawSweeper review passed for head bb9fef7d4c.
- Required merge gates passed before the squash merge.
Prepared head SHA: bb9fef7d4c
Review: https://github.com/openclaw/openclaw/pull/84855#issuecomment-4505423891
Co-authored-by: IWhatsskill <whatsskilll@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
* fix(config): append numeric bound hints to ceiling/floor validation errors
When a config value exceeds a schema-enforced ceiling or falls below a
floor, the error message now includes the constraint explicitly:
- Inclusive: `(maximum: 20)` / `(minimum: 0)`
- Exclusive: `(must be less than 5)` / `(must be greater than 0)`
This matches the clarity that enum/union rejections already get via
`(allowed: …)` hints, and avoids the misleading "minimum: 0" wording
that previous attempts produced for `.positive()` / `.gt(0)` rejections.
Only numeric-origin `too_big`/`too_small` issues are enriched; string,
array, and file-size origins are left unchanged.
Fixes#52500
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(config): update maxFileBytes test for numeric bound hint
The test snapshot for `logging.maxFileBytes: 0` rejection now includes
the `(must be greater than 0)` hint appended by the numeric bound
enrichment added in the previous commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(config): guard nullable record in appendNumericBoundHint call
ClawSweeper P1: `record` from `toIssueRecord()` can be null, but
`appendNumericBoundHint` expects a non-null `UnknownIssueRecord`.
Guard with a ternary so the original message is returned when record
is null (which only happens for malformed/empty issues that already
produce generic "Invalid input" messages).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: tanshanshan <tanshanshan@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(diffs): replace iconMarkup string with ToolbarIconName enum to eliminate XSS sink
Replace createToolbarButton's iconMarkup: string parameter with icon: ToolbarIconName,
a union of known icon names. SVG generation moves into a sealed toolbarIconSvg map so
innerHTML only receives compile-time-known strings. The old splitIcon/unifiedIcon/
wrapIcon/backgroundIcon/themeIcon functions are removed; callers now pass icon name
literals instead of raw markup strings.
Closes#83918
* fix(diffs): remove jsdom dependency from viewer-client test
Use source file string analysis instead of jsdom to avoid missing
@types/jsdom declaration error in check-test-types CI job.
* fix(diffs): restore wrap icon arrow segment in ToolbarIconName map
The wrap-on and wrap-off SVG paths were missing the original wrap arrow
segment (M14 6h-4V5h4.5...). Restore the exact original path data and
rebuild the viewer runtime bundle.
* build(diffs): refresh viewer runtime after rebase
---------
Co-authored-by: tanshanshan <tanshanshan@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Summary:
- The PR adds a diagnostics-otel scoped unhandled-rejection handler for nested OTLPExporterError values, unregisters it on stop/restart, adds regression tests, and adds a changelog entry.
- Reproducibility: yes. The source path is high-confidence: current main has no OTLPExporterError-specific dia ... ror for non-retryable OTLP HTTP failures; I did not run a live collector shutdown in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(diagnostics-otel): avoid stale exporter handler
- PR branch already contained follow-up commit before automerge: fix(diagnostics-otel): suppress exporter rejection crashes
Validation:
- ClawSweeper review passed for head e19c06c992.
- Required merge gates passed before the squash merge.
Prepared head SHA: e19c06c992
Review: https://github.com/openclaw/openclaw/pull/84881#issuecomment-4506249586
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This replacement PR marks the Linux node daemon gateway token as file-backed, writes it to `node.systemd.env`, sanitizes and migrates systemd env artifacts, adds regression tests, and updates the changelog.
- Reproducibility: yes. from source inspection: current `main` copies `OPENCLAW_GATEWAY_TOKEN` into the node s ... e-backed before systemd rendering. I did not run a local live systemd install during this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(systemd): scrub single-quoted env tokens
- PR branch already contained follow-up commit before automerge: [Fix] Keep node systemd tokens out of unit files
Validation:
- ClawSweeper review passed for head f626b66c09.
- Required merge gates passed before the squash merge.
Prepared head SHA: f626b66c09
Review: https://github.com/openclaw/openclaw/pull/84815#issuecomment-4505012292
Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR disables pi-coding-agent auto-retry inside prepared embedded Pi settings, updates the focused settings test, and moves the changelog entry into Unreleased.
- Reproducibility: yes. source-reproducible: current main leaves embedded Pi retry enabled, while pi-coding-ag ... e assistant error before continuing. I did not run a live Feishu/Qwen replay loop in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): disable pi-coding-agent auto-retry to prevent tool call …
Validation:
- ClawSweeper review passed for head ca745fd55d.
- Required merge gates passed before the squash merge.
Prepared head SHA: ca745fd55d
Review: https://github.com/openclaw/openclaw/pull/84798#issuecomment-4504702875
Co-authored-by: yelog <yelogeek@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR filters partial skill snapshot entries in trajectory support metadata, accepts nullish support-redaction paths, adds regression tests, and records the fix in the changelog.
- Reproducibility: yes. Source inspection on current main shows undefined skill path/name values can reach str ... and the related source PR provides redacted live before/after gateway logs for the symlink-escape scenario.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(trajectory): tighten test types for partial skill entries
- PR branch already contained follow-up commit before automerge: fix(trajectory): tolerate partial skill snapshot entries in support c…
Validation:
- ClawSweeper review passed for head ecb3df6c08.
- Required merge gates passed before the squash merge.
Prepared head SHA: ecb3df6c08
Review: https://github.com/openclaw/openclaw/pull/84797#issuecomment-4504703074
Co-authored-by: Luke Boyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Widen the Control UI settings Personal quick-settings card to the intended 3/1 desktop split, keep Personal before Appearance/Automations at the narrower layout, and make the focused CSS assertions tolerant of harmless formatting changes.
Verification:
- pnpm --dir ui test src/styles/config-quick.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/styles/config-quick.test.ts
- git diff --check
- GitHub CI on 4c8f6d7f50
Lazy-load agents CLI action modules from command callbacks so agents --help avoids importing the full agents runtime.
Validated by GitHub required checks and local focused CLI gates.
Summary:
- The PR changes sherpa-onnx CLI audio parsing so structured JSON with an empty `text` field becomes no transcript, while preserving non-empty JSON extraction and adding direct plus auto-detect regression coverage.
- Reproducibility: yes. Source inspection on current main shows empty sherpa structured JSON misses extraction ... scord voice can skip empty transcripts; I did not run a live Discord reproduction in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Fix stale CI guardrails for sherpa transcript PR
- PR branch already contained follow-up commit before automerge: Skip empty sherpa structured transcripts
Validation:
- ClawSweeper review passed for head ac03171cfc.
- Required merge gates passed before the squash merge.
Prepared head SHA: ac03171cfc
Review: https://github.com/openclaw/openclaw/pull/84667#issuecomment-4501484167
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR removes MiniMax music duration support from provider capabilities and docs, stops prompt-injecting duration hints, updates the MiniMax provider test, and adds a changelog entry.
- Reproducibility: yes. by source inspection: current main advertises MiniMax duration support while the reque ... uage hint. I did not rerun a live pre-fix MiniMax request, but the code path and vendor contract are clear.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(minimax): align music controls
- PR branch already contained follow-up commit before automerge: docs(music): remove minimax duration steering claim
- PR branch already contained follow-up commit before automerge: fix(minimax): stop advertising music duration control
Validation:
- ClawSweeper review passed for head 1c616da45c.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1c616da45c
Review: https://github.com/openclaw/openclaw/pull/84765#issuecomment-4504176794
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates Codex app-server system-prompt reporting to tolerate bootstrap files with `path` and `content` but no `name`, adds a focused regression test, and records the fix in the changelog.
- Reproducibility: yes. The PR body supplies current-main before output with the `undefined.trim()` stack, and source inspection confirms hook-supplied path-only bootstrap files can reach the Codex report helper.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(codex): guard path-only bootstrap files [AI-assisted]
Validation:
- ClawSweeper review passed for head 4667110899.
- Required merge gates passed before the squash merge.
Prepared head SHA: 4667110899
Review: https://github.com/openclaw/openclaw/pull/84736#issuecomment-4503672362
Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Adds a `doctor` security warning for plaintext secret-bearing `openclaw.json` fields by reusing the secrets target registry and shared model-provider header sensitivity policy.
- Reproducibility: yes. for source-level behavior: current main has plaintext secret audit coverage but no doc ... llector for those config targets, and the PR body includes live patched CLI output showing the new warning.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Warn on plaintext secret config in doctor
Validation:
- ClawSweeper review passed for head 31f83aae19.
- Required merge gates passed before the squash merge.
Prepared head SHA: 31f83aae19
Review: https://github.com/openclaw/openclaw/pull/84718#issuecomment-4503210496
Co-authored-by: qingsenlab <qingsenlab@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR removes the legacy `cat SKILL.md && printf ... && <skill-wrapper>` exec-approval allowlist path, updates focused exec-approval tests, and adds a changelog entry.
- Reproducibility: yes. Current-main source and tests show the old `cat SKILL.md && printf ... && <wrapper>` c ... ed this by source and test inspection rather than executing tests because the checkout review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Remove skill prelude exec allowlist
Validation:
- ClawSweeper review passed for head 0ca7f3e8ef.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0ca7f3e8ef
Review: https://github.com/openclaw/openclaw/pull/84570#issuecomment-4498357535
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: jesse-merhi
* perf(tui): skip plugin-aware config validation on remote TUI startup
Cold `openclaw tui` against a remote gateway was synchronously calling
loadPluginMetadataSnapshot() via getRuntimeConfig() -> loadConfig() ->
validateConfigObjectWithPlugins(), pulling the full plugin metadata
snapshot (200k+ file reads) onto the TUI's event loop. The TUI itself
never consumes plugin metadata in remote mode; it queries the gateway
over RPC. The work was being done purely to validate the config and
then thrown away.
Thread an opt-in `skipPluginValidation` flag through getRuntimeConfig()
and loadConfig() (createConfigIO already supports pluginValidation: "skip";
it just wasn't reachable from the runtime entrypoints). The TUI passes
skipPluginValidation: !isLocalMode so:
- Remote-mode TUI: no plugin metadata load, no event-loop freeze after
first render
- Embedded (--local) mode: unchanged; the in-process agent runtime
still gets a fully validated config
* remove verbose comments
* perf(tui): move context cache warmup from module top-level to embedded backend
agents/context.ts fired ensureContextWindowCacheLoaded() unconditionally
at module-eval time for non-skip-listed CLI commands. The TUI transitively
imports this module, so the warmup ran on every TUI startup including
remote-mode, cascading into ensureOpenClawModelsJson -> resolveImplicitProviders
-> runProviderCatalog and dominating the cold-start freeze (CPU profile
showed ~55s of resolveProviderSyntheticAuthWithPlugin, lstat, open, etc.).
It also pre-emptively called getRuntimeConfig() without skipPluginValidation,
pinning the full snapshot and nullifying the skip flag added on this branch.
Remove the top-level side effect and trigger the warmup explicitly from
EmbeddedTuiBackend.start(), which only runs when an in-process agent
runtime actually needs the cache.
* perf(tui): defer EmbeddedTuiBackend import until local mode
* refactor(agents): remove dead context-cache warmup helpers
* perf(tui): skip plugin-aware config validation on remote TUI startup
Cold `openclaw tui` against a remote gateway was synchronously calling
loadPluginMetadataSnapshot() via getRuntimeConfig() -> loadConfig() ->
validateConfigObjectWithPlugins(), pulling the full plugin metadata
snapshot (200k+ file reads) onto the TUI's event loop. The TUI itself
never consumes plugin metadata in remote mode; it queries the gateway
over RPC. The work was being done purely to validate the config and
then thrown away.
Thread an opt-in `skipPluginValidation` flag through getRuntimeConfig()
and loadConfig() (createConfigIO already supports pluginValidation: "skip";
it just wasn't reachable from the runtime entrypoints). The TUI passes
skipPluginValidation: !isLocalMode so:
- Remote-mode TUI: no plugin metadata load, no event-loop freeze after
first render
- Embedded (--local) mode: unchanged; the in-process agent runtime
still gets a fully validated config
* remove verbose comments
* perf(tui): move context cache warmup from module top-level to embedded backend
agents/context.ts fired ensureContextWindowCacheLoaded() unconditionally
at module-eval time for non-skip-listed CLI commands. The TUI transitively
imports this module, so the warmup ran on every TUI startup including
remote-mode, cascading into ensureOpenClawModelsJson -> resolveImplicitProviders
-> runProviderCatalog and dominating the cold-start freeze (CPU profile
showed ~55s of resolveProviderSyntheticAuthWithPlugin, lstat, open, etc.).
It also pre-emptively called getRuntimeConfig() without skipPluginValidation,
pinning the full snapshot and nullifying the skip flag added on this branch.
Remove the top-level side effect and trigger the warmup explicitly from
EmbeddedTuiBackend.start(), which only runs when an in-process agent
runtime actually needs the cache.
Summary:
- The PR extracts JSON-mode console-to-stderr routing into a shared CLI helper, wraps root and `nodes` lazy plugin registration, adds nodes registration coverage, and adds a changelog entry.
- Reproducibility: yes. for source-level reproduction: the linked report shows `openclaw nodes list --json 2> ... ssing the existing JSON stderr guard. I did not run the live Helm/container repro in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Route JSON-mode plugin registration logs to stderr
Validation:
- ClawSweeper review passed for head c9d0867db0.
- Required merge gates passed before the squash merge.
Prepared head SHA: c9d0867db0
Review: https://github.com/openclaw/openclaw/pull/84741#issuecomment-4503741078
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* build: suppress rolldown-plugin-dts CommonJS dts warnings from bundled zod locales
After bumping rolldown-plugin-dts to 0.25.1 (94ac563399), every
`pnpm build` emits a 'CommonJS dts' warning per zod `v4/locales/*.d.cts`
file because zod is intentionally inlined for global pnpm install
resolution (#78515) and tsdown's external option cannot be scoped to the
dts pass only. Filter the warning in the existing onLog suppression list
(same pattern as PLUGIN_TIMINGS / UNRESOLVED_IMPORT / EVAL) so other
rolldown-plugin-dts warnings remain visible.
* docs(changelog): move rolldown-dts entry into 2026.5.20 fixes
Summary:
- The PR updates the macOS About settings copyright text to 2026, adds a changelog entry, and adjusts changed-check planning so non-macOS hosts without SwiftLint emit an explicit app-lint skip with matching test coverage.
- Reproducibility: yes. from source inspection: current main still renders the 2025 copyright literal in the m ... launch the app locally, but the source path and source PR proof make the observable issue high-confidence.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8438…
Validation:
- ClawSweeper review passed for head 26816c18d6.
- Required merge gates passed before the squash merge.
Prepared head SHA: 26816c18d6
Review: https://github.com/openclaw/openclaw/pull/84729#issuecomment-4503529931
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Followup nits from the #84711 review:
- Narrow the inspectTokenFile catch in
extensions/telegram/src/account-inspect.ts to FsSafeError so only
fs-safe validation throws map to configured_unavailable; any other
throw (programmer error, unexpected I/O) is rethrown.
- Add a regression test for the IRC NickServ password file symlink
rejection path (extensions/irc/src/accounts.ts:118), paralleling the
existing top-level passwordFile test.
- Add a regression test for the Telegram account-level tokenFile
symlink rejection path (extensions/telegram/src/token.ts:149),
paralleling the existing channel-level tokenFile test.
Behavior was already correct after #84711; this just locks coverage and
tightens the catch.
* fix(infra): restore symlink rejection in tryReadSecretFileSync
The local wrapper added in 9e4eca00ff swallowed all errors from
@openclaw/fs-safe@0.2.7's tryReadSecretFileSync via a bare try/catch,
silently downgrading every rejectSymlink: true caller (Telegram, LINE,
Zalo, IRC, Nextcloud Talk credential files) to accept symlinked
credential files. It also broke the infra-state CI shard's symlink
expectation that #84595 had just realigned with the new fail-closed
upstream contract.
Restore the direct re-export so the upstream contract surfaces:
undefined for blank/missing/not-found, FsSafeError for symlink,
oversize, non-regular file, and hardlink validation failures.
* test(plugins): align stale symlink tests with fail-closed contract
5 token/account resolver tests still asserted the pre-fs-safe-0.2.7
"silent skip" behavior (token: "", source: "none") on rejected symlinks;
they passed only because the swallow-all wrapper in secret-file.ts hid
the throw. Restoring the upstream fail-closed contract surfaces the
throw, so update the tests to expect FsSafeError.
inspectTelegramAccount reports credential status (its return type has an
explicit configured_unavailable state for "configured but unreadable"),
so its callsite is the right boundary to catch the FsSafeError and map
it to configured_unavailable rather than letting the throw bubble.
Affected:
- extensions/zalo/src/token.test.ts
- extensions/line/src/accounts.test.ts
- extensions/telegram/src/token.test.ts
- extensions/irc/src/accounts.test.ts
- extensions/nextcloud-talk/src/setup.test.ts
- extensions/telegram/src/account-inspect.ts (catch + report status)
Summary:
- This PR filters exported sub-CLI descriptors through the private-QA gate, centralizes that filter, adds regr ... ge, and carries small validation repairs in workspace glob and tunnel-timeout tests plus a changelog entry.
- Reproducibility: yes. Current-main source shows the raw SUB_CLI_DESCRIPTORS export can include qa while the helper surfaces filter it, and src/cli/argv.ts consumes that export for root command policy.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): gate exported subcli descriptors
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8451…
Validation:
- ClawSweeper review passed for head ba197a6f30.
- Required merge gates passed before the squash merge.
Prepared head SHA: ba197a6f30
Review: https://github.com/openclaw/openclaw/pull/84519#issuecomment-4496549642
Co-authored-by: Zhaocun <zhaocunsun@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch threads `agents.defaults.imageMaxDimensionPx` into browser screenshot and labeled snapshot image results, adds regression coverage and a changelog entry, and includes small repair-pass type/lint cleanup.
- Reproducibility: yes. source-level reproduction is high confidence: current `main` calls `imageResultFromFil ... both browser image-returning paths, while the shared sanitizer falls back to `1200px` without an override.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(browser): honor image sanitization config for screenshots
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8459…
Validation:
- ClawSweeper review passed for head c01fde7990.
- Required merge gates passed before the squash merge.
Prepared head SHA: c01fde7990
Review: https://github.com/openclaw/openclaw/pull/84595#issuecomment-4499178477
Co-authored-by: Xu Xiang <xx205@outlook.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Add bounded realtime profile context for Discord realtime voice sessions.
Default to `IDENTITY.md`, `USER.md`, and `SOUL.md`; `voice.realtime.bootstrapContextFiles: []` disables the extra context.
Document the config/SDK surface and refresh generated metadata.
Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
Summary:
- The PR updates `src/cli/shared/parse-port.test.ts` to cover numeric strings, whitespace-padded strings, fractional strings, invalid suffixes, and safe-integer overflow for `parsePort`.
- Reproducibility: not applicable. This PR adds test coverage rather than reporting a failing runtime behavior. Source inspection confirms the current parser contract and the exact baseline coverage gap on main.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 14213cc8f4.
- Required merge gates passed before the squash merge.
Prepared head SHA: 14213cc8f4
Review: https://github.com/openclaw/openclaw/pull/84518#issuecomment-4496552268
Co-authored-by: googlerest <127843198+googlerest@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Fixes openclaw#84386. resolveActiveProfileId in extensions/codex/src/command-account.ts returned store.lastGood whenever that profile was still in the resolved order, ignoring rank, so /codex account marked the stale openai-codex:default profile as active after models auth login + models auth order set. Tracks whether the order came from an explicit operator source (store.order / config.auth.order, including the openai alias key), picks the first usable explicit-order profile, and returns undefined when no candidate is eligible so the display surfaces "no working credential" instead of marking a lower-ranked profile active. Runtime selection via resolveCodexAppServerAuthProfileId is unchanged.
* perf(plugins): extend discovery threading to loader, manifest registry, installed-index, and config contracts
Follow-up to #75451. Threads optional discovery?: PluginDiscoveryResult
through the remaining helpers that still call discoverOpenClawPlugins
internally during startup:
- loadOpenClawPlugins / loadOpenClawPluginCliRegistry (src/plugins/loader.ts):
add discovery? to PluginLoadOptions and consult it before falling back to
an internal scan at both call sites.
- loadPluginManifestRegistry (src/plugins/manifest-registry.ts): accept
discovery? as a more ergonomic alternative to the existing candidates? /
diagnostics? pair; candidates? still wins when both are supplied.
- resolveInstalledPluginIndexRegistry (src/plugins/installed-plugin-index-registry.ts):
add discovery? to LoadInstalledPluginIndexParams and use it when
candidates aren't supplied.
- resolvePluginConfigContractsById (src/plugins/config-contracts.ts): add
discovery? and thread it into the bundled-fallback discovery call.
Add discovery-threading.test.ts asserting each entry point skips its
internal discoverOpenClawPlugins call when discovery is supplied, calls it
when nothing is supplied, and prefers explicit candidates over discovery
when both are present (6 tests, all pass).
discoverOpenClawPlugins remains stateless; sharing is function-scoped per
src/plugins/CLAUDE.md guidance. Backward compatible: every change is
additive (new optional param).
* perf(plugins): drop verbose JSDoc from discovery? params
* perf(plugins): scan-scoped package.json cache in discovery
Adds a per-scan Map<string, PackageManifest | null> threaded through
discoverFromPath/discoverInDirectory/readCandidatePackageManifest, keyed
by the directory's resolved real path. Within one discovery scan, a
plugin's package.json is now read from disk once and reused across the
overlapping discovery code paths (bundled overlay scan, stock-root scan,
source-checkout extensions scan, installed-path scan, global-root scan)
that previously each fired their own read.
The cache lifetime is one scan (created in runPluginDiscovery alongside
the existing realpathCache and seen Set, dies when the scan returns).
discoverOpenClawPlugins remains stateless externally; no persistent
metadata cache.
* perf(plugins): expose raw parsed package.json on PluginCandidate
Discovery already reads each plugin's package.json once and produces a
parsed PackageManifest object before distilling it into metadata via
getPackageManifestMetadata. Currently only the distilled metadata is
kept on the candidate; the full parsed manifest is discarded.
Store the full parsed manifest on rawPackageManifest so downstream
consumers iterating candidates can use it instead of re-reading from
disk. This is the candidate-side groundwork for the scenario-C followup
that routes consumers (bundled-plugin-metadata, bundle-* helpers, etc.)
through the cached field; those consumers currently do their own
directory scans and would need to be refactored to iterate
PluginCandidate arrays before they can benefit.
The field is a frozen-at-discovery-time snapshot, same lifetime semantics
as the existing packageManifest / packageName / packageVersion fields on
PluginCandidate. No new staleness window introduced.
* perf(plugins): make package-manifest cache key trust-aware
Summary:
- Adds a 50-page and advancing-`nextOffset` guard to `loadCronJobForShow`, exports that helper for regression tests, and adds an unreleased changelog entry.
- Reproducibility: yes. Current main is source-reproducible because `loadCronJobForShow` loops while `hasMore` ... ed numeric `nextOffset`; the PR discussion also includes terminal before/after proof for the same CLI path.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 7828b4bdae.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7828b4bdae
Review: https://github.com/openclaw/openclaw/pull/83989#issuecomment-4484474655
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The replacement branch adds an owned transcript write context around Pi prompt-time delivery mirror appends and a message-tool-only terminal hook, with focused tests and a changelog entry.
- Reproducibility: yes. the source PR includes before/after redacted live Discord logs for a message-tool-only ... ession-lock and transcript append code. I did not rerun the live Discord scenario in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(pi): keep message-tool delivery in session lock
Validation:
- ClawSweeper review passed for head f16678175c.
- Required merge gates passed before the squash merge.
Prepared head SHA: f16678175c
Review: https://github.com/openclaw/openclaw/pull/84437#issuecomment-4494545360
Co-authored-by: Andrew Meyer <andrewmeyer@andrews-air.lan>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR changes cron store loading to normalize legacy top-level array `jobs.json` files into the versioned store shape and adds store, service, doctor, gateway tests plus a changelog entry.
- Reproducibility: yes. Current `main` clearly maps a top-level parsed array to `{}` before reading `.jobs`, and the PR body supplies before/after runtime output for the load/add/save path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: [AI-assisted] fix(cron): preserve legacy array stores
Validation:
- ClawSweeper review passed for head 446014b4c1.
- Required merge gates passed before the squash merge.
Prepared head SHA: 446014b4c1
Review: https://github.com/openclaw/openclaw/pull/84433#issuecomment-4494478724
Co-authored-by: JARVIS-Glasses <284122573+JARVIS-Glasses@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds a Warning block to `docs/channels/imessage.md` explaining that iMessage `cliPath` wrappers and SSH proxies must stream long-lived JSON-RPC stdin/stdout incrementally.
- Reproducibility: not applicable. for this docs-only PR. Source inspection verifies the runtime uses long-lived line-framed stdio, and current main lacks the operator warning being added.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(imessage): warn that cliPath wrappers must stream JSON-RPC stdio…
Validation:
- ClawSweeper review passed for head a371ee998e.
- Required merge gates passed before the squash merge.
Prepared head SHA: a371ee998e
Review: https://github.com/openclaw/openclaw/pull/84420#issuecomment-4494313781
Co-authored-by: HCL <chenglunhu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch caps async diagnostic drains at 100 events per turn, adds pending/full-drain diagnostic helpers, ... rminal diagnostics to inspect pending events, and adds regression coverage plus changelog/baseline updates.
- Reproducibility: yes. from source inspection. Current main drains the entire async diagnostic queue in one s ... ck, and the PR body supplies a focused 250-event after-fix probe showing 100/200/250 delivery across turns.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: yield diagnostic event drains
Validation:
- ClawSweeper review passed for head 95610934cd.
- Required merge gates passed before the squash merge.
Prepared head SHA: 95610934cd
Review: https://github.com/openclaw/openclaw/pull/82937#issuecomment-4469498220
Co-authored-by: Galin Iliev <galini@microsoft.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Marks skipped and supplemental Microsoft Teams system events as non-owner/untrusted while preserving active primary message dispatch behavior.
Verified before merge:
- PR was open, not draft, mergeable, and clean against main
- Matched head: 4f79f46205
- GitHub checks passed, including Real behavior proof, auto-response, build artifacts, type/lint checks, channel/runtime critical quality checks, and security-fast
- ClawSweeper marked proof sufficient with no concrete contributor-facing blocker remaining
Co-authored-by: GuoJiaming <804436395@qq.com>
Summary:
- The branch gives Codex `image_generate` dynamic-tool calls a 120s default watchdog in main and side-thread paths and updates docs, tests, and changelog.
- Reproducibility: yes. Source inspection on current main shows unconfigured Codex `image_generate` calls fall ... -tool default, and the linked source PR includes live Gateway before/after output for the timeout behavior.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8425…
- PR branch already contained follow-up commit before automerge: Fix Codex image generation tool timeout
Validation:
- ClawSweeper review passed for head 10c7f87023.
- Required merge gates passed before the squash merge.
Prepared head SHA: 10c7f87023
Review: https://github.com/openclaw/openclaw/pull/84369#issuecomment-4493288493
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: moritzmmayerhofer <254141390+moritzmmayerhofer@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates the code-mode exec tool description, adds regression coverage for the model-visible constraints, and records the fix in the changelog.
- Reproducibility: yes. at source level: current main's exec schema omits constraints that the current code-mo ... also includes a live before/after recitation path showing the model receives the changed tool description.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(code-mode): cover exec tool guidance
- PR branch already contained follow-up commit before automerge: fix(code-mode): sharpen exec tool description so models stop wasting …
Validation:
- ClawSweeper review passed for head 8ff85071ce.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8ff85071ce
Review: https://github.com/openclaw/openclaw/pull/84368#issuecomment-4493273853
Co-authored-by: Kaspre <kaspre@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates Gateway agent summary builders to use `agents.list[].identity.name` when explicit `agents.list[].name` is absent, adds focused gateway regression tests, and records a changelog fix.
- Reproducibility: yes. Current main can be source-reproduced: both gateway summary builders set top-level `na ... list[].name`, so identity-only configured agents have no summary name for consumers that read `agent.name`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(gateway): cover missing agent summary names
- PR branch already contained follow-up commit before automerge: fix(gateway): remove stale name fallback import
- PR branch already contained follow-up commit before automerge: gateway: use identity.name in agent summaries when name is unset
Validation:
- ClawSweeper review passed for head 9f7024f55c.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9f7024f55c
Review: https://github.com/openclaw/openclaw/pull/84355#issuecomment-4493008710
Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR promotes direct or nested send receipt IDs into `openclaw message send --json`, adds a focused command test, and adds a changelog entry.
- Reproducibility: yes. at source level. Current main serializes only the raw payload while send receipts can carry `payload.result.messageId`; I did not execute the CLI in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(cli): fix message json payload type
- PR branch already contained follow-up commit before automerge: chore: retrigger PR checks
- PR branch already contained follow-up commit before automerge: Expose messageId in message CLI JSON output
Validation:
- ClawSweeper review passed for head 9eba815fcc.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9eba815fcc
Review: https://github.com/openclaw/openclaw/pull/84191#issuecomment-4489100591
Co-authored-by: OpenClaw Contributor <100menotu001@users.noreply.github.com>
Co-authored-by: Craig <froelich@craigs.mac.studio.froho>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- Adds `disabled` to the message presentation button schema, advertises Discord disabled-button support, prese ... through Discord component mapping and link serialization, and adds regression tests plus a changelog entry.
- Reproducibility: yes. Source inspection on current main shows `disabled` exists in the runtime type but is a ... rtised in Discord capabilities, dropped by adaptation, and omitted from Discord mapping/link serialization.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(discord): advertise disabled presentation support
- PR branch already contained follow-up commit before automerge: fix(discord): preserve disabled link buttons
- PR branch already contained follow-up commit before automerge: Preserve disabled Discord presentation buttons
Validation:
- ClawSweeper review passed for head 9bb60d8cbf.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9bb60d8cbf
Review: https://github.com/openclaw/openclaw/pull/84312#issuecomment-4491983845
Co-authored-by: OpenClaw Contributor <100menotu001@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR adds scoped truncation and hover titles to usage-panel context-breakdown names and adds a changelog entry crediting the source PR.
- Reproducibility: yes. at source/proof level: current main renders long context names without truncation or t ... he overflow before and ellipsis/tooltip after. I did not run a live browser session in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat(ui): tool name style in usage panel
Validation:
- ClawSweeper review passed for head 396e405b3b.
- Required merge gates passed before the squash merge.
Prepared head SHA: 396e405b3b
Review: https://github.com/openclaw/openclaw/pull/84310#issuecomment-4491942108
Co-authored-by: Rain120 <1085131904@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* perf(plugins): extend discovery threading to loader, manifest registry, installed-index, and config contracts
Follow-up to #75451. Threads optional discovery?: PluginDiscoveryResult
through the remaining helpers that still call discoverOpenClawPlugins
internally during startup:
- loadOpenClawPlugins / loadOpenClawPluginCliRegistry (src/plugins/loader.ts):
add discovery? to PluginLoadOptions and consult it before falling back to
an internal scan at both call sites.
- loadPluginManifestRegistry (src/plugins/manifest-registry.ts): accept
discovery? as a more ergonomic alternative to the existing candidates? /
diagnostics? pair; candidates? still wins when both are supplied.
- resolveInstalledPluginIndexRegistry (src/plugins/installed-plugin-index-registry.ts):
add discovery? to LoadInstalledPluginIndexParams and use it when
candidates aren't supplied.
- resolvePluginConfigContractsById (src/plugins/config-contracts.ts): add
discovery? and thread it into the bundled-fallback discovery call.
Add discovery-threading.test.ts asserting each entry point skips its
internal discoverOpenClawPlugins call when discovery is supplied, calls it
when nothing is supplied, and prefers explicit candidates over discovery
when both are present (6 tests, all pass).
discoverOpenClawPlugins remains stateless; sharing is function-scoped per
src/plugins/CLAUDE.md guidance. Backward compatible: every change is
additive (new optional param).
* perf(plugins): drop verbose JSDoc from discovery? params
Summary:
- The PR updates `src/infra/clawhub.ts` URL joining, adds a path-prefix regression test in `src/infra/clawhub.test.ts`, and adds a changelog bullet.
- Reproducibility: yes. Source inspection plus a direct Node URL check show current main drops `/clawhub` when resolving a leading-slash API path against a prefixed base URL.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(clawhub): preserve base URL path prefix [AI-assisted]
Validation:
- ClawSweeper review passed for head 7bb2cb8764.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7bb2cb8764
Review: https://github.com/openclaw/openclaw/pull/83982#issuecomment-4484348274
Co-authored-by: Thiago Costa <thiago12_fera@hotmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Fixes#83901. Honors Commander negated option handling for ACP prompt-prefix forwarding and adds focused CLI regression coverage. Verified with Crabbox AWS cbx_1689d0ad78e9 run run_a406418db6fe and Real behavior proof run 26127392365.
Summary:
- The PR registers Twitch refreshing-token users with Twurple's chat intent and adds regression coverage for that contract.
- Reproducibility: yes. by source and dependency contract. Current main does not register the chat intent, and ... RefreshingAuthProvider only resolves getAccessTokenForIntent('chat') when that intent is mapped to a user.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(twitch): register chat intent for refreshing auth
Validation:
- ClawSweeper review passed for head 1fdadcff04.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1fdadcff04
Review: https://github.com/openclaw/openclaw/pull/83750#issuecomment-4481748086
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- The PR pins managed Gateway package updates, runtime preflight, post-install doctor, post-core update, service refresh, and restart follow-ups to the Node binary and package root baked into the Gateway service.
- Reproducibility: yes. source-level. Current main validates and follows up with the shell process Node in the ... body provides a concrete two-Node Docker reproduction, though I did not execute it in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(update): detect service node mismatch even when package roots match
- PR branch already contained follow-up commit before automerge: fix(update): pin package install to service root when nodes differ wi…
Validation:
- ClawSweeper review passed for head 5607e441f6.
- Required merge gates passed before the squash merge.
Prepared head SHA: 5607e441f6
Review: https://github.com/openclaw/openclaw/pull/84043#issuecomment-4485613931
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Co-authored-by: Alex Knight <aknight@atlassian.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: amknight
Co-authored-by: amknight <15041791+amknight@users.noreply.github.com>
Follow-up to #75451. Threads optional discovery?: PluginDiscoveryResult
through the remaining helpers that still call discoverOpenClawPlugins
internally during startup:
- loadOpenClawPlugins / loadOpenClawPluginCliRegistry (src/plugins/loader.ts):
add discovery? to PluginLoadOptions and consult it before falling back to
an internal scan at both call sites.
- loadPluginManifestRegistry (src/plugins/manifest-registry.ts): accept
discovery? as a more ergonomic alternative to the existing candidates? /
diagnostics? pair; candidates? still wins when both are supplied.
- resolveInstalledPluginIndexRegistry (src/plugins/installed-plugin-index-registry.ts):
add discovery? to LoadInstalledPluginIndexParams and use it when
candidates aren't supplied.
- resolvePluginConfigContractsById (src/plugins/config-contracts.ts): add
discovery? and thread it into the bundled-fallback discovery call.
Add discovery-threading.test.ts asserting each entry point skips its
internal discoverOpenClawPlugins call when discovery is supplied, calls it
when nothing is supplied, and prefers explicit candidates over discovery
when both are present (6 tests, all pass).
discoverOpenClawPlugins remains stateless; sharing is function-scoped per
src/plugins/CLAUDE.md guidance. Backward compatible: every change is
additive (new optional param).
Add optional discovery parameter to loadBundledCapabilityRuntimeRegistry,
resolveBundledPluginSources, and listChannelCatalogEntries so callers
that already hold a PluginDiscoveryResult can skip redundant filesystem
walks.
In contracts/registry.ts, the retry loop in
loadScopedCapabilityRuntimeRegistryEntries computes discovery once
and shares it across retry attempts (function-scoped, not module-scoped).
discoverOpenClawPlugins() itself remains stateless with no hidden cache.
Closes#82308
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Summary:
- The PR changes one bullet in `docs/tools/slash-commands.md` to distinguish `/new` from `/reset` and remove the misleading alias wording.
- Reproducibility: yes. Reading current main reproduces the misleading docs line at `docs/tools/slash-commands.md:127`, and adjacent source/tests show `/new` and `/reset` take different paths in the Control UI.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs/slash-commands: drop inaccurate Control UI/ACP cross-reference (…
- PR branch already contained follow-up commit before automerge: Merge branch 'main' into docs/fix-reset-alias-misleading
Validation:
- ClawSweeper review passed for head bb92b6050a.
- Required merge gates passed before the squash merge.
Prepared head SHA: bb92b6050a
Review: https://github.com/openclaw/openclaw/pull/81073#issuecomment-4432165259
Co-authored-by: Md. Al-Mosabbir Rakib <mrakib50.cse@gmail.com>
Co-authored-by: Md. Al-Mosabbir Rakib <34891461+mosabbirrakib@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates `docs/cli/gateway.md` and `docs/reference/test.md` to document Gateway startup/restart benchmark prerequisites, commands, case IDs, probes, output semantics, and platform limits.
- Reproducibility: not applicable. as a runtime bug; docs correctness is source-checkable against the benchmar ... ipts, and readiness source. The current PR head corrected the earlier startup-hook readiness wording issue.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(gateway): correct benchmark readiness wording
Validation:
- ClawSweeper review passed for head 5bd0f6c463.
- Required merge gates passed before the squash merge.
Prepared head SHA: 5bd0f6c463
Review: https://github.com/openclaw/openclaw/pull/83866#issuecomment-4483820005
Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
The schema.help text for `models.providers.*.timeoutSeconds` documents the
key as the user-facing knob for "slow local or self-hosted model servers".
In practice the option is also the only configurable lever for the LLM
idle/first-token watchdog. However `resolveLlmIdleTimeoutMs` was still
running the explicit provider timeout through `clampImplicitTimeoutMs`,
clamping it back down to the implicit ~120s `DEFAULT_LLM_IDLE_TIMEOUT_MS`
ceiling for any non-cron, non-local provider.
Consequence (matches #77744 and #78361):
- User sets `models.providers.llamacpp.timeoutSeconds: 14400` (or 600 for
a slow Gemini/Opus turn with a large tool payload).
- Hot reload accepts the value, runtime resolves
`modelRequestTimeoutMs = 14_400_000`.
- Idle watchdog still trips at ~120s with
"LLM idle timeout (120s): no response from model", aborting an
otherwise-healthy upstream that is mid-prefill or buffering thinking
tokens.
Fix: when the caller passes an explicit `modelRequestTimeoutMs`
(sourced from `models.providers.<id>.timeoutSeconds` /
`model.requestTimeoutMs`), treat it as a deliberate ceiling for cloud
providers too. The run-timeout / agent-timeout bounds still apply via
`timeoutBounds`, so a shorter explicit run timeout always wins. The
implicit default watchdog still kicks in when the user has not set a
provider timeout, preserving the network-silence-as-hang guard for
default configs.
Updated the two corresponding test cases that asserted the old
clamp-on-cloud behavior; all 71 tests in `llm-idle-timeout.test.ts`
and the wider 430-test `src/agents/pi-embedded-runner/run/` lane pass.
Schema help text refreshed to call out that the same knob raises the
idle watchdog ceiling.
Refs: #77744, #78361
Summary:
- The PR changes `openclaw acp client` error handling to use `formatErrorMessage`, adds a plain-object rejection regression test, and adds a changelog entry.
- Reproducibility: yes. Current main visibly sends `openclaw acp client` caught errors through `String(err)`, ... catch already uses `formatErrorMessage`; I did not run a live failing ACP server in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): format acp client errors with formatErrorMessage (#83904)
Validation:
- ClawSweeper review passed for head 69ef0e7270.
- Required merge gates passed before the squash merge.
Prepared head SHA: 69ef0e7270
Review: https://github.com/openclaw/openclaw/pull/84080#issuecomment-4486666922
Co-authored-by: HCL <chenglunhu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch adds per-agent `agents.list[].experimental.localModelLean` config and applies lean tool filtering through agent, session, and default-agent resolution.
- Reproducibility: not applicable. this is a feature/config PR rather than a current-main bug report. The chan ... or is supported by source review, focused tests in the branch, and the PR body's redacted live runtime log.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat(agents): support per-agent local model lean mode
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8407…
Validation:
- ClawSweeper review passed for head 1f9a9554da.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1f9a9554da
Review: https://github.com/openclaw/openclaw/pull/84073#issuecomment-4486397570
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- The PR updates `openclaw channels logs` tail-window reading to keep a complete first line when the 1 MB window starts on a newline boundary, adds a regression test, and adds a changelog entry.
- Reproducibility: yes. Source inspection on current main shows the unconditional first-line drop, and the PR ... s provide terminal before/after CLI output for a 2 MB log whose tail window starts exactly after a newline.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Merge remote-tracking branch 'origin/main' into fix/channels-logs-dro…
- PR branch already contained follow-up commit before automerge: fix(cli): preserve first line of channels logs at window boundary
Validation:
- ClawSweeper review passed for head 284b312b31.
- Required merge gates passed before the squash merge.
Prepared head SHA: 284b312b31
Review: https://github.com/openclaw/openclaw/pull/84106#issuecomment-4487313048
Co-authored-by: BSG2000 <bsg2000@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch updates queue-by-channel config schema/types for Matrix, Google Chat, and Mattermost, refreshes config baseline hashes, adds config/schema regression tests, and records the user-visible fix in the changelog.
- Reproducibility: yes. Source inspection gives a high-confidence path: current main's strict `messages.queue. ... matrix`, and the linked source PR records the same config failing before the patch and validating after it.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 3865178550.
- Required merge gates passed before the squash merge.
Prepared head SHA: 3865178550
Review: https://github.com/openclaw/openclaw/pull/84104#issuecomment-4487285061
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Adds shared Control UI session-run active-state handling, applies terminal-status precedence in chat/session rendering and lifecycle recovery, and adds focused regressions plus a changelog entry.
- Reproducibility: yes. Current main has a source-visible path where `status: "done"` plus stale `hasActiveRun ... eeps abort/in-progress UI alive, and the linked proof exercises the fixed stale-terminal state in Chromium.
Automerge notes:
- PR branch already contained follow-up commit before automerge: [codex] Fix Control UI terminal run status recovery
Validation:
- ClawSweeper review passed for head f9f503add0.
- Required merge gates passed before the squash merge.
Prepared head SHA: f9f503add0
Review: https://github.com/openclaw/openclaw/pull/84112#issuecomment-4487409085
Co-authored-by: NianJiuZst <3235467914@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR updates CLI root option parsing to preserve embedded equals signs, adds focused Vitest coverage for inline and space-separated values, and records the fix in the changelog.
- Reproducibility: yes. by source inspection: current main uses `raw.split("=", 2)`, so `--token=abc=def` returns only `abc`; the PR body also supplies after-fix live output for the same path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): preserve equals in root option values [AI-assisted]
Validation:
- ClawSweeper review passed for head 8a15801e79.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8a15801e79
Review: https://github.com/openclaw/openclaw/pull/84107#issuecomment-4487314163
Co-authored-by: Thiago Costa <thiago12_fera@hotmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds a 65,535 upper-bound check to the shared CLI `parsePort` helper, a colocated regression test, and a changelog entry for the linked port-range bug.
- Reproducibility: yes. Source inspection on current main shows `parsePort('99999')` delegates to `parseStrict ... sitive safe integer, so the return would be `99999`; I did not execute it because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): reject out-of-range port numbers in parsePort (#83900)
Validation:
- ClawSweeper review passed for head 9ad0705c44.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9ad0705c44
Review: https://github.com/openclaw/openclaw/pull/84008#issuecomment-4484883200
Co-authored-by: HCL <chenglunhu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR moves the existing Motivation section in `.github/pull_request_template.md` from below Linked Issue/PR to immediately after Summary without changing the section text.
- Reproducibility: not applicable. this is a PR-template ordering cleanup, not a runtime bug. Source inspection of current main and the PR head verifies the before/after section order.
Automerge notes:
- PR branch already contained follow-up commit before automerge: chore: move Motivation section above Change Type in PR template
Validation:
- ClawSweeper review passed for head 6c68583fac.
- Required merge gates passed before the squash merge.
Prepared head SHA: 6c68583fac
Review: https://github.com/openclaw/openclaw/pull/84098#issuecomment-4487082864
Co-authored-by: Huan Jiang <seraphjiang@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch makes unknown-capabilities Ollama model definitions explicitly tool-capable, adds regression assertions and changelog text, and guards the issue-labeler job to run only on issue events.
- Reproducibility: yes. for the metadata gap: current main builds unknown-capabilities Ollama models without a ... er-fix live provider output with `supportsTools: true`. I did not run local tests in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ollama): default unknown capabilities to tools
Validation:
- ClawSweeper review passed for head 27527716c0.
- Required merge gates passed before the squash merge.
Prepared head SHA: 27527716c0
Review: https://github.com/openclaw/openclaw/pull/84075#issuecomment-4486492661
Co-authored-by: Bob <dutifulbob@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: osolmaz
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Summary:
- The branch adds a close lifecycle for local memory embedding providers, scoped memory search/index teardown for one agent, Active Memory timeout cleanup, focused tests, and a changelog entry.
- Reproducibility: yes. The linked issue gives a concrete OpenClaw 2026.5.18 Telegram Active Memory timeout pa ... current-main source inspection confirms there is no timeout cleanup for that local embedding provider path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(memory): close local embedding providers on timeout
Validation:
- ClawSweeper review passed for head 8e2e369b5c.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8e2e369b5c
Review: https://github.com/openclaw/openclaw/pull/84048#issuecomment-4485705481
Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: hxy91819
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Adds bounded queued-writer diagnostics to pi-trajectory-flush cleanup timeout warnings so operators can see pending write count, queued bytes, active operation, and append size without exposing paths or payloads.
Closes#82961
Recover stale subagent completion delivery by retrying unsupported transcript-wait wakes without transcript waiting and forcing the existing message-tool handoff when the requester run is stale and direct completion is invisible.\n\nAdds regression coverage for the stale wake sequence and records the maintainer changelog entry.\n\nFixes #83699.
* fix config provider timeout overlays
Allow bundled model provider config entries to act as overlays so fields like timeoutSeconds can be configured without redeclaring baseUrl and models. Keep unknown custom provider declarations strict, and guard configured-provider fallback against overlay entries without models.
* fix(config): include provider aliases in model overlays
* fix(config): guard Foundry timeout overlays
* fix(config): normalize bundled provider overlays
* fix(models): reject overlay-only fallback models
Summary:
- The PR updates WhatsApp inbound listener and group-drop diagnostics, adds focused tests, and documents that observed but unregistered groups must be admitted through `channels.whatsapp.groups`.
- Reproducibility: yes. from source inspection: current main still emits the DM-only startup log and vague gro ... sions/whatsapp/src/auto-reply/monitor.ts` and `extensions/whatsapp/src/auto-reply/monitor/group-gating.ts`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(whatsapp): clarify group drop guidance
- PR branch already contained follow-up commit before automerge: fix(whatsapp): make inbound diagnostics policy-aware
- PR branch already contained follow-up commit before automerge: fix(whatsapp): clarify inbound group diagnostics
Validation:
- ClawSweeper review passed for head 0da24e3bbb.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0da24e3bbb
Review: https://github.com/openclaw/openclaw/pull/83969#issuecomment-4484218945
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR clears the cached CLI config snapshot promise when a read rejects, adds a reject-retry-cache regression test, and adds an Unreleased changelog entry.
- Reproducibility: yes. Current main clearly caches the first snapshot-read promise, and the source PR supplied a focused reject, recover, cached-success probe; I did not rerun it in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: retry config snapshot after rejection
Validation:
- ClawSweeper review passed for head a46b5ec5c7.
- Required merge gates passed before the squash merge.
Prepared head SHA: a46b5ec5c7
Review: https://github.com/openclaw/openclaw/pull/83944#issuecomment-4484051060
Co-authored-by: honor2030 <19909783+honor2030@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Skip embedded-run wake/steer attempts for dormant completion requesters and keep late subagent completions on the requester-agent/direct handoff path.\n\nAlso records the missing regression assertion that dormant completion requesters do not call queueEmbeddedPiMessageWithOutcome and adds the maintainer changelog entry.\n\nVerification:\n- node scripts/run-vitest.mjs src/agents/subagent-announce-delivery.test.ts\n- git diff --check\n- Codex autoreview via local Copilot endpoint: no actionable regressions\n- CI on 0108ebb2b3: clean
Summary:
- Adds `OPENCLAW_IMAGE_PIP_PACKAGES` as an opt-in Dockerfile build arg, passes it through Docker and Podman local setup, and documents/tests the new local image-build option.
- Reproducibility: not applicable. this is an additive Docker/Podman build capability, not a bug report. The s ... image importing requested Python packages, and the branch diff wires the renamed arg through Docker/Podman.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docker: support optional pip packages in local builds
Validation:
- ClawSweeper review passed for head 0ccec19206.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0ccec19206
Review: https://github.com/openclaw/openclaw/pull/83850#issuecomment-4483676614
Co-authored-by: Stephen Redmond <stephen.redmond@straiteis.ie>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR changes queued reply followups so user_request items no longer carry or inherit a source abort signal, preserves room_event abort signals, adds focused regression coverage, and updates CHANGELOG.md.
- Reproducibility: yes. at source level. Current main attaches and later falls back to opts.abortSignal for qu ... ore-fix regression failures for the two implicated paths; I did not execute tests in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Preserve queued Telegram topic followups
Validation:
- ClawSweeper review passed for head 96fa0f69ba.
- Required merge gates passed before the squash merge.
Prepared head SHA: 96fa0f69ba
Review: https://github.com/openclaw/openclaw/pull/83827#issuecomment-4483451436
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch fixes Telegram forum-topic session routing, per-topic text/media buffering, media-group scoping, and outbound group send fairness, with focused Telegram regression tests and a changelog entry.
- Reproducibility: yes. source inspection of current main plus the PR body's before-proof give a high-confiden ... s_forum can collapse to the base group route, and global text/media buffer chains serialize sibling topics.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Fix Telegram forum topic parallel flow
Validation:
- ClawSweeper review passed for head b0f78fa275.
- Required merge gates passed before the squash merge.
Prepared head SHA: b0f78fa275
Review: https://github.com/openclaw/openclaw/pull/83829#issuecomment-4483486851
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* Improve Telegram groups config diagnostics
Add targeted guidance when channels.telegram.groups uses a non-object shape so startup/config validation and doctor explain the required group-id object map and topic nesting.
* fix(config): keep channel validation hints generic
* codex: surface deferred dynamic tool names
* codex: keep prompt snapshots source-backed
* style: wrap mac voice settings help text
* style: satisfy swiftformat for voice wake help text
* style: apply swiftformat to voice wake help text
* test: load codex prompt snapshots through plugin aliases
* test: type codex source surface loader
* test: avoid extra codex loader suppression
---------
Co-authored-by: pashpashpash <nik@vault77.ai>
Summary:
- The PR feeds loopback-scoped MCP tools into CLI system prompts and reports, persists a prompt tool-name hash for CLI session reuse, adds regression tests, and adds a changelog entry.
- Reproducibility: yes. from source inspection: current main builds the CLI prompt and report with `tools: []` ... execute a live CLI turn in this read-only review, but the source path and source PR terminal proof line up.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): gate prompt loopback tools on active runtime
- PR branch already contained follow-up commit before automerge: fix(cli): include loopback tools in cli prompts
Validation:
- ClawSweeper review passed for head d196564d4d.
- Required merge gates passed before the squash merge.
Prepared head SHA: d196564d4d
Review: https://github.com/openclaw/openclaw/pull/83828#issuecomment-4483469332
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR changes the Control UI chat delete confirmation popover from absolute above-trigger positioning to fixed viewport-clamped placement with focused geometry tests and a changelog entry.
- Reproducibility: yes. The related delete-click report maps directly to current main code that appends an abo ... able chat thread without viewport measurement; I did not run a live browser repro in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ui): keep delete confirm in viewport
Validation:
- ClawSweeper review passed for head bc000c5b64.
- Required merge gates passed before the squash merge.
Prepared head SHA: bc000c5b64
Review: https://github.com/openclaw/openclaw/pull/83825#issuecomment-4483439624
Co-authored-by: Thiago Costa <71539514+ThiagoCAltoe@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch narrows Memory Wiki imported-source `FsSafeError` wrapping, adds directory-collision bridge regressions, and adds a changelog entry crediting the source PR.
- Reproducibility: yes. Source inspection shows current main catches all imported-source `FsSafeError`s with symlink wording, and the linked source PR includes live bridge-sync output for the directory-collision path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(memory-wiki): normalize source page stat guard
- PR branch already contained follow-up commit before automerge: fix(memory-wiki): preserve fs-safe write diagnostics
Validation:
- ClawSweeper review passed for head e38ae3b998.
- Required merge gates passed before the squash merge.
Prepared head SHA: e38ae3b998
Review: https://github.com/openclaw/openclaw/pull/83839#issuecomment-4483591199
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds a personal-agent QA-Lab no-fake-progress scenario, registers it in the personal-agent pack, teaches mock-openai the scripted path, and updates focused tests, docs, and changelog.
- Reproducibility: not applicable. This PR adds QA coverage rather than reporting a current-main bug; the branch supplies concrete after-patch QA-Lab/mock-openai commands and copied pass output.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(qa-lab): add personal no-fake-progress scenario
Validation:
- ClawSweeper review passed for head 95d2e46288.
- Required merge gates passed before the squash merge.
Prepared head SHA: 95d2e46288
Review: https://github.com/openclaw/openclaw/pull/83824#issuecomment-4483439200
Co-authored-by: Firas Alswihry <itzfiras@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The replacement PR adds a `watch-targets` skills snapshot invalidation when `ensureSkillsWatcher` rebuilds f ... root set, reads the snapshot version after watcher setup, adds regression tests, and updates the changelog.
- Reproducibility: yes. Source inspection shows current main rebuilds the skills watcher on changed root targe ... the version before watcher setup; I did not run a live Gateway mount reproduction in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(skills): refresh snapshots when watch roots change
Validation:
- ClawSweeper review passed for head 2677dcc35a.
- Required merge gates passed before the squash merge.
Prepared head SHA: 2677dcc35a
Review: https://github.com/openclaw/openclaw/pull/83823#issuecomment-4483425019
Co-authored-by: hclsys <hclsys@openclaw.ai>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch changes memory-core fallback vector search to scan chunks in 256-row rowid batches with `setImmediate` yields, updates regression tests, and adds a changelog entry.
- Reproducibility: yes. from source and supplied live output. Current main synchronously scans fallback vector ... and the PR body shows the before/after heartbeat behavior through the actual `searchVector` fallback path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(memory-core): add boundary, parity, and concurrent-insert covera…
- PR branch already contained follow-up commit before automerge: fix(memory-core): yield event loop during fallback vector search (#81…
Validation:
- ClawSweeper review passed for head 0ede3d7168.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0ede3d7168
Review: https://github.com/openclaw/openclaw/pull/83758#issuecomment-4482137790
Co-authored-by: NW <nitinwadhawan66@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds Anthropic Claude 4.x image-capability normalization for stale text-only resolved model rows, regression tests for provider and fallback model resolution, and a changelog entry.
- Reproducibility: yes. for source-level reproduction: current main gates native images on model.input includi ... s text-only. I did not run the command locally because this review was constrained to read-only inspection.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(anthropic): preserve Claude image capability
Validation:
- ClawSweeper review passed for head 06dd378ea3.
- Required merge gates passed before the squash merge.
Prepared head SHA: 06dd378ea3
Review: https://github.com/openclaw/openclaw/pull/83756#issuecomment-4482116499
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR changes outbound channel registry loading and bootstrap to fall back from pinned setup-only channel entries to the active runtime registry, with regression tests and a changelog entry.
- Reproducibility: yes. at source level. Current main can select a pinned setup-only channel entry and skip th ... module live output showing delivery after the fallback; I did not run local tests in this read-only review.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(outbound): resolve send-capable channel registry
Validation:
- ClawSweeper review passed for head 67c20aa72b.
- Required merge gates passed before the squash merge.
Prepared head SHA: 67c20aa72b
Review: https://github.com/openclaw/openclaw/pull/83733#issuecomment-4481084888
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- This PR removes the WebChat special-case from auto-reply chunk limit/mode resolution, adds WebChat override regression tests, and records the fix in the changelog.
- Reproducibility: yes. from source inspection rather than runtime execution: current main returns the fallbac ... bchat` before reading `cfg.channels`, so a configured `channels.webchat.textChunkLimit` cannot take effect.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(auto-reply): honor webchat textChunkLimit/chunkMode config overri…
Validation:
- ClawSweeper review passed for head cd9ac01a36.
- Required merge gates passed before the squash merge.
Prepared head SHA: cd9ac01a36
Review: https://github.com/openclaw/openclaw/pull/83742#issuecomment-4481570742
Co-authored-by: luyao618 <364939526@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR routes `session.tool` Gateway frames through the Control UI tool-stream handler, adds a regression test, and adds a changelog entry.
- Reproducibility: yes. Current main emits `session.tool` frames for session subscribers, but the Control UI d ... to the tool-stream handler, so the failure path is source-reproducible without needing a live browser run.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ui): render session-scoped tool events
Validation:
- ClawSweeper review passed for head 58be438acb.
- Required merge gates passed before the squash merge.
Prepared head SHA: 58be438acb
Review: https://github.com/openclaw/openclaw/pull/83734#issuecomment-4481086608
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Adds a personal-agent QA-Lab share-safe diagnostics scenario with mock-openai support, pack registration/tests, docs, and changelog coverage.
- Reproducibility: not applicable. This PR adds a new QA-Lab scenario rather than fixing a current-main bug. T ... ce PR provides a clear after-patch validation path using qa-channel, a real gateway child, and mock-openai.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 46eb0af9e4.
- Required merge gates passed before the squash merge.
Prepared head SHA: 46eb0af9e4
Review: https://github.com/openclaw/openclaw/pull/83717#issuecomment-4480393933
Co-authored-by: Firas Alswihry <itzfiras@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR passes the effective OpenAI/Codex auth provider set into `/models` provider-header labeling, adds focused regression tests, and records the user-facing fix in the changelog.
- Reproducibility: yes. Current main lacks `acceptedProviderIds` in the shared picker header path, and the source PR's Mantis baseline/candidate proof shows the visible Telegram header mismatch and after-fix OAuth label.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(models): label picker auth via effective provider order
Validation:
- ClawSweeper review passed for head 8ca2924adc.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8ca2924adc
Review: https://github.com/openclaw/openclaw/pull/83726#issuecomment-4480805713
Co-authored-by: Stellar鱼 <2182712990@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR changes collect-mode follow-up queue routing so unresolved-origin items can batch with a single resolved route and later compatible items can resume batching after a true cross-channel drain.
- Reproducibility: yes. at source level: current main treats unkeyed-plus-same-keyed queue items as cross-chan ... failing path is directly visible in `src/utils/queue-helpers.ts` and `src/auto-reply/reply/queue/drain.ts`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Merge remote-tracking branch 'origin/main' into maint-83701-20260518
Validation:
- ClawSweeper review passed for head e6ad029e23.
- Required merge gates passed before the squash merge.
Prepared head SHA: e6ad029e23
Review: https://github.com/openclaw/openclaw/pull/83701#issuecomment-4479943100
Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds raw explicit-port detection for browser CDP URLs, updates profile resolution precedence, adds regression tests, and records the browser fix in the changelog.
- Reproducibility: yes. Source inspection shows current main resolves a portless profile `cdpUrl` through `par ... 443, and overwrites the configured `cdpPort`; the source PR also provides live before/after Chrome output.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(browser): encapsulate explicit-port detection in parseBrowserHttpUrl
- PR branch already contained follow-up commit before automerge: fix(browser): preserve explicit cdpPort when cdpUrl omits port
Validation:
- ClawSweeper review passed for head 070c31cdcf.
- Required merge gates passed before the squash merge.
Prepared head SHA: 070c31cdcf
Review: https://github.com/openclaw/openclaw/pull/83707#issuecomment-4480058057
Co-authored-by: Hongwei Ma <marvae24@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch restricts exact-head ClawSweeper proof markers to GitHub App-authored comments, adds read-only issue-comment token fallback for the proof workflow, and adds focused regression tests plus a changelog entry.
- Reproducibility: yes. Source inspection of current main shows any issue comment body with a matching `clawsw ... SHA is accepted without author/App authentication; the PR adds focused negative tests for forged comments.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ci): authenticate proof verdict markers
Validation:
- ClawSweeper review passed for head f4c375eaa7.
- Required merge gates passed before the squash merge.
Prepared head SHA: f4c375eaa7
Review: https://github.com/openclaw/openclaw/pull/83692#issuecomment-4479843682
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The branch adds `openclaw browser evaluate --timeout-ms`, forwards it to the evaluate body and request timeo ... ents and tests it, adds a changelog entry, and includes a config.patch no-op shortcut from the repair pass.
- Reproducibility: not applicable. this is a feature PR rather than a bug report. Source inspection shows current main lacks the CLI flag while the branch wires it into an already-supported evaluate `timeoutMs` payload.
Automerge notes:
- PR branch already contained follow-up commit before automerge: feat(browser): add evaluate timeout CLI option
Validation:
- ClawSweeper review passed for head 0d81d3d93e.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0d81d3d93e
Review: https://github.com/openclaw/openclaw/pull/83696#issuecomment-4479900502
Co-authored-by: fred <fengruifree@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR removes the Control UI chat fallback that converts a null stream into an empty stream for abortable runs, adds null-vs-empty stream regression tests, and updates the changelog.
- Reproducibility: yes. source-level reproduction is high confidence: current main converts null stream plus c ... ading indicator. The linked source PR also reports live Control UI verification after the equivalent patch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(ui): prevent reading indicator from sticking after assistant resp…
Validation:
- ClawSweeper review passed for head 44bea55110.
- Required merge gates passed before the squash merge.
Prepared head SHA: 44bea55110
Review: https://github.com/openclaw/openclaw/pull/83711#issuecomment-4480128171
Co-authored-by: 二狗子 <njuboy11@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Adds `--global` to `openclaw skills install` and `openclaw skills update`, routing ClawHub installs and updates to the shared managed skills root with docs, changelog, and CLI command tests.
- Reproducibility: not applicable. as a bug reproduction; this is a new CLI feature request. Source inspection confirms current `main` lacks `--global`, and the source PR includes after-fix terminal proof for the new path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): address skills global review
- PR branch already contained follow-up commit before automerge: feat(cli): support installing skills to shared global directory via -…
Validation:
- ClawSweeper review passed for head 6eb7187fc1.
- Required merge gates passed before the squash merge.
Prepared head SHA: 6eb7187fc1
Review: https://github.com/openclaw/openclaw/pull/83705#issuecomment-4480023577
Co-authored-by: Hongwei Ma <marvae24@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR makes skill-creator quick validation reject empty or whitespace-only `name` and `description` fields, adds regression tests, and records the fix in the changelog.
- Reproducibility: yes. Source inspection on current main shows empty or whitespace-only values skip validation after `.strip()`, and the source PR includes before/after terminal output for the same path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(skill-creator): reject empty name and description in skill valida…
Validation:
- ClawSweeper review passed for head 0fb4555cb2.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0fb4555cb2
Review: https://github.com/openclaw/openclaw/pull/83704#issuecomment-4479984760
Co-authored-by: jay <a1@ponys-Mac.local>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- Adds a symptom-keyed troubleshooting block to `docs/gateway/config-channels.md` for group/channel @mentions that log `queuedFinal=false, replies=0` and explains the `visibleReplies` remedies.
- Reproducibility: yes. for the docs gap and source behavior: current main lacks the exact symptom-keyed troubleshooting entry, and the resolver/tests show when message-tool mode suppresses automatic final delivery.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(gateway): make group reply fix restart conditional
- PR branch already contained follow-up commit before automerge: docs(gateway): qualify direct-chat reply default in troubleshooting
- PR branch already contained follow-up commit before automerge: docs(gateway): align group reply troubleshooting with current automat…
- PR branch already contained follow-up commit before automerge: docs(gateway): scope group reply suppression cause to group config
Validation:
- ClawSweeper review passed for head e60ae89b20.
- Required merge gates passed before the squash merge.
Prepared head SHA: e60ae89b20
Review: https://github.com/openclaw/openclaw/pull/77052#issuecomment-4367898048
Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR removes the empty `mkdirSync({ recursive: true })` catch in the memory host SDK `ensureDir()`, adds a regression test for surfaced mkdir failures, and adds a changelog entry.
- Reproducibility: yes. from source inspection rather than a locally executed repro. Current main swallows eve ... kdir failure in `ensureDir()`, and the active memory database path calls that helper before opening SQLite.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 0f82f185cc.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0f82f185cc
Review: https://github.com/openclaw/openclaw/pull/41259#issuecomment-4326310101
Co-authored-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates the skills CLI formatter, tests, and changelog so `skills info` resolves case-insensitive and ... ator-normalized skill name variants only when non-exact matches are unique, and sanitizes not-found output.
- Reproducibility: yes. by source inspection. The documented `openclaw skills info <name>` command passes the ... ormatter lookup on current main, while skill status entries can have distinct `name` and `skillKey` values.
Automerge notes:
- PR branch already contained follow-up commit before automerge: test(skills): exercise case-insensitive lookup branch
- PR branch already contained follow-up commit before automerge: style(skills): format lookup resolver signature
- PR branch already contained follow-up commit before automerge: fix(skills): sanitize not-found output and avoid ambiguous lookup mat…
- PR branch already contained follow-up commit before automerge: fix(skills): require unique case-insensitive info matches
Validation:
- ClawSweeper review passed for head 01f3e2d468.
- Required merge gates passed before the squash merge.
Prepared head SHA: 01f3e2d468
Review: https://github.com/openclaw/openclaw/pull/38713#issuecomment-4321021300
Co-authored-by: NewdlDewdl <rohin.agrawal@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds highlight.js-backed WebChat code-block highlighting, scoped token CSS, regression tests, a type shim, and a direct UI dependency.
- Reproducibility: not applicable. as a bug reproduction; this is a feature addition. The feature gap is source-evident because current main renders code blocks as escaped plaintext without hljs token markup.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 7bb95c47ed.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7bb95c47ed
Review: https://github.com/openclaw/openclaw/pull/83569#issuecomment-4476990135
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates the memory-wiki `wiki_lint` tool to show vault-relative lint report paths in tool text and details, keeps the core linter/CLI result absolute, adds regression coverage, and adds a changelog entry.
- Reproducibility: yes. there is a high-confidence source reproduction path: current main returns the linter's ... tPath` in `wiki_lint` text and raw details. I did not execute the harness because this review is read-only.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(memory-wiki): make wiki_lint tool output path-safe
Validation:
- ClawSweeper review passed for head df5c7db151.
- Required merge gates passed before the squash merge.
Prepared head SHA: df5c7db151
Review: https://github.com/openclaw/openclaw/pull/83687#issuecomment-4479682214
Co-authored-by: LLagoon3 <choonarm3@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* ci(proof): trust maintainer label for private org members
Private organization memberships report author_association=CONTRIBUTOR
on PRs, so the real-behavior-proof gate currently demands proof from
maintainers whose membership is private. The labeler workflow already
applies the 'maintainer' label via the team-membership API (which sees
private members), so treat that label as an equivalent privileged
signal in evaluateRealBehaviorProof.
* ci(proof): drop noisy comments
* ci(proof): check maintainer team membership via GitHub App token
Replace the label-based private-maintainer skip with a direct
getMembershipForUserInOrg call using a minted GitHub App token, mirroring
the pattern labeler.yml already uses for the same lookup. Removes the
race against the labeler workflow and the implicit dependency on the
'maintainer' label having landed first.
The App-token steps are continue-on-error so the gate still runs (using
the existing author_association path) when the App key secrets are
absent or both mints fail.
* ci(proof): narrow App token to members:read
ClawSweeper review #83418: actions/create-github-app-token defaults to
the full installation permission set, but the proof gate only needs the
org-members read scope used by teams.getMembershipForUserInOrg. Set
permission-members: read on both the primary and fallback mint steps.
* docs(changelog): private maintainers skip the real-behavior-proof gate
Summary:
- The branch updates the transcript tail assistant reader to skip trailing non-message rows, adds cache-ttl gap-fill regression tests, and adds a changelog entry.
- Reproducibility: yes. Source inspection shows cache-ttl custom rows can sit after the canonical assistant me ... r stops on that row; the PR body also supplies a concrete live three-turn CLI reproduction after the patch.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(transcript): skip trailing custom entries in tail assistant reade…
Validation:
- ClawSweeper review passed for head 866aa27ca8.
- Required merge gates passed before the squash merge.
Prepared head SHA: 866aa27ca8
Review: https://github.com/openclaw/openclaw/pull/83635#issuecomment-4478637780
Co-authored-by: yaoyi1222 <yaoyi_1222@163.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- The PR updates cron timer task-run creation to derive `childSessionKey` for isolated agent-turn jobs from the stable cron session key, adds focused timer coverage, and records the fix in the changelog.
- Reproducibility: yes. Current main's timer task creation copies only `job.sessionKey`, while isolated cron e ... Id>:cron:<jobId>` later; the supplied before-test output matches that source path by receiving `undefined`.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cron): link isolated task runs to cron session
Validation:
- ClawSweeper review passed for head 748998b018.
- Required merge gates passed before the squash merge.
Prepared head SHA: 748998b018
Review: https://github.com/openclaw/openclaw/pull/83606#issuecomment-4478039217
Co-authored-by: Jai Govindani <jai.g@ewa-services.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Follow-up and main reply paths re-entered each embedded fallback candidate
with the same queued transcript prompt. After the first candidate persisted
that queued user message, later candidates appended it again. Failed
embedded candidates could also persist an assistant error stub on each
retry, leaving same-role transcript runs that downstream providers reject.
The fallback callers now keep two persistence latches for one fallback run:
queuedUserMessagePersistedAcrossFallback flips from onUserMessagePersisted,
and assistantErrorPersistedAcrossFallback flips only after the session guard
actually persists an assistant stopReason="error" message. Later candidates
suppress only the entries that were already written, so CLI or otherwise
non-persisting failures do not hide the first embedded error separator.
Plumb the assistant-error persistence callback through the embedded runner,
attempt params, and session guard wrapper. Add guard and runner regression
tests for all-embedded fallback retries and CLI-to-embedded fallback.
Closes#83404
Clear stale CLI provider resume bindings when a normal gateway session is reset, while preserving spawned subagent bindings.
Also isolate target normalization in the outbound source-delivery unit test so the CI shard does not load provider/plugin runtime state for a pure matcher case.
Co-authored-by: psyphix-claw <262498103+psyphix-claw@users.noreply.github.com>
Keep QMD-exported archived session transcript hits visible by resolving QMD `.md` archive stems back to their live session ids before applying session visibility policy. Preserve normal markdown session ids that only resemble archive names, reject ambiguous slug fallback matches, and keep deleted same-agent QMD archives readable when the live store entry is gone.
Fixes#83506.
Co-authored-by: tanshanshan <tanshanshan@users.noreply.github.com>
Fixes#83388.
- Honor per-agent `tools.codeMode` in config schema, runtime code-mode resolution, and model payload filtering.
- Preserve grouped OpenAI tool declarations when code-mode filtering keeps only `exec` and `wait`.
- Sync generated config/prompt baselines and carry a narrow media CI unblocker from current `main` fallout.
Co-authored-by: Kaspre <kaspre@gmail.com>
feat(docker): add image apt package build arg
Add OPENCLAW_IMAGE_APT_PACKAGES as the preferred runtime-neutral image build arg for Docker and Podman apt package installs while keeping OPENCLAW_DOCKER_APT_PACKAGES as the legacy fallback.
Maintainer verification:
- pnpm docs:list
- node scripts/run-vitest.mjs run --config test/vitest/vitest.e2e.config.ts src/docker-setup.e2e.test.ts
- node scripts/run-vitest.mjs src/dockerfile.test.ts test/scripts/test-install-sh-docker.test.ts
- node scripts/run-vitest.mjs run --config test/vitest/vitest.cron.config.ts src/cron/isolated-agent.model-overrides.test.ts
- pnpm exec oxfmt --check --threads=1 docs/install/docker.md docs/install/podman.md scripts/clawdock/README.md docs/help/faq.md CHANGELOG.md
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode local
- .agents/skills/autoreview/scripts/autoreview --mode branch
- pnpm check:changed via Blacksmith Testbox tbx_01krwqmfhcdekaczvrkxnb7t59, Actions run 26014630478, exit 0
Known CI note: checks-node-core-runtime-shared timed out repeatedly in unrelated src/cron/isolated-agent.model-overrides.test.ts on GitHub Actions; the same test passes locally after this rebase.
Co-authored-by: Said Urtabajev <said@bumpclub.ee>
Treat Telegram HTTP 421 / Misdirected Request responses as retryable transport failures in both the default channel API retry policy and the strict outbound send retry path.
Wire the 421 handling into isSafeToRetrySendError so non-idempotent Telegram send operations can retry this edge-node rejection without enabling broad ambiguous network retries, and add regression coverage for the default retry path plus strict send predicate handling.
* fix(doctor): archive legacy clawd browser profile residue
* Avoid browser cleanup load without residue
Doctor --fix now skips loading the browser doctor facade unless the legacy browser/clawd profile path exists, preventing broad config repair tests from paying the plugin load cost when there is nothing to archive.
* Use structured health check for browser residue
Register the legacy clawd browser profile residue cleanup through the modern doctor health-check contract so doctor --lint can report it and doctor --fix repairs it through structured effects.
Summary
Problem: root CHANGELOG.md updates currently cause broad pull request and push workflow activity, including CI and workflow sanity fanout, even though changelog-only edits do not touch product, runtime, docs site, or workflow logic.
Why it matters: the PR workflow (review, prepare, and land) can add or adjust CHANGELOG.md entries while processing otherwise-ready PRs. Those changelog-only updates retrigger gates, delay landing, and create avoidable contention when several PRs are being landed close together.
What changed: CI now ignores pull requests whose only changed path is CHANGELOG.md; Workflow Sanity ignores changelog-only pull requests and main-branch pushes; Docs keeps its markdown/docs trigger but excludes root CHANGELOG.md from the push path set.
What did NOT change (scope boundary): metadata-only automation such as labelers, auto-response, real behavior proof, or external GitHub apps can still run on PR events because those workflows are event-driven rather than file-scope CI. Other markdown files, docs files, and workflow files still trigger their existing checks.
OAuth login flow
----------------
- Hard-require refresh_token after the authorization-code exchange in
xai-oauth.ts. Access-only responses persisted credentials that the
downstream usability check later rejected; the new requireRefreshToken
option fails the exchange instead. Error wording explains the missing
refresh_token in OIDC scope terms (offline_access scope rejected),
not a "grant".
- Derive token expiry from the access-token JWT exp claim when
expires_in is missing. id_token exp is intentionally not used as a
fallback because id_token lifetime tracks the OIDC session, not the
access token, and would defer refresh past actual expiry.
- Handle CORS preflight OPTIONS on the loopback OAuth callback in
src/plugin-sdk/provider-auth-runtime.ts. The previous handler treated
any non-callback request as a failed GET, returned "Missing code or
state", and tore the server down before the real GET arrived. The
CORS allowlist is now an optional `corsOriginAllowlist` parameter on
waitForLocalOAuthCallback so the SDK helper stays generic. The xAI
plugin passes ["auth.x.ai", "accounts.x.ai"] from loginXaiOAuth.
Sidecar surfaces
----------------
- speech-provider.ts (POST /v1/tts) honors the xAI OAuth profile in
addition to provider config and XAI_API_KEY. isConfigured now also
reports true when an xAI auth profile is configured (via
isProviderAuthProfileConfigured), so OAuth-only users are no longer
silently filtered out by the selection layer. The bearer resolver
threads req.cfg into resolveApiKeyForProvider so the right xAI auth
profile is picked when a user has multiple.
- realtime-transcription-provider.ts (WSS /stt) gets the same
isConfigured fix, and the lazy headers() resolver threads req.cfg
into the OAuth bearer lookup. createSession stays sync per its
plugin contract.
- stt.ts: drop the plugin-side OAuth fallback. The media-understanding
core already resolves auth (cfg/agentDir-aware) via
resolveProviderExecutionContext before calling transcribeAudio, so
the wrapper was redundant. transcribeAudio is now the registered
hook directly.
User-Agent attribution
----------------------
- New buildXaiAttributionPolicy in src/agents/provider-attribution.ts
injects User-Agent: openclaw/<version>, originator, and version on
/v1/responses and /v1/chat/completions traffic that goes through
resolveProviderRequestHeaders. Gated to xai-native and default
endpoint classes; custom proxy baseUrls remain withheld. reviewNote
is honest about which headers are spec-verified vs mirrored.
- Shared extensions/xai/src/xai-user-agent.ts helper exports
xaiUserAgentHeaderFor(baseUrl) which only emits the User-Agent when
the resolved baseUrl points at the xAI-native API host. Threaded
through TTS and realtime STT (WS upgrade headers) so user-configured
proxy baseUrls do not receive the openclaw identity. OAuth discovery
and token endpoints still send User-Agent unconditionally because
isTrustedXaiOAuthEndpoint already restricts those URLs to *.x.ai.
- Image gen, batch STT, and video gen rely on the attribution policy
alone (no manual User-Agent in defaultHeaders), so attribution
withholding on user-configured proxy baseUrls is preserved
end-to-end.
- UA is bearer-agnostic: same value whether the bearer comes from an
xAI API key or the xAI OAuth flow.
Drop dead api.grok.x.ai alias
-----------------------------
- xAI retired the api.grok.x.ai alias; DNS now returns NXDOMAIN from
xAI's own authoritative nameservers. Drop it from the xai-native
endpoint host set in extensions/xai/openclaw.plugin.json,
extensions/xai/api.ts, extensions/xai/tts.ts, and the
openai-responses payload policy. Update the attribution test to
classify api.grok.x.ai as "custom" (no live user can reach it; the
classification keeps documenting the host's status).
Video generation now matches xAI's actual API behavior
------------------------------------------------------
Previously, real video generation requests failed with
"xAI video generation response malformed" because the poll-status
handler validated against a closed enum that did not match what the
xAI service actually returns. Four fixes:
- Loosen the poll-status handler. xAI returns intermediate strings
outside `["queued", "processing", "done", "failed", "expired"]`
(commonly `submitted`, `pending`, `in_progress`, ...). Treat `done`
as terminal-success, `["failed", "error", "expired", "cancelled"]`
as terminal-failure, and any other string (including empty) as
continue-polling. Also accept `cancelled` as a terminal failure.
- Send default duration/aspect_ratio/resolution on every generate and
reference-image submit. xAI rejects bodies that omit these fields.
Defaults: duration=8s, aspect_ratio="16:9", resolution="720p".
- Accept lowercase resolution input ("480p"/"720p"/"1080p") in
addition to uppercase, normalize to lowercase on the wire.
- Add an `x-idempotency-key` header (fresh `crypto.randomUUID()`) on
every submit so a network retry does not double-charge the user.
Polls intentionally reuse the unmodified `headers` without the key.
Ergonomics
----------
- All "missing xAI credentials" errors (code_execution, lazy
code_execution fallback in extensions/xai/index.ts, x_search,
web_search grok in web-search-provider.runtime.ts, TTS, batch STT,
realtime STT) now mention `openclaw onboard --auth-choice xai-oauth`
first.
- Dedupe the Grok model-id alias table: model-compat.ts re-exports
normalizeXaiModelId from model-id.ts as normalizeNativeXaiModelId.
Test coverage
-------------
- src/plugin-sdk/provider-auth-runtime.test.ts: locks the new pure
buildOAuthCallbackOriginResolver gate (allowlist match,
case-normalization, https-only, non-allowlisted hosts dropped,
multi-Origin handling).
- extensions/xai/xai-oauth.test.ts: locks
XAI_OAUTH_CALLBACK_CORS_ORIGIN_ALLOWLIST so loginXaiOAuth keeps
threading the right hosts to the SDK helper.
- extensions/xai/speech-provider.test.ts: OAuth-only auth profile
flips isConfigured to true; cfg threads into the OAuth fallback
resolver.
- extensions/xai/realtime-transcription-provider.test.ts: same +
upgrade headers carry the OAuth bearer end-to-end.
- extensions/xai/stt.test.ts: explicit assertion that transcribeAudio
trusts the core-resolved apiKey (no plugin-side wrapper).
Verification
------------
- pnpm install: clean
- 154/154 vitest tests pass across 13 touched test files
- pnpm check:changed: typecheck core/ext + tests, oxlint core/ext,
runtime guards, dependency pin guard, package patch guard, runtime
import cycles, sidecar loader guard - all green
- pnpm build: 0 errors, 0 [INEFFECTIVE_DYNAMIC_IMPORT] warnings
Add core and hook mapper regression coverage for the thread-origin contract behind #83302.\n\nThe tests prove a flat reply target can coexist with a thread-addressable OriginatingTo, and hook canonical conversation mapping keeps following OriginatingTo.\n\nProof: focused Vitest, autoreview, Testbox check:changed tbx_01krwaztbwm13sx9e4sbyyz4c1, and CI run 26008670388 passed.
Fix Telegram forum-topic OriginatingTo routing for inbound, audio-preflight, and skipped-message hook contexts.
Centralize Telegram inbound origin target construction so real forum topics stay encoded in the routing target while DM thread ids remain metadata-only.
Fixes#83302.
Summary:
- The PR changes Discord reply delivery, sanitizer, and queued follow-up auto-reply paths so explicit verbose tool-progress payloads are delivered while final assistant replies still use the privacy sanitizer.
- Reproducibility: yes. source-level: current main strips tool-looking Discord payload text at the front-chann ... ds compaction events in queued follow-up runs. I did not run a live Discord repro in this read-only review.
Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Included post-review commit in the final squash: fix: gate queued follow-up progress when verbose is off
- Included post-review commit in the final squash: fix: preserve queued verbose progress under preview suppression
- Included post-review commit in the final squash: ci: rerun discord verbose progress PR
- Included post-review commit in the final squash: fix: preserve Discord verbose progress after rebase
- Included post-review commit in the final squash: fix: serialize discord queued progress
- Included post-review commit in the final squash: Fix Discord verbose tool progress delivery
Validation:
- ClawSweeper review passed for head fd845e773a.
- Required merge gates passed before the squash merge.
Prepared head SHA: fd845e773a
Review: https://github.com/openclaw/openclaw/pull/80042#issuecomment-4414121881
Co-authored-by: Clawsistant <clawsistant@users.noreply.github.com>
Co-authored-by: anyech <anyech@gmail.com>
Co-authored-by: OpenClaw Assistant <assistant@openclaw.local>
Co-authored-by: Shadow <hi@shadowing.dev>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: thewilloftheshadow
Co-authored-by: thewilloftheshadow <35580099+thewilloftheshadow@users.noreply.github.com>
Summary:
- The PR changes ordinary unmanaged gateway restarts to return the existing in-process fallback instead of detached-spawning a replacement child, with focused tests, docs wording, and a changelog entry.
- Reproducibility: yes. at source level: current main and v2026.5.12 detach-spawn unmanaged ordinary restarts, ... e PR body also supplies after-fix terminal proof that the patched helper returns disabled without spawning.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 8c82df6c77.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8c82df6c77
Review: https://github.com/openclaw/openclaw/pull/83138#issuecomment-4471071848
Co-authored-by: mjamiv <74088820+mjamiv@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR adds a generic inbound debounce `cancelKey`, uses Telegram stop-like controls to cancel same-chat pen ... buffers and bypass debounce, and adds focused Telegram regression coverage plus updated channel test mocks.
- Reproducibility: yes. by source inspection: current main enqueues Telegram text through inbound debounce bef ... nly has flush semantics for pending keyed work. I did not run a live Telegram repro in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Fix Telegram stop debounce bypass
Validation:
- ClawSweeper review passed for head 19245a341d.
- Required merge gates passed before the squash merge.
Prepared head SHA: 19245a341d
Review: https://github.com/openclaw/openclaw/pull/83248#issuecomment-4472300906
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Refactor docs/plugins/building-plugins.md into the scoped plugin-author guide, preserving the legacy registering-agent-tools anchor and restoring the original Next steps section.
* feat(doctor): add --lint mode + structured HealthFinding shape
Adds the core machinery for `openclaw doctor --lint` per the
doctor-lint-and-oc-rules upstream proposal. PR-1 of the proposal:
no new top-level verb, no public plugin SDK; everything internal.
Files:
- src/flows/checks.ts ? HealthFinding / HealthCheck / HealthCheckContext
types. Findings carry severity per-finding; checks return
readonly HealthFinding[]. Mode tag (doctor/lint/fix) lets a check
distinguish the calling posture.
- src/flows/health-check-registry.ts ? module-level registry with
duplicate-id rejection + test reset helper.
- src/flows/doctor-lint-flow.ts ? runner over registered checks.
Catches throws into synthetic error findings (anchored at check id;
message scrubbed of control chars, capped at 256 bytes). Sorts
findings by severity desc, check id, path. Exports
exitCodeFromFindings (1 if any warning/error, 0 otherwise).
- src/flows/doctor-core-checks.ts ? 4 modern HealthChecks rewriting
logic from existing legacy run*Health functions:
core/doctor/gateway-config (warning)
core/doctor/command-owner (info)
core/doctor/workspace-status (info)
core/doctor/final-config-validation (error)
Each was audited safe per the proposal's adapter constraints
(no writes, no repair calls, no prompts, no probes incl. local-bind).
Legacy run*Health contributions in doctor-health-contributions.ts
are unchanged ? doctor mode (no --lint) still runs the existing 35.
- src/commands/doctor-lint.ts ? CLI dispatch for --lint. Reads config
snapshot, builds HealthCheckContext (mode: "lint"), runs the registry,
filters by --severity-min, emits human or JSON output, returns exit
code from unfiltered set so --severity-min hides info findings
without changing CI signal.
- src/cli/program/register.maintenance.ts ? adds --lint, --json,
--severity-min, --skip, --only flags to existing doctor command.
--lint branches to runDoctorLintCli; without --lint, doctor runs
unchanged.
LoC: 382 src across 6 files. Tests + doc + oc-path-side rule packs
follow as separate commits on this branch.
* fix: avoid string spread in doctor errors
* chore: refresh plugin SDK API baseline
* docs: clarify doctor lint usage
* feat(doctor): prepare repairs for dry-run reporting
* fix(doctor): detect stale session snapshot paths
Warn when cached session snapshot metadata still references bundled skill paths from inactive OpenClaw runtime roots, while keeping workspace skill roots and current runtime paths quiet.
* fix(doctor): honor configured session stores
* fix(doctor): scan raw snapshot paths
Expand home-relative cached snapshot paths before stale bundled-skill classification and scan raw session-store JSON so persisted resolvedSkills are inspected before normal session-store normalization strips them.
Summary:
- This PR adds a strict initial subagent registry persistence path, rolls back failed registrations, updates affected test seams, adds a regression test, and records the fix in the changelog.
- Reproducibility: yes. Source inspection on current main shows registry save failures are swallowed after the ... s added, and the linked source PR provides an ENOSPC-style after-fix terminal proof for the corrected path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): persist subagent registry before returning accepted (#83…
Validation:
- ClawSweeper review passed for head d564ef051d.
- Required merge gates passed before the squash merge.
Prepared head SHA: d564ef051d
Review: https://github.com/openclaw/openclaw/pull/83238#issuecomment-4472173642
Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR buffers Codex command-output deltas per command item and uses them as a fallback for transcripts, trajectory output, final tool output, and after-tool-call errors when `aggregatedOutput` is empty.
- Reproducibility: yes. A source-level reproduction is clear: send current-turn command-output delta notificat ... aggregatedOutput: null`; current main has no final transcript or trajectory fallback for the streamed text.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(codex): preserve streamed command output
Validation:
- ClawSweeper review passed for head 07393a304f.
- Required merge gates passed before the squash merge.
Prepared head SHA: 07393a304f
Review: https://github.com/openclaw/openclaw/pull/83222#issuecomment-4472054629
Co-authored-by: 0x505badc0de <32790662+rozmiarD@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR exempts run-mode `cleanup: "keep"` subagent registry entries from the session-mode sweep TTL, adds focused regression coverage, and records the fix in the changelog.
- Reproducibility: yes. Current main source shows a run-mode keep entry has no `archiveAtMs` and then matches ... ; the linked source PR also provides before/after terminal proof against a real persisted `runs.json` path.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): preserve run-mode keep subagents past session sweep TTL …
Validation:
- ClawSweeper review passed for head 32faf5cf32.
- Required merge gates passed before the squash merge.
Prepared head SHA: 32faf5cf32
Review: https://github.com/openclaw/openclaw/pull/83226#issuecomment-4472073823
Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR replaces per-bar absolute Usage chart tooltips with one viewport-fixed floating tooltip and adds focus/keyboard handling plus focused jsdom coverage.
- Reproducibility: yes. at source level. Current main renders an absolute `.daily-bar-tooltip` inside `.daily- ... ` overflow contexts, and the linked issue plus PR before screenshot demonstrate the tall-bar clipping case.
Automerge notes:
- PR branch already contained follow-up commit before automerge: Merge branch 'main' into fix-usage-tooltip-clipping
Validation:
- ClawSweeper review passed for head edbb26a5be.
- Required merge gates passed before the squash merge.
Prepared head SHA: edbb26a5be
Review: https://github.com/openclaw/openclaw/pull/82846#issuecomment-4468967811
Co-authored-by: sandypockets <41454557+sandypockets@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Summary:
- The PR updates the CLI post-update gateway recovery formatter and tests to show Linux, macOS, Windows, or generic service-manager guidance, plus a changelog entry.
- Reproducibility: yes. Source inspection gives a high-confidence reproduction path: current main reaches a fo ... hAgent recovery text, while the platform contract says Linux uses systemd and Windows uses Scheduled Tasks.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(update): tailor gateway recovery hints by platform
Validation:
- ClawSweeper review passed for head 0cf2a0c5a7.
- Required merge gates passed before the squash merge.
Prepared head SHA: 0cf2a0c5a7
Review: https://github.com/openclaw/openclaw/pull/83191#issuecomment-4471471293
Co-authored-by: Rubén Cuevas <hi@rubencu.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- The PR adds a 15-second default timeout for legacy `before_agent_start` modifying hooks, regression tests for hung handlers, and a changelog fix entry.
- Reproducibility: yes. Registering a `before_agent_start` handler that returns a never-settling promise is en ... ts the hook and the runner awaits directly; the linked source PR also supplies before/after terminal proof.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(plugins): default 15s timeout for before_agent_start hook (#48534)
Validation:
- ClawSweeper review passed for head 8d2c5b8808.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8d2c5b8808
Review: https://github.com/openclaw/openclaw/pull/83147#issuecomment-4471169756
Co-authored-by: Rahul <rahulnilvan43@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:
- The PR narrows embedded PI session transcript write-lock scope, adds stale/max-hold config plumbing, and updates affected transcript, doctor, gateway, SDK, Codex mirroring, docs, and regression-test surfaces.
- Reproducibility: yes. Current main source still holds the embedded session write lock from early attempt set ... cksmith Testbox contention proof on unmodified main; I did not rerun the live repro in this read-only pass.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): narrow context engine session lock
- PR branch already contained follow-up commit before automerge: fix session lock runner build types
- PR branch already contained follow-up commit before automerge: Release embedded session write lock before model I/O
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8289…
Validation:
- ClawSweeper review passed for head 4c6dd7ed6e.
- Required merge gates passed before the squash merge.
Prepared head SHA: 4c6dd7ed6e
Review: https://github.com/openclaw/openclaw/pull/82891#issuecomment-4469282923
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
* fix: route subagent announce to originating parent session instead of channel-bound peer session
When a subagent is spawned from agent:main:main while a Telegram DM is active,
the completion announce was delivered to the parallel Telegram channel session
instead of the originating parent.
Two interacting bugs:
1. The spawn tool received the sandbox/policy session key (Telegram peer key)
as the requester, instead of the real run session key. Fixed by passing
runSessionKey to createSessionsSpawnTool so the registered requester
points to the actual parent session.
2. resolveSubagentCompletionOrigin checked child session bindings before
requester bindings. When both share the same channel+accountId (common
for Telegram DMs), the child binding hijacked the delivery target.
Fixed by checking requester binding first, with child as fallback.
Fixes#80201
* fix: drop subagent_announce from mediated completion set
The subagent_announce addition to AGENT_MEDIATED_COMPLETION_TOOLS was
unrelated to the routing fix and could cause group/channel completions
to fail silently when the subagent does not use the message tool.
This should be addressed separately with proper message-tool-only
guidance (tracked in #80223).
* fix: separate sandbox policy from completion owner in sessions_spawn
PR #80242 passed runSessionKey as agentSessionKey to createSessionsSpawnTool,
which caused spawnSubagentDirect to use the run session key for sandbox policy
checks (resolveSandboxRuntimeStatus). This could make a sandboxed channel run
appear unsandboxed.
Introduce completionOwnerKey as a separate field that is only used for
registerSubagentRun routing (requesterSessionKey), keeping agentSessionKey
for sandbox enforcement, callerDepth, activeChildren, and all other policy
checks.
* fix(agents): preserve subagent ownership routing
---------
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The warning branch added in the previous commit was committed with an
always-false guard (`if (false && skippedCount > 0 && ...)`), so the
notification never fired — flagged by review as [P1]. Remove the
`false &&` so partial-album media loss actually notifies the user, as
the accompanying tests already expect.
Refs #55216
Telegram albums where some photos failed to download were processed
silently: the agent received only the photos that resolved, and the
user was never told images had been lost.
processMediaGroup now tracks a skippedCount (incremented on a
recoverable per-photo fetch error and on a null resolveMedia result).
When at least one photo still resolved, it emits a single anchored
warning per album (never per photo) using the same
withTelegramApiErrorLogging wrapper + swallowed-send pattern as the
existing single-attachment "Failed to download media" notice. The
all-failed-album case is intentionally left silent (out of scope).
Fixes#55216
* fix(browser): derive Chrome launch readiness from a single CDP diagnostic (#82904)
The pre-fix launch path used `isChromeReachable` (a lightweight HTTP
`/json/version` probe) to decide failure, then called the stronger
`diagnoseChromeCdp` only to format the thrown error. On macOS cold
starts where the HTTP probe transiently fails *between* the polling
loop and the diagnostic call, the runtime would throw
"Failed to start Chrome CDP on port ... { ok: true, wsUrl: ... }"
— a self-contradicting error containing a successful diagnostic
result. Per #82904 this is the actual user-visible bug.
Capture `diagnoseChromeCdp` ONCE after the polling loop and use it for
both the decision and the error text. The diagnostic helper already
includes the lightweight reachability check and adds a websocket
`Browser.getVersion` health command, so it is strictly stronger than
the HTTP probe; if `diagnoseChromeCdp` returns ok the launch
genuinely succeeded.
The existing `withMockChromeCdpServer` success test in
chrome.internal.test.ts still exercises this code path end-to-end
(real HTTP server + real websocket handshake), so the regression-safety
case is covered. The asymmetric `probe-fails-but-diagnostic-succeeds`
scenario is hard to mock without restructuring the existing test
harness; this commit ships the fix and relies on the upstream
ClawSweeper review criteria (manual managed-Chrome cold-start proof)
plus the standalone real-behavior probe in the PR body.
* fix(browser): import ChromeCdpDiagnostic type from chrome.diagnostics
The annotation `let finalDiagnostic: ChromeCdpDiagnostic | null` referenced
a type that was only re-exported (not imported) inside chrome.ts, causing
oxlint/tsc to read it as the implicit `error` type and fail check-lint,
check-prod-types, check-test-types, etc. Add the type to the existing
chrome.diagnostics.js import block.
* fix(browser): preserve Chrome launch diagnostic fallback
* test(browser): satisfy launch diagnostic lint
* fix(browser): keep Chrome launch readiness scoped
* test(browser): answer CDP launch mock probe
---------
Co-authored-by: hclsys <hclsys@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- Split the lightweight secrets runtime state and auth-store cache from the full secrets runtime.
- Use the startup fast path whenever gateway startup has no SecretRef values, while preserving cleanup and refresh semantics.
- Add regression coverage for startup-only empty auth-store snapshots and update affected gateway/tool tests.
Verification:
- pnpm test src/secrets/runtime.fast-path.test.ts src/secrets/runtime-state.test.ts src/gateway/server-startup-config.secrets.test.ts src/gateway/server-import-boundary.test.ts src/gateway/server-aux-handlers.test.ts src/gateway/server-methods/config.shared-auth.test.ts src/agents/tools/web-tools.enabled-defaults.test.ts src/agents/tools/web-tool-runtime-context.test.ts -- --reporter=verbose
- pnpm build
- pnpm format:check -- src/agents/tools/web-tools.enabled-defaults.test.ts src/secrets/runtime-command-secrets.ts src/secrets/runtime-fast-path.ts src/secrets/runtime.fast-path.test.ts src/agents/auth-profiles/store.ts src/agents/auth-profiles/store-cache.ts src/secrets/runtime-state.ts src/secrets/runtime-state.test.ts src/gateway/server-startup-config.ts
- codex-review --mode branch
- isolated gateway token-auth smoke: openclaw gateway run + openclaw gateway health returned ok: true
- GitHub CI on PR #83031 green; newer Real behavior proof run passed on current SHA f27ed3f7ce.
Co-authored-by: samzong <samzong.lu@gmail.com>
Materialize agent-runtime plugin credentials through the shared command
secret resolution path before local web search/fetch runs, matching gateway
runtime behavior for plugins.entries.*.config.webSearch.apiKey refs.
Fixesopenclaw/openclaw#82621
Co-authored-by: Cursor <cursoragent@cursor.com>
Route Together video generation through the v2 video API even when shared Together text config points at the v1 base URL.
Verification:
- pnpm test extensions/together/video-generation-provider.test.ts
- pnpm check:test-types
- git diff --check
- codex-review --parallel-tests "pnpm test extensions/together/video-generation-provider.test.ts"
- gh pr checks 82992 --watch --fail-fast=false
Summary:
- Reuse the prepared gateway startup auth SecretRef snapshot when the startup config still matches the preflight source.
- Preserve fresh activation fallback for config mismatches and shared weak-token, warning, and recovery handling.
- Add focused regression coverage and changelog entry.
Verification:
- pnpm test src/gateway/server-startup-config.secrets.test.ts
- GitHub checks green on 72587758ee
Avoid installing Codex native PostToolUse/Stop hook relays when OpenClaw has no matching local handlers. This keeps pre-tool safety and permission approval relays active while removing idle no-op subprocess fan-out.
Fixes#76552.
Co-authored-by: evgyur <evgyur@users.noreply.github.com>
* fix: route Codex OpenAI runtime through Codex provider
* docs: add Codex routing evidence collection
* fix(agents): bootstrap OAuth credentials for Codex harness with openai/* model refs
When a plugin harness (e.g. Codex) owns its transport but the runtime
plan resolved to openai-codex via agentRuntime.id: codex, the auth
profile store was left empty because pluginHarnessOwnsTransport short-
circuited initializeAuthProfile(). This caused 'No API key found for
openai-codex' at runtime even though the OAuth profile existed in OpenClaw's
store.
- Add pluginHarnessNeedsOpenClawAuthBootstrap flag when harness owns
transport but the provider is openai-codex and the API is openai-codex-
responses
- Populate authStore and attemptAuthProfileStore from OpenClaw's profile
store in this case
- Run initializeAuthProfile() to forward the OAuth token into the harness
- Update overflow-compaction tests to expect 'openai-codex' provider
and add dedicated test for OAuth bootstrap path
* fix(agents): refresh Codex OAuth credentials on profile rotation
---------
Co-authored-by: PsiClawOps <267826480+PsiClawOps@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fixes#82882.
Browser Control UI connect frames now advertise the shared Gateway protocol constants instead of stale protocol 4 literals, and the node UI gateway test asserts the emitted protocol range.
Track the latest partial-preview reply text during reply-agent runs and suppress matching final text-only payloads so Telegram partial streaming does not resend already-previewed blocks when block streaming is disabled.
Keep the dedupe exact-match based to avoid dropping unrelated short finals, preserve errors, and keep unsent media while stripping duplicate caption text.
* Preserve authored config metadata in doctor
* Preserve legacy default model during doctor repair
Keep defaultModel out of the public schema while allowing doctor repair writes to preserve the legacy root metadata key.
Fixes#82787 by keeping session-backed parent subagent runs active when agent.wait only hits a poll timeout before the child session settles. Refactors terminal session-store reconciliation into a shared helper and rejects stale terminal rows from reused child sessions.
Verification:
- CodexReview clean
- pnpm test src/agents/subagent-registry.test.ts src/agents/subagent-registry.lifecycle-retry-grace.e2e.test.ts src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts -- --reporter=dot
- git diff --check
- pnpm check:changed via Blacksmith Testbox tbx_01krt1rxpkb7vj53mkaqwfserq
- GitHub CI/CodeQL/OpenGrep/Workflow Sanity green; proof gate covered by maintainer proof: override label
Split embedded-run startup diagnostics into attempt-workspace, attempt-prompt, attempt-runtime-plan, and final attempt-dispatch subspans. Adds focused timing formatter coverage and a changelog entry. Fixes#82782.
Summary:
- The branch hides brew-only skill dependency installers during Linux-container onboarding when Homebrew is unavailable, adds container-specific missing-brew guidance, and updates docs, tests, i18n, and changelog text.
- Reproducibility: yes. Current main source inspection shows onboarding can offer a brew-only missing skill su ... ric missing-brew failure; the PR body also includes Testbox container output for before and after behavior.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head a4842f3a7d.
- Required merge gates passed before the squash merge.
Prepared head SHA: a4842f3a7d
Review: https://github.com/openclaw/openclaw/pull/82845#issuecomment-4468958593
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Summary:
- The branch gates isolated cron descendant waits and active-descendant delivery suppression on non-best-effort delivery, adds focused regression coverage, and records an unreleased changelog fix.
- Reproducibility: yes. Source inspection on current main shows the best-effort path reaches the full descenda ... nt suppression without checking deliveryBestEffort; the PR body also records before/after Testbox evidence.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 1a4680126f.
- Required merge gates passed before the squash merge.
Prepared head SHA: 1a4680126f
Review: https://github.com/openclaw/openclaw/pull/82843#issuecomment-4468954163
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Summary:
- Add shared SDK helpers for transcript-backed recovery of ellipsis-truncated final text.
- Use the helper in Discord progress preview delivery so long answers fall through to normal chunked delivery with the full transcript text.
- Refactor Telegram to reuse the shared helper.
Verification:
- node scripts/run-vitest.mjs src/plugin-sdk/channel-streaming.test.ts extensions/discord/src/monitor/message-handler.process.test.ts
- pnpm exec oxfmt --check --threads=1 src/plugin-sdk/channel-streaming.ts src/plugin-sdk/channel-streaming.test.ts extensions/telegram/src/lane-delivery-text-deliverer.ts extensions/telegram/src/lane-delivery.ts extensions/telegram/src/bot-message-dispatch.ts extensions/discord/src/monitor/message-handler.process.ts extensions/discord/src/monitor/message-handler.process.test.ts
- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo
- git diff --check
- pnpm check:changed via Blacksmith Testbox tbx_01krsy80a5qgfw790nm45770xt
- GitHub PR checks green on #82862
- codex-review --mode local: clean, no accepted/actionable findings
Fixes#82807.
* fix(memory): catch up stale sessions on startup
Add a startup catch-up scan for memory session source files so clean gateway restarts compare on-disk transcripts against persisted index file state and mark only missing/newer/resized session files dirty for a normal incremental sync.
* fix(memory): catch up sessions for cli indexing
Ensure one-shot memory index managers also compare session transcripts against persisted source state before no-force CLI syncs, so openclaw memory index can recover stale session rows without requiring --force.
* chore: refresh CI after main repairs
- Refresh selected session usage summaries with bounded background work instead of blocking Gateway responses on full transcript scans.
- Persist transcript-level usage metadata so cached full and ranged summaries preserve totals, model usage, tool usage, latency, and time buckets.
- Add regression coverage for background refresh, range derivation, cache-version invalidation, append-only upgrades, and untimestamped usage.
Fixes#82773.
Co-authored-by: hclsys <hclsys@openclaw.ai>
Keep the top-level Telegram default account in the account list when named accounts or bindings are added alongside top-level credentials. This preserves default polling while still allowing named-only configs to resolve to their single configured account.
Include the checked credential source in missing API key errors so users can see which env var, profile, or config path to fix.
Fixes#82785.
Co-authored-by: gleb <116607327+loeclos@users.noreply.github.com>
Fix CLI web search/fetch command SecretRef resolution for provider-scoped plugin credentials.
- Carry command provider overrides through gateway and local secret resolution.
- Mark the selected web provider targets active and unrelated plugin refs inactive.
- Cover Tavily, DuckDuckGo, legacy Firecrawl fetch, protocol overrides, and runtime command-secret behavior.
- Add public plugin-sdk test mock exports needed by existing plugin tests after CI boundary enforcement.
Fixes#82621.
Replacement for #82699.
Co-authored-by: 吴杨帆 <39647285+leno23@users.noreply.github.com>
Fix diagnostics/session usage limit handling and voice-call numeric CLI validation.
- Treat explicit zero, negative, and non-finite diagnostics/session limits as empty results instead of falling back to defaults.
- Reject invalid, non-finite, and fractional voice-call numeric flags.
- Add focused tests and a live repro proof for the canonical edge cases.
Fixes#82646, #82650, #82651, #82653.
Co-authored-by: wuyangfan <1102042793@qq.com>
* Honor cwd for native subagent spawns
Thread sessions_spawn cwd through the native subagent path, use the resolved child workspace for attachment materialization, and keep workspace metadata internal to the gateway boundary.
* Refresh checks after proof update
* Default bootstrap truncation warnings to always
Make bootstrap truncation warnings surface on every affected run by default while preserving explicit off and once configuration.
* Refresh checks after proof formatting fix
* Refresh checks after live proof update
* docs: align bootstrap warning default reference
Update the public agent config reference to match the new default bootstrapPromptTruncationWarning mode and recommended example.
No-arg session_status calls now resolve against the live run session when
runSessionKey is available, so thinking level and other session state match
the active run instead of a stale sandbox/policy key.
Fixesopenclaw/openclaw#82669
Co-authored-by: Cursor <cursoragent@cursor.com>
Fix QQBot debug logging so only explicit truthy `QQBOT_DEBUG` values (`1`, `true`, `yes`, `on`) enable debug output. False-like values such as `0`, `false`, `off`, and `no` now keep debug logs disabled, preventing accidental message-text logging.
Also add the release changelog entry and remove a stale unused daemon inspection helper that failed current `tsgo:prod` after rebasing onto latest main.
Fixes#82644.
Thanks @leno23.
Co-authored-by: wuyangfan <1102042793@qq.com>
* Recover edit tool failures for file_path
Honor file_path and related aliases when resolving edit recovery paths so post-write errors do not surface false edit failures after the file changed.
* Refresh checks after proof formatting fix
* Refresh checks after live proof update
The openai-completions OpenRouter passthrough records the response field
name ("reasoning", "reasoning_details", "reasoning_content",
"reasoning_text", "content") as the assistant block's
`thinkingSignature`. Those values are provenance tags rather than
JSON-encoded reasoning items, so replaying them in the next request body
breaks providers that expect a structured signature (OpenRouter returns
HTTP 500 on the 2nd turn for Anthropic Claude and xAI Grok via the
openai-completions API).
Stop persisting the provenance tag (only keep replayable JSON signatures)
and harden the responses replay path with a matching JSON guard so
existing transcripts with poisoned signatures recover cleanly.
Fixes#82335
Restore Omit on public plugin-sdk ReplyPayload; set trustedLocalMedia via
runtime assertion in speech-core and explicitly on dispatch TTS-only finals.
Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid per-block final-mode synthesis (duplicate with dispatch tail). Mark
TTS output as trusted local media and pass the flag through the TTS-only
final payload WebChat consumes after block streaming.
Fixes#82628
Co-authored-by: Cursor <cursoragent@cursor.com>
WebChat streaming uses kind=block for assistant text; final-mode TTS skipped
those payloads. Mark synthesized audio as trustedLocalMedia and export the
full ReplyPayload type so the gateway can serve local TTS files.
Fixes#82628
Co-authored-by: Cursor <cursoragent@cursor.com>
Updates the xAI image model catalog and docs to use `grok-imagine-image-quality` after `grok-imagine-image-pro` retirement.
Co-authored-by: Kate <kate@trantor.dev>
* feat: show provider quota in control ui overview
* feat: show provider quota in chat header
* fix: recover stale control ui chat runs
* fix: polish control ui quota refresh
* Add config unset dry-run
Add --dry-run support to config unset, including JSON output and allow-exec validation parity with config set/patch dry-run handling.
* Refresh checks after proof update
* fix(config): address unset dry-run review
Return structured JSON when config unset dry-run misses a path and validate broad secret provider/default unsets against affected SecretRefs.
Fix logs.tail credential-header redaction and JSON-mode gateway transport errors.\n\nFixes #66832.\nFixes #79108.\nSupersedes #67041.\nSupersedes #79233.\n\nCo-authored-by: Mil Wang <mingjwan@microsoft.com>\nCo-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
* Fix chat session picker agent switching
Reset the chat session picker to the selected agent main session when switching agents and hide inactive sub-agent sessions from the normal picker options.
* fix(ui): preserve dashboard session on agent switch
Choose the most recent eligible normal/dashboard session for the selected agent while excluding subagent/internal rows; fall back to main only when no eligible session exists.
* fix(ui): avoid mutating session option sort
ClawSweeper R3 flagged that the previous follow-up added the
`cancelDelivered` hook to the public approval-handler runtime interaction
surface but left the channel plugin docs describing `interactions` as
only bind/unbind/clear-action hooks. Extend the bullet so plugin authors
whose `deliverPending` registers in-process or persistent state know
when to implement the cancellation hook.
AI-assisted: drafted with claude code (claude-opus-4-7).
Address the ClawSweeper R2 finding that the pre-bind stopped guard
introduced in this PR drops a delivered entry without any cleanup. The
prior PR comment block was correct only for adapters whose deliverPending
has no in-process side effects; Matrix registers a reaction target in
both an in-memory Map and a persistent store inside deliverPending, so
the entry would leak until the 24h TTL (or process restart) every time
stop() landed between deliverPending and bindPending.
Add an optional cancelDelivered interaction hook on the runtime types,
forward it through both the spec-to-adapter wrapper
(createChannelApprovalNativeRuntimeAdapter) and the lazy adapter wrapper
(createLazyChannelApprovalNativeRuntimeAdapter), and invoke it from the
two stopped guards in deliverTarget: the pre-bind guard always calls it,
and the post-bind guard calls it on the branch where bindPending
returned no handle (so unbindPending cannot run). Matrix implements the
hook by calling unregisterMatrixApprovalReactionTarget on the entry's
roomId + reactionEventId, which is the exact key
registerMatrixApprovalReactionTarget uses inside deliverPending.
The other native runtime adapters (Slack, Discord, Telegram, qqbot)
leave the hook unimplemented because their deliverPending paths only
emit remote messages and keep no in-process state to drop.
Regression coverage:
- invokes cancelDelivered when stop() fires between deliverPending and
bindPending (Deferred-gated deliverPending, asserts bindPending /
unbindPending never run and cancelDelivered receives the entry)
- invokes cancelDelivered when stop() fires after bindPending returned
null (asserts unbindPending stays uncalled while cancelDelivered fires)
AI-assisted: drafted with claude code (claude-opus-4-7).
The previous commit invoked unbindPending in the deliverPending→bindPending
race path before any binding existed; nativeRuntime.interactions.unbindPending
requires a binding, so the dts build failed with TS2345. In production the
race window that PROOF-CAND-040 measured is always after bindPending (3/3
trials had bindPending=1), so dropping the pre-bindPending unbindPending
call does not change observed cleanup behavior: that branch now just nulls
out the in-flight delivery. The post-bindPending branch keeps the
unbindPending call (binding handle present) and remains the only path
required to fix the leak.
The regression test is updated to park bindPending (not deliverPending)
before invoking stop(), matching the production race window.
AI-assisted: drafted with claude code (claude-opus-4-7).
createChannelApprovalHandlerFromCapability shares a closure-scoped
activeEntries Map across deliverTarget / finalizeResolved /
finalizeExpired / onStopped, with no synchronization primitives in the
file. deliverTarget's two awaits (transport.deliverPending then
interactions.bindPending) bracket a read-modify-write on activeEntries;
if onStopped clears the map between those awaits, the wrapped entry is
inserted into an already-cleared map and never reaches unbindPending —
the native side keeps its listener / channel binding open forever.
Production-faithful e2e measured this 3/3 trials: bindPending=1,
unbindPending=0 per request.
Track a closure-scoped `stopped` flag set by onStopped, and have
deliverTarget call unbindPending and bail to null on each await when
stopped becomes true. nativeRuntime contracts (transport / interactions
signatures) are untouched.
AI-assisted: drafted with claude code (claude-opus-4-7).
Fixes #73990.\n\nAdds a transcript-derived token estimate for local/OpenAI-compatible session transcripts that have real content but no provider usage telemetry, preserving provider-reported usage when available and gating estimation on assistant model identity.\n\nVerification:\n- CI run 25965717279: success\n- Real behavior proof run 25965716561: success\n- Azure Crabbox clean-clone proof: pnpm test src/gateway/session-utils.fs.test.ts src/status/status-message.test.ts; pnpm check:changed; pnpm exec tsx /tmp/openclaw-transcript-proof.mts; git diff --check origin/main...HEAD
* fix(slack): route DM thread replies to main session instead of thread-scoped session
DM thread replies (user replies inside a thread under a bot message in a
DM) were routed to a thread-specific session key instead of the user's
main DM session. This caused the agent to never receive the inbound on
the expected session, making the bot appear unresponsive.
The root cause was in prepare-routing.ts: canonicalThreadId for
isDirectMessage was set to threadTs when isThreadReply was true, creating
a session key like agent:main:slack:direct:u3🧵<ts>. DM threads
are a UI affordance — not a session boundary — so all DM messages should
route to the main DM session regardless of thread_ts.
Also adds a diagnostic logVerbose warning when assistant_app_thread
message_changed events fail sender resolution (Case 2 of #82390),
which was previously completely silent.
Fixes#82390
* chore(slack): polish DM thread routing PR
* test(slack): update DM thread routing contract
* test(slack): flatten non-main DM thread expectations
* fix(slack): preserve bound DM thread routes
* test(slack): align DM thread session fixtures
* fix(slack): keep flattened DM thread metadata scoped
* fix(slack): preserve DM thread delivery routes
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fixes#82576.
Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations.
Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
* Fix bundled channel dist-runtime setup roots
Resolve bundled channel generated entries from dist-runtime before falling back to source paths, and select the dist-runtime plugin root as the boundary root for packaged setup modules. This keeps the fs-safe module open boundary check intact while preventing packaged bundled setup entries from being checked against the source extensions root.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Repair session store validation test fixtures
Update current-main tests that wrote persisted session entries without valid session IDs after session store loading started filtering invalid entries. Keep the fixture-only repair separate from the bundled channel loader fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Repair pairing and cron validation fixtures
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add first-class session.operation start/end events for manual compaction and render the existing WebChat compaction indicator from those events.
Co-authored-by: Conan Scott <271909525+Conan-Scott@users.noreply.github.com>
Preserve hard validation failures for official external memory slot plugins that are blocked by registry diagnostics, while keeping missing uninstalled official memory plugins warning-only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Route WebChat image attachments through the configured imageModel when the active session model cannot accept images, while keeping one-turn image auth and fallback state ephemeral.
Thanks @frankekn.
Summary:
- The PR adds model-scoped `claude-cli` runtime policy to Anthropic CLI migration/default backfill, updates the gateway CLI live-smoke config, tests, and changelog.
- Reproducibility: yes. source inspection gives a high-confidence reproduction path: current main writes `clau ... del/provider-scoped runtime policy. I did not run a live Telegram/Dashboard repro in this read-only review.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 62cf54484f.
- Required merge gates passed before the squash merge.
Prepared head SHA: 62cf54484f
Review: https://github.com/openclaw/openclaw/pull/82546#issuecomment-4466676206
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Summary:
- The PR preserves Kimi Coding reasoning_content replay for OpenAI-compatible tool-call follow-up turns, extends replay model-id matching, adds Kimi wrapper/tests, and updates the changelog.
- Reproducibility: yes. at source level: current main drops or fails to synthesize reasoning_content for kimi- ... es a concrete Kimi 400 after tool-call history. I did not run a live Kimi request in this read-only review.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 9a4605ee38.
- Required merge gates passed before the squash merge.
Prepared head SHA: 9a4605ee38
Review: https://github.com/openclaw/openclaw/pull/82550#issuecomment-4466701075
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
Summary:
- Limit canonical OpenAI Codex app-server attribution rewrites to local transcript and trajectory records.
- Keep runtime/tool routing on the selected OpenAI model metadata, including OpenAI API-key backup profiles.
- Fix the current gateway-readiness lint blocker that was red on main.
Verification:
- codex-review branch helper clean with focused Codex app-server tests.
- pnpm lint --threads=8
- pnpm test src/commands/gateway-readiness.test.ts
- GitHub CI run 25960997256 green.
Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
Adapts @tynamite's fix from the abandoned #77945 to current main (which
moved to replaceFileAtomic after that PR was opened), and adds the docs +
changelog updates clawsweeper flagged plus a regression test for the
field condition from #80960.
When repairSessionFileIfNeeded writes a cleaned transcript, the sibling
*.bak-<pid>-<ts> snapshot is deleted after the atomic replace succeeds.
It is only retained — and only then reported via backupPath — when the
cleanup itself fails. This prevents the unbounded accumulation observed
in #80960, where a stuck operations-agent session with a persistently
malformed JSONL line caused 2,180 ~1.8 MB backup files to pile up over
~25 hours inside two gateway processes (PIDs 1220 and 2640).
Test changes:
- Replace requireBackupPath helper with expectNoRetainedBackup that
also asserts no .bak-* siblings remain on disk.
- Update the four call sites that used to read the retained backup.
- Add a regression test that drives repair five times against a file
with a recurring malformed tail and asserts zero retained backups.
Docs:
- docs/reference/transcript-hygiene.md: describe backup as transient,
retained only on cleanup failure.
Fixes#80960. Supersedes #77945. Co-authored by @tynamite — credit for
the original approach.
Co-authored-by: tynamite <35367599+tynamite@users.noreply.github.com>
* fix doctor codex plugin runtime repair
* add changelog for codex doctor repair
* avoid implicit codex repair without agent routes
* expect codex repair in doctor config flow
* fix(cron): bootstrap external channel delivery targets
Allow isolated cron delivery target resolution to opt into outbound channel plugin bootstrap when the loaded-plugin fast path misses. Thread the explicit allowBootstrap flag through resolveOutboundTarget so externalized non-startup channel plugins can be resolved without changing default hot-path behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore: refresh proof for cron bootstrap PR
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Downgrade stale optional web search provider plugin installs to validation warnings so Gateway and doctor repair paths keep running after startup provider selection landed in #82376.
Refs #82313.
Validate Discord read message results before normalizing channel history, preserving the Discord array contract while replacing opaque map crashes with a clear boundary error.
Fixes#82252.
Raise bounded gateway lifecycle hook wait budgets to 5 seconds for shutdown and 10 seconds for pre-restart, keeping the fix to defaults only instead of adding config surface.
Includes regression coverage, hook docs, changelog credit for @bryanbaer, and replaces #82186 with the narrower maintainer fix.
Summary:
- Preserve inbound sender metadata and source-channel provenance in Codex app-server prompt mirrors.
- Reuse the shared prompt-mirror builder for normal and `turn/start` failure snapshots.
- Add regression coverage for provider variants such as `discord-voice` while keeping `sourceChannel` on the originating channel.
Verification:
- `pnpm test extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `pnpm exec oxfmt --check extensions/codex/src/app-server/transcript-mirror.ts extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `git diff --check temp/landpr-82184..HEAD`
- `/Users/steipete/Projects/agent-scripts/skills/codex-review/scripts/codex-review --parallel-tests "pnpm test extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts"`
Defense-in-depth safety net for #81628: even with the cron-tool fix in
place, any other code path that ever produces a 33-char LINE-shaped
recipient missing its leading capital (C/U/R) would otherwise hit the
LINE API and return HTTP 400 with no permanent-error signal, causing
delivery-recovery to retry five times before moving the entry to
failed/.
normalizeTarget now throws "Recipient is not a valid LINE id ..." when
the post-strip value looks like a LINE id but the case was lost. The
message matches the existing /recipient is not a valid/i pattern in
delivery-queue-recovery's PERMANENT_ERROR_PATTERNS, so recovery moves
the entry to failed/ on the first attempt instead of silently retrying.
Short fixtures (length < 33) are left alone so existing tests using
"U123", "line:user:1", etc. keep working.
LINE chat ids are case-sensitive (push requires capital C/U/R) but the
session key holds the peer id lowercased for canonical routing. When
cron-tool runs without currentDeliveryContext (delivery-recovery, queue
replay after reply-token expiry), inferDeliveryFromSessionKey was
lifting the lowercased fragment straight into delivery.to, producing a
value LINE rejects with HTTP 400 — the job retried five times silently
and the dashboard reported "delivered" while the LINE group received
nothing.
Refuse the session-key fallback for channel === "line" so the missing
target surfaces explicitly instead of scheduling an undeliverable job.
Fix Gemini/Gemma attributed and self-closing <final> tag leaks across sanitizer, reasoning cleanup, and embedded Pi streaming enforcement.\n\nProof posted in PR body: focused Vitest, formatting, diff check, real Google Gemini/OpenRouter/local Gemma live output.
DeepSeek V4 via OpenRouter injects reasoning_content: "" on assistant
messages that contain tool_calls. The sanitizer only deleted the field
when it was not a string, so empty strings slipped through and were
replayed on follow-up turns. OpenRouter rejects the field with an
HTTP 500 Internal Server Error instead of a descriptive 4xx, breaking
every subsequent tool-call turn for the session.
Also strip empty-string reasoning for the same reason.
Closes#82150
Fix Codex app-server turns that go quiet after the last non-assistant current-turn item completes without turn/completed.\n\nMaintainer proof: focused watchdog regression passed on rebased head, diff whitespace check passed, and local OpenClaw CLI + WebSocket app-server transport proof observed turn/interrupt after the short idle watchdog.\n\nCo-authored-by: funmerlin <funmerlin@users.noreply.github.com>
Route Discord and Slack prepared message turns through the core prepared-turn runner directly.
Local proof before landing:
- node scripts/run-vitest.mjs src/channels/turn/kernel.test.ts extensions/discord/src/monitor/message-handler.process.test.ts extensions/slack/src/monitor/message-handler/prepare.test.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental false
- node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental false
- OPENCLAW_TESTBOX_REMOTE_RUN=1 OPENCLAW_VITEST_MAX_WORKERS=1 pnpm check:changed
- codex-review clean after accepted Slack bot-loop history cleanup finding was fixed in core
GitHub checks had no failures; Blacksmith/GitHub runner jobs were still queued when maintainer approved landing based on local proof.
canBridgeNoDeviceChatApprovalFromBackend used matchesRequiredString for
turnSourceTo, which returns false when expected is null. Channels without
a recipient concept (webchat, control-ui) leave turnSourceTo null on both
the approval snapshot and the replay params, so every backend
gateway-client replay was rejected with APPROVAL_CLIENT_MISMATCH after
the approval prompt was answered. turnSourceAccountId and turnSourceThreadId
in the same function already use matchesOptionalString for the same reason;
turnSourceTo was missed when PR #78728 added the helper.
Switch to matchesOptionalString so null-on-both-sides matches. Cross-channel
replay protection is preserved by the existing required turnSourceChannel
and sessionKey checks. Added a regression test asserting webchat replay
with null turnSourceTo is accepted.
Ensure runtime plugins are loaded before resolving cron delivery context,
preventing multi-channel ambiguity errors when using external channels.
Implemented via a lazy facade to preserve fast isolated agent startup.
Slack link unfurls (inline message previews) are enabled by default
when unfurl_links is not explicitly set in chat.postMessage. This means
bot messages containing Slack message links or URLs automatically expand
into rich preview cards, which can be noisy in channels.
Default unfurl_links to false so outbound messages don't show inline
link previews unless the operator explicitly opts in via:
channels.slack.unfurlLinks: true
unfurlMedia remains opt-in (only sent when explicitly configured).
Threads the runtime config through buildKnownAgentRunFailureReplyPayload
into resolveExternalRunFailureTextForConversation so the documented
agents.defaults.silentReply / surfaces.<id>.silentReply policy is
consulted before silencing failure copy in groups/channels. Default
policy (group: allow, direct: disallow, internal: allow) preserves the
existing 'groups stay quiet on generic runner failure' behavior; opting
into silentReply.group: disallow now lets the run-failure copy reach
the chat instead of disappearing.
Resolves an internal inconsistency: route-reply.ts already routes
NO_REPLY-style payloads through resolveSilentReplyPolicy(), but the
failure-fallback path in agent-runner-execution.ts hardcoded silence on
chat type alone, ignoring the operator-visible knob.
Refs #82060.
* feat: attach recent inbound history images
* fix: bound recent history media downloads
* fix: preserve sticker history media
* fix: enforce history media cap for stickers
* refactor: name agent turn attachments generically
* refactor: share pending history media recording
* fix: gate historical media attachment visibility
* fix: avoid media runtime on text-only turns
* fix: preserve fallback history media selection
* fix: avoid sparse media history index collisions
* fix: skip history images for current non-image media
* test: import history media type directly
* test: satisfy agent media runtime mock lint
* fix: respect mocked Slack media fetches
* fix: settle history media recording races
Keep queued system-event owner downgrades as structured runtime metadata while rendering the model-visible prompt as plain `System:` lines.
This preserves least-privilege wakeups for webhook/node/exec/cron/reaction/hook producers, keeps legacy `trusted: false` compatibility for installed plugins and older hosts, and updates representative gateway, agent, cron, plugin, and OpenGrep coverage.
* fix(agents): scope provider SSRF trust by origin
* fix(provider): preserve explicit private-network deny
* docs(provider): document exact-origin SSRF trust
* test(provider): cover exact-origin SSRF edges
* docs(provider): align local model private-origin guidance
* refactor(ssrf): keep policy merging in infra
* test(ssrf): cover exact-origin trust through guard
* test(ssrf): block sibling private-origin redirects
* fix(provider): keep loopback trust origin-scoped
* fix(provider): block metadata origin trust
* fix(ssrf): keep metadata rebinding blocked
* fix(ssrf): block cloud metadata origins
* fix(ssrf): block ipv6 metadata origins
* fix(ssrf): block embedded metadata origins
* test(ssrf): cover embedded link-local metadata
* test(provider): cover custom anthropic proxy classification
* test(provider): widen transport policy mock
* test(plugin-sdk): assert metadata-IP allowedOrigins entries are rejected
Plugin authors can construct an SsrFPolicy that lists any well-formed
http(s) origin in allowedOrigins. The abuse-resistance lives one layer
deeper, in resolvePinnedHostnameWithPolicy's metadata/link-local block.
Add an SDK-level smoke test asserting that contract directly:
- AWS/Alibaba IMDS IPv4 literals, GCP metadata canonical hostname,
IPv6 ULA metadata literal, and non-metadata link-local IPv4 entries
build a policy via ssrfPolicyFromHttpBaseUrlAllowedOrigin and are
then rejected at resolvePinnedHostnameWithPolicy.
- DNS rebinding from a trusted private DNS origin to a metadata IP is
rejected even when the request hostname is origin-trusted.
This would fail if the SDK helper or resolveSsrFPolicyForUrl ever
short-circuited past the metadata block.
* chore(docs): regenerate baselines after upstream rebase
upstream/main moved between rebases; the merged source state for the
PR's `src/config/schema.help.ts` change and the upstream plugin-sdk
surface changes both produce different hashes than the committed
baselines, so `config:docs:check` and `plugin-sdk:api:check` would fail.
Regenerated via `pnpm config:docs:gen` + `pnpm plugin-sdk:api:gen` on
Crabbox; both baselines verified with their respective `--check`
generators.
* test(plugin-sdk): assert SSRF blocked error class
* fix(lint): satisfy exact-origin PR lint rules
* docs: clarify custom provider origin trust
* chore(docs): refresh plugin sdk api baseline
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- Align WebChat desktop header controls to a compact 44px header and 36px control rhythm.
- Replace the auto-scroll text dropdown with an icon toggle that keeps tooltip, title, aria-label, and pressed state.
- Lay out mobile chat action icons as a five-column full-width grid.
Verification:
- git diff --check origin/main...HEAD
- pnpm changed:lanes --json
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/ui/app-render.helpers.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/styles/layout.css ui/src/styles/layout.mobile.css ui/src/styles/chat/layout.css ui/src/styles/chat/layout.test.ts ui/src/styles/layout.mobile.test.ts
- pnpm lint:core
- pnpm test ui/src/styles/chat/layout.test.ts ui/src/styles/layout.mobile.test.ts ui/src/ui/app-render.helpers.browser.test.ts
- pnpm ui:build
- Browser proof at desktop 1200x760 and mobile 390x844
- Exact-head GitHub CI green for a25444c5fa
Summary:
- The branch changes the Azure OpenAI Responses transport default API version from `2024-12-01-preview` to `preview`, updates the focused unit assertion, and adds a changelog entry.
- Reproducibility: yes. The source PR provides live Azure curl/OpenClaw commands showing dated defaults fail w ... `api-version=preview` succeeds, and current main still resolves an unset env var to the old dated default.
Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: update DEFAULT_AZURE_OPENAI_API_VERSION to 2025-04-01-preview (i…
- PR branch already contained follow-up commit before automerge: fix: use preview literal for AZURE_OPENAI_API_VERSION
- PR branch already contained follow-up commit before automerge: fix: repair Azure API version PR diff and tests
- PR branch already contained follow-up commit before automerge: fix: keep Azure image API version default
- PR branch already contained follow-up commit before automerge: fix: update Azure OpenAI API version default to preview
Validation:
- ClawSweeper review passed for head d7062f162f.
- Required merge gates passed before the squash merge.
Prepared head SHA: d7062f162f
Review: https://github.com/openclaw/openclaw/pull/82072#issuecomment-4458291270
Co-authored-by: Leo Ge <116452300+leoge007@users.noreply.github.com>
Co-authored-by: leoge007 <leoge@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Summary:\n- Add optional per-agent bootstrap profile overrides for contextInjection, bootstrapMaxChars, and bootstrapTotalMaxChars.\n- Resolve per-agent bootstrap profile settings before agents.defaults and thread the resolved session agent through embedded, compact, CLI, and /context diagnostic paths.\n- Update schema/help/docs/changelog plus focused runtime, schema, and /context regression coverage.\n\nVerification:\n- Local focused auto-reply tests and formatter checks passed.\n- Local pnpm check:changed passed before landing follow-ups.\n- Local Node 24 pnpm check:test-types passed after merging latest main into the PR branch.\n- GitHub PR state CLEAN at 0ff12062840f42daf2666c5fabb127c3f7631669.\n- ClawSweeper re-review completed successfully with no actionable repair finding.\n\nFixes #69966.
Treat configured-but-unresolved Discord token refs as configured so gateway startup reaches the explicit SecretRef resolution error instead of silently classifying the account as unconfigured. Also cover runtime snapshot resolution for active Discord token refs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary:
- Add the existing delegated markdown code-block copy handler to the Control UI chat sidebar container.
- Fix sidebar-rendered markdown code copy buttons that previously emitted no clipboard write because `.chat-sidebar` sits outside `.chat-thread`.
Verification:
- Unpatched current `origin/main` (`b24a6d2cbd636b0b39b732c962d58e574c748abe`) + temporary regression assertion: `pnpm test ui/src/ui/views/chat.test.ts -t "chat sidebar markdown copy"` failed with 0 `navigator.clipboard.writeText` calls.
- PR patch applied onto current `origin/main` + same temporary regression assertion: `pnpm test ui/src/ui/views/chat.test.ts -t "chat sidebar markdown copy"` passed, 1 test passed and 32 skipped.
- Live PR state before merge: `MERGEABLE`, `CLEAN`, head `2e04e981e992b32920476edc648009ddff7976d0`.
- Duplicate sweep found no same-failure duplicate PR/issue.
- Security check clear: UI event binding only; no dependency, workflow, auth, secret, network, or command-execution surface changes.
Known proof gap:
- No full browser walkthrough was run; the focused jsdom proof covers the exact DOM delegation boundary.
Thanks @tikitoki.
* fix(plugins): keep metadata memo freshness
* fix(plugins): keep metadata memo freshness
* fix(plugins): resolve metadata memo review gaps
* fix(plugins): scope metadata memo watches to env
* fix(plugins): tighten metadata memo fingerprint return type
`resolvePersistedRegistryFastMemoFingerprint` was annotated `: unknown`
but always returns object literals (`{ disabled: true }` or
`{ index, npmPackageJson }`). Spreading the unknown-typed result on
line 478 (`...fastFingerprint`) was rejected by tsgo with TS2698, which
cascaded across every check that runs the project compile (build,
tsgo:prod, check:test-types, lint, all node test shards).
Tighten the return type to `Record<string, unknown>` to match the
function's actual return shapes and unblock the spread.
* test(gateway): tolerate ENOENT in sessions.list spy predicate
The `sessions.list configuredAgentsOnly hides disk-discovered
unregistered agent stores` test spies on `fsSync.readFileSync` and
predicates with `fsSync.realpathSync.native(file) === realDiskOnlyStorePath`
for every captured read. The native realpath call throws on missing
files, so any new readFileSync of a path that may not exist (e.g. the
persisted plugin install records probe added in this PR) crashes the
predicate before the assertion runs.
Wrap the predicate in ENOENT tolerance so the test stays robust against
any future readFileSync of files that may not exist on disk.
* fix(plugins): refresh memo from cached registry
* fix(plugins): use high resolution memo fingerprints
* test(plugins): stabilize memo freshness regression
* test(cli): satisfy config mutation mock hash contract
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Fix the active Control UI WebChat composer path so mobile standalone PWA layouts keep the toolbar above the iOS home indicator even when safe-area insets under-report.
- apply the mobile safe-area composer margin in the later-loading chat layout stylesheet
- add a standalone PWA defensive floor for broken zero safe-area reports
- cover the CSS contract with focused regression coverage
Verification:
- corepack pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/styles/chat/layout.css ui/src/styles/chat/layout.test.ts
- git diff --check
- corepack pnpm test ui/src/styles/chat/layout.test.ts ui/src/ui/chat/chat-responsive.browser.test.ts -- --reporter=verbose
- corepack pnpm check:changed
- GitHub CI green on exact head b2b6007f43Fixes#77408.
Thanks @BunsDev.
Split generic channel config schema out of the provider schema barrel so OpenClawSchema no longer imports provider-specific channel schemas for generic channel defaults validation.
Co-authored-by: samzong <samzong.lu@gmail.com>
Harden Telegram HTML parse fallback so plain-text retries render readable labels and links instead of raw anchors.
Co-authored-by: Sam (OpenClaw) <sam.kpg5stars@gmail.com>
Route managed LaunchAgent package self-updates through the post-exit CLI handoff path and persist handoff helper failures through the update restart sentinel so agent-invoked updates cannot stay pending indefinitely.
Add handoff ownership guards for stale helpers, atomic helper sentinel writes, and regression coverage for unrelated and newer pending sentinels.
Fixes#81894.
Co-authored-by: B.K. <bandark@mac.com>
Add optional context budget/source/reference metadata to plugin hook contexts plus llm_output and sanitized model_call_* hook events.
Thread the existing resolved context-window info through Pi embedded runs, CLI harness runs, and Codex app-server hook emission so plugins can observe the effective budget after agent/model/config caps.
Document the metadata and cover the CLI, Pi, Codex app-server, and model-call paths with focused tests.
Fixes#64327.
Summary:
- Replace the fixed 500px Control UI Logs stream cap with a viewport-responsive max-height plus a 200px floor.
- Keep the offset documented inline and add the changelog entry for #53916.
Verification:
- git diff --check origin/main...HEAD
- git merge-tree --name-only origin/main HEAD
- node assertion confirmed `.log-stream` has `max-height: calc(100vh - 280px)`, `min-height: 200px`, and no `max-height: 500px`
- Source path check confirmed `renderLogs` renders the affected `.log-stream` container
Maintainer note:
- Real behavior proof requirement intentionally overridden by maintainer proof comment: https://github.com/openclaw/openclaw/pull/53916#issuecomment-4455196712
Treat forced OAuth refresh as a hard refresh contract: fallback credentials may be reused only when they changed after the attempted refresh began.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Clever <clever@users.noreply.github.com>
Add a CLI-runtime-gated bridge in runAgentTurnWithFallback that subscribes
to `stream: "assistant"` agent-events for the current runId and re-emits
them as reasoning content through `params.opts.onReasoningStream`. Mirrors
the assistant-text bridge from #76914 and the tool-event bridge from #80046:
same Promise-chain serialization + drain, same silentExpected gate, same
unsubscribe pattern at success/catch/finally.
The reply lane is untouched -- `onPartialReply` continues to settle the
final assistant text via #76914. The reasoning lane now reflects the
model's live text output during streaming, which is the only "what is the
model producing right now" signal available for claude-opus-4-7 over
claude-cli (Anthropic suppresses readable thinking_delta events on the
wire for opus-4-7; only thinking content_block + signature_delta arrive).
The bridge is gated on isCliProvider so API/native runtimes that already
get reasoning content from real thinking_delta events do NOT double-receive
text_delta as reasoning.
Tests cover:
- Forwards assistant agent-events to onReasoningStream with correct text
- Respects silentExpected (heartbeat / NO_REPLY runs don't emit)
- Does not fire on the API/native runtime path (gate works)
Summary:
- Sanitize Control UI form-mode config submissions after schema coercion and before config.set/config.apply.
- Drop stale redacted placeholders only when the loaded form also had the redaction sentinel and the original raw config lacks that path.
- Preserve restorable saved secrets and user-entered literal sentinels so the gateway's fail-closed validation remains authoritative.
Verification:
- node scripts/run-vitest.mjs ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/ui/controllers/config.ts ui/src/ui/controllers/config/form-utils.ts ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts docs/web/control-ui.md CHANGELOG.md
- git diff --check origin/main...HEAD
- pnpm check:changed
- GitHub PR checks green on head b35a5b975d
Remove the bundled codex-cli backend, migrate legacy codex-cli refs and runtime pins to the Codex app-server runtime, and update live/backend workflow coverage for the supported CLI lanes.
Adds owner-level startup trace attribution for gateway auth, plugin loading, lookup counts, and plugin sidecar services.
Verification:
- node scripts/run-vitest.mjs src/plugins/startup-trace-segment.test.ts src/plugins/services.test.ts src/plugins/loader.test.ts src/gateway/server-startup-config.secrets.test.ts
- pnpm build
- pnpm check
CI override:
- Red checks are unrelated baseline noise. The failed CI shard is src/cli/plugins-install-persist.test.ts, which fails on origin/main 336ba2a2b3 with the same missing resolveIsNixMode mock export. PR #81738 touches gateway/plugin startup trace files and CHANGELOG.md, not the failing CLI plugin install test.
Thanks @samzong.
Co-authored-by: samzong <13782141+samzong@users.noreply.github.com>
Widen daily memory filename discovery so slugged session-memory files flow through Dreaming, rem-backfill, rem-harness, doctor, and short-term promotion.
Preserve exact slugged source paths during historical seeding and rem-backfill attribution, including multiple files for the same day.
Add regression coverage for slugged ingestion, rem-backfill, rem-harness preview paths, and doctor backfill day extraction.
Fixes#69536.
Co-authored-by: Jack Storment <crazycoder131@gmail.com>
`deliverMattermostReplyPayload` accepted a substantive (non-reasoning) reply
payload, called the shared `deliverTextOrMediaReply`, and dropped its
`"empty"|"text"|"media"` return value on the floor. When the underlying chunker
or media-resolution produced no text and no media to send, the function
returned `Promise<void>` and the caller in `monitor.ts` unconditionally logged
`delivered reply to <channel>` — masking a silent completion where no
Mattermost API send ever happened (the symptom in #80501).
Thread the outcome through the helper, evaluate it against the original
payload to distinguish intentional reasoning suppression from a substantive
payload that vanished, and log a structured `mattermost no-visible-reply`
diagnostic for the substantive-vanished case. The misleading "delivered
reply to" log now only fires on actual visible delivery; reasoning-skipped
payloads correctly stay silent.
No behavior change: visible-delivery decisions, preview-finalization, and the
existing reasoning-suppression contract are untouched. Operators can now grep
the new diagnostic to detect the failure class instead of seeing the agent
appear to go silent.
Fixes#80501.
- (#63074) Security/sandbox: include Windows USERPROFILE in blocked home roots. Thanks @luoyanglang.
- Models config/auth: stop inferring providers from broad env-var name patterns; use structured SecretRefs only. Thanks @sallyom.
- Media fetch: avoid buffering bodyless responses. Thanks @shakkernerd.
The wizard's applyAuthChoice call dropped provider-specific flag values
like --openai-api-key, only forwarding token/tokenProvider. As a result,
maybeApplyApiKeyFromOption could not honor the flag and onboarding still
prompted "Use existing OPENAI_API_KEY?" when the operator already
passed --openai-api-key alongside an existing env var (e.g. onboard-fast
harnesses that pre-seed --openai-api-key "$OPENAI_API_KEY").
Spread opts into the inner opts bag so provider-specific flag values
reach the provider auth method via ctx.opts. When no flag is passed the
env-confirm prompt still fires unchanged.
Discover provider plugins from setup.providers[].envVars credentials during provider discovery while keeping the deprecated providerAuthEnvVars fallback.
Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>
Treat high-confidence app-server OAuth refresh invalidation as terminal auth-profile failure, while keeping entitlement and rate-limit payloads out of re-auth classification.
Refs #75839.\n\nRebases and lands the sessions.list resolver-cache fix from #77187 after maintainer conflict repair. The change keeps cache state scoped to a single sessions.list call and memoizes deterministic per-row resolver work for repeated provider/model tuples.\n\nVerification:\n- pnpm test src/gateway/session-utils.perf.test.ts src/gateway/session-utils.test.ts\n- pnpm exec oxfmt --check --threads=1 src/gateway/session-utils.ts src/gateway/session-utils.perf.test.ts scripts/github/real-behavior-proof-policy.mjs\n- git diff --check HEAD -- CHANGELOG.md scripts/github/real-behavior-proof-policy.mjs src/gateway/session-utils.perf.test.ts src/gateway/session-utils.ts\n- GitHub PR checks: 87 passing, CodeQL neutral, 21 skipped\n\nCo-authored-by: OpenClaw Agent <openclaw-agent@users.noreply.github.com>
Fix stale Control UI active-run cleanup across terminal, reconnect, reset, and session-switch paths. Adds shared run lifecycle cleanup, stale compaction/fallback reconciliation, focused tests, and the compact composer run-status chip. Fixes#76874 and #64220; refs #71630. Validated with green PR CI on head 141f07158f and focused local UI tests.
Add a persisted Control UI/WebChat auto-scroll mode setting with near-bottom, always, and off modes. The implementation preserves the current near-bottom behavior by default, keeps manual scroll-to-bottom available when automatic scrolling is off, exposes the selector in desktop and mobile chat controls, syncs i18n fallbacks, and adds focused storage/render/scroll coverage.
Verification:
- pnpm test ui/src/ui/app-settings.test.ts ui/src/ui/views/chat.test.ts ui/src/ui/app-render.helpers.node.test.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/storage.node.test.ts ui/src/ui/app-scroll.test.ts -- --reporter=verbose
- pnpm check:changed
- pnpm ui:i18n:check
- pnpm ui:build
- PR CI green on head 1b8859c8baFixes#7648.
Fixes#81287.
Resize iOS chat PhotosPicker image attachments through the shared JPEG transcoder before staging/sending. Cap long edge and payload bytes, strip source metadata, preserve previews from processed data, and add focused processor/view-model regression tests.\n\nFixes #68524.\nSupersedes #73710.
Preserve update-time config state by snapshotting before repair/restart writes, keeping plugin install records available for migration, and blocking unsafe update-time config size drops.
Also documents the Codex reserved SDK subpaths needed by the plugin contract guardrail.
Fixes#80077.
Thanks @Jerry-Xin and @vincentkoc.
Co-authored-by: Jerry-Xin <3401616+Jerry-Xin@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Manual-review items are kind:"manual" with status:"skipped" so they were rendering with ⏭️, which reads like "done, ignored" — exactly the wrong signal for items that still need user attention. Render with 🔍 instead so the row says "look closer here".
Archive items end up status:"migrated" once written to the report dir, so they were rendering with ✅, which overstates what happened — the file was saved aside, not imported. Render with 📖 so the row reads "filed away".
Skill/plugin/secret/memory rows continue to render with their status glyphs (✅❌⏭️⚠️) unchanged. JSON output (--json) is unaffected.
Treat selectable configured OpenAI agent models as Codex runtime requirements during plugin auto-enable, startup planning, and doctor install repair.\n\nPR: https://github.com/openclaw/openclaw/pull/81591
description: "Add a redacted agent transcript section to GitHub PR or issue bodies during OpenClaw agent-created PR/issue workflows."
---
# Agent Transcript
Best-effort local-only provenance for OpenClaw PR/issue bodies. Use during agent-created GitHub PR or issue workflows before creating/updating the body.
## Contract
- Never use network. Session discovery reads local agent logs only.
- Never upload raw logs. Render sanitized Markdown first.
- Always ask the user before adding transcript logs to a GitHub PR/issue body.
- Tell the user sanitized session logs help reviewers and can make PRs easier to prioritize.
- Offer a local HTML preview before insertion. If the user wants preview, open it and wait for confirmation before adding the section.
- Fail closed on unresolved secrets, private keys, browser/session/cookie details, or auth URLs.
- Drop system/developer prompts, raw tool outputs, reasoning, env, cookies, tokens, and broad local paths.
- Keep user prompts, assistant visible decisions, terse tool summaries, and test/proof outcomes.
- Remove session turns unrelated to the PR/issue work. Use the PR/issue title, branch name, changed files, and stated goal as scope; omit earlier/later unrelated tasks even when they are in the same session log.
- Best effort only: PR/issue creation must continue if no safe transcript is found.
- Add the `## Agent Transcript` section only when inserting a real transcript. Never add a placeholder transcript heading or text such as "A sanitized local transcript preview was generated but not included."
- Use a collapsed `<details>` section and update existing markers instead of duplicating sections.
`find` scans the newest 400 matching local JSONL logs by default across Codex, Claude, Pi, and OpenClaw agent sessions. Use `--max-files N` for a wider local search.
2. Run `find` with title, branch, PR URL/number if known, and cwd.
3. If a high-confidence session is found, ask:
`Include a redacted agent transcript? It helps reviewers and can make the PR easier to prioritize. I can open a local preview first.`
4. If the user wants preview, run `preview`, open the HTML with `open`, and wait for confirmation.
5. Before insertion, trim unrelated session turns from the generated section. Keep only turns that explain this PR/issue's goal, implementation choices, files, tests, proof, blockers, and final outcome.
6. If the user approves, run `append-body`.
7. Use the enriched body file for creation/update.
8. If no safe session is found, say nothing and continue without transcript. If the user declines, continue without transcript and do not add any transcript placeholder section.
## Review Artifacts
For manual audits across many PR/session candidates, create a local HTML preview from a local JSON file. This is for maintainers only and is not part of the PR/issue workflow:
```bash
.agents/skills/agent-transcript/scripts/agent-transcript html \
description: "Auto Review closeout. Codex review is the default when no engine is set and is the recommended reviewer."
---
# Auto Review
Run the bundled structured review helper as a closeout check. This is code review, not Guardian `auto_review` approval routing.
Codex review is the default when no engine is set. It usually delivers the best review results and should remain the normal final closeout engine.
Use when:
- user asks for Codex review / Claude review / autoreview / second-model review
- after non-trivial code edits, before final/commit/ship
- reviewing a local branch or PR branch after fixes
## Contract
- Treat review output as advisory. Never blindly apply it.
- Verify every finding by reading the real code path and adjacent files.
- Read dependency docs/source/types when the finding depends on external behavior.
- Reject unrealistic edge cases, speculative risks, broad rewrites, and fixes that over-complicate the codebase.
- Prefer small fixes at the right ownership boundary; no refactor unless it clearly improves the bug class.
- Keep going until structured review returns no accepted/actionable findings.
- If a review-triggered fix changes code, rerun focused tests and rerun the structured review helper.
- For security-audit suppression changes, verify accepted findings remain auditable: suppressed findings stay in structured output, active output keeps an unsuppressible suppression notice, and aggregate findings cannot hide unrelated active risk.
- Never switch or override the requested review engine/model. If the review hits model capacity, retry the same command a few times with the same engine/model.
- Be patient with large bundles. Structured review can take up to 30 minutes while the model call is active, especially with Codex tools or web search.
- Treat heartbeat lines like `review still running: ... elapsed=... pid=...` as healthy progress, not a hang. Let the helper continue while heartbeats are advancing. Pass `--stream-engine-output` when live engine text is useful; Codex and Claude filter tool/file chatter, other engines pass raw output through.
- Do not kill a review just because it has been quiet for 2-5 minutes, or because it is still running under the 30-minute window. Inspect the process only after missing multiple expected heartbeats, after 30 minutes, or after an obviously failed subprocess; prefer letting the same helper command finish.
- Tools are useful in review mode. The helper allows read-only inspection tools and web search by default so reviewers can check dependency contracts, upstream docs, and current behavior.
- Security perspective is always included, but it should not cripple legitimate functionality. Report security findings only when the change creates a concrete, actionable risk or removes an important safety check.
- For regression provenance, if no blamed PR is traceable, use the blamed commit as the provenance: commit SHA, date, and author username. Do not guess a merger or frame missing PR metadata as a separate finding.
- Do not invoke built-in `codex review`, nested reviewers, or reviewer panels from inside the review. The helper builds one bundle, calls one selected engine, validates one structured result, and stops.
- Stop as soon as the helper exits 0 with no accepted/actionable findings. Do not run an extra review just to get a nicer "clean" line, a second opinion, or clearer closeout wording.
- Treat the helper's successful exit plus absence of actionable findings as the clean review result, even if the underlying Codex CLI output is terse.
- Multi-reviewer panels are opt-in only. Use them when explicitly requested or when risk justifies the extra spend; the main agent still verifies every accepted finding before fixing.
- If rejecting a finding as intentional/not worth fixing, add a brief inline code comment only when it explains a real invariant or ownership decision that future reviewers should know.
- If `gh`/Gitcrawl reports `database disk image is malformed`, run `gitcrawl doctor --json` once to let the portable cache repair before retrying review; do not bypass the shim unless repair fails and freshness requires live GitHub.
- If Gitcrawl reports a portable manifest mismatch, source/runtime DB health error, or stale portable-store checkout, run `gitcrawl doctor --json` and inspect `source_db_health`, `runtime_db_health`, and `portable_store_status` before falling back to live GitHub.
- Do not push just to review. Push only when the user requested push/ship/PR update.
## Pick Target
Dirty local work:
```bash
<autoreview-helper> --mode local
```
Use this only when the patch is actually unstaged/staged/untracked in the
current checkout. `--mode uncommitted` is accepted as an alias for `--mode local`.
For committed, pushed, or PR work, point the helper at the commit
or branch diff instead; do not force dirty modes just
because the helper docs mention dirty work first. A clean local review
/Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode commit --commit HEAD
```
Use commit review for already-landed or already-pushed work on `main`. Reviewing
clean `main` against `origin/main` is usually an empty diff after push. For a
small stack, review each commit explicitly or review the branch before merging
with `--base`.
## Parallel Closeout
Format first if formatting can change line locations. Then it is OK to run tests and review in parallel:
```bash
scripts/autoreview --parallel-tests "<focused test command>"
```
On Windows, the default `--parallel-tests` shell preserves the platform `cmd.exe`
semantics used by Python `shell=True`. Use `--parallel-tests-shell powershell`
or `--parallel-tests-shell pwsh` when the focused test command is PowerShell-specific.
Tradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain. Once that rerun exits cleanly, stop; do not spend another long review cycle on redundant confirmation.
## Review Panels
Run multiple reviewers against one frozen bundle:
```bash
<autoreview-helper> --reviewers codex,claude
```
`--panel` is shorthand for Codex plus Claude unless `--engine` changes the first reviewer:
```bash
<autoreview-helper> --panel
```
Set reviewer models and thinking/effort explicitly:
Codex maps thinking to `model_reasoning_effort` and accepts `low`, `medium`,
`high`, or `xhigh`. Claude maps thinking to `--effort` and also accepts `max`.
Engines without a real thinking knob reject `--thinking`.
## Context Efficiency
Run the helper directly so target selection, engine choice, structured validation, and exit status all stay in one path. If output is noisy, summarize the completed helper output after it returns; do not ask another agent or reviewer to rerun the review.
- accepts `--mode uncommitted` as an alias for `--mode local`
- otherwise uses current PR base if `gh pr view` works
- otherwise uses `origin/main` for non-main branches
- supports `--engine codex`, `claude`, `droid`, and `copilot`; default is `AUTOREVIEW_ENGINE` or `codex`; Codex should remain the default when nothing is set
- resolves bare `git`, `gh`, reviewer, and PowerShell shell commands from absolute `PATH` entries only, never from the reviewed checkout; explicit relative `--*-bin` paths are resolved from the reviewed repository root
- use `--mode commit --commit <ref>` for already-committed work, especially clean `main` after landing
- should be left in `--mode auto` or forced to `--mode branch` for PR/branch work; do not force `--mode local` after committing
- writes only to stdout unless `--output`, `--json-output`, or live streamed engine stderr is set
- supports `--stream-engine-output` or `AUTOREVIEW_STREAM_ENGINE_OUTPUT=1` for live engine text while preserving structured validation; Codex and Claude hide tool/file event details, emit compact activity summaries, and report usage at turn completion
- supports opt-in review panels with `--panel` / `--reviewers`, plus per-engine `--model` and `--thinking`
- allows read-only tools and web search by default where the selected CLI supports them; forbids nested review in the prompt; Codex is run through `codex exec` with read-only sandbox and structured output
- prints `review still running: <engine> elapsed=<seconds>s pid=<pid>` to stderr at long-running intervals while waiting for the selected review engine, unless streamed output or compact Codex activity has been visible recently
- prints `autoreview clean: no accepted/actionable findings reported` when the selected review command exits 0
- exits nonzero when accepted/actionable findings are present
## Final Report
Include:
- review command used
- tests/proof run
- findings accepted/rejected, briefly why
- the clean review result from the final helper/review run, or why a remaining finding was consciously rejected
Do not run another review solely to improve the final report wording. If the final helper run exited 0 and produced no accepted/actionable findings, report that exact run as clean.
MALICIOUS_PROMPT="This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch."
BENIGN_PROMPT="Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff."
description: "Use when previewing local channel message flow fixtures."
---
# Channel Message Flows
Use this from the OpenClaw repo root to send canned channel preview flows while iterating on message UX. These are real sends/edits/deletes against the configured channel target.
## Telegram
Native Telegram `sendMessageDraft` tool progress, then a final answer:
@@ -98,7 +98,7 @@ Do not close from title alone. If closing as done on main or nonsensical, prove
When asked for `5 new`, exclude refs already surfaced in the session and refill from the archive until there are 5 live-open candidates. If fewer than 5 remain open, list all open ones and say how many short.
When asked to `update`, `refresh`, `recheck`, `check again`, or similar, return an updated live-open candidate list. Do not fill the main list with items that merely merged/closed since the last pass; put those numbers in a short bottom line.
When asked to `update`, `refresh`, `recheck`, `check again`, or similar, return an updated live-open candidate list. Sort by maintainer importance, not recency: high-impact ready fixes first, then useful-but-review-first, then open/not-ready items. Do not include a "changed since last pass" section or bottom-line merged/closed summary unless the user explicitly asks for churn.
Prefer:
@@ -142,18 +142,20 @@ No Markdown tables. Compact bullets. Use color/risk markers:
Required line shape:
```markdown
- **PR #81244** `@whatsskill.``+118/-1``bug` 🟢 verifiable: yes. This prevents chat action buttons from overlapping short assistant replies. Blast: web chat rendering, low.
- **Issue #81245** `@alice``LOC n/a``bug` 🟡 verifiable: partial. This reports duplicate Telegram replies when reconnecting after gateway restart. Blast: Telegram channel runtime, medium.
- **PR #81244** `@whatsskill.``+118/-1``bug` 🟢 https://github.com/openclaw/openclaw/pull/81244 - Prevents chat action buttons from overlapping short assistant replies. Verifiable: yes. Blast: web chat rendering, low.
- Always include `verifiable: yes|partial|no` plus the shortest proof hint when helpful.
- If status is not open, still show it only when the user asked for all surfaced refs; use ✅ or ⚪ and state merged/closed.
- For refresh-style asks, bottom line: `Merged/closed since last pass: #81016 merged, #81026 closed.` Omit if none.
- For refresh-style asks, prefer section order: `Best Open Now`, `Useful But Review First`, `Still Open / Not Ready`. Omit merged/closed churn by default.
description: Use when testing, fixing, or extending the OpenClaw Control UI GUI with Vitest + Playwright end-to-end checks, mocked Gateway WebSocket flows, mocked dashboard runs, screenshots/videos, or agent-verifiable browser proof.
---
# Control UI E2E
Use this for Control UI changes that need a real browser flow with deterministic Gateway data.
## Test Shape
- Use `ui/src/**/*.e2e.test.ts` for full GUI flows.
- Use `ui/src/test-helpers/control-ui-e2e.ts` to start the Vite Control UI and install a mocked Gateway WebSocket.
- Keep scenarios deterministic. Do not use live provider keys, real channel credentials, or a real Gateway unless the user explicitly asks for live proof.
- Prefer existing `.browser.test.ts` or unit tests for narrow rendering logic; use this E2E lane when the proof should cover routing, app boot, Gateway handshake, requests, and visible UI behavior together.
## Commands
- Target one E2E test in a Codex worktree:
```bash
node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/ui/e2e/chat-flow.e2e.test.ts
```
- Run the whole local lane in a normal checkout:
```bash
pnpm test:ui:e2e
```
If dependencies are missing in a Codex worktree, install once with `pnpm install`; for broad GUI proof or dependency-heavy checks, use Testbox/Crabbox instead of running a wide local pnpm lane.
## Visual Proof Default
When running mocked Control UI/dashboard validation for a user-facing feature, produce visual proof by default unless the user explicitly opts out.
- Keep the Vitest E2E assertions deterministic; do not commit generated screenshots or videos.
- After or alongside the focused E2E test, run the mocked Control UI app when available, for example `pnpm dev:ui:mock -- --port <port>`.
- Drive Chromium with Playwright against the local mock URL and capture a video plus screenshots for each meaningful state: initial view, interaction input, result state, and final/paginated/selected state.
- Use `browser.newContext({ recordVideo: { dir, size }, viewport })`, `page.screenshot({ path })`, and close the context before reporting the video path.
- Put artifacts under `.artifacts/control-ui-e2e/<short-feature-name>/` or another clearly named local temp directory, and report the absolute paths in the final answer.
- Treat recording as validation, not only demo capture. If the recorder fails or shows surprising behavior, stop, fix the behavior, add or update a regression test, then rerecord.
- If visual proof is blocked, state the exact blocker and still report the textual E2E evidence.
## Mock Pattern
Start the app server, install the mock before `page.goto`, then assert both Gateway traffic and visible UI:
Extend `installMockGateway` with typed scenario options or method responses when a new flow needs more Gateway surface.
## Standalone Recording
When recording an already-running mocked Control UI URL, use a temporary Playwright script or `playwright test` spec and keep the recording flow focused:
- Open the mock URL, interact through stable `data-*` selectors or user-facing role selectors, and wait on asserted states instead of relying on fixed sleeps.
- Assert both visible UI state and mocked Gateway traffic for request-driven flows. For example, verify the expected count/row is visible and that `sessions.list` was called with the expected `search`, `offset`, and `limit`.
- Use short sleeps only after assertions to make the captured video readable.
- Store the generated video under `.artifacts/control-ui-e2e/<feature>/`; do not commit it.
description: Use Crabbox for OpenClaw remote validation across Linux, macOS, Windows, and WSL2. Default to Blacksmith Testbox for broad Linux proof; includes direct Blacksmith and owned AWS/Hetzner fallback notes when Crabbox fails.
description: Use the Crabbox wrapper for OpenClaw remote validation across Linux, macOS, Windows, and WSL2, including delegated Blacksmith Testbox proof. Report the actual provider and id.
---
# Crabbox
Use Crabbox when OpenClaw needs remote Linux proof for broad tests, CI-parity
CI=1NODE_OPTIONS=--max-old-space-size=4096OPENCLAW_TEST_PROJECTS_PARALLEL=6OPENCLAW_VITEST_MAX_WORKERS=1OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test
pnpm crabbox:run -- --debug --timing-json -- \
pnpm test
```
Auth fallback, only when `blacksmith` says auth is missing:
@@ -451,9 +589,10 @@ Raw Blacksmith footguns:
- Treat `blacksmith testbox list` as cleanup diagnostics, not a shared reusable
queue.
Escalate to owned AWS/Hetzner only when Blacksmith is down, quota-limited,
missing the needed environment, or owned capacity is the explicit goal. Use the
Owned Cloud Fallback section below.
Use Blacksmith only when the task is specifically about Testbox, brokered AWS
is unavailable, or an explicit comparison is needed. If Blacksmith is down or
quota-limited, do not keep probing it; stay on brokered AWS and note the
delegated-provider outage.
## Blacksmith Backend Notes
@@ -466,13 +605,14 @@ Crabbox Blacksmith backend delegates setup to:
The hydration workflow owns checkout, Node/pnpm setup, dependency install,
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) from messages;"
```
## SQL
Use `discrawl sql` for exact counts, joins, and ranking queries when normal
CLI reads are too coarse. The command is read-only by default, accepts SQL as
args or stdin, and supports `--json` for agent parsing.
Useful examples:
```bash
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) as messages from messages;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(c.name, ''), m.channel_id) as channel, count(*) as messages from messages m left join channels c on c.id = m.channel_id group by m.channel_id order by messages desc limit 20;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(mm.display_name, ''), nullif(mm.global_name, ''), nullif(mm.username, ''), m.author_id) as author, count(*) as messages from messages m left join members mm on mm.guild_id = m.guild_id and mm.user_id = m.author_id group by m.guild_id, m.author_id order by messages desc limit 20;"
```
Never use `--unsafe --confirm` unless the user explicitly asks for a database
mutation and the write has been reviewed.
When the installed CLI lacks a new feature, build or run from a verified
`openclaw/discrawl` checkout before concluding the feature is missing.
## Discord Boundaries
Bot API sync requires configured Discord bot credentials; do not invent token
availability. Desktop wiretap mode reads local Discord Desktop artifacts and
must not extract credentials, use user tokens, call Discord as the user, or
write to Discord application storage. Wiretap/Desktop cache DMs are local-only
and must not be described as part of the published Git snapshot. Git-share
snapshots must not include secrets or `@me` DM rows.
## Verification
For repo edits, prefer existing Go gates:
```bash
GOWORK=off go test ./...
```
Then run targeted CLI smoke for the touched surface, for example:
short_description:"Search local Discord archives and freshness"
default_prompt:"Use $discrawl to search local Discord archives, check freshness, inspect DMs or channel slices, and report exact date spans and source gaps."
description: Use gitcrawl for OpenClaw issue and PR archive search, duplicate discovery, related-thread clustering, and local GitHub mirror freshness checks.
Use this skill before live GitHub search when triaging OpenClaw issues or PRs.
`gitcrawl` is the local candidate-discovery layer. It is fast, includes open and closed threads, and can surface duplicate attempts, related issues, and already-landed fixes. It is not the final source of truth for comments, labels, merges, closes, or current CI.
## Default Flow
1. Check local state:
Use local GitHub issue/PR archives before live GitHub search. Check freshness first:
- Treat `gitcrawl` as stale if `doctor` shows no target thread, an old `last_sync_at`, missing embeddings for neighbor/search commands, or a clearly wrong open/closed state.
- If stale data blocks the decision, refresh the portable store first:
- Run expensive update commands such as `gitcrawl sync --include-comments` only when the user asked to update the local store or stale data is blocking the decision.
- The sync default is all GitHub thread states; pass `--state open`, `--state closed`, or `--state all` only when a task requires a narrower or explicit scope.
## Boundaries
- Use `gitcrawl` for candidates, clusters, and historical context.
- Use `gh`, `gh api`, and the current checkout for live state before commenting, labeling, closing, reopening, merging, or filing a PR review.
- Do not close or label based only on `gitcrawl` similarity. Require matching problem intent plus live verification.
- If `gitcrawl` is unavailable, say so and fall back to targeted `gh search` rather than blocking normal maintainer work.
Report absolute dates, repo names, issue/PR numbers, cluster ids, and source gaps. Do not close/label from similarity alone; require matching intent plus live verification.
Use local Granola archive data first. Check freshness for recent/current questions:
```bash
graincrawl doctor --json
graincrawl status --json
```
Refresh only when stale or asked:
```bash
graincrawl sync --source private-api
graincrawl sync --source desktop-cache
```
Query with bounded reads:
```bash
graincrawl search "query"
graincrawl notes --json
graincrawl note get <id>
graincrawl transcripts get <id>
graincrawl panels get <id>
graincrawl --json sql "select count(*) as notes from notes;"
```
Report absolute date spans, note titles, source gaps, and transcript/panel availability. Use read-only SQL for exact counts/rankings. Before encrypted source debugging, run explicit unlock/secrets checks; do not surprise-prompt Keychain.
Use local Notion archive data before browsing or live Notion API calls. Check freshness for recent/current questions:
```bash
notcrawl doctor
notcrawl status --json
```
Refresh only when stale or asked:
```bash
notcrawl sync --source desktop
notcrawl sync --source api
```
Query with bounded reads:
```bash
notcrawl search "query"
notcrawl databases
notcrawl report
notcrawl sql "select count(*) from pages;"
```
Report workspace/teamspace, page/database titles, absolute date spans, counts, and known gaps. Use read-only SQL only; never mutate the archive. API mode requires `NOTION_TOKEN`; do not assume token availability.
short_description:"Search local Notion archives and freshness"
default_prompt:"Use $notcrawl to search local Notion pages and databases, check freshness, inspect exports, and report exact date spans and source gaps."
description: Write or review high-quality OpenClaw developer documentation.
dependencies: []
---
# OpenClaw Docs
## Overview
Use this skill when writing, editing, or reviewing OpenClaw developer documentation for APIs, SDKs, CLI tools, integrations, quickstarts, platform guides, or technical product docs.
Write documentation that is concise, helpful, and comprehensive: fast for first success, precise for production, and easy to scan when debugging.
## Core Model
Use an OpenClaw documentation model, strengthened by Write the Docs principles:
- Lead with what the developer is trying to do.
- Give one recommended path before alternatives.
- Make examples runnable and realistic.
- Keep guides task-oriented and references exhaustive.
- Explain production risks exactly where developers can make mistakes.
- Link concepts, guides, API references, SDKs, testing, and troubleshooting so readers can move between them without rereading.
- Treat docs as part of the product lifecycle: draft them before or alongside implementation, review them with code, and keep them current.
- Make each page discoverable, addressable, cumulative, complete within its stated scope, and easy to skim.
## Structure
Choose the page type before writing:
- Overview: route readers to the right product, integration path, or guide.
- Quickstart: get a new user to a working result with the fewest safe steps.
- Topic page: give an end-to-end overview of a major domain entity, with setup,
key subtopics, troubleshooting, and links to deeper references.
- Guide: explain one workflow from prerequisites to production readiness.
- API reference: define every object, endpoint, parameter, enum, response, error, and version rule.
- SDK or CLI reference: document install, auth, commands or methods, options, examples, and failure modes.
- Testing guide: show sandbox setup, fixtures, test data, simulated failures, and live-mode differences.
- Troubleshooting guide: map symptoms to checks, causes, and fixes.
Use this default topic page structure:
1. Title: name the major entity or surface.
2. Opening overview: start with a few unheaded sentences that explain what it
is, what it owns, and what it does not own. Do not add a `## Overview`
heading unless the page is itself an overview index.
3. Requirements: include only when setup needs specific accounts, versions,
permissions, plugins, operating systems, or credentials.
4. Quickstart: show the recommended setup path and smallest reliable verification.
5. Configuration: show the minimum configuration needed to use the surface,
common variants users must choose between, and where each option is set:
CLI, config file, environment variable, plugin manifest, dashboard, or API.
6. Major subtopics: organize the entity's major concepts, workflows, and
decisions by reader intent. Put each major subtopic under its own heading;
do not wrap them in a generic `## Subtopics` section.
7. Troubleshooting: diagnose common observable failures under an explicit
`## Troubleshooting` heading.
8. Related: link to guides, references, commands, concepts, and adjacent topics.
Topic pages may be longer than quickstarts, but they should not become exhaustive
references. Move field tables, API contracts, narrow internals, legacy details,
and rare debugging workflows to linked reference or troubleshooting pages when
they interrupt the end-to-end overview.
For configuration, keep task-critical options inline. Link to reference docs for
full option lists, defaults, enums, generated schemas, and advanced settings. Do
not duplicate exhaustive config reference tables in topic pages unless the topic
page is itself the reference.
Use this default guide structure:
1. Title: name the outcome, not the implementation detail.
2. Opening: state what the reader can accomplish in one or two sentences.
3. Before you begin: list accounts, keys, permissions, versions, tools, and assumptions.
4. Choose a path: compare options only when the reader must decide.
5. Steps: use verb-led headings with code, expected output, and checks.
6. Test: show the smallest reliable proof that the integration works.
7. Production readiness: cover security, idempotency, retries, limits, observability, migrations, and cleanup.
8. Troubleshooting: include common errors near the workflow that causes them.
9. See also: link to concepts, API references, SDK docs, and adjacent guides.
Keep navigation user-intent based. Do not force readers to understand internal product taxonomy before they can pick a task.
## Documentation Lifecycle
Write and maintain docs with the same discipline as code:
- Draft docs early enough to expose unclear product, API, CLI, or config design.
- Keep docs source near the code, config, command, plugin, or protocol it describes when the repo layout allows it.
- Avoid duplicate truth. If the same contract appears in multiple places, pick the canonical page and link to it.
- Update docs in the same change as behavior, config, API, CLI, plugin, or troubleshooting changes.
- Remove, redirect, or clearly mark stale docs. Incorrect docs are worse than missing docs.
- Involve the right reviewers: code owners for behavior, support or QA for user failure modes, and docs maintainers for structure and style.
- Preserve older-version guidance only when users need it; otherwise document the current supported behavior.
Do not use FAQs as a dumping ground for unrelated material. Promote recurring questions into task, concept, troubleshooting, or reference pages.
## Writing Style
Write in a direct, practical voice:
- Use present tense and active voice.
- Address the reader as "you" when giving instructions.
- Publishing fails with HTTP 422 if required fields are missing or the private fork still has open PRs.
- A payload that looks correct in shell can still be wrong if Markdown was assembled with escaped newline strings.
- Advisory PATCH sequencing matters; separate field updates when GHSA API constraints require it.
- Public hardening/no-publish comments and draft text should avoid raw commit hashes, PR titles/numbers, and fix-mechanism summaries. Prefer patched-version fields or release-only wording; keep SHAs, PRs, and implementation notes in internal evidence.
description: "Find or repair small high-confidence non-SDK-boundary OpenClaw bugfix PRs until five are landable."
---
# OpenClaw Landable Bug Sweep
Autonomous maintainer workflow for producing five landable OpenClaw bugfix PR URLs.
Use for broad issue/PR sweeps where the bar is high and the output is PRs, not notes.
Do not use for plugin SDK/API boundary work; those need separate architecture review.
## Target
Return exactly five PR URLs, each with:
- bug summary
- why the fix is low-risk
- proof: rebased-head local/Testbox/live commands or run IDs
- autoreview: clean result on the exact head being shown
- CI green on the exact pushed PR head
- issue/duplicate cleanup done or still pending
The five URLs may be existing PRs that were reviewed/fixed, or new PRs created from issues/clusters.
Do not present a PR URL to the maintainer until it has been refreshed on current `main`, left-tested, autoreviewed clean, pushed, and verified green in live GitHub CI.
If code, tests, changelog, PR body, or branch base changes after autoreview, rerun autoreview before showing the URL.
## Companion Skills
Use `$gitcrawl` for discovery/clustering, `$openclaw-pr-maintainer` for live GitHub mutation rules, `$github-author-context` when contributor trust matters, `$openclaw-testing` for proof choice, `$autoreview` before publishing/landing, and `$crabbox` for broad/E2E/live proof.
## Candidate Bar
Accept only when all are true:
- bug or paper cut, not feature/product/support/docs-only
- root cause is proven in current code
- dependency behavior checked via upstream docs/source/types when relevant
- production/runtime diff is small, ideally much smaller than 500 LOC and always below 500 LOC
- tests may be larger, but focused
- no new dependency
- no new config option
- no backward-incompatible behavior
- no security/product/owner-boundary decision needed
- no plugin SDK, public plugin API, or `src/plugin-sdk/**` boundary change
- no broad refactor smell
- focused proof is feasible
- branch can be rebased/refreshed and pushed, or a replacement PR can be created
Good examples:
- provider parameter mismatch proven against dependency/API contract
- CLI command diverges from adjacent command behavior
- narrow runtime state/serialization bug with failing test
- issue already fixed on current `main`, with proof and closeable duplicates
Reject:
- feature requests, new knobs, migrations, release work, workflow policy, support
- plugin SDK/API boundary changes, including compatibility shims, new SDK methods, SDK exports, or plugin-facing channel/provider seams
- if already fixed on `main`, prove with current source/test/commit and close kindly
5. Patch:
- prefer existing PR when good and writable
- if unwritable or wrong shape, create own PR and preserve useful contributor credit
- if no PR exists, create one
- add regression test when it fits
- release-note context for user-facing fixes in PR body or commit message; credit human reporter/contributor when known
6. Review, refresh, and publish:
- rebase or otherwise refresh the PR branch on current `origin/main`
- resolve drift, including newly exposed CI failures, rather than counting the PR as ready
- do not add `CHANGELOG.md` during normal sweep PRs; release automation generates it from PRs and commits
- left-test the rebased head with the smallest meaningful local/Testbox/live command that proves the bug
- run `$autoreview` until no accepted/actionable findings remain before creating, updating, or presenting the PR URL
- create/update PR with real body and proof fields
- push the exact reviewed head
- verify live GitHub CI is green for that pushed head; do not count pending, red, dirty, conflicting, or externally blocked PRs in the five
7. Hygiene:
- close duplicates and fixed-on-main issues/PRs with proof as soon as you notice them during the sweep
- never mutate more than five associated items in one cluster without explicit confirmation
- comments must be kind, concrete, and include proof/PR/commit links
8. Repeat until five landable PR URLs are ready.
## PR Body Proof
Use the repo PR template. Include these exact labels:
```text
Behavior addressed:
Real environment tested:
Exact steps or command run after this patch:
Evidence after fix:
Observed result after fix:
What was not tested:
```
## Existing PR Rules
- Review code path beyond the diff before trusting it.
- If PR is good: rebase/refresh on current `main`, fix small issues, left-test, autoreview clean, push, and get CI green before showing or counting it.
- If PR is not good but has a useful idea: recreate locally, co-author when warranted, close original with thanks and explanation.
- If PR is duplicate or fixed on `main`: comment proof, close.
- If maintainer cannot push to contributor branch: create own branch/PR, preserve useful commits or credit.
- If CI turns red after local proof, treat that as normal work: inspect the failing job, fix or reject, rerun, and only count the PR once green.
short_description:"Find five small non-SDK landable bugfix PRs"
default_prompt:"Use $openclaw-landable-bug-sweep to find or repair five small high-confidence non-SDK-boundary OpenClaw bugfix PRs and get them landable."
@@ -58,7 +58,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- For beta/stable verification, resolve the tag immediately before the run (`npm view openclaw@beta version dist.tarball` or `npm view openclaw@latest ...`). Tags can move while a long VM matrix is already running; restart the matrix when the intended prerelease appears after an earlier registry 404/tag-lag check.
- Use the configured secret workflow to inject only the provider keys needed by OpenAI/Anthropic lanes. Do not print secrets or env dumps; pass provider secrets through the guest exec environment.
- Same-guest update verification should set the default model explicitly to `openai/gpt-5.4` before the agent turn and use a fresh explicit `--session-id` so old session model state does not leak into the check.
- The aggregate npm-update wrapper must resolve the Linux VM with the same Ubuntu fallback policy as `parallels-linux-smoke.sh` before both fresh and update lanes. Treat any Ubuntu guest with major version `>= 24` as acceptable when the exact default VM is missing, preferring the closest version match. On Peter's current host today, missing `Ubuntu 24.04.3 ARM64` should fall back to`Ubuntu 25.10`.
- The aggregate npm-update wrapper must resolve the Linux VM with the same Ubuntu fallback policy as `parallels-linux-smoke.sh` before both fresh and update lanes. Treat any Ubuntu guest with major version `>= 24` as acceptable when the exact default VM is missing, preferring the newest versioned Ubuntu guest with a fresh poweroff snapshot. On Peter's current host today, use`Ubuntu 26.04`.
- On macOS same-guest update checks, restart the gateway after the npm upgrade before `gateway status` / `agent`; launchd can otherwise report a loaded service while the old process has exited and the fresh process is not RPC-ready yet.
- The npm-update aggregate's macOS update leg writes the guest update script as root, then runs it as the desktop user. If `prlctl exec "$MACOS_VM" --current-user ...` cannot authenticate, retry through plain root `prlctl exec` plus `sudo -u <desktop-user> /usr/bin/env HOME=/Users/<desktop-user> USER=<desktop-user> LOGNAME=<desktop-user> PATH=/opt/homebrew/bin:/opt/homebrew/opt/node/bin:/usr/bin:/bin:/usr/sbin:/sbin ...`. That is a Parallels transport fallback; still verify `openclaw --version`, gateway RPC, and an agent turn after the update.
- On Windows same-guest update checks, restart the gateway after the npm upgrade before `gateway status` / `agent`; in-place global npm updates can otherwise leave stale hashed `dist/*` module imports alive in the running service.
@@ -93,8 +93,8 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- If that release-to-dev lane fails with `reason=preflight-no-good-commit` and repeated `sh: pnpm: command not found` tails from `preflight build`, treat it as an updater regression first. The fix belongs in the git/dev updater bootstrap path, not in Parallels retry logic.
- Until the public stable train includes that updater bootstrap fix, the macOS release-to-dev lane may seed a temporary guest-local `pnpm` shim immediately before `openclaw update --channel dev`. Keep that workaround scoped to the smoke harness and remove it once the latest stable no longer needs it.
- In Tahoe `prlctl exec --current-user` runs, prefer explicit `node .../openclaw.mjs ...` invocations for the release->dev handoff itself and for post-update verification. The shebanged global `openclaw` wrapper can fail with `env: node: No such file or directory`, and self-updating through the wrapper is a weaker lane than invoking the entrypoint under a fixed `node`.
- Default to the snapshot closest to `macOS 26.3.1 latest`.
- On Peter's Tahoe VM, `fresh-latest-march-2026` can hang in `prlctl snapshot-switch`; if restore times out there, rerun with `--snapshot-hint 'macOS 26.3.1 latest'` before blaming auth or the harness.
- Default to the snapshot closest to `macOS 26.5 latest`.
- On Peter's Tahoe VM, `fresh-latest-march-2026` can hang in `prlctl snapshot-switch`; if restore times out there, rerun with `--snapshot-hint 'macOS 26.5 latest'` before blaming auth or the harness.
-`parallels-macos-smoke.sh` now retries `snapshot-switch` once after force-stopping a stuck running/suspended guest. If Tahoe still times out after that recovery path, then treat it as a real Parallels/host issue and rerun manually.
- The macOS smoke should include a dashboard load phase after gateway health: resolve the tokenized URL with `openclaw dashboard --no-open`, verify the served HTML contains the Control UI title/root shell, then open Safari and require an established localhost TCP connection from Safari to the gateway port.
- For Tahoe `fresh.gateway-status`, prefer non-TTY `prlctl exec --current-user ... openclaw gateway status ...` plus a few short retries. `prlctl enter` can spam TTY control bytes and hang the phase log even when the CLI itself is healthy.
@@ -140,8 +140,8 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- Use the snapshot closest to fresh`Ubuntu 24.04.3 ARM64`.
- If that exact VM is missing on the host, any Ubuntu guest with major version `>= 24` is acceptable; prefer the closest versioned Ubuntu guest with a fresh poweroff snapshot. On Peter's host today, that is `Ubuntu 25.10`.
- Use the newest versioned Ubuntu guest with a fresh poweroff snapshot. On Peter's host today, that is`Ubuntu 26.04`.
- If an exact requested Ubuntu VM is missing on the host, any Ubuntu guest with major version `>= 24` is acceptable; prefer the newest versioned Ubuntu guest over older fallback snapshots.
- Use plain `prlctl exec`; `--current-user` is not the right transport on this snapshot.
- Fresh snapshots may be missing `curl`, and `apt-get update` can fail on clock skew. Bootstrap with `apt-get -o Acquire::Check-Date=false update` and install `curl ca-certificates`.
- Fresh `main` tgz smoke still needs the latest-release installer first because the snapshot has no Node or npm before bootstrap.
When a maintainer asks Codex to review, triage, fix, or land a specific OpenClaw issue/PR, check assignment before deep work.
- Identify the requesting maintainer's GitHub login. In this environment, default Peter to `steipete`; if another maintainer is clearly the requester, use that maintainer's bare login.
- Read current assignees with live `gh issue view` / `gh pr view`; `gitcrawl` is not enough for assignment state.
- If unassigned, assign the requester before deep review. This is allowed for specific requested targets; do not auto-assign broad discovery candidates or shortlists.
- If assigned to someone else, say so clearly before analysis and include assignment age:
- fresh: assigned within 6h; treat as actively owned unless user explicitly asks to continue or reassign
- stale: assigned 6h+ ago; treat as ownership hint, not a hard block; continue only with that caveat
- If assigned to requester plus others, mention co-assignees and continue.
- If assignment event time is unavailable, say `assigned, time unknown`; treat as assigned, not stale.
- Never remove or replace assignees unless explicitly asked.
Assignment time proof:
```bash
gh api "repos/openclaw/openclaw/issues/<number>/timeline" --paginate \
Use the newest `assigned` event for each current assignee. Issue timeline events expose `created_at`; GitHub GraphQL `AssignedEvent.createdAt` is also valid when REST pagination is awkward.
Claim command for issues or PRs:
```bash
gh api -X POST "repos/openclaw/openclaw/issues/<number>/assignees" -f 'assignees[]=<login>' >/dev/null
```
## Surface opener identity
- For every reviewed, triaged, closed, or landed issue/PR, show the opener's human name when available, GitHub login, and account age.
@@ -109,12 +139,12 @@ Issue triage is review/prove/patch-local by default:
2. Fix only issues that are easy, high-confidence, and narrowly owned by the implicated path.
3. Add focused regression proof when practical.
4. Stop with the dirty diff, touched files, and test/gate output for maintainer review.
5. After maintainer approval to ship, make one commit per accepted fix, with its own changelog entry when user-facing.
5. After maintainer approval to ship, make one commit per accepted fix, with release-note context in the PR body or commit message when user-facing.
6. Pull/rebase, push, then comment and close only the issues that were fixed or explicitly triaged closed.
Do not batch unrelated issue fixes into one commit. Do not publish, comment, close, or label during the review/prove phase.
Missing changelog is not a PR review finding or merge blocker. If landing/fixing a user-visible change, add/update changelog automatically when practical; never ask or block solely on it.
Missing `CHANGELOG.md` is not a PR review finding or merge blocker. If landing/fixing a user-visible change, make sure the PR body or commit message captures the release-note context; never ask or block solely on it.
Only list candidates that pass all gates:
@@ -138,17 +168,56 @@ Output only qualifying candidates, with: ref, surface, proof, cause, fix sketch,
- Start every PR review with 1-3 plain sentences explaining what the change does and why it matters. Put this before `Findings`.
- Then list findings first. If none, say `No blocking findings` or `No findings`.
-Always answer: bug/behavior being fixed, PR/issue URL and affected surface, and best-fix verdict.
-Show size near the top as `LOC: +<additions>/-<deletions> (<changedFiles> files)`, using live PR stats or local diff stats.
- Always answer: bug/behavior being fixed, PR/issue URL and affected surface, provenance for regressions when traceable, and best-fix verdict.
- For bug/regression fixes, include a compact `Provenance:` line after cause/root-cause when a bounded history pass can identify it. Use `git log -S/-G`, `git blame`, linked PRs/issues, and tests.
- Provenance must separate roles when they differ: blamed code author username, blamed PR author username, blamed PR merger/committer username, automerge trigger when known, current PR author username, PR number, and date. Do not collapse them into one "introduced by" actor.
- If the blamed PR was merged by `clawsweeper[bot]` or another automation, identify the human trigger when practical. Check live PR timeline/comments first; if rate-limited, use gitcrawl/cache or public PR HTML. Look for maintainer command comments such as `@clawsweeper automerge`, `/landpr`, labels/events that armed automerge, and ClawSweeper status comments. Report `automerge triggered by @login`; if not found, say trigger unknown rather than naming the bot as the human decision-maker.
- For any confirmed bug, run `git blame` on the implicated line(s) after identifying the root cause. Report who broke it as the blamed PR merger/committer, and also name the blamed code author. Include the PR number. If no PR is traceable, use the blamed commit as the provenance: commit SHA, date, and author username. Do not guess a merger or frame missing PR metadata as a separate finding.
- Phrase provenance as `introduced by`, `made visible by`, or `carried forward by`, with confidence (`clear`, `likely`, `unknown`). If unclear, say what evidence is missing instead of guessing. For features, docs, and refactors, use `Provenance: N/A` or omit it when no broken behavior is being fixed.
- Keep summaries compact, but include enough proof that the verdict is auditable without rereading the PR.
- Review the surrounding code path, not just changed lines. Open the caller, callee, data contracts, adjacent tests, and owner module.
- Before any verdict, read enough code to fill this map: changed surface, runtime entry point, owner boundary, one caller, one callee, sibling implementations sharing the invariant, adjacent tests, current `main` behavior, and shipped/dependency/Codex contracts when relevant.
- For large-codebase PRs, sample enough related files to understand the runtime boundary before deciding. Default to more code reading when the change touches agents, gateway, plugins, auth, sessions, process, config, or provider/runtime seams.
- Compare the PR against current `origin/main` behavior. Check whether recent main already changed the same surface.
- Dependency-backed behavior: MUST read upstream docs/source/types before judging API use, defaults, output shapes, errors, timeouts, memory behavior, or compatibility. Do not assume dependency contracts from memory or PR text.
- Judge solution quality, not only correctness. Ask whether the PR is the clean owner-boundary fix or a wart/workaround that should be replaced by a small refactor, moved seam, contract change, or deletion of duplicate logic.
- Mention the main files read when the verdict depends on code-path evidence.
- If the user challenges the verdict or asks whether the idea is really good, resume code reading first. Do not defend, soften, or reverse the verdict until the missing caller/callee/sibling/dependency path is checked.
## Best-fix review loop
Every PR review must explicitly answer: "Is this the best fix, or only a plausible fix?"
Before verdict:
1. Reconstruct the bug, feature need, or behavior claim from issue/PR/proof.
2. Trace current behavior from entry point to failure or decision point.
4. Read sibling surfaces that should share the invariant or could be broken by a one-sided fix.
5. Compare against current `origin/main` and shipped behavior when regression/compat matters.
6. Inspect upstream dependency/Codex source or docs for dependency-backed behavior.
7. Identify at least one alternative fix location or shape, then reject it with evidence.
8. If any required path above is uninspected, keep reading or mark `Remaining uncertainty`; do not call the PR best, blocked, proof-sufficient, or merge-ready.
Review output must include:
-`Best-fix verdict:` best / acceptable mitigation / wrong layer / too narrow / too broad.
-`Alternatives considered:` 1-3 concrete alternatives and why rejected.
-`Code read:` compact list of main files/contracts checked.
-`Remaining uncertainty:` what was not proven.
If the best-fix answer is only "maybe", keep reading or state the missing evidence. Do not call proof sufficient until the best-fix judgment is explicit.
## Enforce the bug-fix evidence bar
@@ -160,8 +229,9 @@ Output only qualifying candidates, with: ref, surface, proof, cause, fix sketch,
- Before landing, require:
1. symptom evidence such as a repro, logs, or a failing test
2. a verified root cause in code with file/line
3.a fix that touches the implicated code path
4. a regression test when feasible, or explicit manual verification plus a reason no test was added
3.blame-backed provenance for regressions when traceable, including blamed PR merger and automerge trigger when known, or commit SHA/date when no PR is traceable
4. a fix that touches the implicated code path
5. a regression test when feasible, or explicit manual verification plus a reason no test was added
- If the claim is unsubstantiated or likely wrong, request evidence or changes instead of merging.
- If the linked issue appears outdated or incorrect, correct triage first. Do not merge a speculative fix.
- If Crabbox/E2E proof is blocked, say exactly why and use the closest available
- Never mention merge conflicts that are relatively easy to resolve, such as
`CHANGELOG.md` entries, in review-only output. These are landing mechanics,
not correctness findings.
- Never mention release-note bookkeeping in review-only output. It is landing
or release-generation mechanics, not a correctness finding.
- If bot review conversations exist on your PR, address them and resolve them yourself once fixed.
- Leave a review conversation unresolved only when reviewer or maintainer judgment is still needed.
- Before landing any PR with non-trivial code changes, run `$autoreview` until no accepted/actionable findings remain, unless equivalent manual review already covered it, the change is trivial/docs-only, or the user opts out.
- When landing or merging any PR, follow the global `/landpr` process.
- Use `scripts/committer "<msg>" <file...>` for scoped commits instead of manual `git add` and `git commit`.
- Keep commit messages concise and action-oriented.
default_prompt:"Use $openclaw-pre-release-plugin-testing to plan or run pre-release OpenClaw plugin validation across package, lifecycle, doctor, gateway, SDK, and live-ish proof."
description: Prepare or verify OpenClaw stable/beta releases, changelogs, release notes, publish commands, and artifacts.
---
# OpenClaw Release Maintainer
Use this skill for release and publish-time workflow. Keep ordinary development changes and GHSA-specific advisory work outside this skill.
## Respect release guardrails
- Do not change version numbers without explicit operator approval.
- Ask permission before any npm publish or release step.
- This skill should be sufficient to drive the normal release flow end-to-end.
- Use the private maintainer release docs for credentials, recovery steps, and mac signing/notary specifics, and use `docs/reference/RELEASING.md` for public policy.
- Core `openclaw` publish is manual `workflow_dispatch`; creating or pushing a tag does not publish by itself.
- Normal release work happens on a branch cut from `main`, not directly on
`main`. Use `release/YYYY.M.D` for the branch name.
- If the operator asks for a release without saying stable/full, default to
beta only. Continue from beta to stable only when the operator explicitly asks
for the full release or an automated beta-and-stable train.
- Before release branching, pull latest `main` and confirm current `main` CI is
green. Then branch from that commit so regular development can continue on
`main` while release validation runs.
- Before release branching, commit any dirty files in coherent groups, push,
pull/rebase, then run `/changelog` on `main` and commit/push/pull that
changelog rewrite immediately before creating the release branch.
- During release planning, inspect both `src/plugins/compat/registry.ts` and
`src/commands/doctor/shared/deprecation-compat.ts` before branching and again
before final publish. For every deprecated or removal-pending compatibility
record whose `removeAfter` date is on or before the release date, either
remove the compatibility path where safe and validate the affected tests, or
write down why removal is blocked and get explicit maintainer approval before
shipping the expired compatibility path.
- When removing deprecated runtime/config compatibility, preserve any doctor
migration, repair, or hint that is still needed by supported upgrade paths.
Doctor-side compatibility should stay tracked in
`src/commands/doctor/shared/deprecation-compat.ts` until maintainers confirm
the repair is no longer needed.
- Revalidate compatibility replacement text during release planning. The
recommended replacement can shift as plugin ownership, externalization, and
config footprint move, so do not blindly copy stale replacement annotations
into release notes.
- Do not delete or rewrite beta tags after their matching npm package has been
published. If a pushed beta tag fails before npm publish, the version is not
consumed: keep the same `-beta.N`, delete/recreate or force-move the git tag
and prerelease to the fixed commit, and rerun preflight. Do not increment to
the next beta number until the matching npm package has actually published.
If a published beta needs a fix, commit the fix on the release branch and
increment to the next `-beta.N`.
- For a beta release train, run the fast local preflight first, publish the
beta to npm `beta`, then run the expensive published-package roster focused
on install/update/Docker/Parallels/NPM Telegram. If anything fails, fix it on
the release branch, commit/push/pull, increment beta number, and repeat. Run
the full expensive roster at least once before stable/latest promotion; for
later beta attempts, rerun only lanes whose evidence changed unless the fix
touches broad release, install/update, plugin, Docker, Parallels, or live QA
behavior. After each beta is published, scan current `main` once for critical
fixes that landed after the release branch cut and backport only important
low-risk fixes. Operators may authorize up to 4 autonomous beta attempts;
after 4 failed beta attempts, stop and report.
- Use `/changelog` before version/tag preparation so the top changelog section
is deduped and ordered by user impact.
- Do not create beta-specific `CHANGELOG.md` headings. Beta releases use the
stable base version section, for example `v2026.4.20-beta.1` uses
`## 2026.4.20` release notes.
- When any beta or stable release is live, make a best-effort Discord
announcement using the configured secret workflow; do not block or roll back
the release if the announcement fails.
- When asked to announce on X, use `~/Projects/bird/bird` and follow the
release tweet style below.
## Keep release channel naming aligned
-`stable`: tagged releases only, published to npm `beta` by default; operators may target npm `latest` explicitly or promote later
-`beta`: prerelease tags like `vYYYY.M.D-beta.N`, with npm dist-tag `beta`
- Prefer `-beta.N`; do not mint new `-1` or `-2` beta suffixes
-`dev`: moving head on `main`
- When using a beta Git tag, publish npm with the matching beta version suffix so the plain version is not consumed or blocked
- Before creating a release tag, make every version location above match the version encoded by that tag.
- For fallback correction tags like `vYYYY.M.D-N`, the repo version locations still stay at `YYYY.M.D`.
- “Bump version everywhere” means all version locations above except `appcast.xml`.
- Release signing and notary credentials live outside the repo in the private maintainer docs.
- Every stable OpenClaw release ships the npm package and macOS app together.
Beta releases normally ship npm/package artifacts first and skip mac app
build/sign/notarize unless the operator requests mac beta validation.
- Do not let the slower macOS signing/notary path block npm publication once
the npm preflight has passed. Keep mac validation/publish running in
parallel, publish npm from the successful npm preflight, then start published
npm install/update, Docker, and Parallels verification while mac artifacts
continue.
- After a beta is published, overlap remote/manual release rosters where useful,
but avoid piling local Docker, Parallels, and QA-Lab work onto the same host
when it would create system-load noise. Use selective reruns after failures or
fixes, but keep proof that Docker, Parallels, and QA-Lab each passed at least
once before stable/latest promotion.
- Mac packaging may be built from a slight release-branch variation of the
tagged commit when the delta is mac packaging, signing, workflow, or
validation-only release machinery. If mac packaging needs release-branch-only
fixes after the stable npm package or GitHub tag is already published, do not
create a `vYYYY.M.D-N` correction tag just to change the workflow source.
Dispatch the private mac workflows for the original `tag=vYYYY.M.D` with
`source_ref=release/YYYY.M.D` and `public_release_branch=release/YYYY.M.D`;
provenance checks must prove the source SHA descends from the tag and
validation/preflight use the same source. Reserve `vYYYY.M.D-N` correction
tags for emergency hotfixes that must publish a new npm package/release
identity, not for ordinary mac-only packaging recovery.
- The production Sparkle feed lives at `https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`, and the canonical published file is `appcast.xml` on `main` in the `openclaw` repo.
- That shared production Sparkle feed is stable-only. Beta mac releases may
upload assets to the GitHub prerelease, but they must not replace the shared
`appcast.xml` unless a separate beta feed exists.
- For fallback correction tags like `vYYYY.M.D-N`, the repo version still stays
at `YYYY.M.D`, but the mac release must use a strictly higher numeric
`APP_BUILD` / Sparkle build than the original release so existing installs
see it as newer.
## Build changelog-backed release notes
- Before release branching or tagging, rewrite the target `CHANGELOG.md`
section from commit history, not just from existing notes: scan commits since
the last reachable release tag, add missed user-facing changes, dedupe
overlapping entries, and sort each section from most to least interesting for
users.
- Changelog entries should be user-facing, not internal release-process notes.
- GitHub release and prerelease bodies must use the full matching
`CHANGELOG.md` version section, not highlights or an excerpt. When creating
or editing a release, extract from `## YYYY.M.D` through the line before the
next level-2 heading and use that complete block as the release notes.
- When preparing release notes, scan `src/plugins/compat/registry.ts` and
`src/commands/doctor/shared/deprecation-compat.ts` for compatibility records
with `warningStarts` or `removeAfter` within 7 days after the release date.
Add an `Upcoming deprecations` note to the release notes when any exist,
including the compatibility code, target date, replacement, and a link to the
record's `docsPath` or `/plugins/compatibility` when no more specific
deprecation page exists.
- When cutting a mac release with a beta GitHub prerelease:
- tag `vYYYY.M.D-beta.N` from the release commit
- create a prerelease titled `openclaw YYYY.M.D-beta.N`
- use release notes from the stable base `CHANGELOG.md` version section
(`## YYYY.M.D`), not a beta-specific heading
- attach at least the zip and dSYM zip, plus dmg if available
- Keep the top version entries in `CHANGELOG.md` sorted by impact:
-`### Changes` first
-`### Fixes` deduped with user-facing fixes first
## Write release tweets
Use the OpenClaw account's existing release-post style:
- Format: `OpenClaw YYYY.M.D 🦞` or `🦞 OpenClaw YYYY.M.D is live`, blank line,
then 3-4 emoji-led bullets, blank line, one short punchline, then the release
link.
- For beta: say `OpenClaw YYYY.M.D-beta.N 🦞` or `OpenClaw YYYY.M.D beta N is
live`; keep it clearly beta and avoid implying stable promotion.
- Lead with user-visible capabilities, then important integrations, then
reliability/security/install fixes. Compress "lots of fixes" into one
readable bullet.
- Read the full changelog section before drafting. Do not lead with coverage,
CI, validation, or internal release mechanics unless the release is explicitly
about those. Peter prefers concrete user wins: features, integrations,
workflow improvements, and practical reliability fixes.
- Tone: high-signal, slightly cheeky, confident, not corporate. One joke is
enough. Avoid punching down, insulting users, or promising what was not
verified.
- Peter likes dry, compact taglines when they feel earned. Good example:
`Big release, tiny release notes... kidding.` Keep the joke short and let the
feature bullets carry the tweet; do not turn the punchline into a second
paragraph or a forced bit.
- Length: release tweets are always standard tweets under 280 characters, with
room for one URL. Trim to 3-4 bullets and count the final text before posting.
- Links/media: include the GitHub release or changelog link at the end of the
first release tweet.
- Thread follow-ups: if doing a thread, keep the first release tweet as the
compact launch post, then publish one focused feature explainer per reply.
Follow-up replies should not repeat "new in VERSION" or the version number
when the thread context already makes it obvious.
- Peter's preferred thread workflow: first agree on the generic launch tweet,
then proceed through follow-up tweets one by one. When he says `next`, provide
or copy the next follow-up only; do not dump the full thread again unless asked.
- Every follow-up tweet should include a docs URL for that specific feature.
Prefer a bare URL over `Docs: <url>` unless the label is needed for clarity.
Keep follow-ups concise: around 160-220 raw characters is usually the sweet
spot; under 280 is the hard cap. If a URL makes a tweet fail, trim prose
before dropping the URL.
Prefer explaining diagnostics, trajectory/export, provider setup, model
commands, or other setup-heavy features in follow-ups instead of overloading
the first release tweet.
- Hotfix/correction: be direct and accountable. State what slipped, what is
fixed, and the new version. Keep jokes out of incident-style posts.
Examples to adapt:
```text
OpenClaw 2026.4.20-beta.1 🦞
🐳 Docker install/update smoke
🖥️ Parallels upgrade checks
🔧 Package verification tightened
Beta first. Stable after the gauntlet.
<release link>
```
```text
OpenClaw 2026.4.20 🦞
🚀 Faster install + update
🐳 Docker + Parallels verified
🍎 macOS signed + notarized
🔧 Channel/plugin fixes
Good boring release. Best kind.
<release link>
```
```text
Packaging issue in 2026.4.20-beta.1.
2026.4.20-beta.2 fixes install/update verification. No tag rewrites; beta moves
forward.
Upgrade with the beta channel.
<release link>
```
## Run publish-time validation
Before tagging or publishing, run:
```bash
pnpm check:architecture
pnpm build
pnpm ui:build
pnpm qa:otel:smoke
pnpm release:check
pnpm test:install:smoke
```
- Use `pnpm qa:otel:smoke` when release validation needs telemetry coverage.
It starts a local OTLP/HTTP trace receiver, runs QA-lab's
`otel-trace-smoke`, and checks span names plus content/identifier redaction
from `main` with `package_spec=openclaw@<beta-version>` and
`provider_mode=mock-openai`, and require success. This workflow is
maintainer-dispatched and intentionally has no `npm-release` approval gate;
`qa-live-shared` only supplies the shared QA secrets. This is the default
button path for installed-package onboarding, Telegram setup, and real
Telegram E2E against the published npm package.
Use the local `pnpm test:docker:npm-telegram-live` lane with the matching
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC` and Convex CI env only as a fallback
or debugging path.
- Parallels published beta install/update coverage with both OpenAI and
Anthropic provider keys available
- Parallels install/update proof must keep plugin installs enabled unless the
operator explicitly scopes a harness-only isolation check; a lane that
disables bundled plugin installs is not valid plugin/dependency release
evidence.
- targeted QA reruns only for areas touched by fixes after the full pre-npm
roster, unless the operator requests the full QA roster again. If the fix
touches live channel QA, credential plumbing, Matrix, Telegram, or the QA
harness, rerun Actions > `QA-Lab - All Lanes`.
- Check all release-related build surfaces touched by the release, not only the npm package.
- For beta-style full e2e batteries, hard-cap top-level long lanes instead of letting them run indefinitely. Use host `timeout --foreground`/`gtimeout --foreground` caps such as:
- `45m` for `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke`
- `90m` for `pnpm test:docker:all`
- `60m` each for standalone Docker live lanes
- `180m` for local full QA live OpenAI + Anthropic rosters when explicitly
requested; the default release channel QA gate is Actions >
`QA-Lab - All Lanes`
- Parallels caps from the `openclaw-parallels-smoke` skill
If a lane hits its cap, stop and inspect/fix the affected lane before continuing; do not continue to wait on the same process.
- Actual npm install/update phases are capped at 5 minutes. If `npm install -g`, installer package install, or `openclaw update` takes longer than 300s in release e2e, stop treating the run as healthy progress and debug the installer/updater or harness.
- Serialize host build/package mutations ahead of VM lanes. Finish `pnpm build`, `pnpm ui:build`, `pnpm release:check`, install smoke, and any Docker/package-prep lanes before starting Parallels `npm pack` lanes; otherwise `dist` can disappear during VM pack prep and produce false failures.
- Include mac release readiness in preflight by running the public validation
workflow in `openclaw/openclaw` and the real mac preflight in
`openclaw/releases-private` for every release.
- Treat the `appcast.xml` update on `main` as part of mac release readiness, not an optional follow-up.
- The workflows remain tag-based. The agent is responsible for making sure
preflight runs complete successfully before any publish run starts.
- Any fix after preflight means a new commit. Delete and recreate the tag and
matching GitHub release from the fixed commit, then rerun preflight from
scratch before publishing.
Exception: never delete or recreate a beta tag whose matching npm package has
already been published; increment to the next beta number instead. If only the
pushed tag/prerelease exists and npm publish has not happened, recreate that
same beta tag at the fixed commit.
- For stable mac releases, generate the signed `appcast.xml` before uploading
public release assets so the updater feed cannot lag the published binaries.
- Serialize stable appcast-producing runs across tags so two releases do not
generate replacement `appcast.xml` files from the same stale seed.
- For stable releases, rely primarily on the latest beta's broader release
workflow confidence. When promoting the matching non-beta build to npm
`latest`, prefer a light time-bounded verification pass: published npm
@@ -34,10 +34,10 @@ Supports single or multiple alerts. For multiple alerts, process in ascending or
For each alert:
1.**Identify** — `fetch-alert` + `fetch-content` to get metadata and body
2.**Decide** — Agent reads the body file, identifies all secrets, produces redacted version
3.**Redact** — `redact-body` for issue/PR body; skip for comments (delete directly)
2.**Decide** — Agent reads the body file, identifies whether plaintext secrets remain, and produces a redacted version only when needed
3.**Redact** — `redact-body-if-needed` for issue/PR body; skip for comments (delete directly)
4.**Purge** — `delete-comment` + `recreate-comment` for comments; cannot purge body history
5.**Notify** — `notify` posts the right template per location type
5.**Notify** — `notify` posts the right template per location type, unless the current issue/PR body is already redacted
6.**Resolve** — `resolve` closes the alert
7.**Summary** — `summary` prints formatted results
@@ -81,11 +81,20 @@ The `fetch-content` output includes:
The agent reads the body file from `fetch-content` output and:
1. Identifies ALL secrets in the content (there may be more than the alert flagged)
2.Replaces each secret with `[REDACTED <secret_type>]` — **no partial values, no prefix/suffix**
3.Saves the redacted content to a new temp file
2.Determines whether any plaintext credential remains in the current body
3.Replaces each remaining secret with `[REDACTED <secret_type>]` — **no partial values, no prefix/suffix**
4. Saves the redacted content to a new temp file
This is the only step that requires semantic understanding. Everything else is mechanical.
For `issue_body` and `pull_request_body`: if the current body has already been redacted by the author and no plaintext credential remains, **do not post a public notification comment**. Resolve the alert with a maintainer-only resolution comment such as:
```bash
node secret-scanning.mjs resolve <ALERT_NUMBER> revoked "Current issue/PR body is already redacted; no public notification posted."
```
This avoids creating a fresh public pointer to historical sensitive content.
## Step 3: Redact
### For comments (issue_comment / PR comments)
@@ -95,9 +104,11 @@ This is the only step that requires semantic understanding. Everything else is m
Use the `body_file` from `fetch-content` as `<current-body-file>`. The command writes `notify_required` to `<result-file>` and only PATCHes the body when the redacted file differs from the current body.
## Step 4: Purge Edit History
### Comments — Delete and Recreate
@@ -134,10 +145,12 @@ The recreated comment should follow this format:
<redacted original content>
```
### issue_body / pull_request_body — Cannot Purge
### issue_body / pull_request_body — Cannot Purge Edit History
Editing creates an edit history revision with the pre-edit plaintext. This cannot be cleared via API.
Do not advise authors publicly to delete/recreate issues or close/reopen PRs. That can draw attention to historical content. Keep purge guidance maintainer-only.
**Output to maintainer terminal only (never in public comments):**
```
@@ -155,12 +168,13 @@ Cannot clean. Notify author to delete branch or force-push (for unmerged PRs).
- For non-discussion types, `<TARGET>` is the issue/PR number.
- For `discussion_comment`, `<TARGET>` is the `discussion_node_id` returned by `fetch-content`.
- For reply-style `discussion_comment` locations, pass the optional `reply_to_node_id` from `fetch-content` so the notification stays in the same thread.
- For `issue_body` and `pull_request_body`, pass the `<result-file>` from `redact-body-if-needed`. The script skips notification when `notify_required` is `false` and refuses body notifications without this file.
Secret types are comma-separated: `"Discord Bot Token,Feishu App Secret"`
@@ -170,6 +184,8 @@ The script picks the right template:
- **body types**: "your issue/PR description … redacted in place"
- **commit**: "code you committed"
For `issue_body` and `pull_request_body`, only notify when the current body still contained plaintext and maintainers redacted it. If the user already redacted the current body, skip this step and resolve silently.
Resolution is `revoked` by default. As maintainers we cannot control whether users rotate — our responsibility is to redact + notify. The `revoked` means "this secret should be considered leaked", not "I confirmed it was revoked".
Resolution is `revoked` by default. As maintainers we cannot control whether users rotate — our responsibility is to remove current plaintext exposure and notify only when public notification is useful. The `revoked` means "this secret should be considered leaked", not "I confirmed it was revoked".
- For cancelled same-branch runs, confirm whether a newer run superseded it.
- Fetch full logs only for failed or relevant jobs.
- Prefer `gh run view <run-id> --json jobs` over PR rollup while debugging; rollup can be stale/noisy.
- For `prompt:snapshots:check` failures, treat Linux Node 24 as CI truth. If macOS passes but CI drifts, reproduce in a Linux Node 24 container or Testbox, commit that generated output, then rerun.
## GitHub Release Workflows
@@ -180,7 +215,7 @@ workflow only spends setup and queue time on that suite.
### Release Evidence
After release-candidate validation or before a release decision, record the
important run ids in the private `openclaw/releases-private` evidence ledger.
important run ids in the public `openclaw/releases` evidence ledger.
Use the manual `OpenClaw Release Evidence`
(`openclaw-release-evidence.yml`) workflow there. It writes durable summaries
under `evidence/<release-id>/` and commits:
@@ -203,13 +238,13 @@ short release-manager notes there. Do not store raw logs, provider
prompts/responses, channel transcripts, signing material, or secret-bearing
config in git; raw logs stay in Actions artifacts.
When `Full Release Validation` completes and
`OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN` is configured in the public repo, it
requests the private `OpenClaw Release Evidence From Full Validation` workflow.
That private workflow reads the parent full-validation run, extracts the child
CI/release-checks/Telegram run ids from the parent logs, and opens the evidence
PR automatically. If the token is absent or the run predates this wiring, trigger
that private workflow manually with the full-validation run id.
When `Full Release Validation` completes and`OPENCLAW_RELEASES_DISPATCH_TOKEN`
is configured in the source repo, it requests the public
`OpenClaw Release Evidence From Full Validation` workflow. That workflow reads
the parent full-validation run, extracts the child CI/release-checks/Telegram
run ids from the parent logs, and opens the evidence PR automatically. If the
token is absent or the run predates this wiring, trigger that workflow manually
short_description:"Benchmark and speed up OpenClaw tests"
default_prompt:"Use $optimizetests to benchmark slow OpenClaw tests, optimize imports and duplicated setup, move misplaced core coverage to extensions, verify gates, commit scoped changes, push, and keep CI green without adding shards or dropping coverage."
description: "Draft or post OpenClaw beta/stable Discord release announcements from changelog, GitHub release, registry, and validation evidence. Use when announcing a beta, stable release, release candidate, or asking what users should test after an OpenClaw release."
---
# OpenClaw Release Announcement
Use with `release-openclaw-maintainer` after a beta or stable release is live.
Use with `openclaw-discord` when actually posting to Discord.
## Evidence First
Before drafting focus areas, read real release evidence:
1. Current GitHub release body for the tag.
2.`CHANGELOG.md` section for the released base version.
3. Commits since the previous shipped version or the operator-specified base.
4. Registry/package metadata for the exact version and current dist-tag.
5. Validation status that is relevant to user confidence.
Do not claim a full changelog audit unless you did it. If you only read the
generated release notes or top changelog section, say that and either audit
properly or draft with that limitation.
For beta focus areas, prioritize user-observable changes over internal test or
CI mechanics:
- install/update paths
- OS/platform-specific behavior
- Gateway startup/restart, config, and runtime behavior
- provider/model/runtime routing
- plugin loading and local plugin development
- channels and media paths
- security/data-loss/user-impact fixes
Do not let late release-branch fixes automatically dominate the announcement.
If the version includes a large delta from the previous shipped version, rank
focus areas by the whole release delta and expected user impact; mention late
fixes in their natural category.
## Required Copy
Every beta announcement must make beta status explicit and include:
- exact version, e.g. `OpenClaw 2026.5.25-beta.1`
- one-sentence risk framing: beta, useful for testing, not stable promotion
- focused test areas derived from evidence, not guesswork
- update command promoted near the top:
```sh
openclaw update --channel beta --yes
openclaw --version
```
- fresh install path:
`Install from https://openclaw.ai`
- GitHub release link
- concise validation note, without making CI the headline
Do not suggest npm install commands in beta announcements unless the operator
explicitly asks for npm-specific copy or troubleshooting text. It is fine to use
registry metadata as evidence; do not turn that into public install guidance.
For stable announcements, use the stable channel wording:
```sh
openclaw update --channel stable --yes
openclaw --version
```
Fresh installs still point to `https://openclaw.ai`.
## Style
- Discord Markdown, no tables.
- Keep it skimmable: short intro, bullets, commands, links.
- Lead with what users can feel or test, not proof plumbing.
- Mention validation only after install/update instructions.
- Be specific about where feedback is useful.
- Do not mention private local proof paths in public announcements.
- Do not overstate unverified platforms, channels, or provider behavior.
## Posting
When asked to post, use the configured Discord workflow from
`openclaw-discord` or the approved OpenClaw relay. Never print tokens.
For public channels, inspect the final body before sending.
short_description:"Draft Discord beta/stable release announcements from evidence."
default_prompt:"Use this skill to draft an OpenClaw beta or stable Discord announcement from changelog, release notes, npm/GitHub release proof, and validation evidence."
description: "Run, watch, debug, and summarize OpenClaw full release CI, release checks, live provider gates, install/update proofs, and release-secret preflights."
---
# OpenClaw Release CI
Use this with `$release-openclaw-maintainer` and `$openclaw-testing` when a release candidate needs full validation, install/update proof, live provider checks, or CI recovery.
## Guardrails
- No version bump, tag, npm publish, GitHub release, or release promotion without explicit operator approval.
- Validate provider secrets before dispatching expensive full release matrices.
- Do not set GitHub secrets from unvalidated 1Password candidates. If a candidate returns 401/403, leave the existing secret alone and report the exact missing provider.
- Use `$one-password` for secret reads/writes: one persistent tmux session, targeted items only, no secret output.
- Watch one parent run plus compact child summaries. Avoid broad `gh run view` polling loops; REST quota is easy to burn.
- Fetch logs only for failed or currently-blocking jobs. If quota is low, stop polling and wait for reset.
- Treat live-provider flakes separately from code failures: prove key validity, provider HTTP status, retry evidence, and exact failing lane before editing code.
1Password service-account values are the first source for release provider
preflight. Inject those exact targeted keys first, then run the verifier; use
ambient env only when it was already intentionally injected for this release.
The script prints only provider status and HTTP class, never tokens.
## Dispatch
Start product performance evidence as early as the release SHA exists, in
parallel with other release work:
```bash
gh workflow run openclaw-performance.yml \
--repo openclaw/openclaw \
--ref main \
-f target_ref=<release-sha> \
-f profile=release \
-f repeat=3\
-f deep_profile=false\
-f live_openai_candidate=false\
-f fail_on_regression=false
```
- Do not wait for full release validation to start this early perf signal.
- Compare available Kova, gateway startup, and CLI startup metrics with earlier
release evidence or clawgrit reports before publish/closeout.
- Call out any regression in the release proof. Treat a major regression as a
release blocker until it is fixed, waived by the operator, or proven to be
infrastructure noise.
- Full Release Validation also records advisory product-performance evidence;
the early standalone run is for overlap and faster regression discovery.
Prefer the trusted workflow on `main`, target the exact release SHA:
```bash
gh workflow run full-release-validation.yml \
--repo openclaw/openclaw \
--ref main \
-f ref=<release-sha> \
-f provider=openai \
-f mode=both \
-f release_profile=full \
-f rerun_group=all
```
Use `release_profile=stable` unless the operator explicitly asks for the broad advisory provider/media matrix. Use narrow `rerun_group` after focused fixes.
## Watch
Use the summary helper instead of repeated raw polling:
gh run watch <full-release-run-id> --repo openclaw/openclaw --exit-status
```
Stop watchers before ending the turn or switching strategy.
## Failure Triage
1. Confirm parent SHA and child run IDs.
2. List failed jobs only:
```bash
gh run view <child-run-id> --repo openclaw/openclaw --json jobs \
--jq '.jobs[] | select(.conclusion=="failure" or .conclusion=="timed_out" or .conclusion=="cancelled") | [.databaseId,.name,.conclusion,.url] | @tsv'
```
3. Fetch one failed job log. If rate-limited, note reset time and avoid more REST calls.
4. For secret-looking failures, validate the provider endpoint from the same secret source before editing code.
5. For live-cache failures, inspect whether it is missing/invalid key, empty text, provider refusal, timeout, or baseline miss. Do not weaken release gates without clear provider evidence.
6. Fix narrowly, run local/changed proof, commit, push, rerun the smallest matching group.
## Evidence
Record:
- release SHA
- full parent run URL
- child run IDs and conclusions: CI, Release Checks, Plugin Prerelease, NPM Telegram, Product Performance
- performance comparison result versus earlier releases when available
- targeted local proof commands
- provider-secret preflight result
- known gaps or unrelated failures
For lessons and recovery patterns, read `references/release-ci-notes.md`.
short_description:"Verify and debug OpenClaw release validation runs"
default_prompt:"Use $release-openclaw-ci to preflight provider secrets, watch full release validation, summarize child runs, and triage only failing release lanes."
description: "Run or recover OpenClaw macOS release signing, notarization, appcast, and asset promotion."
---
# OpenClaw Mac Release
Use with `$release-openclaw-maintainer`, `$release-openclaw-ci`, `$one-password`, and `$release-private` if it exists when stable macOS assets, private mac preflight, notarization, appcast promotion, or mac release recovery is involved.
## Credentials
- Resolve Peter-owned ASC item refs, key ids, issuer ids, and service-token provenance from `$release-private`.
description: Prepare or verify OpenClaw stable/beta releases, changelogs, release notes, publish commands, and artifacts.
---
# OpenClaw Release Maintainer
Use this skill for release and publish-time workflow. Load `$release-private` if it exists before resolving Peter-owned credential locators or private host topology. Keep ordinary development changes and GHSA-specific advisory work outside this skill.
## Respect release guardrails
- Do not change version numbers without explicit operator approval.
- Ask permission before any npm publish or release step.
- This skill should be sufficient to drive the normal release flow end-to-end.
- Use the private maintainer release docs for credentials, recovery steps, and mac signing/notary specifics, and use `docs/reference/RELEASING.md` for public policy.
- Core `openclaw` publish is manual `workflow_dispatch`; creating or pushing a tag does not publish by itself.
- Normal release work happens on a branch cut from `main`, not directly on
`main`. Use `release/YYYY.M.D` for the branch name.
- If the operator asks for a release without saying stable/full, default to
beta only. Continue from beta to stable only when the operator explicitly asks
for the full release or an automated beta-and-stable train.
- Before release branching, pull latest `main` and confirm current `main` CI is
green. Then branch from that commit so regular development can continue on
`main` while release validation runs.
- Before release branching, commit any dirty files in coherent groups, push,
pull/rebase, then generate `CHANGELOG.md` on `main` from merged PRs and all
direct commits since the last reachable release tag. Commit/push/pull that
changelog rewrite immediately before creating the release branch.
- During release planning, inspect both `src/plugins/compat/registry.ts` and
`src/commands/doctor/shared/deprecation-compat.ts` before branching and again
before final publish. For every deprecated or removal-pending compatibility
record whose `removeAfter` date is on or before the release date, either
remove the compatibility path where safe and validate the affected tests, or
write down why removal is blocked and get explicit maintainer approval before
shipping the expired compatibility path.
- When removing deprecated runtime/config compatibility, preserve any doctor
migration, repair, or hint that is still needed by supported upgrade paths.
Doctor-side compatibility should stay tracked in
`src/commands/doctor/shared/deprecation-compat.ts` until maintainers confirm
the repair is no longer needed.
- Revalidate compatibility replacement text during release planning. The
recommended replacement can shift as plugin ownership, externalization, and
config footprint move, so do not blindly copy stale replacement annotations
into release notes.
- Do not delete or rewrite beta tags after their matching npm package has been
published. If a pushed beta tag fails before npm publish, the version is not
consumed: keep the same `-beta.N`, delete/recreate or force-move the git tag
and prerelease to the fixed commit, and rerun preflight. Do not increment to
the next beta number until the matching npm package has actually published.
If a published beta needs a fix, commit the fix on the release branch and
increment to the next `-beta.N`.
- For a beta release train, run the fast local preflight first, publish the
beta to npm `beta`, then run the expensive published-package roster focused
on install/update/Docker/Parallels/NPM Telegram. If anything fails, fix it on
the release branch, commit/push/pull, increment beta number, and repeat. Run
the full expensive roster at least once before stable/latest promotion; for
later beta attempts, rerun only lanes whose evidence changed unless the fix
touches broad release, install/update, plugin, Docker, Parallels, or live QA
behavior. After each beta is published, scan current `main` once for critical
fixes that landed after the release branch cut and backport only important
low-risk fixes. Operators may authorize up to 4 autonomous beta attempts;
after 4 failed beta attempts, stop and report.
- As soon as the release candidate SHA exists, dispatch `OpenClaw Performance`
with `target_ref=<release-sha>` in parallel with the other release work. Do
not wait for full release validation to start the performance signal.
- Before publish/closeout, compare available product performance metrics with
earlier releases: Kova agent-turn/resource metrics, gateway startup
ready/listen/RSS/CPU metrics, and CLI startup metrics from release evidence
or clawgrit reports. Report regressions explicitly. A major regression is a
release blocker unless the operator waives it or the data clearly proves
infrastructure noise.
- Generate the changelog before every beta, beta rerun, stable release, or
stable rerun, before version/tag preparation. Use
`$openclaw-changelog-update` for the rewrite. Do not continue release prep if
the target `CHANGELOG.md` section does not have `### Highlights`,
`### Changes`, and `### Fixes`, grouped by user-facing surface while
preserving every relevant PR/issue ref and every human `Thanks @...`
attribution in the grouped bullet.
- Do not create beta-specific `CHANGELOG.md` headings. Beta releases use the
stable base version section, for example `v2026.4.20-beta.1` uses
`## 2026.4.20` release notes.
- When any beta or stable release is live, make a best-effort Discord
announcement using the configured secret workflow; do not block or roll back
the release if the announcement fails.
- When asked to announce on X, use `~/Projects/bird/bird` and follow the
release tweet style below.
## Keep release channel naming aligned
-`stable`: tagged releases only, published to npm `beta` by default; operators may target npm `latest` explicitly or promote later
-`beta`: prerelease tags like `vYYYY.M.D-beta.N`, with npm dist-tag `beta`
- Prefer `-beta.N`; do not mint new `-1` or `-2` beta suffixes
-`dev`: moving head on `main`
- When using a beta Git tag, publish npm with the matching beta version suffix so the plain version is not consumed or blocked
- Before creating a release tag, make every version location above match the version encoded by that tag.
- For fallback correction tags like `vYYYY.M.D-N`, the repo version locations still stay at `YYYY.M.D`.
- “Bump version everywhere” means all version locations above except `appcast.xml`.
- Release signing and notary credentials live outside the repo in the private maintainer docs.
- Every stable OpenClaw release ships the npm package and macOS app together.
Beta releases normally ship npm/package artifacts first and skip mac app
build/sign/notarize unless the operator requests mac beta validation.
- Do not let the slower macOS signing/notary path block npm publication once
the npm preflight has passed. Keep mac validation/publish running in
parallel, publish npm from the successful npm preflight, then start published
npm install/update, Docker, and Parallels verification while mac artifacts
continue.
- After a beta is published, overlap remote/manual release rosters where useful,
but avoid piling local Docker, Parallels, and QA-Lab work onto the same host
when it would create system-load noise. Use selective reruns after failures or
fixes, but keep proof that Docker, Parallels, and QA-Lab each passed at least
once before stable/latest promotion.
- Mac packaging may be built from a slight release-branch variation of the
tagged commit when the delta is mac packaging, signing, workflow, or
validation-only release machinery. If mac packaging needs release-branch-only
fixes after the stable npm package or GitHub tag is already published, do not
create a `vYYYY.M.D-N` correction tag just to change the workflow source.
Dispatch the private mac workflows for the original `tag=vYYYY.M.D` with
`source_ref=release/YYYY.M.D` and `public_release_branch=release/YYYY.M.D`;
provenance checks must prove the source SHA descends from the tag and
validation/preflight use the same source. Reserve `vYYYY.M.D-N` correction
tags for emergency hotfixes that must publish a new npm package/release
identity, not for ordinary mac-only packaging recovery.
- The production Sparkle feed lives at `https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`, and the canonical published file is `appcast.xml` on `main` in the `openclaw` repo.
- That shared production Sparkle feed is stable-only. Beta mac releases may
upload assets to the GitHub prerelease, but they must not replace the shared
`appcast.xml` unless a separate beta feed exists.
- For fallback correction tags like `vYYYY.M.D-N`, the repo version still stays
at `YYYY.M.D`, but the mac release must use a strictly higher numeric
`APP_BUILD` / Sparkle build than the original release so existing installs
see it as newer.
## Build changelog-backed release notes
-`CHANGELOG.md` is release-owned. Normal PRs and direct `main` fixes should
not edit it.
- Before release branching or tagging, rewrite the target `CHANGELOG.md`
section from history, not existing notes. Use the last reachable stable or
beta release tag as the base, then inspect every commit through the target
release SHA.
- The changelog rewrite is not optional for beta reruns: any `beta.N` after a
rebase or backport must refresh the same stable-base `## YYYY.M.D` section
before the new version/tag commit.
- Include both merged PR commits and direct commits on `main`. Direct commits
matter: infer notes from their subject, body, touched files, linked issues,
tests, and nearby code when no PR body exists.
- Prefer PR bodies, issue links, review proof, and commit bodies over commit
subjects alone. If a commit fixed an issue directly, the commit body should
name the user-visible behavior, affected surface, issue ref, and credited
reporter/contributor when known.
- Treat missing context as a release-note audit gap: inspect the diff and linked
issue, draft the best accurate entry, and note the uncertainty for maintainer
from `main` with `package_spec=openclaw@<beta-version>` and
`provider_mode=mock-openai`, and require success. This workflow is
maintainer-dispatched and intentionally has no `npm-release` approval gate;
`qa-live-shared` only supplies the shared QA secrets. This is the default
button path for installed-package onboarding, Telegram setup, and real
Telegram E2E against the published npm package.
Use the local `pnpm test:docker:npm-telegram-live` lane with the matching
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC` and Convex CI env only as a fallback
or debugging path.
- Parallels published beta install/update coverage with both OpenAI and
Anthropic provider keys available
- Parallels install/update proof must keep plugin installs enabled unless the
operator explicitly scopes a harness-only isolation check; a lane that
disables bundled plugin installs is not valid plugin/dependency release
evidence.
- targeted QA reruns only for areas touched by fixes after the full pre-npm
roster, unless the operator requests the full QA roster again. If the fix
touches live channel QA, credential plumbing, Matrix, Telegram, or the QA
harness, rerun Actions > `QA-Lab - All Lanes`.
- Check all release-related build surfaces touched by the release, not only the npm package.
- For beta-style full e2e batteries, hard-cap top-level long lanes instead of letting them run indefinitely. Use host `timeout --foreground`/`gtimeout --foreground` caps such as:
- `45m` for `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke`
- `90m` for `pnpm test:docker:all`
- `60m` each for standalone Docker live lanes
- `180m` for local full QA live OpenAI + Anthropic rosters when explicitly
requested; the default release channel QA gate is Actions >
`QA-Lab - All Lanes`
- Parallels caps from the `openclaw-parallels-smoke` skill
If a lane hits its cap, stop and inspect/fix the affected lane before continuing; do not continue to wait on the same process.
- Actual npm install/update phases are capped at 5 minutes. If `npm install -g`, installer package install, or `openclaw update` takes longer than 300s in release e2e, stop treating the run as healthy progress and debug the installer/updater or harness.
- Serialize host build/package mutations ahead of VM lanes. Finish `pnpm build`, `pnpm ui:build`, `pnpm release:check`, install smoke, and any Docker/package-prep lanes before starting Parallels `npm pack` lanes; otherwise `dist` can disappear during VM pack prep and produce false failures.
- Include mac release readiness in preflight by running the public validation
workflow in `openclaw/openclaw` and the real mac preflight in
`openclaw/releases-private` for every release.
- Treat the `appcast.xml` update on `main` as part of mac release readiness, not an optional follow-up.
- The workflows remain tag-based. The agent is responsible for making sure
preflight runs complete successfully before any publish run starts.
- Any fix after preflight means a new commit. Delete and recreate the tag and
matching GitHub release from the fixed commit, then rerun preflight from
scratch before publishing.
Exception: never delete or recreate a beta tag whose matching npm package has
already been published; increment to the next beta number instead. If only the
pushed tag/prerelease exists and npm publish has not happened, recreate that
same beta tag at the fixed commit.
- For stable mac releases, generate the signed `appcast.xml` before uploading
public release assets so the updater feed cannot lag the published binaries.
- Serialize stable appcast-producing runs across tags so two releases do not
generate replacement `appcast.xml` files from the same stale seed.
- For stable releases, rely primarily on the latest beta's broader release
workflow confidence. When promoting the matching non-beta build to npm
`latest`, prefer a light time-bounded verification pass: published npm
description: "OpenClaw Tideclaw alpha/nightly release automation: isolated branches, local fixes, release CI, branch retention, and forward-port to main."
---
# Nightly Release
Use for Tideclaw/OpenClaw alpha/nightly release automation, manual alpha triggers, beta prep, release-branch repair, and post-release forward-port. Load `$release-private` if it exists before using Tideclaw host paths, cron ids, or Discord routing ids.
## Policy
- Alpha/nightly runs every 12h or by manual trigger.
- Beta is human-triggered from Discord from a proven alpha/release branch.
- Stable/latest always needs explicit human confirmation.
- Never publish from a dirty checkout or directly from `main`.
- Main can be busy or broken; alpha work must be isolated so transient main failures do not block a usable nightly.
- Publish only after release-branch proof is green.
- After a successful alpha, forward-port release-branch commits back to `main` and prove main CI green.
- Forward-port PRs contain only reusable fixes needed to make nightly/release checks pass. They must not contain alpha version bumps, release notes, changelog release entries, tags, generated artifacts, or state-file updates.
- Keep only alpha/nightly branches from the last 3 days, plus any branch with an active run, open PR, or release tag.
- Never run broad env/token dumps. For GitHub writes on the Tideclaw host, use the Tideclaw `gh` write wrapper below.
## Identity
Tideclaw should commit under its own machine identity on release branches and forward-port branches:
```bash
git config user.name "Tideclaw"
git config user.email "tideclaw@openclaw.ai"
```
This is good for auditability if commits are clearly machine-authored and gated by CI. Avoid direct pushes to protected `main`; forward-port via PR/automerge unless the repo policy explicitly allows the bot to push after green checks. Include human `Co-authored-by` only when a human supplied the patch or explicit commit text.
## Branch Shape
- Branch prefix: `tideclaw/alpha/`
- Branch name: `tideclaw/alpha/YYYY-MM-DD-HHMMZ`
- Base: current `origin/main` SHA at trigger time.
- State file: resolve from `$release-private` on the Tideclaw host.
- Release tag: `vYYYY.M.D-alpha.N`
- npm dist-tag: `alpha`
Do not reuse old alpha branches for a new run. If rerunning the same base SHA, create a new timestamped branch and record why.
## Start
1. Work in the Tideclaw host checkout from `$release-private`.
3. Read repo release docs/scripts before changing anything:
-`AGENTS.md`
- release docs under `docs/`
- release scripts under `scripts/`
-`.github/workflows/*release*`
4. Compare `$BASE_SHA` with the last successful alpha state and current git/npm/GitHub alpha tags. If already released, report skip and do not publish.
Manual trigger:
```bash
CRON_ID="<from release-private>"
OPENCLAW_ALLOW_ROOT=1 openclaw cron run "$CRON_ID" --expect-final --timeout 21600000
```
## Discord Alpha Trigger
Tideclaw may run alpha immediately from Discord when a maintainer mentions Tideclaw in `#releases` or `#maintainers`.
Accepted shapes:
```text
@Tideclaw run alpha now
@Tideclaw alpha release from main now
@Tideclaw trigger alpha
```
Rules:
1. Treat this as a manual alpha trigger equivalent to the alpha cron job.
2. Start from current `origin/main` and create a fresh `tideclaw/alpha/YYYY-MM-DD-HHMMZ` branch.
3. Follow the normal alpha workflow: reuse prior fixes, run local checks, fix on the alpha branch, run release CI, publish alpha after green gates, then forward-port reusable fixes via fixes-only PR.
4. If another alpha/beta/stable release run is already active, report the active branch/run and stop.
5.`#maintainers` trigger requires an explicit Tideclaw mention; do not react to unmentioned release chatter there.
6. Resolve Discord role/user ids and live host hotfix notes from `$release-private`.
## Discord Beta Trigger
Tideclaw may run beta releases from `#releases` or mentioned `#maintainers` commands only when a maintainer sends an explicit beta trigger. Treat this as human approval for beta, not for stable/latest.
Accepted shapes:
```text
@Tideclaw beta release from vYYYY.M.D-alpha.N
@Tideclaw beta release from tideclaw/alpha/YYYY-MM-DD-HHMMZ
@Tideclaw beta release from latest proven alpha
```
Rules:
1. Require the words `beta release` and a source alpha tag/branch, or `latest proven alpha`.
2. If the source is ambiguous, ask one clarifying question in `#releases` and stop.
3. Verify the source alpha first: GitHub release, npm `alpha` package, release CI, recorded state file, and branch/tag SHA.
4. Create a fresh beta branch `tideclaw/beta/YYYY-MM-DD-HHMMZ` from the proven alpha source, not directly from a moving `main`.
5. Reuse/squash only stabilization fixes already proven on alpha. Do not import unrelated alpha release mechanics unless the beta release docs require them.
6. Compute beta as `vYYYY.M.D-beta.N`, matching npm `--tag beta`.
7. Run beta release validation/preflight/full release CI and fix failures on the beta branch.
8. Publish beta only after green beta gates. Use GitHub Actions/OIDC, never direct npm publish from the host.
9. Final Discord summary must include source alpha, beta tag/version, branch, fix commits, workflow run IDs, npm/GitHub proof, and any skipped/blocked reason.
10. After beta publishes, forward-port reusable fixes to `main` using the same fixes-only PR rules below.
## Reuse Prior Fixes
Before running checks, mine recent Tideclaw alpha branches for fixes already made during previous release attempts:
1. Read the Tideclaw state file from `$release-private` for the last successful alpha branch and fix commit SHAs.
5. Cherry-pick only real stabilization fixes that still apply to the new alpha branch. Prefer commits recorded as `fixCommitShas` in the state file.
6. Skip version bumps, changelog release entries, tag artifacts, generated release notes, state-file-only commits, and one-off debug instrumentation.
7. If a cherry-pick conflicts, inspect whether current main already contains an equivalent fix. If not, resolve minimally and keep the commit message clear.
8. Record reused commit SHAs separately from newly authored fix SHAs in the alpha state and final Discord summary.
Use `git cherry`, `git range-diff`, and targeted test reruns to avoid duplicating fixes already present on `main`.
## Repair Loop
Use the branch as a release-candidate repair surface:
1. Run narrow local checks first: changed tests, release preflight, type/lint/build gates required by release docs.
2. If local checks fail, fix on the alpha branch with minimal commits.
3. Commit each coherent fix as Tideclaw.
4. Re-run the failed local check after each fix.
5. Do not hide failures by editing baselines, expected-failure lists, ignore files, or release inventory unless the release docs explicitly require it and the diff is justified.
6. If a failure is flaky, rerun once; if still red, treat it as real.
7. If the fix is clearly useful for main, keep it small and forward-portable. Avoid broad refactors during alpha stabilization.
Commit examples:
```bash
git add <files>
git commit -m "fix: stabilize alpha release preflight"
git push -u origin "$BRANCH"
```
## Release CI
After local proof:
1. Compute the next `vYYYY.M.D-alpha.N` from existing git tags, npm versions, and GitHub releases.
2. Make the alpha branch package version and release metadata match that tag, commit it, and push the branch.
3. Run release validation from the alpha branch, using GitHub CLI, not browser/fetch tools. On the Tideclaw host, bare `gh` is a read-only Codex sandbox wrapper; use `/usr/local/bin/gh-tideclaw-write` for write-capable commands such as `workflow run`, `run cancel`, and publish dispatch:
"$GH" workflow run full-release-validation.yml --repo openclaw/openclaw --ref "$BRANCH"\
-f ref="$BRANCH"\
-f release_profile=beta \
-f rerun_group=all
"$GH" workflow run openclaw-npm-release.yml --repo openclaw/openclaw --ref "$BRANCH"\
-f tag="$SHA"\
-f preflight_only=true\
-f npm_dist_tag=alpha
```
4. Watch the exact workflow run IDs and head SHA with `gh run list`, `gh run view`, and `gh api`. Read-only `gh` is fine for polling; use `$GH` only when a command mutates GitHub. Do not use Codex browser/fetch for GitHub API polling; prior Tideclaw runs failed there after successful preflight.
5. For alpha, blocking gates are the ones Tideclaw can repair directly or that prove package safety: normal CI, plugin prerelease, npm preflight, package preparation, install smoke, tag/reachability, and publish verification. Treat cross-OS, live channel, QA Lab, package acceptance, long Docker E2E, and Telegram package E2E failures as advisory; report them in Discord and continue if the blocking gates are green.
- If `rerun_group=all` is stuck only on advisory lanes after CI, plugin prerelease, npm preflight, package preparation, and install smoke are green, dispatch a focused Full Release Validation on the same head with `-f rerun_group=install-smoke`. Use that successful focused Full Release Validation run as the publish proof, and include the separate CI/plugin/full advisory run IDs in the Discord summary.
6. If a blocking gate fails, fix on the alpha branch, push, and rerun only the failed or required release CI. If the commit changes, discard old preflight/full-validation run IDs and rerun them for the new head.
7. After full validation and npm preflight are green on the same branch head, create and push the release tag from that exact commit:
```bash
git tag -a "$TAG""$SHA" -m "openclaw ${TAG#v}"
git push origin "$TAG"
```
8. Dispatch the publish wrapper from the same alpha branch. Use the successful npm preflight run ID and full release validation run ID from the same head SHA:
```bash
"$GH" workflow run openclaw-release-publish.yml --repo openclaw/openclaw --ref "$BRANCH"\
9. Watch the publish wrapper plus child runs. If `openclaw-npm-release.yml` is waiting on the `npm-release` environment and Tideclaw cannot approve it, report that as the only blocker; do not call the release done.
10. Do not publish npm directly from the host; use GitHub Actions/OIDC.
Important: `openclaw-npm-release.yml` with `preflight_only=true` only prepares artifacts. It does not publish. A successful alpha requires the later `openclaw-release-publish.yml` wrapper, a pushed git tag, npm `alpha` dist-tag proof, and a GitHub prerelease.
## Verify Published Alpha
Release is not done until all are true:
- GitHub tag exists.
- GitHub Release exists and is marked prerelease.
- Release body links npm version page, registry tarball, integrity, and CI/proof.
-`npm view openclaw@<version>` shows the exact version, dist-tag `alpha`, tarball, integrity, and publish time.
- The Tideclaw state file from `$release-private` records version, tag, base SHA, branch, fix commit SHAs, workflow run IDs, npm integrity, and timestamp.
Final Discord summary in `#releases`:
- tag/version
- base SHA
- branch
- fix commits
- workflow run IDs
- npm/GitHub proof
- skipped/blocked reason if not released
Use Discord-safe Markdown links with angle-bracket targets. Never print secrets.
## Forward-Port
After a successful alpha, raise a fixes-only PR back to `main`:
1. Create/update a forward-port branch from current `origin/main`:
2. Cherry-pick only release-branch commits that are real fixes required to make nightly/release checks pass.
3. Exclude alpha version bumps, changelog release entries, release notes, tag artifacts, generated release assets, state-file-only commits, and any commit whose only purpose was publishing the alpha.
4. If a commit mixes a real fix with release/version changes, split it: replay only the fix hunks into a new commit on the forward-port branch.
5. Resolve conflicts in favor of the minimal main-compatible fix.
6. Run the relevant changed/local gate.
7. Push and open a PR, or use the repo’s allowed bot merge path.
8. Wait for required main CI to go green. If CI fails, fix on the forward-port branch and rerun.
9. Report the PR/merge SHA and any commits intentionally not forward-ported.
If `origin/main` is independently red before the forward-port, document the unrelated failing check and still keep the forward-port PR green against its head when possible.
## Branch Retention
Before and after each run, prune old alpha branches:
1. List `origin/tideclaw/alpha/*`.
2. Keep branches whose timestamp is within the last 3 days UTC.
3. Keep branches referenced by a live workflow run, open PR, release tag, or state file.
default_prompt:"Use $release-openclaw-plugin-testing to plan or run pre-release OpenClaw plugin validation across package, lifecycle, doctor, gateway, SDK, and live-ish proof."
description: Triage OpenClaw security advisories, drafts, and GHSA reports with shipped-tag and trust-model proof.
description: "Triage OpenClaw security advisories, drafts, and GHSA reports with shipped-tag and trust-model proof."
---
# Security Triage
@@ -87,11 +87,19 @@ When preparing a maintainer-ready close reply:
- exact reason for close
- exact code refs
- exact shipped tag / release facts
-exact fix commit or canonical duplicate GHSA when applicable
-fix provenance or canonical duplicate GHSA when applicable
- optional hardening note only if worthwhile and functionality-preserving
Keep tone firm, specific, non-defensive.
## Public Wording Hygiene
- Keep raw commit hashes, PR titles/numbers, and fix-mechanism summaries out of public advisory text. Use the patched release/version field only.
- Keep exact commit SHAs, PRs, and implementation notes in internal notes and verification files.
- For hardening/no-publish outcomes, do not add exploit-heavy details, "Fixed by" text, or a "Fix Commit(s)" section. Thank reporters, preserve credit, state the `SECURITY.md` boundary, and say clearly that the GHSA will close without publication.
- For published CVE/GHSA text, prefer `### Patched Versions` with the fixed release. Do not explain how the patch works unless Peter explicitly asks for that public detail.
- Keep GHSA ids out of changelog and release-note wording unless Peter explicitly asks.
## Discussion Mode
When Peter is manually posting GHSA comments, use this flow:
Use local Slack archive data first. Check freshness for recent/current questions:
```bash
slacrawl doctor
slacrawl status --json
```
Refresh only when stale or asked:
```bash
slacrawl sync --source desktop
slacrawl sync --source api --latest-only
```
Query with bounded slices:
```bash
slacrawl search --limit 20"query"
slacrawl messages --since 7d --limit 50
slacrawl sql "select count(*) from messages;"
```
Report workspace/channel names, absolute date spans, counts, and token/source limits. Use read-only SQL for exact counts/rankings. API sync and full thread/DM hydration require Slack tokens; do not assume they exist.
short_description:"Search local Slack archives and freshness"
default_prompt:"Use $slacrawl to search local Slack archives, check freshness, inspect channel or DM slices, and report exact date spans and token/source limits."
description: Build and review high-quality technical docs as well as agent instruction files in your repository.
license: MIT
metadata:
source: "https://github.com/vincentkoc/dotskills"
---
# Technical Documentation
## Purpose
Produce and review technical documentation that is clear, actionable, and maintainable for both humans and agents, including contributor-governance files and agent instruction files.
## When to use
- Creating or overhauling docs in an existing product/codebase (brownfield).
- Building evergreen docs meant to stay accurate and reusable over time.
- Reviewing doc diffs for structure, clarity, and operational correctness.
- Running full-repo documentation audits that must include both governance files and product docs surfaces (`docs/`, `README*`, `.md/.mdx/.mdc`, Fern/Sphinx/Mintlify-style sources).
- Updating or reviewing AGENTS.md and/or CONTRIBUTING.md to keep agent and contributor workflows aligned with current repo practices.
- Improving repository onboarding/docs that include contribution instructions, issue templates, PR flow, and review gates.
- Designing governance documentation strategy for repos with alias instruction files (for example `CLAUDE.md`, `AGENT.md`, `.cursorrules`, `.cursor/rules/*`, `.agent/`, `.agents/`, `.pi/`) where `AGENTS.md` is treated as canonical when present and aliases should be kept as compatibility surfaces.
- Diagnosing agent-file drift where teams had to prompt iteratively to surface missing files, broken commands, or policy conflicts.
- Applying repository-specific documentation overlays, including OpenClaw page-type, docs IA, preservation, and validation rules when present.
## Workflow
1. Classify task: `build` or `review`; context: `brownfield` or `evergreen`.
2. Inventory full documentation scope early (governance + product docs): AGENTS/CONTRIBUTING/aliases plus docs directories, framework sources, and root/module READMEs.
3. Detect multilingual scope (README/docs in multiple languages) and define required parity level.
4. Read `references/agent-and-contributing.md` for agent instruction and `CONTRIBUTING.md` workflow rules (inventory, canonical/alias mapping, dual-mode balance, deliverable standards, and precedence/conflict handling).
5. Read `references/principles.md` for the governing ruleset (Matt Palmer & OpenAI).
6. For OpenClaw docs work, read `references/openclaw.md` before the build/review playbook.
7. For build tasks, follow `references/build.md`.
8. For review tasks, follow `references/review.md` and proactively detect issues without waiting for repeated prompts.
9. For complex or high-risk tasks (build or review), it is acceptable to run longer, deeper, and more exhaustive investigations when needed for confidence.
10. When available, use sub-agents for bounded parallel discovery/review work, then merge outputs into one coherent final deliverable.
11. Use `references/tooling.md` when platform/tooling choices affect recommendations.
12. Run a proactive issue sweep for both governance and docs-content surfaces, and fix high-confidence defects in the same pass unless explicitly asked for report-only mode.
13. In brownfield mode, prioritize compatibility with current docs IA, tooling, and release state.
14. In evergreen mode, prioritize timeless wording, update strategy, and durable structure.
15. Return deliverables plus validation notes, parity status, and remaining gaps.
## Sub-agent orchestration guidance
Prefer sub-agents when the repo is large or the requested change set is broad; use them by default for repo-wide, multi-framework, or high-conflict work.
-`inventory-agent` -> `agents/inventory-agent.md` (`fast` / Claude `haiku`): file/config discovery, coverage map, and missing-path checks.
-`governance-agent` -> `agents/governance-agent.md` (`thinking` / Claude `sonnet`): AGENTS/CONTRIBUTING/alias precedence, conflicts, and policy drift.
-`docs-framework-agent` -> `agents/docs-framework-agent.md` (`thinking` / Claude `sonnet`): framework config, relative path base, and file-path vs URL-path mapping checks.
-`synthesis-agent` -> `agents/synthesis-agent.md` (`long` / Claude `opus`): merge sub-agent outputs into one prioritized fix plan and unified precedence model.
## Inputs
- Doc type (tutorial, how-to, reference, explanation) and audience.
2. Read the root and nearest-scope `AGENTS.md`/`CONTRIBUTING.md` pair before editing.
3. If alias files exist, normalize to one canonical source (`AGENTS.md` preferred when present; otherwise nearest alias), plus compatibility pointers or explicit symlink notes.
4. Document conflicting instructions and precedence decisions.
1. Run a conflict matrix review across AGENTS/aliases/CONTRIBUTING and related command/rule docs before finalizing.
2. Treat the following as high-priority defects: missing referenced files, non-existent setup commands, command scope mismatches, and branch/commit policy conflicts.
3. Do not stop at caveat-only notes when a low-risk fix is clear; apply the fix in the same pass.
4. If a canonical entry file is missing (for example a directory `README.md` that docs depend on), create a minimal actionable file and update references.
5. Long-running investigations are acceptable when needed to uncover cross-file drift, especially in agent-instruction ecosystems.
## Discovery
1. Agents prefer simple terminal commands so having a well defined `make *` or `npm run *` is ideal
2. Agents can discover terminal commands through shell completion so providing shell completion helps
- Success criteria: what must be true after publish.
## 5. Build structure before prose
- Follow the funnel: what/why, quickstart, next steps.
- Keep headings informative and scannable.
- Open each section with the takeaway sentence.
- Add decision points with concrete branch guidance.
- For OpenClaw docs work, choose a page type from `references/openclaw.md` before drafting.
- Keep task-critical OpenClaw configuration inline; link exhaustive defaults, enums, schemas, generated references, and rare debugging workflows.
## 6. Build AGENTS.md and CONTRIBUTING.md intentionally
- Keep AGENTS.md structure consistent with `agents.md` ecosystem patterns:
- include YAML frontmatter when present in repo style (`name`, `description`).
- state persona scope and explicit instruction boundaries: `Always`, `Ask first`, `Never`.
- include concrete commands and representative code examples.
- For CONTRIBUTING.md, prioritize issue triage flow, PR expectations, setup/test commands, and review gates.
- Add `Code of Conduct`, `Testing`, `Local checks`, and `PR expectations` sections when missing but required by the repo.
- If CONTRIBUTING.md is becoming too large, split by scope into linked docs (for example, framework/tool-specific setup and release workflows) and keep the root file as a concise entry point.
- Keep cross-file consistency: links from CONTRIBUTING.md to AGENTS.md (and vice versa) should be accurate and non-circular.
- If multiple AGENTS.md files exist, document the directory-level scope and avoid conflicting advice.
- If a required canonical entry file is missing (for example referenced `README.md` under a major directory), create the file in the same pass instead of adding a caveat-only note.
- For new entry files, keep them minimal and actionable: purpose, prerequisites, concrete run commands, and pointers to deeper docs.
## 7. Keep agent context tight
- Author once, expose twice:
- keep one shared policy core and avoid duplicating guidance in separate agent-specific files.
- publish that core through bounded glob-friendly files for Cursor/Claude plus explicit path references for Codex.
- For Cursor and Claude-style agents, avoid broad references. Use minimal globbing and narrow rule files that each serve one concern (for example, repo-wide setup, test rules, security checks).
- Keep AGENTS and alias files short-to-medium; move detailed runbooks to linked docs.
- For Codex, prefer explicit file references and concrete paths for exact reuse.
- Avoid adding unrelated historical or process details to avoid token/context drift during future tool reads.
## 8. Brownfield build mode
- Match existing terminology, navigation, and component patterns.
- Preserve existing IA unless there is a documented migration plan.
- For rewrites, include a migration note from old to new paths.
- Prefer smallest safe change set that improves utility.
## 9. Evergreen build mode
- Prefer stable concepts over release-tied narrative.
- Isolate volatile details under clearly marked version sections.
- Include maintenance signals: owners, refresh triggers, stale criteria.
- Include lifecycle notes: deprecation and replacement paths.
## 10. Writing constraints
- Use precise language and short, imperative instructions.
- Keep code examples copy-ready and self-contained.
- Include common failure modes and safe defaults.
- Avoid placeholder guidance that cannot be executed.
## 11. Agent and automation readiness
- Keep key facts in text (not image-only).
- Prefer structured lists/tables when choices matter.
- Add links and anchors that allow deterministic navigation.
- Document what can be checked automatically in CI.
## 12. Build validation
- Validate commands and snippets where possible.
- Verify links and references in changed sections.
- Run a reference existence sweep for every path/command you introduced.
- Verify docs-framework consistency when in scope (for example Sphinx/Fern config and referenced doc paths).
- For OpenClaw docs work, apply the validation checklist in `references/openclaw.md`.
## 13. Multilingual parity mode (when applicable)
- Pick one source-of-truth language for technical accuracy and release timing.
- Define parity target: full parity, staged parity, or intentional divergence per section.
- Keep structure aligned across locales (headings, anchors, section order) when possible.
- Preserve command/code correctness first; localize explanatory text second.
- If parity is not feasible, add a visible note with missing scope and expected sync window.
- Run a locale parity check for changed sections (added/removed steps, warnings, prerequisites).
- Prefer specific and accurate terminology over niche jargon.
- Keep examples self-contained and minimize dependencies.
- Prioritize high-value topics over edge-case depth.
- Do not teach unsafe patterns (for example, exposed secrets).
- Open with context that helps readers orient quickly.
- Apply empathy and override rigid rules when it clearly improves outcomes.
## Practical merge policy
When these rules conflict:
1. Preserve reader task success first.
2. Preserve structural clarity second.
3. Preserve long-term maintainability third.
4. Add agent optimization only if it does not reduce human clarity.
For agent-instructions and contributor-governance specifics (AGENTS/aliases/CONTRIBUTING), use `references/agent-and-contributing.md` as the detailed additional source of truth.
When the target repo or request is OpenClaw-specific, layer `references/openclaw.md` on top of these general rules. Otherwise ignore that repo-specific overlay.
## Execution policy for this skill
- Long-running and extensive investigations are allowed for both build and review work when needed to resolve ambiguity or cross-file drift.
- Use sub-agents when available for bounded parallel discovery, verification, or cross-source comparison.
- Keep one merged outcome: sub-agent outputs must be normalized into a single consistent recommendation/fix set.
## Multilingual parity rule
When docs exist in multiple languages, target cross-locale parity for task-critical content (steps, warnings, prerequisites, and limits). If full parity is not possible, publish explicit parity status and sync intent.
Read `principles.md` first, then apply this checklist.
## 1. Scope and classification
- Identify doc type and target audience.
- Confirm brownfield vs evergreen intent.
- Confirm expected outcome for the reader.
- For full-repo reviews, explicitly include both governance surfaces and product-doc surfaces (`docs/`, README trees, `.md/.mdx/.mdc`, `.rst/.rsc`, framework docs configs).
- For OpenClaw docs reviews, apply `references/openclaw.md` for page type, docs IA, preservation, examples, and validation checks.
## 2. Investigation behavior
- Proactively find issues and risks without waiting for repeated prompts.
- If there are signals of deeper problems, continue investigation beyond the first pass.
- Long-running and extensive investigations are acceptable when needed for confidence and correctness.
- When available, use sub-agents for bounded parallel discovery (for example file-inventory, command validation, or cross-doc consistency checks), then merge to one final issue set.
- When no issues are found, state that explicitly and call out residual risks or validation gaps.
- Default to `apply-fixes` for high-confidence documentation defects unless the user explicitly requests `report-only`.
- Do not stop at AGENTS/CONTRIBUTING checks when the task is documentation-wide; continue into docs-content and docs-framework surfaces.
## 3. Governance surface review
- Use `references/agent-and-contributing.md` as the source of truth for inventory, canonical/alias mapping, and precedence/conflict handling.
For AGENTS.md:
- confirm persona intent, scope, and command/tool boundaries are explicit.
- check frontmatter style matches repo conventions when present.
- ensure `Always`, `Ask first`, and `Never` boundaries are present when expected.
- require concrete command examples and repo-specific paths to avoid ambiguity.
For CONTRIBUTING.md:
- verify issue/PR workflow is complete and actionable.
- ensure local setup, lint/test commands, and review criteria are accurate.
- ensure governance does not conflict with nested AGENTS instructions.
- flag oversized files that should be split into linked section docs (for example tool-specific setup and release docs).
For agent-platform awareness:
- confirm references are minimal and scoped for Cursor/Claude glob behavior.
- verify canonical rule directory and symlink state match repo policy
- verify symlink target integrity and platform/tooling expectations
- verify AGENTS policy references remain canonical for Codex even when `.cursor` compatibility exists
- check for context bloat from duplicated policy statements across agent and contributor files.
- check for conflicting rules, skills and agent instructions
- check for conflicting information in agent instructions vs codebase
- check for broken or missing referenced files (for example README/index files named as canonical entry points).
- check for setup/command drift (for example non-existent install commands, root-level commands that should be module-scoped).
## 4. Product documentation surface review
- Verify docs IA coverage across root/module `README*` files and `docs/**` trees.
- Review framework-native docs sources in scope (for example Fern, Mintlify, Sphinx, MkDocs) and ensure guidance matches actual source-of-truth files.
- Check `.md/.mdx/.mdc/.rst/.rsc` for stale commands, missing prerequisites, and broken cross-links.
- Confirm referenced doc paths and anchors exist.
- Flag docs that should be split/merged to improve discoverability and maintenance.
- For OpenClaw docs, check `docs/docs.json`, docs-list routing hints, main path versus `Reference` placement, and generated-reference visibility.
- For OpenClaw rewrites or page splits, require source-backed keep/drop/move/destination coverage for important claims, warnings, examples, commands, fields, and troubleshooting facts.
## 5. Framework config and path mapping checks
- Detect and read framework config first (for example Fern config, Sphinx `conf.py`, Mintlify config, or equivalent).
- Resolve path references relative to the declaring file/config.
- Treat filesystem paths and published URL routes as separate maps; verify both.
- Flag path-map drift explicitly (`missing file`, `stale route`, `wrong base path`).
## 6. Structural review
- Funnel check: what/why, quickstart, next steps.
- Validate heading flow and navigation discoverability.
- Flag critical content trapped in images or buried sections.
- Check Diataxis alignment and split mixed-purpose sections.
- For OpenClaw docs, confirm the content matches an explicit page type from `references/openclaw.md`.
## 7. Writing quality review
- Check for concise, scannable paragraphs.
- Remove ambiguous pronouns and undefined terms.
- Verify examples are executable and scoped correctly.
- Verify tone is directive, technical, and non-hand-wavy.
## 8. Brownfield review mode
- Verify compatibility with existing docs IA and conventions.
- Verify anchors, redirects, and cross-doc links remain valid.
- Flag regressions in onboarding and task completion paths.
- Ensure changed terminology is intentionally propagated.
## 9. Evergreen review mode
- Flag date-stamped or brittle wording without version scope.
- Check ownership and refresh signals are present.
- Ensure recommendations remain valid after routine product evolution.
Do not speculate or infer beyond the evidence. If a narrative section cannot be answered from the available evidence, respond with exactly `NOT_ENOUGH_INFO`.
If this is a plugin beta-release blocker, rename the issue title to `Beta blocker: <plugin-name> - <summary>` and apply the `beta-blocker` label after filing.
Please only report one issue per submission. Break multiple issues up into separate submissions.
This PR description is the contributor's durable explanation of the change. Write it for human maintainers first; ClawSweeper and Barnacle use the same text to understand intent, proof, risk, and current review state.
Describe the intent and outcome in 2-5 bullets. Avoid restating the diff; reviewers and bots can read the changed files.
If this PR fixes a plugin beta-release blocker, title it `fix(<plugin-id>): beta blocker - <summary>` and link the matching `Beta blocker: <plugin-name> - <summary>` issue labeled `beta-blocker`. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.
- Problem:
- Why it matters:
- What changed:
- What did NOT change (scope boundary):
</details>
## Change Type (select all)
## Linked context
- [ ] Bug fix
- [ ] Feature
- [ ] Refactor required for the fix
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
Which issue does this close?
## Scope (select all touched areas)
Closes #
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
Which issues, PRs, or discussions are related?
## Linked Issue/PR
Related #
- Closes #
- Related #
- [ ] This PR fixes a bug or regression
Was this requested by a maintainer or owner?
<details>
<summary>Linked context guidance</summary>
Link the issue, PR, discussion, maintainer request, or owner request that explains why this PR should exist. Maintainer context helps reviewers and automation distinguish intended work from drive-by churn.
</details>
## Real behavior proof (required for external PRs)
External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only. Screenshots are encouraged even for CLI, console, text, or log changes; terminal screenshots and copied live output count. Be mindful of private information like IP addresses, API keys, phone numbers, non-public endpoints, or other private details when providing evidence.
- Behavior or issue addressed:
- Real environment tested:
- Exact steps or command run after this patch:
- Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
- Observed result after fix:
- What was not tested:
- Proof limitations or environment constraints:
- Before evidence (optional but encouraged):
## Root Cause (if applicable)
<details>
<summary>Real behavior proof guidance</summary>
For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write `N/A`. If the cause is unclear, write `Unknown`.
External contributors must show after-fix evidence from a real OpenClaw setup. Unit tests, mocks, lint, typechecks, snapshots, and CI are supplemental only.
- Root cause:
- Missing detection / guardrail:
- Contributing context (if known):
Screenshots are encouraged even for CLI, console, text, or log changes. Terminal screenshots, copied live output, redacted runtime logs, recordings, and linked artifacts count.
## Regression Test Plan (if applicable)
If your environment cannot produce the ideal proof, explain that under `Proof limitations or environment constraints` so reviewers and ClawSweeper can direct the next step properly.
For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write `N/A`.
Be mindful of private information like IP addresses, API keys, phone numbers, non-public endpoints, or other private details when providing evidence.
- Coverage level that should have caught this:
- [ ] Unit test
- [ ] Seam / integration test
- [ ] End-to-end test
- [ ] Existing coverage already sufficient
- Target test or file:
- Scenario the test should lock in:
- Why this is the smallest reliable guardrail:
- Existing test that already covers this (if any):
- If no new test is added, why not:
</details>
## User-visible / Behavior Changes
## Tests and validation
List user-visible changes (including defaults/config).
If none, write `None`.
Which commands did you run?
## Diagram (if applicable)
For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write `N/A`.
List focused commands, not every incidental check. CI is useful support, but external PRs still need real behavior proof above when behavior changes.
- OS:
- Runtime/container:
- Model/provider:
- Integration/channel (if any):
- Relevant config (redacted):
</details>
### Steps
## Risk checklist
1.
2.
3.
Did user-visible behavior change? (`Yes/No`)
### Expected
-
Did config, environment, or migration behavior change? (`Yes/No`)
### Actual
-
Did security, auth, secrets, network, or tool execution behavior change? (`Yes/No`)
## Evidence
Attach at least one:
What is the highest-risk area?
- [ ] Failing test/log before + passing after
- [ ] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)
## Human Verification (required)
How is that risk mitigated?
What you personally verified (not just CI), and how:
<details>
<summary>Risk guidance</summary>
- Verified scenarios:
- Edge cases checked:
- What you did **not** verify:
Use this for author judgment that is not obvious from the diff. ClawSweeper can see touched files, but it cannot know which behavior you think is risky, why the risk is acceptable, or what mitigation reviewers should verify.
## Review Conversations
</details>
- [ ] I replied to or resolved every bot review conversation I addressed in this PR.
- [ ] I left unresolved only the conversations that still need reviewer or maintainer judgment.
## Current review state
If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.
What is the next action?
## Compatibility / Migration
- Backward compatible? (`Yes/No`)
- Config/env changes? (`Yes/No`)
- Migration needed? (`Yes/No`)
- If yes, exact upgrade steps:
What is still waiting on author, maintainer, CI, or external proof?
## Risks and Mitigations
List only real risks for this PR. Add/remove entries as needed. If none, write `None`.
Which bot or reviewer comments were addressed?
- Risk:
- Mitigation:
<details>
<summary>Review state guidance</summary>
Keep this as the durable state for review progress. If useful information appears in comments, fold the current next action or blocker back here so maintainers and ClawSweeper do not need to reconstruct state from comment history.
| select(startswith("+") and (startswith("+++") | not))
| "\($file): \(.)"
' > "$added_lines"
if grep -En '(from|require\().*["'\''](node:)?(net|tls|http2)["'\'']|\b(net|tls|http2)\.(connect|createConnection)\b|new Socket\(|HTTP_PROXY|HTTPS_PROXY|NO_PROXY|GLOBAL_AGENT_|OPENCLAW_PROXY_' "$added_lines"; then
for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE; do
for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE XDG_CACHE_HOME COREPACK_HOME NODE_BIN PNPM_HOME PNPM_CONFIG_CHILD_CONCURRENCY PNPM_CONFIG_MODULES_DIR PNPM_CONFIG_NETWORK_CONCURRENCY PNPM_CONFIG_STORE_DIR PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN PNPM_CONFIG_VIRTUAL_STORE_DIR PATH; do
write_export "$key"
done
} > "${env_file}.tmp"
mv "${env_file}.tmp" "$env_file"
{
echo "# Docker containers visible from the hydrated runner"
for key in CI GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_NUMBER GITHUB_RUN_ATTEMPT GITHUB_REF GITHUB_REF_NAME GITHUB_SHA GITHUB_EVENT_NAME GITHUB_ACTOR RUNNER_OS RUNNER_ARCH RUNNER_TEMP RUNNER_TOOL_CACHE NODE_BIN PNPM_HOME PNPM_CONFIG_CHILD_CONCURRENCY PNPM_CONFIG_MODULES_DIR PNPM_CONFIG_NETWORK_CONCURRENCY PNPM_CONFIG_STORE_DIR PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN PNPM_CONFIG_VIRTUAL_STORE_DIR PATH; do
write_export "$key"
done
} > "${env_file}.tmp"
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.