Compare commits

...

63 Commits

Author SHA1 Message Date
Peter Steinberger
013a2c50f6 chore(release): refresh release metadata for 2026.5.5 beta 1 2026-05-06 03:03:03 +01:00
Peter Steinberger
6896bd3ddf chore(release): keep 2026.5.5 beta 1 2026-05-06 02:50:50 +01:00
Peter Steinberger
9cb0b97f74 docs(release): clarify unpublished beta tag movement 2026-05-06 02:48:55 +01:00
Peter Steinberger
e820821950 chore(release): prepare 2026.5.5 beta 2 2026-05-06 02:45:51 +01:00
Peter Steinberger
ecf2dc58e1 chore(release): prepare 2026.5.5 beta 1 2026-05-06 02:39:25 +01:00
Vincent Koc
817b56f22d fix(cli): repair legacy config before update channel switch (#77069)
* fix(cli): repair legacy config before update channel switch

* docs(changelog): note update channel legacy config repair

* fix(update): keep legacy config repair doctor-owned

* fix(update): keep dry runs read-only

* fix(update): avoid include-flattening legacy repair
2026-05-06 02:31:02 +01:00
Vincent Koc
258e153705 fix(doctor): repair legacy Codex route config
Repair legacy openai-codex route config and session pins safely.
2026-05-06 02:31:02 +01:00
Vincent Koc
acdf0e432a fix(plugins): sync official plugin installs during update (#78065)
* fix(plugins): sync official npm installs during update

* fix(plugins): sync official clawhub installs during update

* test(update): mock official plugin sync helpers

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-05-06 02:30:17 +01:00
Vincent Koc
3c04d7e710 fix(video): recover generation parameter fallbacks 2026-05-06 02:29:39 +01:00
Vincent Koc
1205c9ef1f feat(status): show uptime in chat status
Show compact Gateway process and host system uptime in chat /status output.
2026-05-06 02:29:03 +01:00
Vincent Koc
ba5bc48f70 fix(gateway): keep reset and refresh paths responsive (#77701)
* fix(hooks): keep session memory slugging off reset hot path

* fix(hooks): run session memory capture asynchronously

* fix(cli): avoid stuck gateway command exits

* fix(gateway): cache empty read-only model catalog

* fix(doctor): stop stale TUI clients for WhatsApp responsiveness
2026-05-06 02:28:25 +01:00
Vincent Koc
cbbdaf92a4 fix(hooks): avoid session memory filename collisions
Add collision suffixes for session-memory fallback filenames so repeated same-minute reset/new captures do not overwrite earlier archives.
2026-05-06 02:27:46 +01:00
Vincent Koc
1692c84b8c test(live): classify provider HTTP 5xx as server drift 2026-05-06 02:27:11 +01:00
Vincent Koc
0097427d08 fix(tui): bound session list recency (#77752) 2026-05-06 02:27:11 +01:00
Vincent Koc
2d2fc19e36 fix(core): avoid session export filename collisions (#77762) 2026-05-06 02:26:39 +01:00
Vincent Koc
daff8916de fix(agents): filter runtime context from context engines
- filter hidden runtime-context custom messages before context-engine assemble, afterTurn, and ingest fallback hooks
- preserve the pre-prompt/new-turn boundary after filtering
- add regression coverage for assemble, afterTurn, and ingestBatch fallback behavior

- pnpm test:serial src/agents/harness/context-engine-lifecycle.test.ts -- --reporter=verbose
- pnpm exec oxfmt --check --threads=1 src/agents/harness/context-engine-lifecycle.ts src/agents/harness/context-engine-lifecycle.test.ts CHANGELOG.md
- git diff --check origin/main...HEAD
- pnpm changed:lanes --json
- pnpm testbox:run --id tbx_01kqx8fy1ktpqczkcej2pgpryz -- "OPENCLAW_TESTBOX_REMOTE_RUN=1 pnpm check:changed"
2026-05-06 02:11:24 +01:00
Vincent Koc
3569edb38e fix(tui): prevent orphaned terminal sessions (#77662)
* fix(tui): prevent orphaned terminal sessions

* fix(doctor): repair heartbeat-poisoned main sessions

* fix(tui): preserve startup tls respawn

* fix: harden tui and doctor recovery paths
2026-05-06 02:10:54 +01:00
Eden
9cc6cca75d fix(gateway): improve shutdown error visibility and add close timeout
Adds structured warning collection to gateway shutdown, preserves lifecycle timeout handling, and covers HTTP/WebSocket/subsystem warning paths.

Co-authored-by: Eden <146086744+edenfunf@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
2026-05-06 02:10:21 +01:00
Vincent Koc
e8ad813282 fix(update): avoid lint-blocked dev installs (#77181) 2026-05-06 02:08:59 +01:00
Vincent Koc
e8f0608b09 fix(cli): fast-path bare channels help (#77659)
* fix(cli): fast-path bare channels help

* fix(cli): normalize channels add argv gating

* fix(cli): restore channel add completion flags
2026-05-06 02:08:26 +01:00
Vincent Koc
7470ea9073 fix(gateway): cancel delayed maintenance on shutdown 2026-05-06 02:07:54 +01:00
Vincent Koc
ed4ed5aead fix(status): show runtime in CLI sessions (#77776)
* fix(status): show agent runtime in cli status

* fix(status): preserve configured runtime labels
2026-05-06 02:07:21 +01:00
Vincent Koc
3544ef0afa fix(sessions): show runtime in sessions table 2026-05-06 02:06:51 +01:00
Vincent Koc
7da737c67d fix(ui): show session runtime in sessions table 2026-05-06 02:06:10 +01:00
Peter Steinberger
95e9e29219 fix(release): tighten xai and corrupt plugin checks 2026-05-06 02:04:00 +01:00
Peter Steinberger
31633bc0ec fix(release): unblock 2026.5.5 validation 2026-05-06 01:06:49 +01:00
Patrick Erichsen
30927c8491 Tolerate corrupt plugins during update (#77706)
* fix(update): tolerate corrupt plugin state

* fix(update): preserve corrupt plugin proof state

* fix(update): narrow corrupt plugin warnings

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit 8aa7b7a4ca)
2026-05-05 23:51:57 +01:00
Peter Steinberger
9a61edb419 fix(discord): show reasoning text in progress drafts (#78050)
* fix(discord): show reasoning text in progress drafts

* fix(discord): handle reasoning progress snapshots

* test: isolate usage-format models fixture

(cherry picked from commit d94e7f5114)
2026-05-05 23:49:57 +01:00
Vincent Koc
e12dbf527f fix(gateway): skip media sidecar for unrelated HTTP routes
(cherry picked from commit d38e30e02c)
2026-05-05 23:49:22 +01:00
Peter Steinberger
23319a3cc2 fix: restore Codex agent dir runtime import
(cherry picked from commit a6d88e3cd9)
2026-05-05 23:48:50 +01:00
Peter Steinberger
82e914e506 fix(gateway): mark openai role chunks unfinished
(cherry picked from commit fd86ab2e50)
2026-05-05 23:48:50 +01:00
Peter Steinberger
c82f66e3c2 fix(gateway): flush initial openai chat stream chunk
(cherry picked from commit d520bc4cb6)
2026-05-05 23:48:50 +01:00
Ayaan Zaidi
191e821b71 fix(update): stop dev updates after fetch failure
(cherry picked from commit c1a385df83)
2026-05-05 23:48:15 +01:00
Chunyue Wang
7a2e7dba73 fix(auth-profiles): exclude format rejections from profile cooldown (#77280)
Merged via squash.

Prepared head SHA: f4188b4dc3
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Reviewed-by: @openperf

(cherry picked from commit 31da1fe5b0)
2026-05-05 23:48:15 +01:00
Ayu
eda33431de security: harden gateway container privileges
Adds cap_drop and no-new-privileges hardening for the bundled gateway Docker Compose services.\n\nThanks @VintageAyu.

(cherry picked from commit f9da484365)
2026-05-05 23:48:15 +01:00
Peter Steinberger
4aa91b0b97 fix: backport media completion fallback 2026-05-05 23:34:08 +01:00
Peter Steinberger
8a601b0607 fix: avoid media completion fallback while announce pending
(cherry picked from commit b32d4c5255)
2026-05-05 23:31:22 +01:00
Peter Steinberger
6f9f36a38f test: cover generated media delivery evidence fallback
(cherry picked from commit add9a49c40)
2026-05-05 23:28:10 +01:00
Peter Steinberger
c03449678e fix: recognize attachment message sends
(cherry picked from commit a0ea07e462)
2026-05-05 23:27:11 +01:00
Peter Steinberger
edbd3355be chore(release): bump version to 2026.5.5
(cherry picked from commit c37871e77b)
2026-05-05 23:25:59 +01:00
Peter Steinberger
325df3efef chore(release): bump to 2026.5.4 2026-05-05 08:37:19 +01:00
Peter Steinberger
2fc80754cf ci: parallelize release publish workflows 2026-05-05 07:35:28 +01:00
Peter Steinberger
41f028e2ea fix(diagnostics): drop stale session recovery event cases 2026-05-05 06:06:02 +01:00
Peter Steinberger
303ff716d4 chore(release): refresh plugin SDK API baseline 2026-05-05 05:56:41 +01:00
Peter Steinberger
5fcdeae80c chore(release): bump to 2026.5.4-beta.3 2026-05-05 05:51:46 +01:00
6607changchun
b73317c217 fix(sandbox): support Windows drive-letter bind sources
Accept drive-absolute Windows sandbox Docker bind sources in config and runtime validation while keeping blocked-path and allowed-root comparisons case-insensitive for Windows drive paths.

Also remove a stale WhatsApp setup import that blocked extension lint after the rebase.

Co-authored-by: 6607changchun <84566142+6607changchun@users.noreply.github.com>
Co-authored-by: Brad Groux <3053586+BradGroux@users.noreply.github.com>
(cherry picked from commit d02fbc6116)
2026-05-05 05:45:56 +01:00
兰之
8f6bf65162 fix(agents): enforce exact skill path from <available_skills> [AI-assisted] (#74161)
Summary:
- The PR updates agents skill prompt guidance to require exact `<location>` paths for single- and multi-skill selection, adds prompt assertions, and records the fix in the changelog.
- Reproducibility: yes. Static source reproduction is enough: current main lacks the exact-`<location>` guard  ... illsSection()`, while the PR diff adds it to both selection branches and asserts the resulting prompt text.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: enforce exact skill paths for all skill matches

Validation:
- ClawSweeper review passed for head 743c9840c1.
- Required merge gates passed before the squash merge.

Prepared head SHA: 743c9840c1
Review: https://github.com/openclaw/openclaw/pull/74161#issuecomment-4341488109

Co-authored-by: tianguicheng <tianguicheng@xiaomi.com>
Co-authored-by: sallyom <somalley@redhat.com>
(cherry picked from commit c739088d62)
2026-05-05 05:45:56 +01:00
saram ali
8017dc4c3b fix(gateway): skip IPv6 loopback binding on Windows (#69701)
Bind the default loopback gateway listener only to `127.0.0.1` on Windows so libuv dual-stack `::1` behavior cannot wedge localhost HTTP requests.

Also keeps non-Windows dual-loopback behavior covered, replaces the redundant Windows passthrough test with guard coverage, and adds the required changelog entry.

Fixes #69674.

Tests:
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/gateway/net.ts src/gateway/net.test.ts
- pnpm test src/gateway/net.test.ts
- pnpm check:changed
- GitHub required checks: green

Thanks @SARAMALI15792.

Co-authored-by: saram ali <140950904+SARAMALI15792@users.noreply.github.com>
Co-authored-by: Brad Groux <3053586+BradGroux@users.noreply.github.com>
(cherry picked from commit 978bc53e80)
2026-05-05 05:45:56 +01:00
Peter Steinberger
578d9072cf test: align beta plugin repair expectations 2026-05-05 05:40:52 +01:00
Vincent Koc
30b73bbf41 fix(plugins): honor beta channel for auto installs
(cherry picked from commit b0f841ef37)
2026-05-05 05:37:52 +01:00
Vincent Koc
ade922ba98 fix(telegram): reuse preview for long text finals (#77658)
* fix(telegram): reuse preview for long text finals

* test(qa): cover long telegram finals

* fix(qa): satisfy extension lint

* fix(qa): keep telegram long final fixture to two chunks

* test(telegram): cover three chunk finals

* fix(telegram): force long final preview boundary

(cherry picked from commit e03fe1e289)
2026-05-05 05:37:52 +01:00
Vincent Koc
997f8af734 fix(whatsapp): normalize onboarding allowlist numbers
Normalize WhatsApp onboarding allowlist entries to digit-only WhatsApp IDs and reject invalid owner-phone inputs during prompt validation.

(cherry picked from commit 68a500c465)
2026-05-05 05:37:52 +01:00
Vincent Koc
6204a6fecc fix(update): authenticate restart health probes
(cherry picked from commit b546aa91e1)
2026-05-05 05:37:25 +01:00
Peter Steinberger
9f15c29397 fix: explain missing git during plugin install
(cherry picked from commit a91c17c426)
2026-05-05 05:23:01 +01:00
Bek
cac973972c fix: slack mention-gating thread participation
(cherry picked from commit cf3ce08b91)
2026-05-05 05:14:29 +01:00
Peter Steinberger
f8f18d53fc fix: start configured generation providers
(cherry picked from commit 0eb06caae3)
2026-05-05 05:10:02 +01:00
pickaxe
696f639cf6 docs: note plugin peer-link update repair
(cherry picked from commit 712aa96a8f)
2026-05-05 05:06:31 +01:00
pickaxe
079b937b46 fix(plugins): repair missing openclaw peer links on update
(cherry picked from commit 2e8761c5c1)
2026-05-05 05:06:31 +01:00
Kelaw - Keshav's Agent
32e36d355d fix: recover missing Codex bound threads
(cherry picked from commit a373468d82)
2026-05-05 04:58:18 +01:00
Peter Steinberger
12e1c67f22 fix(build): route externalized plugin entry chunks 2026-05-05 04:31:46 +01:00
Peter Steinberger
766d02ff3b fix(build): route externalized plugin chunks 2026-05-05 04:23:24 +01:00
Peter Steinberger
e9ebb6ce6c fix(release): prune externalized plugin chunks 2026-05-05 04:15:20 +01:00
Peter Steinberger
e0002c4b5b chore(release): prepare 2026.5.4 beta 2 2026-05-05 02:42:03 +01:00
332 changed files with 9247 additions and 1070 deletions

View File

@@ -42,10 +42,12 @@ Use this skill for release and publish-time workflow. Keep ordinary development
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 preflight before npm publish, delete and
recreate the tag and prerelease at the fixed commit so npm prerelease versions
stay contiguous. If a published beta needs a fix, commit the fix on the
release branch and increment to the next `-beta.N`.
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

View File

@@ -558,7 +558,7 @@ jobs:
artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
package_sha256: ${{ needs.prepare_release_package.outputs.package_sha256 }}
suite_profile: custom
docker_lanes: doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
docker_lanes: doctor-switch update-channel-switch update-corrupt-plugin upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
published_upgrade_survivor_baselines: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'all-since-2026.4.23' || '' }}
published_upgrade_survivor_scenarios: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'reported-issues' || '' }}
telegram_mode: mock-openai

View File

@@ -33,7 +33,7 @@ on:
required: false
type: string
publish_openclaw_npm:
description: Publish the OpenClaw npm package after plugin npm and ClawHub publish complete
description: Publish the OpenClaw npm package after plugin npm succeeds; ClawHub may still run
required: true
default: true
type: boolean
@@ -169,15 +169,15 @@ jobs:
run: |
set -euo pipefail
dispatch_and_wait() {
dispatch_workflow() {
local workflow="$1"
shift
local before_json dispatch_output run_id status conclusion url
local before_json dispatch_output run_id
before_json="$(gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --event workflow_dispatch --limit 100 --json databaseId --jq '[.[].databaseId]')"
dispatch_output="$(gh workflow run --repo "$GITHUB_REPOSITORY" "$workflow" --ref "$CHILD_WORKFLOW_REF" "$@" 2>&1)"
printf '%s\n' "$dispatch_output"
printf '%s\n' "$dispatch_output" >&2
run_id="$(
printf '%s\n' "$dispatch_output" |
sed -nE 's#.*actions/runs/([0-9]+).*#\1#p' |
@@ -202,15 +202,14 @@ jobs:
exit 1
fi
echo "Dispatched ${workflow}: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${run_id}"
echo "Dispatched ${workflow}: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${run_id}" >&2
printf '%s\n' "${run_id}"
}
cancel_child() {
if [[ -n "${run_id:-}" ]]; then
echo "Cancelling child workflow ${workflow}: ${run_id}" >&2
gh run cancel --repo "$GITHUB_REPOSITORY" "$run_id" >/dev/null 2>&1 || true
fi
}
trap cancel_child EXIT INT TERM
wait_for_run() {
local workflow="$1"
local run_id="$2"
local status conclusion url
while true; do
status="$(gh run view --repo "$GITHUB_REPOSITORY" "$run_id" --json status --jq '.status')"
@@ -219,7 +218,6 @@ jobs:
fi
sleep 30
done
trap - EXIT INT TERM
conclusion="$(gh run view --repo "$GITHUB_REPOSITORY" "$run_id" --json conclusion --jq '.conclusion')"
url="$(gh run view --repo "$GITHUB_REPOSITORY" "$run_id" --json url --jq '.url')"
@@ -229,16 +227,36 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
if [[ "$conclusion" != "success" ]]; then
gh run view --repo "$GITHUB_REPOSITORY" "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
exit 1
return 1
fi
}
wait_for_run_background() {
local workflow="$1"
local run_id="$2"
local result_file="$3"
(
if wait_for_run "${workflow}" "${run_id}"; then
printf 'success\n' > "${result_file}"
else
printf 'failure\n' > "${result_file}"
fi
) &
wait_run_pid="$!"
}
{
echo "### Publish sequence"
echo
echo "- Workflow ref: \`${CHILD_WORKFLOW_REF}\`"
echo "- Release tag: \`${RELEASE_TAG}\`"
echo "- Release SHA: \`${TARGET_SHA}\`"
echo "- Plugin npm and ClawHub publish: dispatched in parallel"
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" ]]; then
echo "- OpenClaw npm publish: starts after plugin npm succeeds; ClawHub may still be running"
else
echo "- OpenClaw npm publish: skipped by input"
fi
} >> "$GITHUB_STEP_SUMMARY"
npm_args=(-f publish_scope="${PLUGIN_PUBLISH_SCOPE}" -f ref="${TARGET_SHA}")
@@ -248,15 +266,53 @@ jobs:
clawhub_args+=(-f plugins="${PLUGINS}")
fi
dispatch_and_wait plugin-npm-release.yml "${npm_args[@]}"
dispatch_and_wait plugin-clawhub-release.yml "${clawhub_args[@]}"
plugin_npm_run_id="$(dispatch_workflow plugin-npm-release.yml "${npm_args[@]}")"
plugin_clawhub_run_id="$(dispatch_workflow plugin-clawhub-release.yml "${clawhub_args[@]}")"
if ! wait_for_run plugin-npm-release.yml "${plugin_npm_run_id}"; then
echo "Plugin npm publish failed; cancelling ClawHub publish child ${plugin_clawhub_run_id}." >&2
gh run cancel --repo "$GITHUB_REPOSITORY" "${plugin_clawhub_run_id}" >/dev/null 2>&1 || true
exit 1
fi
openclaw_npm_run_id=""
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" ]]; then
dispatch_and_wait openclaw-npm-release.yml \
openclaw_npm_run_id="$(dispatch_workflow openclaw-npm-release.yml \
-f tag="${RELEASE_TAG}" \
-f preflight_only=false \
-f preflight_run_id="${PREFLIGHT_RUN_ID}" \
-f npm_dist_tag="${RELEASE_NPM_DIST_TAG}"
-f npm_dist_tag="${RELEASE_NPM_DIST_TAG}")"
else
echo "- OpenClaw npm publish: skipped by input" >> "$GITHUB_STEP_SUMMARY"
fi
clawhub_result="$RUNNER_TEMP/clawhub-result.txt"
wait_run_pid=""
wait_for_run_background plugin-clawhub-release.yml "${plugin_clawhub_run_id}" "${clawhub_result}"
clawhub_pid="${wait_run_pid}"
openclaw_result=""
openclaw_pid=""
if [[ -n "${openclaw_npm_run_id}" ]]; then
openclaw_result="$RUNNER_TEMP/openclaw-npm-result.txt"
wait_run_pid=""
wait_for_run_background openclaw-npm-release.yml "${openclaw_npm_run_id}" "${openclaw_result}"
openclaw_pid="${wait_run_pid}"
fi
failed=0
if ! wait "${clawhub_pid}"; then
failed=1
fi
if [[ -n "${openclaw_pid}" ]] && ! wait "${openclaw_pid}"; then
failed=1
fi
if [[ -f "${clawhub_result}" && "$(cat "${clawhub_result}")" != "success" ]]; then
failed=1
fi
if [[ -n "${openclaw_result}" && -f "${openclaw_result}" && "$(cat "${openclaw_result}")" != "success" ]]; then
failed=1
fi
if [[ "${failed}" != "0" ]]; then
exit 1
fi

View File

@@ -386,10 +386,10 @@ jobs:
docker_lanes="npm-onboard-channel-agent gateway-network config-reload"
;;
package)
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update"
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch update-corrupt-plugin upgrade-survivor published-upgrade-survivor plugins-offline plugin-update"
;;
product)
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins plugin-update mcp-channels cron-mcp-cleanup openai-web-search-minimal openwebui"
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch update-corrupt-plugin upgrade-survivor published-upgrade-survivor plugins plugin-update mcp-channels cron-mcp-cleanup openai-web-search-minimal openwebui"
include_openwebui=true
;;
full)

View File

@@ -182,7 +182,7 @@ jobs:
contents: read
strategy:
fail-fast: false
max-parallel: 6
max-parallel: 12
matrix:
plugin: ${{ fromJson(needs.preview_plugins_clawhub.outputs.matrix) }}
steps:
@@ -263,7 +263,7 @@ jobs:
id-token: write
strategy:
fail-fast: false
max-parallel: 6
max-parallel: 12
matrix:
plugin: ${{ fromJson(needs.preview_plugins_clawhub.outputs.matrix) }}
steps:

View File

@@ -2,7 +2,41 @@
Docs: https://docs.openclaw.ai
## Unreleased
## 2026.5.5
### Fixes
- CLI/sessions: prune old unreferenced transcript, compaction checkpoint, and trajectory artifacts during normal `sessions cleanup`, so gateway restart or crash orphans do not accumulate indefinitely outside `sessions.json`. Fixes #77608. Thanks @slideshow-dingo.
- Doctor/Codex: repair legacy `openai-codex/*` routes in primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel overrides, and stale session pins to canonical `openai/*`, selecting `agentRuntime.id: "codex"` only when the Codex plugin is installed, enabled, contributes the `codex` harness, and has usable OAuth; otherwise select `agentRuntime.id: "pi"`. Thanks @vincentkoc.
- Plugins/update: keep installed official npm and ClawHub plugins such as Codex, Discord, WhatsApp, and diagnostics plugins synced during host updates even when disabled or previously exact-pinned, while preserving third-party plugin pins. Thanks @vincentkoc.
- Video generation: accept provider-specific aspect-ratio and resolution hints at the tool boundary, normalize `720P` to MiniMax's supported `768P`, and stop sending Google `generateAudio` on Gemini video requests so provider fallback can recover from model-specific parameter differences. Thanks @vincentkoc.
- Status: show compact Gateway process uptime and host system uptime in `/status`, making restart and host-lifetime checks visible from chat. Thanks @vincentkoc.
- WhatsApp responsiveness: stop only verified stale local TUI clients when they degrade the Gateway event loop and delay replies. Thanks @vincentkoc.
- Hooks/session-memory: run reset memory capture off the command reply path and make model-generated memory filename slugs opt-in with `llmSlug: true`, so `/new` and `/reset` no longer block WhatsApp and other message-channel reset replies on hook housekeeping or a nested model call. Thanks @vincentkoc.
- CLI/gateway: pause non-TTY stdin after full CLI command completion and stop `openclaw agent` from falling back to embedded mode after gateway request/auth failures, so parent help commands exit cleanly and scoped delivery probes surface the real Gateway error immediately. Thanks @vincentkoc.
- Gateway/model catalog: cache empty read-only model catalog results until reload, so TUI and control-plane refresh loops cannot hammer plugin metadata reads when no usable models are currently discovered. Thanks @vincentkoc.
- Hooks/session-memory: add collision suffixes to fallback memory filenames so repeated `/new` or `/reset` captures in the same minute do not overwrite the earlier session archive. Thanks @vincentkoc.
- TUI/sessions: bound the session picker to recent rows and use exact lookup-style refreshes for the active session, so dusty stores no longer make TUI hydrate weeks-old transcripts before becoming responsive. Thanks @vincentkoc.
- Agents/context engines: keep hidden OpenClaw runtime-context custom messages out of context-engine assemble, afterTurn, and ingest hooks so transcript reconstruction plugins only see conversation messages. Thanks @vincentkoc.
- TUI: skip the generic CLI respawn wrapper for interactive launches, exit cleanly on terminal loss, and refuse to restore heartbeat sessions as the remembered chat session, preventing stale heartbeat history and orphaned `openclaw-tui` processes on first boot. Thanks @vincentkoc.
- Doctor/sessions: move heartbeat-poisoned default main session store entries to recovery keys and clear stale TUI restore pointers, so `doctor --fix` can repair instances already stuck on `agent:main:main` heartbeat history. Thanks @vincentkoc.
- Gateway/shutdown: report structured shutdown warnings and HTTP close timeout warnings through `ShutdownResult` while preserving lifecycle hook hardening. Carries forward #41296. Thanks @edenfunf.
- CLI/update: make dev-channel preflight lint opt-in and constrained when enabled, so `openclaw update --channel dev` no longer walks back otherwise-good main commits when Ubuntu hosts OOM-kill or fail parallel oxlint shards. Thanks @vincentkoc.
- CLI/channels: skip config, proxy, channel-option catalog, banner-config, and plugin startup bootstrap for the bare `openclaw channels` parent-help command, so it exits promptly after printing help instead of loading configured channel plugins. Thanks @vincentkoc.
- Gateway/shutdown: cancel delayed post-ready maintenance during close and suppress maintenance/cron startup after quick restarts, preventing orphaned background timers. Thanks @vincentkoc.
- CLI/status: show the selected agent runtime/harness in `openclaw status` session rows so terminal status matches the `/status` runtime line. Thanks @vincentkoc.
- Sessions CLI: show the selected agent runtime in the `openclaw sessions` table so terminal output matches the runtime visibility already present in JSON/status surfaces. Thanks @vincentkoc.
- Control UI/sessions: show each session's agent runtime in the Sessions table and allow filtering by runtime labels, matching the Agents panel runtime wording. Thanks @vincentkoc.
- Docker/Gateway: harden the gateway container by dropping `NET_RAW` and `NET_ADMIN` capabilities and enabling `no-new-privileges` in the bundled `docker-compose.yml`. Thanks @VintageAyu.
- OpenAI/Gateway: flush the initial chat stream chunk correctly so first-token streaming is visible instead of being delayed behind later chunks.
- Gateway/media: skip media sidecar handling for unrelated HTTP routes so non-media requests do not pay the media route behavior.
- Discord: show reasoning text in progress drafts so streaming replies expose useful thinking/progress instead of blank draft updates.
- Auth profiles: avoid putting providers on cooldown for format-level rejections, so fallback profiles can still be tried when a model name is unsupported.
- Update/plugins: tolerate corrupt managed plugin records during update so core package updates can still complete and report the plugin repair path.
- Update: stop dev-channel updates cleanly after a fetch failure instead of continuing into later update steps.
- Agents/generated media: treat attachment-style message tool actions as completed chat sends, preventing duplicate fallback media posts when generated files were already uploaded.
## 2026.5.4
### Highlights
@@ -10,6 +44,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Gateway/Windows: bind the default loopback gateway listener only to `127.0.0.1` on Windows so libuv's dual-stack `::1` behavior cannot wedge localhost HTTP requests. (#69701, fixes #69674) Thanks @SARAMALI15792.
- Plugins/migration: emit catalog-backed install hints when `plugins.entries` or `plugins.allow` references an official external plugin that is not installed, so upgraded configs point operators to `openclaw plugins install <spec>` instead of telling them to remove valid plugin config. (#77483) Thanks @hclsys.
- OpenAI/Codex media: advertise Codex audio transcription in runtime and manifest metadata and route active Codex chat models to the OpenAI transcription default instead of sending chat model ids to audio transcription. Thanks @vincentkoc.
- Dependencies: refresh runtime and provider packages including Pi 0.73.0, ACPX adapters, OpenAI, Anthropic, Slack, and TypeScript native preview, while keeping the Bedrock runtime installer override pinned below the Windows ARM Node 24 npm resolver failure.
@@ -59,22 +94,32 @@ Docs: https://docs.openclaw.ai
- Plugins/ClawHub: annotate 429 errors from ClawHub with the reset window from `RateLimit-Reset`/`Retry-After` and append a `Sign in for higher rate limits.` hint when the request was unauthenticated, so users can see when downloads will recover and how to lift the cap. Thanks @romneyda.
- Plugins/runtime state: add `registerIfAbsent` for atomic keyed-store dedupe claims that return whether a plugin successfully claimed a key without overwriting an existing live value. Thanks @amknight.
- Plugin SDK: add plugin-owned `SessionEntry` slot projection and scoped trusted-policy session extension reads. (#75609; replaces part of #73384/#74483) Thanks @100yenadmin.
- Sandbox/Windows: accept drive-absolute Docker bind sources while keeping sandbox blocked-path and allowed-root policy comparisons Windows-case-insensitive. (#42174) Thanks @6607changchun.
### Fixes
- Plugins/install: honor the beta update channel for onboarding and doctor-managed plugin installs by requesting floating npm and ClawHub specs with `@beta` while keeping persistent install records on the catalog default. Thanks @vincentkoc.
- WhatsApp/onboarding: canonicalize setup and pairing allowlist entries to WhatsApp's digit-only phone ids while still accepting E.164, JID, and `whatsapp:` inputs, so personal-phone allowlists match WhatsApp Web sender ids after setup. Thanks @vincentkoc.
- Gateway/startup: load provider plugins that own explicitly configured image, video, or music generation defaults so generation tools become live after gateway restart instead of remaining catalog-only. Fixes #77244. Thanks @buyuangtampan, @Nikoxx99, and @vincentkoc.
- Slack/subagents: keep resumed parent `message.send` calls in the originating Slack thread when ambient session thread context is present, and suppress successful silent child completion rows from follow-up findings. Thanks @bek91.
- Slack/mentions: record thread participation for successful visible threaded Slack sends, including message-tool and media delivery paths, so unmentioned replies in bot-participated threads can bypass mention gating as documented. Fixes #77648. Thanks @bek91.
- Infra/Windows: skip the POSIX `/tmp/openclaw` preferred path on Windows in `resolvePreferredOpenClawTmpDir` so log files, TTS temp files, and other writes land in `%TEMP%\openclaw-<uid>` instead of `C:\tmp\openclaw`. Fixes #60713. Thanks @juan-flores077.
- Media/Windows: open saved attachment temp files read/write before fsync so Windows WebChat and `chat.send` media offloads no longer fail with EPERM during durability flush. (#76593) Thanks @qq230849622-a11y.
- Agents/tools: honor narrow runtime tool allowlists when constructing embedded-runner tool families and bundled MCP/LSP runtimes, so cron/subagent runs that request tools such as `update_plan`, `browser`, `x_search`, channel login tools, or `group:plugins` no longer start with missing tools or unrelated bootstrap work. (#77519, #77532)
- Codex plugin: mirror the experimental upstream app-server protocol and format generated TypeScript before drift checks, keeping OpenClaw's `experimentalApi` bridge compatible with latest Codex while preserving formatter gates.
- Telegram/media: derive no-caption inbound media placeholders from saved MIME metadata instead of the Telegram `photo` shape, so non-image and mixed attachments no longer reach the model as `<media:image>`. Fixes #69793. Thanks @aspalagin.
- Telegram/streaming: reuse the active preview as the first chunk for long text finals, so multi-chunk replies no longer create a transient extra bubble that appears and then disappears. Thanks @vincentkoc.
- Agents/cache: keep per-turn runtime context out of ordinary chat system prompts while still delivering hidden current-turn context, restoring prompt-cache reuse on chat continuations. Fixes #77431. Thanks @Udjin79.
- Gateway/startup: include resolved thinking and fast-mode defaults in the `agent model` startup log line, defaulting unset startup thinking to `medium` without mixing in reasoning visibility.
- Gateway/update: resolve local gateway probe auth from the installed config during post-update restart verification, so token/device-authenticated VPS gateways are not misreported as unhealthy port conflicts after a package swap. Thanks @vincentkoc.
- Agents/Tools: add post-compaction loop guard in `pi-embedded-runner` that arms after auto-compaction-retry and aborts the run with `compaction_loop_persisted` when the agent emits the same `(tool, args, result)` triple `windowSize` times (default 3) within that window. Disable via existing `tools.loopDetection.enabled`; tune via `tools.loopDetection.postCompactionGuard.windowSize`. Targets the failure mode where context-overflow + compaction does not break a tool-call loop. Refs #77474; carries forward #21597. Thanks @efpiva.
- Gateway/watch: suppress sync-I/O trace output during `pnpm gateway:watch --benchmark` unless explicitly requested, so CPU profiling no longer floods the terminal with stack traces.
- Gateway/watch: when benchmark sync-I/O tracing is explicitly enabled, tee trace blocks to the benchmark output log and filter them from the terminal pane while keeping normal Gateway logs visible.
- Plugins/runtime-deps: include `json5` in the memory-core plugin runtime dependency set so packaged `memory_search` sandboxes can resolve generated OpenClaw runtime chunks that parse JSON5 config. Fixes #77461.
- Plugins/Windows: show a Git install hint when npm plugin installation fails with `spawn git ENOENT`, and document the WhatsApp plugin's Git-on-PATH requirement for Baileys/libsignal installs.
- Codex harness: preserve app-server usage-limit reset details and deliver OpenClaw-owned runtime failure notices through tool-only source-reply mode, so Telegram and other chat channels tell users when Codex subscription limits or API failures block a turn instead of going silent. (#77557) Thanks @pashpashpash.
- Agents/OpenAI: default direct OpenAI Responses models to the SSE transport instead of WebSocket auto-selection, preventing pi runtime chat turns from hanging on servers where the WebSocket path stalls while the OpenAI HTTP stream works. Thanks @vincentkoc.
- Plugins/update: repair missing plugin-local `openclaw` peer links before skipping unchanged npm plugin updates, so current external Codex installs can recover `openclaw/plugin-sdk/*` resolution during OTA repair. (#77544) Thanks @ProspectOre.
- Discord/replies: treat failed final reply delivery as a failed turn instead of counting it as a delivered automatic visible reply, so guild/channel turns no longer show done when the final message was dropped. Fixes #77520. Thanks @Patrick-Erichsen.
- Discord: prefer IPv4 for Discord REST and gateway WebSocket startup paths so IPv4-only networks no longer stall before Gateway READY and inbound message dispatch. Fixes #77398; refs #77526. Thanks @Beandon13.
- Channels/plugins: key bundled package-state probes, env/config presence, and read-only command defaults by channel id instead of manifest plugin id, preserving setup and native-command detection for channel plugins whose package id differs from the channel alias. Thanks @vincentkoc.
@@ -216,6 +261,7 @@ Docs: https://docs.openclaw.ai
- Google Meet: make Twilio setup status require an enabled `voice-call` plugin entry instead of treating a missing entry as ready. Thanks @vincentkoc.
- Telegram: render shared interactive reply buttons in reply delivery so plugin approval messages show inline keyboards. (#76238) Thanks @keshavbotagent.
- Cron/sessions: keep cron metadata rows without an on-disk transcript non-resumable until a transcript exists, so doctor and `sessions cleanup --fix-missing` no longer report or prune pre-transcript cron rows as broken sessions. Refs #77011.
- OpenAI Codex: recreate missing bound app-server threads once when a stale `/codex bind` sidecar survives a restart, preserving the selected auth profile and turn overrides before retrying the inbound turn. (#76936) Thanks @keshavbotagent.
- Agents/cli-runner: drop a saved `claude-cli` resume sessionId at preparation time when its on-disk transcript no longer exists in `~/.claude/projects/`, so a stale binding from a half-installed `update.run` cannot trap follow-up runs (auto-reply / Telegram direct) in a `claude --resume` timeout loop; the run starts fresh and the new sessionId is written back through the existing post-run flow. (#77030; refs #77011) Thanks @openperf.
- Release validation: install the cross-OS TypeScript harness through Windows-safe Node/npm shims so native Windows package checks reach the OpenClaw smoke suites instead of exiting before artifact capture. Thanks @vincentkoc.
- Release validation: let Windows packaged-upgrade checks continue after the shipped 2026.5.2 updater hits its native-module swap cleanup fallback, verifying the fallback-installed candidate through package metadata and downstream smoke instead of crashing on the immediate update-status probe. Thanks @vincentkoc.
@@ -324,6 +370,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Update: repair doctor-migratable legacy config before persisting `openclaw update --channel ...`, so old Slack/Telegram streaming keys do not block switching to beta after a package update. Thanks @vincentkoc.
- Web fetch: late-bind `web_fetch` config and provider fallback metadata from the active runtime snapshot, matching `web_search` so long-lived tools do not use stale fetch provider settings. Thanks @vincentkoc.
- Plugins/discovery: demote the source-only TypeScript runtime check on already-installed `origin: "global"` plugin packages from a config-blocking error to a warning and let the runtime fall through to the TypeScript source via jiti, so a single broken installed package no longer blocks `plugins install` for unrelated plugins; install-time rejection of newly-installed source-only packages is unchanged. Thanks @romneyda.
- Providers/OpenAI Codex: stop the OAuth progress spinner before showing the manual redirect paste prompt, so callback timeouts do not spam `Browser callback did not finish` across terminals.
@@ -583,6 +630,7 @@ Docs: https://docs.openclaw.ai
- Agents/reply context: label replied-to messages as the current user message target in model-visible metadata, so short replies are grounded to their explicit reply target instead of nearby chat history. (#76817) Thanks @obviyus.
- Doctor/plugins: install configured missing official plugins such as Discord and Brave during doctor/update repair, auto-enable repaired provider plugins, preserve config when a download fails, and stop auto-enable from inventing plugin entries when no manifest declares a configured channel. Fixes #76872. Thanks @jack-stormentswe.
- Codex/app-server: stabilize transcript mirror dedupe across re-mirrored turns so reordered snapshots no longer drop reasoning entries or duplicate the assistant reply. Refs #77012. (#77046) Thanks @openperf.
- Agents/auth-profiles: do not record request-shape (`format`) rejections as auth-profile health failures, so a single per-session transcript-shape error (such as a prefill-strict 400 "conversation must end with a user message") no longer triggers a profile-wide cooldown that blocks every other healthy session sharing the same auth profile. Refs #77228. (#77280) Thanks @openperf.
## 2026.5.2
@@ -1396,6 +1444,7 @@ Docs: https://docs.openclaw.ai
- Gateway/plugins: enable the native `require()` fast path on Windows for bundled plugin modules so plugin loading uses `require()` instead of Jiti's transform pipeline, reducing startup from ~39s to ~2s on typical 6-plugin setups. Fixes #68656. (#74173) Thanks @galiniliev.
- macOS app: detect stale Gateway TLS certificate pins, automatically repair trusted Tailscale Serve rotations, and surface paired-but-disconnected Mac companion nodes so partial Gateway connections no longer look healthy. Thanks @guti.
- Feishu: recreate WebSocket clients with monitor-owned backoff only after SDK reconnect exhaustion, preserving heartbeat defaults and shutdown cleanup without treating recoverable SDK callback errors as terminal, so persistent connections recover without manual gateway restart. Fixes #52618; duplicate evidence #59753; related #55532, #68766, #72411, and #73739. Thanks @vincentkoc, @schumilin, @alex-xuweilong, @120106835, @sirfengyu, and @tianhaocui.
- Agents/skills: require exact `<location>` skill paths for both single-skill and multi-skill prompt selection, so agents do not guess or hard-code skill file paths. (#74161) Thanks @lanzhi-lee.
## 2026.4.27

View File

@@ -65,8 +65,8 @@ android {
applicationId = "ai.openclaw.app"
minSdk = 31
targetSdk = 36
versionCode = 2026050400
versionName = "2026.5.4"
versionCode = 2026050500
versionName = "2026.5.5"
ndk {
// Support all major ABIs — native libs are tiny (~47 KB per ABI)
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")

View File

@@ -1,5 +1,9 @@
# OpenClaw iOS Changelog
## 2026.5.5 - 2026-05-05
Maintenance update for the current OpenClaw development release.
## 2026.5.4 - 2026-05-04
Maintenance update for the current OpenClaw development release.

View File

@@ -2,8 +2,8 @@
// Source of truth: apps/ios/version.json
// Generated by scripts/ios-sync-versioning.ts.
OPENCLAW_IOS_VERSION = 2026.5.4
OPENCLAW_MARKETING_VERSION = 2026.5.4
OPENCLAW_IOS_VERSION = 2026.5.5
OPENCLAW_MARKETING_VERSION = 2026.5.5
OPENCLAW_BUILD_VERSION = 1
#include? "../build/Version.xcconfig"

View File

@@ -1,3 +1 @@
Maintenance update for the current OpenClaw development release.
- Gateway pairing now supports scanning QR codes from Settings and accepts full copied setup-code messages while keeping non-loopback `ws://` setup links blocked.

View File

@@ -1,3 +1,3 @@
{
"version": "2026.5.4"
"version": "2026.5.5"
}

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.5.4</string>
<string>2026.5.5</string>
<key>CFBundleVersion</key>
<string>2026050400</string>
<string>2026050500</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -49,6 +49,11 @@ services:
# Let bundled local-model providers reach host-side LM Studio/Ollama via
# http://host.docker.internal:<port>. Docker Desktop usually provides this
# alias; the host-gateway mapping makes it work on Linux Docker Engine too.
cap_drop:
- NET_RAW
- NET_ADMIN
security_opt:
- no-new-privileges:true
extra_hosts:
- "host.docker.internal:host-gateway"
ports:

View File

@@ -1,2 +1,2 @@
43c6f668cd8301f485c64e6a663dc1b19d38c146ce2572943e2dc961973e0c6f plugin-sdk-api-baseline.json
1d877d94bebb634d90d929fe0581ba4bccf4d12d8342d179ae9bf1053e68c013 plugin-sdk-api-baseline.jsonl
9cee7bd20801c7101d19a7912aa2c799b94de926ea9d2619d94770334889070e plugin-sdk-api-baseline.json
a00d67f47382b5826711640bffebb18615ca54cc6cc5ab1b618ba57ee15e84f7 plugin-sdk-api-baseline.jsonl

View File

@@ -178,7 +178,7 @@ openclaw hooks enable <hook-name>
### session-memory details
Extracts the last 15 user/assistant messages, generates a descriptive filename slug via LLM, and saves to `<workspace>/memory/YYYY-MM-DD-slug.md` using the host local date. Requires `workspace.dir` to be configured.
Extracts the last 15 user/assistant messages and saves to `<workspace>/memory/YYYY-MM-DD-HHMM.md` using the host local date. Memory capture runs in the background so `/new` and `/reset` acknowledgements are not delayed by transcript reads or optional slug generation. Set `hooks.internal.entries.session-memory.llmSlug: true` to generate descriptive filename slugs with the configured model. Requires `workspace.dir` to be configured.
<a id="bootstrap-extra-files"></a>

View File

@@ -344,6 +344,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
For text-only replies:
- short DM/group/topic previews: OpenClaw keeps the same preview message and performs a final edit in place, unless a visible non-preview message was sent after the preview appeared
- long text finals that split into multiple Telegram messages reuse the existing preview as the first final chunk when possible, then send only the remaining chunks
- previews followed by visible non-preview output: OpenClaw sends the completed reply as a fresh final message and cleans up the older preview, so the final answer appears after intermediate output
- previews older than about one minute: OpenClaw sends the completed reply as a fresh final message and then cleans up the preview, so Telegram's visible timestamp reflects completion time instead of the preview creation time

View File

@@ -31,12 +31,13 @@ Healthy baseline:
### WhatsApp failure signatures
| Symptom | Fastest check | Fix |
| ------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Connected but no DM replies | `openclaw pairing list whatsapp` | Approve sender or switch DM policy/allowlist. |
| Group messages ignored | Check `requireMention` + mention patterns in config | Mention the bot or relax mention policy for that group. |
| QR login times out with 408 | Check gateway `HTTPS_PROXY` / `HTTP_PROXY` env | Set a reachable proxy; use `NO_PROXY` only for bypasses. |
| Random disconnect/relogin loops | `openclaw channels status --probe` + logs | Recent reconnects are flagged even when currently connected; watch logs, restart the gateway, then relink if flapping continues. |
| Symptom | Fastest check | Fix |
| ----------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Connected but no DM replies | `openclaw pairing list whatsapp` | Approve sender or switch DM policy/allowlist. |
| Group messages ignored | Check `requireMention` + mention patterns in config | Mention the bot or relax mention policy for that group. |
| QR login times out with 408 | Check gateway `HTTPS_PROXY` / `HTTP_PROXY` env | Set a reachable proxy; use `NO_PROXY` only for bypasses. |
| Random disconnect/relogin loops | `openclaw channels status --probe` + logs | Recent reconnects are flagged even when currently connected; watch logs, restart the gateway, then relink if flapping continues. |
| Replies arrive seconds/minutes late | `openclaw doctor --fix` | Doctor stops verified stale local TUI clients when they are degrading the Gateway event loop. |
Full troubleshooting: [WhatsApp troubleshooting](/channels/whatsapp#troubleshooting)

View File

@@ -26,6 +26,16 @@ openclaw plugins install @openclaw/whatsapp
Use the bare package to follow the current official release tag. Pin an exact
version only when you need a reproducible install.
On Windows, the WhatsApp plugin needs Git on `PATH` during npm install because
one of its Baileys/libsignal dependencies is fetched from a git URL. Install
Git for Windows, then restart the shell and rerun the install:
```powershell
winget install --id Git.Git -e
```
Portable Git also works if its `bin` directory is on `PATH`.
<CardGroup cols={3}>
<Card title="Pairing" icon="link" href="/channels/pairing">
Default DM policy is pairing for unknown senders.

View File

@@ -45,6 +45,8 @@ Notes:
- State integrity checks now detect orphan transcript files in the sessions directory. Archiving them as `.deleted.<timestamp>` requires an interactive confirmation; `--fix`, `--yes`, and headless runs leave them in place.
- Doctor also scans `~/.openclaw/cron/jobs.json` (or `cron.store`) for legacy cron job shapes and can rewrite them in place before the scheduler has to auto-normalize them at runtime.
- On Linux, doctor warns when the user's crontab still runs legacy `~/.openclaw/bin/ensure-whatsapp.sh`; that script is no longer maintained and can log false WhatsApp gateway outages when cron lacks the systemd user-bus environment.
- When WhatsApp is enabled, doctor checks for a degraded Gateway event loop with local `openclaw-tui` clients still running. `doctor --fix` stops only verified local TUI clients so WhatsApp replies are not queued behind stale TUI refresh loops.
- Doctor rewrites legacy `openai-codex/*` model refs to canonical `openai/*` refs across primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale session route pins. `--fix` selects `agentRuntime.id: "codex"` only when the Codex plugin is installed, enabled, contributes the `codex` harness, and has usable OAuth; otherwise it selects `agentRuntime.id: "pi"` so the route stays on the default OpenClaw runner.
- Doctor cleans legacy plugin dependency staging state created by older OpenClaw versions. It also repairs missing downloadable plugins that are referenced by config, such as `plugins.entries`, configured channels, configured provider/search settings, or configured agent runtimes. During package updates, doctor skips package-manager plugin repair until the package swap is complete; rerun `openclaw doctor --fix` afterward if a configured plugin still needs recovery. If the download fails, doctor reports the install error and preserves the configured plugin entry for the next repair attempt.
- Doctor repairs stale plugin config by removing missing plugin ids from `plugins.allow`/`plugins.entries`, plus matching dangling channel config, heartbeat targets, and channel model overrides when plugin discovery is healthy.
- Doctor quarantines invalid plugin config by disabling the affected `plugins.entries.<id>` entry and removing its invalid `config` payload. Gateway startup already skips only that bad plugin so other plugins and channels can keep running.

View File

@@ -282,7 +282,7 @@ Saves session context to memory when you issue `/new` or `/reset`.
openclaw hooks enable session-memory
```
**Output:** `~/.openclaw/workspace/memory/YYYY-MM-DD-slug.md`
**Output:** `~/.openclaw/workspace/memory/YYYY-MM-DD-HHMM.md` by default. Set `hooks.internal.entries.session-memory.llmSlug: true` for model-generated filename slugs.
**See:** [session-memory documentation](/automation/hooks#session-memory)

View File

@@ -26,6 +26,7 @@ Notes:
- Session status output separates `Execution:` from `Runtime:`. `Execution` is the sandbox path (`direct`, `docker/*`), while `Runtime` tells you whether the session is using `OpenClaw Pi Default`, `OpenAI Codex`, a CLI backend, or an ACP backend such as `codex (acp/acpx)`. See [Agent runtimes](/concepts/agent-runtimes) for the provider/model/runtime distinction.
- MiniMax's raw `usage_percent` / `usagePercent` fields are remaining quota, so OpenClaw inverts them before display; count-based fields win when present. `model_remains` responses prefer the chat-model entry, derive the window label from timestamps when needed, and include the model name in the plan label.
- When the current session snapshot is sparse, `/status` can backfill token and cache counters from the most recent transcript usage log. Existing nonzero live values still win over transcript fallback values.
- `/status` includes compact Gateway process uptime and host system uptime.
- Transcript fallback can also recover the active runtime model label when the live session entry is missing it. If that transcript model differs from the selected model, status resolves the context window against the recovered runtime model instead of the selected one.
- For prompt-size accounting, transcript fallback prefers the larger prompt-oriented total when session metadata is missing or smaller, so custom-provider sessions do not collapse to `0` token displays.
- Output includes per-agent session stores when multiple agents are configured.

View File

@@ -38,8 +38,9 @@ openclaw --update
- `--tag <dist-tag|version|spec>`: override the package target for this update only. For package installs, `main` maps to `github:openclaw/openclaw#main`.
- `--dry-run`: preview planned update actions (channel/tag/target/restart flow) without writing config, installing, syncing plugins, or restarting.
- `--json`: print machine-readable `UpdateRunResult` JSON, including
`postUpdate.plugins.integrityDrifts` when npm plugin artifact drift is
detected during post-update plugin sync.
`postUpdate.plugins.warnings` when corrupt or unloadable managed plugins need
repair after the core update succeeds, and `postUpdate.plugins.integrityDrifts`
when npm plugin artifact drift is detected during post-update plugin sync.
- `--timeout <seconds>`: per-step timeout (default is 1800s).
- `--yes`: skip confirmation prompts (for example downgrade confirmation).
@@ -147,7 +148,7 @@ manually.
Dev only.
</Step>
<Step title="Preflight build (dev only)">
Runs lint and TypeScript build in a temp worktree. If the tip fails, walks back up to 10 commits to find the newest clean build.
Runs the TypeScript build in a temp worktree. If the tip fails, walks back up to 10 commits to find the newest buildable commit. Set `OPENCLAW_UPDATE_PREFLIGHT_LINT=1` to also run lint during this preflight; lint runs in constrained serial mode because user update hosts are often smaller than CI runners.
</Step>
<Step title="Rebase">
Rebases onto the selected commit (dev only).
@@ -177,7 +178,7 @@ If an exact pinned npm plugin update resolves to an artifact whose integrity dif
</Warning>
<Note>
Post-update plugin sync failures fail the update result and stop restart follow-up work. Fix the plugin install or update error, then rerun `openclaw update`.
Post-update plugin sync failures that are scoped to a managed plugin are reported as warnings after the core update succeeds. The JSON result keeps the top-level update `status: "ok"` and reports `postUpdate.plugins.status: "warning"` with `openclaw doctor --fix` and `openclaw plugins inspect <id> --runtime --json` guidance. Unexpected updater or sync exceptions still fail the update result. Fix the plugin install or update error, then rerun `openclaw doctor --fix` or `openclaw update`.
When the updated Gateway starts, plugin loading is verify-only: startup does not run package managers or mutate dependency trees. Package-manager `update.run` restarts bypass the normal idle deferral and restart cooldown after the package tree has been swapped, so the old process cannot keep lazy-loading removed chunks.

View File

@@ -232,6 +232,8 @@ Scenarios (`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime
- `telegram-tools-compact-command`
- `telegram-whoami-command`
- `telegram-context-command`
- `telegram-long-final-reuses-preview`
- `telegram-long-final-three-chunks`
Output artifacts:

View File

@@ -107,6 +107,8 @@ cat ~/.openclaw/openclaw.json
- Matrix channel legacy state migration (in `--fix` / `--repair` mode).
- Gateway runtime checks (service installed but not running; cached launchd label).
- Channel status warnings (probed from the running gateway).
- WhatsApp responsiveness checks for degraded Gateway event-loop health with local TUI clients still running; `--fix` stops only verified local TUI clients.
- Codex route repair for legacy `openai-codex/*` model refs in primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and session route pins; `--fix` rewrites them to `openai/*` and selects `agentRuntime.id: "codex"` only when the Codex plugin is installed, enabled, contributes the `codex` harness, and has usable OAuth. Otherwise it selects `agentRuntime.id: "pi"`.
- Supervisor config audit (launchd/systemd/schtasks) with optional repair.
- Embedded proxy environment cleanup for gateway services that captured shell `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` values during install or update.
- Gateway runtime best-practice checks (Node vs Bun, version-manager paths).
@@ -259,21 +261,22 @@ That stages grounded durable candidates into the short-term dreaming store while
<Accordion title="2e. Codex OAuth provider overrides">
If you previously added legacy OpenAI transport settings under `models.providers.openai-codex`, they can shadow the built-in Codex OAuth provider path that newer releases use automatically. Doctor warns when it sees those old transport settings alongside Codex OAuth so you can remove or rewrite the stale transport override and get the built-in routing/fallback behavior back. Custom proxies and header-only overrides are still supported and do not trigger this warning.
</Accordion>
<Accordion title="2f. Codex plugin route warnings">
When the bundled Codex plugin is enabled, doctor also checks whether `openai-codex/*` primary model refs still resolve through the default PI runner. That combination is valid when you want Codex OAuth/subscription auth through PI, but it is easy to confuse with the native Codex app-server harness. Doctor warns and points to the explicit app-server shape: `openai/*` plus `agentRuntime.id: "codex"` or `OPENCLAW_AGENT_RUNTIME=codex`.
<Accordion title="2f. Codex route repair">
Doctor checks for legacy `openai-codex/*` model refs. Native Codex harness routing uses canonical `openai/*` model refs plus `agentRuntime.id: "codex"` so the turn goes through the Codex app-server harness instead of the OpenClaw PI OpenAI path.
Doctor does not repair this automatically because both routes are valid:
In `--fix` / `--repair` mode, doctor rewrites affected default-agent and per-agent refs, including primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale persisted session route state:
- `openai-codex/*` + PI means "use Codex OAuth/subscription auth through the normal OpenClaw runner."
- `openai/*` + `agentRuntime.id: "codex"` means "run the embedded turn through native Codex app-server."
- `openai-codex/gpt-*` becomes `openai/gpt-*`.
- The matching agent runtime becomes `agentRuntime.id: "codex"` only when Codex is installed, enabled, contributes the `codex` harness, and has usable OAuth.
- Otherwise the matching agent runtime becomes `agentRuntime.id: "pi"`.
- Existing model fallback lists are preserved with their legacy entries rewritten; copied per-model settings move from the legacy key to the canonical `openai/*` key.
- Persisted session `modelProvider`/`providerOverride`, `model`/`modelOverride`, fallback notices, auth-profile pins, and Codex harness pins are repaired across all discovered agent session stores.
- `/codex ...` means "control or bind a native Codex conversation from chat."
- `/acp ...` or `runtime: "acp"` means "use the external ACP/acpx adapter."
If the warning appears, choose the route you intended and edit config manually. Keep the warning as-is when PI Codex OAuth is intentional.
</Accordion>
<Accordion title="2g. Session route cleanup">
Doctor also scans the active sessions store for stale auto-created route state after you move the configured default/fallback model or runtime away from a plugin-owned route such as Codex.
Doctor also scans discovered agent session stores for stale auto-created route state after you move configured models or runtime away from a plugin-owned route such as Codex.
`openclaw doctor --fix` can clear auto-created stale state such as `modelOverrideSource: "auto"` model pins, runtime model metadata, pinned harness ids, CLI session bindings, and auto auth-profile overrides when their owning route is no longer configured. Explicit user or legacy session model choices are reported for manual review and left untouched; switch them with `/model ...`, `/new`, or reset the session when that route is no longer intended.

View File

@@ -167,7 +167,7 @@ targets the shipped npm package instead.
Release checks call Package Acceptance with the package/update/plugin set:
```text
doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
doctor-switch update-channel-switch update-corrupt-plugin upgrade-survivor published-upgrade-survivor plugins-offline plugin-update
```
They also pass:
@@ -178,9 +178,10 @@ published_upgrade_survivor_scenarios=reported-issues
telegram_mode=mock-openai
```
This keeps package migration, update channel switching, stale plugin dependency
cleanup, offline plugin coverage, plugin update behavior, and Telegram package
QA on the same resolved artifact.
This keeps package migration, update channel switching, corrupt managed-plugin
tolerance, stale plugin dependency cleanup, offline plugin coverage, plugin
update behavior, and Telegram package QA on the same resolved artifact without
making the default release package gate walk every published release.
`all-since-2026.4.23` is the Full Release CI upgrade sample: every stable npm-published release from `2026.4.23` through `latest`. For exhaustive published
update migration coverage, use `all-since-2026.4.23` in the separate Update

View File

@@ -332,7 +332,7 @@ See [ClawDock](/install/clawdock) for the full helper guide.
`openclaw-cli` uses `network_mode: "service:openclaw-gateway"` so CLI
commands can reach the gateway over `127.0.0.1`. Treat this as a shared
trust boundary. The compose config drops `NET_RAW`/`NET_ADMIN` and enables
`no-new-privileges` on `openclaw-cli`.
`no-new-privileges` on both `openclaw-gateway` and `openclaw-cli`.
</Accordion>
<Accordion title="Permissions and EACCES">

View File

@@ -87,9 +87,10 @@ If your config uses `plugins.allow`, include `codex` there too:
}
```
Do not use `openai-codex/gpt-*` when you mean native Codex runtime. That prefix
is the explicit "Codex OAuth through PI" route. Config changes apply to new or
reset sessions; existing sessions keep their recorded runtime.
Do not use `openai-codex/gpt-*` in config. That prefix is a legacy route that
`openclaw doctor --fix` rewrites to `openai/gpt-*` across primary models,
fallbacks, heartbeat/subagent/compaction overrides, hooks, channel overrides,
and stale persisted session route pins.
## What this plugin changes
@@ -106,7 +107,9 @@ The bundled `codex` plugin contributes several separate capabilities:
Enabling the plugin makes those capabilities available. It does **not**:
- start using Codex for every OpenAI model
- convert `openai-codex/*` model refs into the native runtime
- convert `openai-codex/*` model refs into the native runtime without doctor
verifying that Codex is installed, enabled, contributes the `codex` harness,
and is OAuth-ready
- make ACP/acpx the default Codex path
- hot-switch existing sessions that already recorded a PI runtime
- replace OpenClaw channel delivery, session files, auth-profile storage, or
@@ -145,10 +148,10 @@ want native app-server execution. Legacy `codex/*` model refs still auto-select
the harness for compatibility, but runtime-backed legacy provider prefixes are
not shown as normal model/provider choices.
If the `codex` plugin is enabled but the primary model is still
`openai-codex/*`, `openclaw doctor` warns instead of changing the route. That is
intentional: `openai-codex/*` remains the PI Codex OAuth/subscription path, and
native app-server execution stays an explicit runtime choice.
If any configured model route is still `openai-codex/*`, `openclaw doctor --fix`
rewrites it to `openai/*`. For matching agent routes, it sets the agent runtime
to `codex` only when the Codex plugin is installed, enabled, contributes the
`codex` harness, and has usable OAuth; otherwise it sets the runtime to `pi`.
## Route map
@@ -158,15 +161,18 @@ Use this table before changing config:
| ---------------------------------------------------- | -------------------------- | -------------------------------------- | ---------------------------- | ------------------------------ |
| ChatGPT/Codex subscription with native Codex runtime | `openai/gpt-*` | `agentRuntime.id: "codex"` | Codex OAuth or Codex account | `Runtime: OpenAI Codex` |
| OpenAI API through normal OpenClaw runner | `openai/gpt-*` | omitted or `runtime: "pi"` | OpenAI API key | `Runtime: OpenClaw Pi Default` |
| ChatGPT/Codex subscription through PI | `openai-codex/gpt-*` | omitted or `runtime: "pi"` | OpenAI Codex OAuth provider | `Runtime: OpenClaw Pi Default` |
| Legacy config that needs doctor repair | `openai-codex/gpt-*` | repaired to `codex` or `pi` | Existing configured auth | Recheck after `doctor --fix` |
| Mixed providers with conservative auto mode | provider-specific refs | `agentRuntime.id: "auto"` | Per selected provider | Depends on selected runtime |
| Explicit Codex ACP adapter session | ACP prompt/model dependent | `sessions_spawn` with `runtime: "acp"` | ACP backend auth | ACP task/session status |
The important split is provider versus runtime:
- `openai-codex/*` answers "which provider/auth route should PI use?"
- `agentRuntime.id: "codex"` answers "which loop should execute this
embedded turn?"
- `openai-codex/*` is a legacy route that doctor rewrites.
- `agentRuntime.id: "codex"` requires the Codex harness and fails closed if it
is unavailable.
- `agentRuntime.id: "auto"` lets registered harnesses claim matching provider
routes, but canonical OpenAI refs are still PI-owned unless a harness supports
that provider/model pair.
- `/codex ...` answers "which native Codex conversation should this chat bind
or control?"
- ACP answers "which external harness process should acpx launch?"
@@ -175,33 +181,30 @@ The important split is provider versus runtime:
OpenAI-family routes are prefix-specific. For the common subscription plus
native Codex runtime setup, use `openai/*` with `agentRuntime.id: "codex"`.
Use `openai-codex/*` only when you intentionally want Codex OAuth through PI:
Treat `openai-codex/*` as legacy config that doctor should rewrite:
| Model ref | Runtime path | Use when |
| --------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------- |
| `openai/gpt-5.4` | OpenAI provider through OpenClaw/PI plumbing | You want current direct OpenAI Platform API access with `OPENAI_API_KEY`. |
| `openai-codex/gpt-5.5` | OpenAI Codex OAuth through OpenClaw/PI | You want ChatGPT/Codex subscription auth with the default PI runner. |
| `openai-codex/gpt-5.5` | Legacy route repaired by doctor | You are on old config; run `openclaw doctor --fix` to rewrite it. |
| `openai/gpt-5.5` + `agentRuntime.id: "codex"` | Codex app-server harness | You want ChatGPT/Codex subscription auth with native Codex execution. |
GPT-5.5 can appear on both direct OpenAI API-key and Codex subscription routes
when your account exposes them. Use `openai/gpt-5.5` with the Codex app-server
harness for native Codex runtime, `openai-codex/gpt-5.5` for PI OAuth, or
`openai/gpt-5.5` without a Codex runtime override for direct API-key traffic.
harness for native Codex runtime, or `openai/gpt-5.5` without a Codex runtime
override for direct API-key traffic.
Legacy `codex/gpt-*` refs remain accepted as compatibility aliases. Doctor
compatibility migration rewrites legacy primary runtime refs to canonical model
refs and records the runtime policy separately, while fallback-only legacy refs
are left unchanged because runtime is configured for the whole agent container.
New PI Codex OAuth configs should use `openai-codex/gpt-*`; new native
app-server harness configs should use `openai/gpt-*` plus
`agentRuntime.id: "codex"`.
compatibility migration rewrites legacy runtime refs to canonical model refs
and records the runtime policy separately. New native app-server harness configs
should use `openai/gpt-*` plus `agentRuntime.id: "codex"`.
`agents.defaults.imageModel` follows the same prefix split. Use
`openai-codex/gpt-*` when image understanding should run through the OpenAI
Codex OAuth provider path. Use `codex/gpt-*` when image understanding should run
through a bounded Codex app-server turn. The Codex app-server model must
advertise image input support; text-only Codex models fail before the media turn
starts.
`openai/gpt-*` for the normal OpenAI route and `codex/gpt-*` when image
understanding should run through a bounded Codex app-server turn. Do not use
`openai-codex/gpt-*`; doctor rewrites that legacy prefix to `openai/gpt-*`. The
Codex app-server model must advertise image input support; text-only Codex
models fail before the media turn starts.
Use `/status` to confirm the effective harness for the current session. If the
selection is surprising, enable debug logging for the `agents/harness` subsystem
@@ -211,22 +214,20 @@ in `auto` mode, each plugin candidate's support result.
### What doctor warnings mean
`openclaw doctor` warns when all of these are true:
`openclaw doctor` warns when configured model refs or persisted session route
state still use `openai-codex/*`. `openclaw doctor --fix` rewrites those routes
to:
- the bundled `codex` plugin is enabled or allowed
- an agent's primary model is `openai-codex/*`
- that agent's effective runtime is not `codex`
- `openai/<model>`
- `agentRuntime.id: "codex"` when Codex is installed, enabled, contributes the
`codex` harness, and has usable OAuth
- `agentRuntime.id: "pi"` otherwise
That warning exists because users often expect "Codex plugin enabled" to imply
"native Codex app-server runtime." OpenClaw does not make that leap. The warning
means:
- **No change is required** if you intended ChatGPT/Codex OAuth through PI.
- Change the model to `openai/<model>` and set
`agentRuntime.id: "codex"` if you intended native app-server
execution.
- Existing sessions still need `/new` or `/reset` after a runtime change,
because session runtime pins are sticky.
The `codex` route forces the native Codex harness. The `pi` route keeps the
agent on the default OpenClaw runner instead of enabling or installing Codex as
a side effect of legacy-route cleanup.
Doctor also repairs stale persisted session pins across discovered agent session
stores so old conversations do not stay wedged on the removed route.
Harness selection is not a live session control. When an embedded turn runs,
OpenClaw records the selected harness id on that session and keeps using it for
@@ -349,7 +350,7 @@ Agents should route user requests by intent, not by the word "Codex" alone:
| "File a support report for a bad Codex run" | `/diagnostics [note]` |
| "Only send Codex feedback for this attached thread" | `/codex diagnostics [note]` |
| "Use my ChatGPT/Codex subscription with Codex runtime" | `openai/*` plus `agentRuntime.id: "codex"` |
| "Use my ChatGPT/Codex subscription through PI" | `openai-codex/*` model refs |
| "Repair old `openai-codex/*` config/session pins" | `openclaw doctor --fix` |
| "Run Codex through ACP/acpx" | ACP `sessions_spawn({ runtime: "acp", ... })` |
| "Start Claude Code/Gemini/OpenCode/Cursor in a thread" | ACP/acpx, not `/codex` and not native sub-agents |

View File

@@ -18,6 +18,16 @@ Adds the WhatsApp channel surface for sending and receiving OpenClaw messages.
channels: whatsapp
## Windows install note
On Windows, the WhatsApp plugin needs Git on `PATH` during npm install because one of its Baileys/libsignal dependencies is fetched from a git URL. Install Git for Windows, then restart the shell and rerun the install:
```powershell
winget install --id Git.Git -e
```
Portable Git also works if its `bin` directory is on `PATH`.
## Related docs
- [whatsapp](/channels/whatsapp)

View File

@@ -77,10 +77,13 @@ the maintainer-only release runbook.
prior evidence stale.
9. For beta, tag `vYYYY.M.D-beta.N`, then run `OpenClaw Release Publish` from
the matching `release/YYYY.M.D` branch. It verifies `pnpm plugins:sync:check`,
publishes all publishable plugin packages to npm first, publishes the same
set to ClawHub second as ClawPack npm-pack tarballs, and then promotes the
prepared OpenClaw npm preflight artifact with the matching dist-tag. After
publish, run post-publish package
dispatches all publishable plugin packages to npm and the same set to
ClawHub in parallel, and then promotes the prepared OpenClaw npm preflight
artifact with the matching dist-tag as soon as plugin npm publish succeeds.
ClawHub publishing may still be running while OpenClaw npm publishes, but the
release publish workflow does not finish until both plugin publish paths and
the OpenClaw npm publish path have completed successfully. After publish, run
the post-publish package
acceptance against the published `openclaw@YYYY.M.D-beta.N` or
`openclaw@beta` package. If a pushed or published prerelease needs a fix,
cut the next matching prerelease number; do not delete or rewrite the old

View File

@@ -152,7 +152,7 @@ Current source-of-truth:
- `/help` shows the short help summary.
- `/commands` shows the generated command catalog.
- `/tools [compact|verbose]` shows what the current agent can use right now.
- `/status` shows execution/runtime status, including `Execution`/`Runtime` labels and provider usage/quota when available.
- `/status` shows execution/runtime status, Gateway and system uptime, plus provider usage/quota when available.
- `/diagnostics [note]` is the owner-only support-report flow for Gateway bugs and Codex harness runs. It asks for explicit exec approval every time before running `openclaw gateway diagnostics export --json`; do not approve diagnostics with an allow-all rule. After approval, it sends a pasteable report with the local bundle path, manifest summary, privacy notes, and relevant session ids. In group chats, the approval prompt and report go to the owner privately. When the active session uses the OpenAI Codex harness, the same approval also sends relevant Codex feedback to OpenAI servers and the completed reply lists the OpenClaw session ids, Codex thread ids, and `codex resume <thread-id>` commands. See [Diagnostics Export](/gateway/diagnostics).
- `/crestodian <request>` runs the Crestodian setup and repair helper from an owner DM.
- `/tasks` lists active/recent background tasks for the current session.

View File

@@ -198,9 +198,9 @@ role or use `first_frame` for single-image image-to-video.
### Style controls
<ParamField path="aspectRatio" type="string">
`1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`, or `adaptive`.
Aspect-ratio hint such as `1:1`, `16:9`, `9:16`, `adaptive`, or a provider-specific value. OpenClaw normalizes or ignores unsupported values per provider.
</ParamField>
<ParamField path="resolution" type="string">`480P`, `720P`, `768P`, or `1080P`.</ParamField>
<ParamField path="resolution" type="string">Resolution hint such as `480P`, `720P`, `768P`, `1080P`, `4K`, or a provider-specific value. OpenClaw normalizes or ignores unsupported values per provider.</ParamField>
<ParamField path="durationSeconds" type="number">
Target duration in seconds (rounded to nearest provider-supported value).
</ParamField>

View File

@@ -82,7 +82,7 @@ Notes:
- Model picker: list available models and set the session override.
- Agent picker: choose a different agent.
- Session picker: shows only sessions for the current agent.
- Session picker: shows up to 50 sessions for the current agent updated in the last 7 days. Use `/session <key>` to jump to an older known session.
- Settings: toggle deliver, tool output expansion, and thinking visibility.
## Keyboard shortcuts

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/acpx",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw ACP runtime backend",
"repository": {
"type": "git",
@@ -25,10 +25,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4",
"openclawVersion": "2026.5.5-beta.1",
"staticAssets": [
{
"source": "./src/runtime-internals/mcp-proxy.mjs",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/alibaba-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Alibaba Model Studio video provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Amazon Bedrock Mantle (OpenAI-compatible) provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Amazon Bedrock provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Anthropic Vertex provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Anthropic provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/arcee-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Arcee provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/azure-speech",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Azure Speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/bluebubbles",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw BlueBubbles channel plugin",
"repository": {
"type": "git",
@@ -12,7 +12,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -53,10 +53,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/bonjour",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Bonjour/mDNS gateway discovery",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/brave-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Brave plugin",
"repository": {
"type": "git",
@@ -20,10 +20,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/browser-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw browser tool plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/byteplus-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw BytePlus provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cerebras-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Cerebras provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/chutes-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Chutes.ai provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cloudflare-ai-gateway-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Cloudflare AI Gateway provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/codex",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Codex harness and model provider plugin",
"repository": {
"type": "git",
@@ -27,10 +27,10 @@
"minHostVersion": ">=2026.5.1-beta.1"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -48,7 +48,10 @@ describe("codex conversation binding", () => {
});
beforeEach(() => {
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({ version: 1, profiles: {} });
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({
version: 1,
profiles: {},
});
agentRuntimeMocks.resolveAuthProfileOrder.mockReturnValue([]);
agentRuntimeMocks.resolveOpenClawAgentDir.mockReturnValue("/agent");
agentRuntimeMocks.resolveProviderIdForAuth.mockImplementation((provider: string) => provider);
@@ -56,7 +59,9 @@ describe("codex conversation binding", () => {
it("uses the default Codex auth profile and omits the public OpenAI provider for new binds", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const config = { auth: { order: { "openai-codex": ["openai-codex:default"] } } };
const config = {
auth: { order: { "openai-codex": ["openai-codex:default"] } },
};
const requests: Array<{ method: string; params: Record<string, unknown> }> = [];
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({
version: 1,
@@ -220,6 +225,142 @@ describe("codex conversation binding", () => {
expect(result).toEqual({ handled: true });
});
it("recreates a missing bound thread and preserves auth plus turn overrides", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({
version: 1,
profiles: {
work: {
type: "oauth",
provider: "openai-codex",
access: "access-token",
},
},
});
await fs.writeFile(
`${sessionFile}.codex-app-server.json`,
JSON.stringify({
schemaVersion: 1,
threadId: "thread-old",
cwd: tempDir,
authProfileId: "work",
model: "gpt-5.4-mini",
modelProvider: "openai",
approvalPolicy: "on-request",
sandbox: "workspace-write",
serviceTier: "fast",
}),
);
const requests: Array<{ method: string; params: Record<string, unknown> }> = [];
const notificationHandlers: Array<(notification: Record<string, unknown>) => void> = [];
sharedClientMocks.getSharedCodexAppServerClient.mockResolvedValue({
request: vi.fn(async (method: string, requestParams: Record<string, unknown>) => {
requests.push({ method, params: requestParams });
if (method === "turn/start" && requestParams.threadId === "thread-old") {
throw new Error("thread not found: thread-old");
}
if (method === "thread/start") {
return {
thread: { id: "thread-new", cwd: tempDir },
model: "gpt-5.4-mini",
};
}
if (method === "turn/start" && requestParams.threadId === "thread-new") {
setImmediate(() => {
for (const handler of notificationHandlers) {
handler({
method: "turn/completed",
params: {
threadId: "thread-new",
turn: {
id: "turn-new",
status: "completed",
items: [
{
id: "assistant-1",
type: "agentMessage",
text: "Recovered",
},
],
},
},
});
}
});
return { turn: { id: "turn-new" } };
}
throw new Error(`unexpected method: ${method}`);
}),
addNotificationHandler: vi.fn((handler) => {
notificationHandlers.push(handler);
return () => undefined;
}),
addRequestHandler: vi.fn(() => () => undefined),
});
const result = await handleCodexConversationInboundClaim(
{
content: "hi again",
bodyForAgent: "hi again",
channel: "telegram",
isGroup: false,
commandAuthorized: true,
},
{
channelId: "telegram",
pluginBinding: {
bindingId: "binding-1",
pluginId: "codex",
pluginRoot: tempDir,
channel: "telegram",
accountId: "default",
conversationId: "5185575566",
boundAt: Date.now(),
data: {
kind: "codex-app-server-session",
version: 1,
sessionFile,
workspaceDir: tempDir,
},
},
},
{ timeoutMs: 500 },
);
expect(result).toEqual({ handled: true, reply: { text: "Recovered" } });
expect(requests.map((request) => request.method)).toEqual([
"turn/start",
"thread/start",
"turn/start",
]);
expect(sharedClientMocks.getSharedCodexAppServerClient).toHaveBeenCalledWith(
expect.objectContaining({ authProfileId: "work" }),
);
expect(requests[1]?.params).toMatchObject({
model: "gpt-5.4-mini",
approvalPolicy: "on-request",
sandbox: "workspace-write",
serviceTier: "fast",
});
expect(requests[1]?.params).not.toHaveProperty("modelProvider");
expect(requests[2]?.params).toMatchObject({
threadId: "thread-new",
approvalPolicy: "on-request",
serviceTier: "fast",
});
const savedBinding = JSON.parse(
await fs.readFile(`${sessionFile}.codex-app-server.json`, "utf8"),
);
expect(savedBinding).toMatchObject({
threadId: "thread-new",
authProfileId: "work",
approvalPolicy: "on-request",
sandbox: "workspace-write",
serviceTier: "fast",
});
expect(savedBinding).not.toHaveProperty("modelProvider");
});
it("returns a clean failure reply when app-server turn start rejects", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
await fs.writeFile(

View File

@@ -10,8 +10,11 @@ import { CODEX_CONTROL_METHODS } from "./app-server/capabilities.js";
import {
codexSandboxPolicyForTurn,
resolveCodexAppServerRuntimeOptions,
type CodexAppServerApprovalPolicy,
type CodexAppServerSandboxMode,
} from "./app-server/config.js";
import {
type CodexServiceTier,
type CodexThreadResumeResponse,
type CodexThreadStartResponse,
type CodexTurnStartResponse,
@@ -59,6 +62,9 @@ type CodexConversationStartParams = {
model?: string;
modelProvider?: string;
authProfileId?: string;
approvalPolicy?: CodexAppServerApprovalPolicy;
sandbox?: CodexAppServerSandboxMode;
serviceTier?: CodexServiceTier;
};
type BoundTurnResult = {
@@ -100,6 +106,9 @@ export async function startCodexConversationThread(
model: params.model,
modelProvider: params.modelProvider,
authProfileId,
approvalPolicy: params.approvalPolicy,
sandbox: params.sandbox,
serviceTier: params.serviceTier,
config: params.config,
});
} else {
@@ -110,6 +119,9 @@ export async function startCodexConversationThread(
model: params.model,
modelProvider: params.modelProvider,
authProfileId,
approvalPolicy: params.approvalPolicy,
sandbox: params.sandbox,
serviceTier: params.serviceTier,
config: params.config,
});
}
@@ -137,7 +149,7 @@ export async function handleCodexConversationInboundClaim(
}
try {
const result = await enqueueBoundTurn(data.sessionFile, () =>
runBoundTurn({
runBoundTurnWithMissingThreadRecovery({
data,
prompt,
event,
@@ -177,9 +189,14 @@ async function attachExistingThread(params: {
model?: string;
modelProvider?: string;
authProfileId?: string;
approvalPolicy?: CodexAppServerApprovalPolicy;
sandbox?: CodexAppServerSandboxMode;
serviceTier?: CodexServiceTier;
config?: CodexAppServerAuthProfileLookup["config"];
}): Promise<void> {
const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
const runtime = resolveCodexAppServerRuntimeOptions({
pluginConfig: params.pluginConfig,
});
const modelProvider = resolveThreadRequestModelProvider({
authProfileId: params.authProfileId,
modelProvider: params.modelProvider,
@@ -196,10 +213,12 @@ async function attachExistingThread(params: {
threadId: params.threadId,
...(params.model ? { model: params.model } : {}),
...(modelProvider ? { modelProvider } : {}),
approvalPolicy: runtime.approvalPolicy,
approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
approvalsReviewer: runtime.approvalsReviewer,
sandbox: runtime.sandbox,
...(runtime.serviceTier ? { serviceTier: runtime.serviceTier } : {}),
sandbox: params.sandbox ?? runtime.sandbox,
...((params.serviceTier ?? runtime.serviceTier)
? { serviceTier: params.serviceTier ?? runtime.serviceTier }
: {}),
persistExtendedHistory: true,
},
{ timeoutMs: runtime.requestTimeoutMs },
@@ -217,9 +236,9 @@ async function attachExistingThread(params: {
authProfileId: params.authProfileId,
modelProvider: response.modelProvider ?? params.modelProvider,
}),
approvalPolicy: runtime.approvalPolicy,
sandbox: runtime.sandbox,
serviceTier: runtime.serviceTier,
approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
sandbox: params.sandbox ?? runtime.sandbox,
serviceTier: params.serviceTier ?? runtime.serviceTier,
},
{
config: params.config,
@@ -234,9 +253,14 @@ async function createThread(params: {
model?: string;
modelProvider?: string;
authProfileId?: string;
approvalPolicy?: CodexAppServerApprovalPolicy;
sandbox?: CodexAppServerSandboxMode;
serviceTier?: CodexServiceTier;
config?: CodexAppServerAuthProfileLookup["config"];
}): Promise<void> {
const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
const runtime = resolveCodexAppServerRuntimeOptions({
pluginConfig: params.pluginConfig,
});
const modelProvider = resolveThreadRequestModelProvider({
authProfileId: params.authProfileId,
modelProvider: params.modelProvider,
@@ -253,10 +277,12 @@ async function createThread(params: {
cwd: params.workspaceDir,
...(params.model ? { model: params.model } : {}),
...(modelProvider ? { modelProvider } : {}),
approvalPolicy: runtime.approvalPolicy,
approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
approvalsReviewer: runtime.approvalsReviewer,
sandbox: runtime.sandbox,
...(runtime.serviceTier ? { serviceTier: runtime.serviceTier } : {}),
sandbox: params.sandbox ?? runtime.sandbox,
...((params.serviceTier ?? runtime.serviceTier)
? { serviceTier: params.serviceTier ?? runtime.serviceTier }
: {}),
developerInstructions:
"This Codex thread is bound to an OpenClaw conversation. Answer normally; OpenClaw will deliver your final response back to the conversation.",
experimentalRawEvents: true,
@@ -276,9 +302,9 @@ async function createThread(params: {
authProfileId: params.authProfileId,
modelProvider: response.modelProvider ?? params.modelProvider,
}),
approvalPolicy: runtime.approvalPolicy,
sandbox: runtime.sandbox,
serviceTier: runtime.serviceTier,
approvalPolicy: params.approvalPolicy ?? runtime.approvalPolicy,
sandbox: params.sandbox ?? runtime.sandbox,
serviceTier: params.serviceTier ?? runtime.serviceTier,
},
{
config: params.config,
@@ -293,7 +319,9 @@ async function runBoundTurn(params: {
pluginConfig?: unknown;
timeoutMs?: number;
}): Promise<BoundTurnResult> {
const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
const runtime = resolveCodexAppServerRuntimeOptions({
pluginConfig: params.pluginConfig,
});
const binding = await readCodexAppServerBinding(params.data.sessionFile);
const threadId = binding?.threadId;
if (!threadId) {
@@ -350,7 +378,10 @@ async function runBoundTurn(params: {
"turn/start",
{
threadId,
input: buildCodexConversationTurnInput({ prompt: params.prompt, event: params.event }),
input: buildCodexConversationTurnInput({
prompt: params.prompt,
event: params.event,
}),
cwd: binding.cwd || params.data.workspaceDir,
approvalPolicy: binding.approvalPolicy ?? runtime.approvalPolicy,
approvalsReviewer: runtime.approvalsReviewer,
@@ -389,6 +420,39 @@ async function runBoundTurn(params: {
}
}
async function runBoundTurnWithMissingThreadRecovery(params: {
data: CodexConversationBindingData;
prompt: string;
event: PluginHookInboundClaimEvent;
pluginConfig?: unknown;
timeoutMs?: number;
}): Promise<BoundTurnResult> {
try {
return await runBoundTurn(params);
} catch (error) {
if (!isCodexThreadNotFoundError(error)) {
throw error;
}
const binding = await readCodexAppServerBinding(params.data.sessionFile);
await startCodexConversationThread({
pluginConfig: params.pluginConfig,
sessionFile: params.data.sessionFile,
workspaceDir: binding?.cwd || params.data.workspaceDir,
model: binding?.model,
modelProvider: binding?.modelProvider,
authProfileId: binding?.authProfileId,
approvalPolicy: binding?.approvalPolicy,
sandbox: binding?.sandbox,
serviceTier: binding?.serviceTier,
});
return await runBoundTurn(params);
}
}
function isCodexThreadNotFoundError(error: unknown): boolean {
return /\bthread not found:/iu.test(formatErrorMessage(error));
}
function enqueueBoundTurn<T>(key: string, run: () => Promise<T>): Promise<T> {
const state = getGlobalState();
const previous = state.queues.get(key) ?? Promise.resolve();

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/comfy-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw ComfyUI provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot-proxy",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Copilot Proxy provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepgram-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Deepgram media-understanding provider",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepinfra-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw DeepInfra provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw DeepSeek provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw diagnostics OpenTelemetry exporter",
"repository": {
"type": "git",
@@ -34,10 +34,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw diagnostics Prometheus exporter",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diffs",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw diff viewer plugin",
"repository": {
"type": "git",
@@ -30,10 +30,10 @@
"minHostVersion": ">=2026.4.30"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4",
"openclawVersion": "2026.5.5-beta.1",
"staticAssets": [
{
"source": "./assets/viewer-runtime.js",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/discord",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Discord channel plugin",
"repository": {
"type": "git",
@@ -21,7 +21,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -65,10 +65,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -82,6 +82,8 @@ export function createDiscordDraftPreviewController(params: {
});
let previewToolProgressSuppressed = false;
let previewToolProgressLines: string[] = [];
let reasoningProgressRawText = "";
let lastReasoningProgressLine: string | undefined;
const progressSeed = `${params.accountId}:${params.deliverChannelId}`;
const renderProgressDraft = async (options?: { flush?: boolean }) => {
@@ -116,6 +118,8 @@ export function createDiscordDraftPreviewController(params: {
draftChunker?.reset();
previewToolProgressSuppressed = false;
previewToolProgressLines = [];
reasoningProgressRawText = "";
lastReasoningProgressLine = undefined;
};
const forceNewMessageIfNeeded = () => {
@@ -163,8 +167,11 @@ export function createDiscordDraftPreviewController(params: {
return;
}
const normalized = line?.replace(/\s+/g, " ").trim();
if (!normalized) {
return;
}
if (discordStreamMode !== "progress") {
if (!previewToolProgressEnabled || previewToolProgressSuppressed || !normalized) {
if (!previewToolProgressEnabled || previewToolProgressSuppressed) {
return;
}
const previous = previewToolProgressLines.at(-1);
@@ -200,6 +207,36 @@ export function createDiscordDraftPreviewController(params: {
await renderProgressDraft();
}
},
async pushReasoningProgress(text?: string) {
if (!draftStream || discordStreamMode !== "progress" || !text) {
return;
}
reasoningProgressRawText = mergeReasoningProgressText(reasoningProgressRawText, text);
const normalized = normalizeReasoningProgressLine(reasoningProgressRawText);
if (!normalized) {
return;
}
if (previewToolProgressEnabled && !previewToolProgressSuppressed) {
const priorIndex =
lastReasoningProgressLine === undefined
? -1
: previewToolProgressLines.lastIndexOf(lastReasoningProgressLine);
if (priorIndex >= 0) {
previewToolProgressLines = [...previewToolProgressLines];
previewToolProgressLines[priorIndex] = normalized;
} else {
previewToolProgressLines = [...previewToolProgressLines, normalized].slice(
-resolveChannelProgressDraftMaxLines(params.discordConfig),
);
}
lastReasoningProgressLine = normalized;
}
const alreadyStarted = progressDraftGate.hasStarted;
await progressDraftGate.noteWork();
if (alreadyStarted && progressDraftGate.hasStarted) {
await renderProgressDraft();
}
},
resolvePreviewFinalText(text?: string) {
if (typeof text !== "string") {
return undefined;
@@ -329,3 +366,29 @@ export function createDiscordDraftPreviewController(params: {
},
};
}
function normalizeReasoningProgressLine(text: string): string {
return text
.replace(/^\s*(?:>\s*)?Reasoning:\s*/i, "")
.replace(/\s+/g, " ")
.trim();
}
function mergeReasoningProgressText(current: string, incoming: string): string {
if (!current) {
return incoming;
}
const normalizedCurrent = normalizeReasoningProgressLine(current);
const normalizedIncoming = normalizeReasoningProgressLine(incoming);
if (!normalizedIncoming || normalizedIncoming === normalizedCurrent) {
return current;
}
if (isReasoningSnapshotText(incoming) || normalizedIncoming.startsWith(normalizedCurrent)) {
return incoming;
}
return `${current}${incoming}`;
}
function isReasoningSnapshotText(text: string): boolean {
return /^\s*(?:>\s*)?Reasoning:\s*/i.test(text);
}

View File

@@ -96,7 +96,7 @@ type DispatchInboundParams = {
sendFinalReply: (payload: ReplyPayload) => boolean | Promise<boolean>;
};
replyOptions?: {
onReasoningStream?: () => Promise<void> | void;
onReasoningStream?: (payload?: { text?: string }) => Promise<void> | void;
onReasoningEnd?: () => Promise<void> | void;
onToolStart?: (payload: {
name?: string;
@@ -105,6 +105,7 @@ type DispatchInboundParams = {
detailMode?: "explain" | "raw";
}) => Promise<void> | void;
onItemEvent?: (payload: {
kind?: string;
progressText?: string;
summary?: string;
title?: string;
@@ -1616,6 +1617,72 @@ describe("processDiscordMessage draft streaming", () => {
expect(draftStream.update).toHaveBeenCalledWith("Shelling\n🛠 Exec\n• done");
});
it("shows reasoning text instead of a bare Reasoning progress line", async () => {
const draftStream = createMockDraftStreamForTest();
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
await params?.replyOptions?.onItemEvent?.({
kind: "analysis",
title: "Reasoning",
});
await params?.replyOptions?.onReasoningStream?.({ text: "Reading " });
await params?.replyOptions?.onReasoningStream?.({ text: "the event projector" });
return createNoQueuedDispatchResult();
});
const ctx = await createAutomaticSourceDeliveryContext({
discordConfig: {
streaming: {
mode: "progress",
progress: {
label: "Clawing...",
},
},
},
});
await runProcessDiscordMessage(ctx);
expect(draftStream.update).toHaveBeenCalledWith(
"Clawing...\n🛠 Exec\n• Reading the event projector",
);
expect(draftStream.update).not.toHaveBeenCalledWith(expect.stringContaining("Reasoning"));
});
it("replaces reasoning snapshots instead of appending duplicates", async () => {
const draftStream = createMockDraftStreamForTest();
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
await params?.replyOptions?.onReasoningStream?.({ text: "Reasoning:\n_Checking files_" });
await params?.replyOptions?.onReasoningStream?.({
text: "Reasoning:\n_Checking files and tests_",
});
return createNoQueuedDispatchResult();
});
const ctx = await createAutomaticSourceDeliveryContext({
discordConfig: {
streaming: {
mode: "progress",
progress: {
label: "Clawing...",
},
},
},
});
await runProcessDiscordMessage(ctx);
expect(draftStream.update).toHaveBeenCalledWith(
"Clawing...\n🛠 Exec\n• _Checking files and tests_",
);
expect(draftStream.update).not.toHaveBeenCalledWith(
expect.stringContaining("_Checking files_Reasoning:"),
);
});
it("keeps Discord progress lines across assistant boundaries", async () => {
const draftStream = createMockDraftStreamForTest();

View File

@@ -660,8 +660,9 @@ export async function processDiscordMessage(
onModelSelected,
suppressDefaultToolProgressMessages:
draftPreview.suppressDefaultToolProgressMessages ? true : undefined,
onReasoningStream: async () => {
onReasoningStream: async (payload) => {
await statusReactions.setThinking();
await draftPreview.pushReasoningProgress(payload?.text);
},
onToolStart: async (payload) => {
if (isProcessAborted(abortSignal)) {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/document-extract-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw local document extraction plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/duckduckgo-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw DuckDuckGo plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/elevenlabs-speech",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw ElevenLabs speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/exa-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Exa plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fal-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw fal provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/feishu",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -47,10 +47,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/file-transfer",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw file transfer plugin (file_fetch, dir_list, dir_fetch, file_write)",
"type": "module",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/firecrawl-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Firecrawl plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fireworks-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Fireworks provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/github-copilot-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw GitHub Copilot provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-meet",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Google Meet participant plugin",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -33,10 +33,10 @@
"minHostVersion": ">=2026.4.20"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -88,7 +88,7 @@ export function createGoogleVideoGenerationProviderMetadata(): Omit<
supportsAspectRatio: true,
supportsResolution: true,
supportsSize: true,
supportsAudio: true,
supportsAudio: false,
},
imageToVideo: {
enabled: true,
@@ -101,7 +101,7 @@ export function createGoogleVideoGenerationProviderMetadata(): Omit<
supportsAspectRatio: true,
supportsResolution: true,
supportsSize: true,
supportsAudio: true,
supportsAudio: false,
},
videoToVideo: {
enabled: true,
@@ -114,7 +114,7 @@ export function createGoogleVideoGenerationProviderMetadata(): Omit<
supportsAspectRatio: true,
supportsResolution: true,
supportsSize: true,
supportsAudio: true,
supportsAudio: false,
},
},
};

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-plugin",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Google plugin",
"type": "module",

View File

@@ -86,11 +86,11 @@ describe("google video generation provider", () => {
durationSeconds: 4,
aspectRatio: "16:9",
resolution: "720p",
generateAudio: true,
}),
}),
);
expect(request?.config).not.toHaveProperty("numberOfVideos");
expect(request?.config).not.toHaveProperty("generateAudio");
expect(result.videos).toHaveLength(1);
expect(result.videos[0]?.mimeType).toBe("video/mp4");
expect(createGoogleGenAIMock).toHaveBeenCalledWith(

View File

@@ -322,7 +322,6 @@ async function generateGoogleVideoViaRest(params: {
durationSeconds?: number;
aspectRatio?: "16:9" | "9:16";
resolution?: "720p" | "1080p";
audio?: boolean;
}): Promise<unknown> {
let operation = await requestGoogleVideoJson({
url: `${params.baseUrl}/${resolveGoogleVideoRestModelPath(params.model)}:predictLongRunning`,
@@ -337,7 +336,6 @@ async function generateGoogleVideoViaRest(params: {
: {}),
...(params.aspectRatio ? { aspectRatio: params.aspectRatio } : {}),
...(params.resolution ? { resolution: params.resolution } : {}),
...(params.audio === true ? { generateAudio: true } : {}),
},
},
});
@@ -429,7 +427,6 @@ export function buildGoogleVideoGenerationProvider(): VideoGenerationProvider {
...(typeof durationSeconds === "number" ? { durationSeconds } : {}),
...(aspectRatio ? { aspectRatio } : {}),
...(resolution ? { resolution } : {}),
...(req.audio === true ? { generateAudio: true } : {}),
},
});
} catch (error) {
@@ -446,7 +443,6 @@ export function buildGoogleVideoGenerationProvider(): VideoGenerationProvider {
durationSeconds,
aspectRatio,
resolution,
audio: req.audio,
});
}
@@ -480,7 +476,6 @@ export function buildGoogleVideoGenerationProvider(): VideoGenerationProvider {
durationSeconds,
aspectRatio,
resolution,
audio: req.audio,
});
generatedVideos = extractGeneratedVideos(operation);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/googlechat",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Google Chat channel plugin",
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -75,10 +75,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/gradium-speech",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Gradium speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/groq-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Groq media-understanding provider",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/huggingface-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Hugging Face provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/image-generation-core",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw image generation runtime package",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/imessage",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw iMessage channel plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/inworld-speech",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Inworld speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/irc",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw IRC channel plugin",
"type": "module",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/kilocode-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Kilo Gateway provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/kimi-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw Kimi provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/line",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw LINE channel plugin",
"repository": {
"type": "git",
@@ -15,7 +15,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -45,10 +45,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/litellm-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw LiteLLM provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/llm-task",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw JSON-only LLM task plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/lmstudio-provider",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw LM Studio provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/lobster",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
"repository": {
"type": "git",
@@ -25,10 +25,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,5 +1,11 @@
# Changelog
## 2026.5.5
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.5.4
### Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/matrix",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Matrix channel plugin",
"repository": {
"type": "git",
@@ -21,7 +21,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/mattermost",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw Mattermost channel plugin",
"repository": {
"type": "git",
@@ -15,7 +15,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/media-understanding-core",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw media understanding runtime package",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-core",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw core memory search plugin",
"type": "module",
@@ -14,7 +14,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-lancedb",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture",
"repository": {
"type": "git",
@@ -26,10 +26,10 @@
"minHostVersion": ">=2026.4.10"
},
"compat": {
"pluginApi": ">=2026.5.4"
"pluginApi": ">=2026.5.5-beta.1"
},
"build": {
"openclawVersion": "2026.5.4"
"openclawVersion": "2026.5.5-beta.1"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/memory-wiki",
"version": "2026.5.4",
"version": "2026.5.5-beta.1",
"private": true,
"description": "OpenClaw persistent wiki plugin",
"type": "module",
@@ -13,7 +13,7 @@
"openclaw": "workspace:*"
},
"peerDependencies": {
"openclaw": ">=2026.5.4"
"openclaw": ">=2026.5.5-beta.1"
},
"peerDependenciesMeta": {
"openclaw": {

Some files were not shown because too many files have changed in this diff Show More