Compare commits

..

3729 Commits

Author SHA1 Message Date
scoootscooob
f0635aeca7 plugins: match installed plugin records by root 2026-05-15 20:30:35 -07:00
scoootscooob
2171e714f5 plugins: keep model-profile runtime llm compat 2026-05-15 20:28:33 -07:00
scoootscooob
9dc496986a docs: align runtime llm profile override docs 2026-05-15 20:28:33 -07:00
Eva (agent)
80c54f8288 Normalize same-model profile selection in runtime LLM 2026-05-15 20:28:33 -07:00
Eva (agent)
074621dfd9 Test auth-profile override gates across runtime LLM lanes 2026-05-15 20:28:33 -07:00
Eva (agent)
9588d72156 Gate structured LLM auth profiles consistently 2026-05-15 20:28:33 -07:00
Eva (agent)
9c0e21f239 plugin-sdk: add host-owned structured runtime llm 2026-05-15 20:28:32 -07:00
Shadow
90ae151154 fix: prevent barnacle vetoing clawsweeper proof 2026-05-15 22:25:29 -05:00
Brad
372a8e4d22 Add wait mode for manual cron runs (#81929)
Adds wait mode for manual cron runs, exact run-id lookup for cron run logs, protocol/Swift schema support, and docs/changelog coverage.
2026-05-15 20:17:48 -07:00
Vincent Koc
9aa9c57625 fix(doctor): skip unsupported group allowFrom repair 2026-05-16 11:14:53 +08:00
Vincent Koc
c2c7396ffb fix(test): avoid walking core extension facade scans 2026-05-16 11:10:54 +08:00
Vincent Koc
bb07cbc2be fix(config): sanitize plugin session hydration 2026-05-16 11:02:41 +08:00
Vincent Koc
72581fbb48 fix(test): avoid walking package boundary scans 2026-05-16 11:02:08 +08:00
Vincent Koc
9c7e36bf81 fix(test): avoid walking extension runtime dependency scans 2026-05-16 10:54:25 +08:00
Vincent Koc
aa6ea4510c fix(test): avoid walking channel import guardrails 2026-05-16 10:46:44 +08:00
Vincent Koc
445c7d050a changelog: note foreign-bot /stop topic-lane scoping in #82162 entry 2026-05-16 10:43:05 +08:00
Vincent Koc
f1c8570e0c fix(test): avoid walking plugin sdk package guardrails 2026-05-16 10:38:13 +08:00
Vincent Koc
069ad23b74 fix(test): avoid scanning bundled capability metadata 2026-05-16 10:28:59 +08:00
Vincent Koc
81d1424ad9 fix(update): allow plugin convergence after package doctor repairs 2026-05-16 10:28:26 +08:00
Peter Steinberger
0d21524736 test(telegram): type targeted stop metadata stubs 2026-05-16 03:25:21 +01:00
Peter Steinberger
84c9286434 fix(telegram): keep foreign stop commands on topic lanes 2026-05-16 03:25:21 +01:00
Peter Steinberger
12d3ebe1e0 chore: credit stop abort fix 2026-05-16 03:25:21 +01:00
Peter Steinberger
9f7d606469 fix(gateway): match stop by stored session id 2026-05-16 03:25:21 +01:00
VACInc
b72f008183 fix: stop active turns reliably 2026-05-16 03:25:21 +01:00
Vincent Koc
37799a1437 fix(test): avoid walking plugin tool contracts 2026-05-16 10:23:28 +08:00
Vincent Koc
d095319b08 fix(test): avoid walking provider catalog guard 2026-05-16 10:15:49 +08:00
Vincent Koc
dc6528f9ff fix(config): warn for stale web search providers
Downgrade stale optional web search provider plugin installs to validation warnings so Gateway and doctor repair paths keep running after startup provider selection landed in #82376.

Refs #82313.
2026-05-16 10:14:57 +08:00
Vincent Koc
111b65a6fb fix(providers): harden video response schemas 2026-05-16 10:10:38 +08:00
Peter Steinberger
e01a885d18 fix: complete ended subagent cleanup after helper failures
Fixes #82306.
Supersedes #75462.

Co-authored-by: Sebastien Tardif <SebTardif@ncf.ca>
2026-05-16 03:09:29 +01:00
Vincent Koc
b3ede77528 fix(test): avoid walking provider family scans 2026-05-16 10:08:28 +08:00
Vincent Koc
6c8f49386c fix(config): sanitize pending delivery hydration 2026-05-16 10:06:49 +08:00
Peter Steinberger
cf7c46dff6 docs(codex): clarify raw tool output watchdog 2026-05-16 03:06:39 +01:00
joshavant
5d93fb3ed8 docs(changelog): add codex watchdog entry 2026-05-16 03:06:39 +01:00
joshavant
44a3301e50 fix(codex): keep raw tool output watchdog armed 2026-05-16 03:06:39 +01:00
Vincent Koc
3b663ad1c1 fix(gateway): harden image-named attachment sniffing 2026-05-16 10:02:28 +08:00
Peter Steinberger
7206811b80 fix: start xai oauth callback before browser 2026-05-16 03:02:07 +01:00
Peter Steinberger
8bc927b294 docs: clarify xai oauth coverage 2026-05-16 03:02:07 +01:00
Peter Steinberger
6208f2b678 fix: satisfy xai oauth lint 2026-05-16 03:02:07 +01:00
Peter Steinberger
af2b313194 feat: add xai grok oauth 2026-05-16 03:02:07 +01:00
Vincent Koc
2754dc895a fix(update): skip plugin schema validation during package doctor writes 2026-05-16 10:00:46 +08:00
Vincent Koc
ae594d263c fix(test): avoid walking message turn guardrails 2026-05-16 09:59:58 +08:00
Vincent Koc
48b3a1cff9 fix(plugins): reject escaped package metadata 2026-05-16 09:59:11 +08:00
joshavant
1ea48edeff docs: add changelog for web search startup fix 2026-05-16 02:56:04 +01:00
joshavant
37f8507b4b fix: start configured web search providers 2026-05-16 02:56:04 +01:00
Vincent Koc
4d2acd9481 fix(test): avoid walking lint suppression scans 2026-05-16 09:53:28 +08:00
Vincent Koc
5f85e6b692 fix(lint): remove redundant unknown unions 2026-05-16 09:48:28 +08:00
Vincent Koc
89a9b4e75a fix(plugins): preserve host package during managed peer repair 2026-05-16 09:48:28 +08:00
Vincent Koc
56aec53dde fix(test): avoid walking extension boundary scans 2026-05-16 09:47:50 +08:00
Vincent Koc
e403af2d85 fix(test): avoid walking CI node shard plans 2026-05-16 09:43:03 +08:00
Vincent Koc
31cc26230f fix(test): avoid scanning bundled source metadata 2026-05-16 09:36:04 +08:00
Vincent Koc
721fb6570e fix(agents): skip malformed gap-fill tails 2026-05-16 09:33:42 +08:00
Vincent Koc
a70c90a52b test(plugins): cover malformed npm package metadata 2026-05-16 09:29:40 +08:00
Vincent Koc
3064d6181d fix(test): avoid scanning static asset metadata 2026-05-16 09:26:56 +08:00
Vincent Koc
783ef1d22b Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix(msteams): sniff inline image attachments
  fix(providers): harden image response schemas
2026-05-16 09:17:22 +08:00
Vincent Koc
eb7a082b77 fix(providers): harden image response schemas 2026-05-16 09:16:01 +08:00
Vincent Koc
859286b95e Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix(msteams): sniff inline image attachments
2026-05-16 09:15:20 +08:00
Vincent Koc
b436927a43 fix(msteams): sniff inline image attachments 2026-05-16 09:14:52 +08:00
Vincent Koc
46b0fc0c0a fix(providers): harden image response schemas 2026-05-16 09:14:51 +08:00
Vincent Koc
14142a927d fix(msteams): sniff inline image attachments 2026-05-16 09:14:37 +08:00
Vincent Koc
7d96d1f41a fix(test): avoid scanning bundled build entries 2026-05-16 09:14:07 +08:00
Vincent Koc
c320da79ed fix(test): avoid scanning extension ids 2026-05-16 09:08:19 +08:00
Vincent Koc
c8cee2dce4 fix(voice-call): persist rejected replay keys 2026-05-16 09:02:28 +08:00
Vincent Koc
7ccd3b8e8e fix(test): avoid walking extension test plans 2026-05-16 09:02:10 +08:00
Vincent Koc
c4810e33f4 Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix(test): avoid walking contract shard plans
2026-05-16 08:59:42 +08:00
Vincent Koc
f553dad560 Reapply "chore(release): set 2026.5.16 version"
This reverts commit 73aab6abd8.
2026-05-16 08:59:33 +08:00
Vincent Koc
2ee856985b fix(test): avoid walking contract shard plans 2026-05-16 08:57:57 +08:00
Vincent Koc
0e7cc1ca53 fix(test): avoid walking gateway suite targets 2026-05-16 08:47:05 +08:00
Vincent Koc
efabae2f9b fix(test): avoid walking unit-fast candidate roots 2026-05-16 08:39:00 +08:00
Josh Avant
a1e208ee26 Recover stale embedded tool calls during gateway diagnostics (#82369)
* fix(gateway): recover stale embedded tool calls

* chore(changelog): note stale embedded tool recovery
2026-05-15 19:36:59 -05:00
Vincent Koc
9a1fa5f23f fix(test): defer unit coverage source discovery 2026-05-16 08:32:56 +08:00
Vincent Koc
9c2044d3b7 changelog: credit reporters for #82239, #65867, #82167, #47444 follow-up 2026-05-16 08:28:13 +08:00
Vincent Koc
73aab6abd8 Revert "chore(release): set 2026.5.16 version"
This reverts commit b7e8f6da6a.
2026-05-16 08:20:19 +08:00
Josh Avant
1dac68c0bb fix fallback provenance across reloads (#82363) 2026-05-15 19:12:34 -05:00
Peter Steinberger
b08e0da25b fix: clarify provider timeout ceiling 2026-05-16 01:08:07 +01:00
Peter Steinberger
49e9382cc0 fix(configure): unify OpenAI auth provider picker (#82324) 2026-05-16 01:02:33 +01:00
Peter Steinberger
8d3b5c2d19 fix(auto-reply): abort active text stop runs 2026-05-16 01:00:52 +01:00
Josh Avant
64b94daf92 Fix gateway auth logout aborting active runs (#82346)
* fix gateway auth logout aborts active runs

* docs changelog for auth logout abort fix

* test fix auth logout typecheck

* test fix auth profile mock shape
2026-05-15 18:36:49 -05:00
Josh Avant
ea16a5e9e1 fix(codex): yield app-server notification projection (#82333)
* fix(codex): yield app-server notification projection

* docs(changelog): note codex notification yield fix
2026-05-15 16:53:10 -05:00
Jesse Merhi
6921d9072e Adopt Proxyline for managed proxy routing
Route managed HTTP/WebSocket/fetch interception through Proxyline 0.3.0, preserving Gateway loopback bypass behavior and root undici hardening.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
2026-05-15 22:51:36 +01:00
Peter Steinberger
0ad3d25fb7 refactor(agents): share subagent cron fallback selection (#82328)
* fix(agents): honor subagent cron fallbacks

* refactor(agents): share cron subagent model selection

* test(agents): align subagent fallback policy expectation

* fix(agents): keep subagent fallbacks on selected model

* fix(agents): preserve subagent fallback-only overrides
2026-05-15 22:36:15 +01:00
Peter Steinberger
b7e8f6da6a chore(release): set 2026.5.16 version 2026-05-15 22:06:19 +01:00
Peter Steinberger
a87fcefe31 fix: repair release validation type and lint gates 2026-05-15 22:06:12 +01:00
Peter Steinberger
e22a7e45a4 fix(cron): honor subagent model fallbacks 2026-05-15 21:54:48 +01:00
Peter Steinberger
d0218d3e59 fix(telegram): retain transcript-backed truncated finals 2026-05-15 21:53:14 +01:00
Peter Steinberger
25a8f5f3f8 fix: surface stalled telegram ingress backlog 2026-05-15 21:52:43 +01:00
Peter Steinberger
a6dd9fdf08 fix(cron): separate failure notification delivery 2026-05-15 21:51:25 +01:00
Peter Steinberger
cce12697a1 fix(doctor): materialize group allowFrom fallback (#82316)
* fix(doctor): materialize group allowFrom fallback

* fix: normalize doctor account records
2026-05-15 21:47:49 +01:00
Peter Steinberger
903e246e87 fix: satisfy room-event strict smoke types 2026-05-15 21:47:46 +01:00
Peter Steinberger
2e5a86adfe fix: finish room event gating 2026-05-15 21:47:46 +01:00
Peter Steinberger
b9ffc0eda9 fix: cancel queued room event followups 2026-05-15 21:47:46 +01:00
Peter Steinberger
fa9c7ddadf fix: abort superseded telegram room events 2026-05-15 21:47:46 +01:00
Peter Steinberger
ad29f089e4 fix: preserve overlapping telegram room event correlations 2026-05-15 21:47:46 +01:00
Peter Steinberger
f1351bcbcf fix: carry room event gateway actions 2026-05-15 21:47:46 +01:00
Peter Steinberger
ddcfde1489 fix: propagate room event tool context 2026-05-15 21:47:46 +01:00
Peter Steinberger
4b11d65ada fix: keep telegram room events fully quiet 2026-05-15 21:47:46 +01:00
Peter Steinberger
b5fde36c41 fix: isolate telegram room event delivery correlation 2026-05-15 21:47:46 +01:00
Peter Steinberger
8c8241140e fix: keep room events quiet without breaking delivery fallback 2026-05-15 21:47:46 +01:00
Peter Steinberger
46409d30b7 fix: isolate telegram room event dispatch fence 2026-05-15 21:47:46 +01:00
Peter Steinberger
ba8b4377f7 fix: keep explicit quiet replies suppressed 2026-05-15 21:47:46 +01:00
Peter Steinberger
d4b98f0dc9 fix: gate ambient room event turns 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
61f3a4d71d fix(telegram): keep room events quiet 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
4db5cb1a20 fix(agents): submit quiet room events to model 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
7ed4ad8d17 fix(reply): clarify room event turn context 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
6f7897d8ad fix(channels): isolate inbound turn kind type 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
fb0f29b9cc fix(telegram): keep room events fully quiet 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
c2e659472a docs(channels): describe room events 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
56cc150771 feat(telegram): route ambient chatter as room events 2026-05-15 21:47:46 +01:00
Ayaan Zaidi
503c3d139c feat(reply): add room event turn semantics 2026-05-15 21:47:46 +01:00
Radek Sienkiewicz
3de97057d0 fix(codex): use stable hooks feature flag (#82078) 2026-05-15 13:35:49 -07:00
Peter Steinberger
445ed9b0b4 fix(auto-reply): clean up no-reply migration paths 2026-05-15 21:29:39 +01:00
Peter Steinberger
f0ceb3c5aa fix(auto-reply): restrict no-reply to automatic groups 2026-05-15 21:29:39 +01:00
Peter Steinberger
68e0cdc478 fix(auto-reply): avoid NO_REPLY prompt in direct chats 2026-05-15 21:29:39 +01:00
Peter Steinberger
333f65fc8a fix: tighten release tooling checks 2026-05-15 21:21:17 +01:00
Vincent Koc
0b7ff665f6 fix(trajectory): report malformed export rows 2026-05-16 04:07:22 +08:00
Vincent Koc
ba8a6499f0 fix(providers): harden malformed success responses 2026-05-16 03:57:25 +08:00
Vincent Koc
ea4e3cd4fa fix(config): harden persisted store shapes 2026-05-16 03:52:22 +08:00
Peter Steinberger
628c753f3b docs: document wildcard runtime policy 2026-05-15 20:50:49 +01:00
Peter Steinberger
638bfc0bf5 fix: honor wildcard model runtime policy 2026-05-15 20:50:49 +01:00
Vincent Koc
dd4613a268 fix(test): reduce changed-target import graph IO 2026-05-16 03:47:47 +08:00
Vincent Koc
9e9a825aa5 fix(media): sniff input file payloads 2026-05-16 03:47:08 +08:00
Vincent Koc
d2e0a8231f fix(plugins): reject malformed package entries 2026-05-16 03:44:33 +08:00
Peter Steinberger
4add9bab77 fix(discord): harden read message results (#82276)
Validate Discord read message results before normalizing channel history, preserving the Discord array contract while replacing opaque map crashes with a clear boundary error.

Fixes #82252.
2026-05-15 20:42:41 +01:00
Peter Steinberger
8ba0bb2a8a fix: scope local agent gateway dispatch (#82284) 2026-05-15 20:35:53 +01:00
Vincent Koc
947c9512c3 changelog: add codex MCP agent scoping and Responses cached usage clamp 2026-05-16 03:24:53 +08:00
Peter Steinberger
d5eec80e34 fix(agents): honor completions token aliases (#82278) 2026-05-15 20:19:41 +01:00
Vincent Koc
f964b1c3aa fix(agents): clamp Responses cached usage 2026-05-16 03:17:31 +08:00
Sergio Cadavid
472523360d fix(codex): scope user MCP servers by agent (#82180) 2026-05-15 20:17:16 +01:00
Vincent Koc
dea6207dd1 fix(plugins): require npm package compatibility metadata 2026-05-16 03:08:42 +08:00
Peter Steinberger
532759e1ab docs: add streaming usage changelog entry 2026-05-15 20:07:53 +01:00
Peter Steinberger
b376780715 fix(openai): keep volcengine streaming usage opt-in 2026-05-15 20:07:53 +01:00
Rui Xu
ff6b38750e fix(openai): honor streaming usage compat 2026-05-15 20:07:53 +01:00
Peter Steinberger
66f89540c2 fix(gateway): raise lifecycle hook timeout defaults
Raise bounded gateway lifecycle hook wait budgets to 5 seconds for shutdown and 10 seconds for pre-restart, keeping the fix to defaults only instead of adding config surface.

Includes regression coverage, hook docs, changelog credit for @bryanbaer, and replaces #82186 with the narrower maintainer fix.
2026-05-15 19:53:58 +01:00
Vincent Koc
a6aa48350b fix: route crabbox proof through brokered aws 2026-05-16 02:44:06 +08:00
Vincent Koc
b21d3e5362 fix(plugins): verify packaged setup runtime entries 2026-05-16 02:32:32 +08:00
Vincent Koc
317f1f8b5b fix(media): reject malformed sniff base64 2026-05-16 02:29:18 +08:00
Vincent Koc
4e10969ade fix(codex): ignore empty rate-limit buckets 2026-05-16 02:15:36 +08:00
Peter Steinberger
48b4e5b361 docs: add cron delivery mirror changelog 2026-05-15 18:49:30 +01:00
Peter Steinberger
c3a211993c fix(cron): preserve isolated delivery awareness policy 2026-05-15 18:49:30 +01:00
Cavit Erginsoy
5ce1e45848 test: isolate media provider registry mocks 2026-05-15 18:49:30 +01:00
Cavit Erginsoy
f3403708a3 fix(cron): tighten session mirror classification 2026-05-15 18:49:30 +01:00
Cavit Erginsoy
7de413499f fix(cron): mirror announce delivery into destination session 2026-05-15 18:49:30 +01:00
Peter Steinberger
7270bb95b7 fix(telegram): drain outbound queue after polling reconnect (#82227)
* fix(telegram): drain outbound queue after polling reconnect

* fix(telegram): keep reconnect drain backoff-safe
2026-05-15 18:46:18 +01:00
Peter Steinberger
6ca9de1e0a refactor: deprecate legacy reply history helpers (#82236) 2026-05-15 18:44:04 +01:00
Peter Steinberger
fc9798a788 refactor: resolve cron delivery from context (#82241) 2026-05-15 18:42:52 +01:00
Peter Steinberger
daef8e73fc fix: prune replay control messages 2026-05-15 18:35:46 +01:00
Ayaan Zaidi
c7dcf79585 fix(qa): emit Discord trigger timing artifacts 2026-05-15 23:00:09 +05:30
Peter Steinberger
1bcc071385 ci(release): harden beta validation gates 2026-05-15 18:28:52 +01:00
Zach Knickerbocker
7715b29aa2 fix(codex): preserve inbound sender metadata
Summary:
- Preserve inbound sender metadata and source-channel provenance in Codex app-server prompt mirrors.
- Reuse the shared prompt-mirror builder for normal and `turn/start` failure snapshots.
- Add regression coverage for provider variants such as `discord-voice` while keeping `sourceChannel` on the originating channel.

Verification:
- `pnpm test extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `pnpm exec oxfmt --check extensions/codex/src/app-server/transcript-mirror.ts extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts`
- `git diff --check temp/landpr-82184..HEAD`
- `/Users/steipete/Projects/agent-scripts/skills/codex-review/scripts/codex-review --parallel-tests "pnpm test extensions/codex/src/app-server/event-projector.test.ts extensions/codex/src/app-server/run-attempt.test.ts"`
2026-05-15 18:12:16 +01:00
Peter Steinberger
011f98c5a6 docs: note file-transfer lazy policy loading (#82211) 2026-05-15 18:12:10 +01:00
samzong
c746ec5fc7 fix(file-transfer): avoid eager invoke policy load
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-15 18:12:10 +01:00
Peter Steinberger
dd457474b3 fix(ui): avoid inline image previews in webchat send (#82228) 2026-05-15 18:08:52 +01:00
Peter Steinberger
e51d27d2ac chore(release): refresh plugin SDK API baseline 2026-05-15 18:00:31 +01:00
Peter Steinberger
ae5591eca9 test(release): use usage accumulator fixture 2026-05-15 17:57:14 +01:00
Peter Steinberger
8ac30279b3 fix: strip delivery function response leaks
Strip adjacent plural function-call/function-response XML on delivery paths while preserving prose examples.
2026-05-15 17:47:27 +01:00
Peter Steinberger
30e2654ac2 fix: route active-memory Telegram recall through provider 2026-05-15 17:46:42 +01:00
Peter Steinberger
f1708f8b14 fix(release): satisfy preflight lint 2026-05-15 17:46:26 +01:00
Peter Steinberger
69eb76b9bb docs: require regression provenance in PR reviews 2026-05-15 17:40:15 +01:00
Peter Steinberger
4859edd9f8 test(release): align hosted runner assertions 2026-05-15 17:34:29 +01:00
Peter Steinberger
55c275b00a ci(release): require full validation before npm publish 2026-05-15 17:33:28 +01:00
Peter Steinberger
3e5070efbf fix(release): preserve provider reasoning replay 2026-05-15 17:33:28 +01:00
Peter Steinberger
6330fe607d fix(release): verify npm tarball before publish 2026-05-15 17:33:28 +01:00
Peter Steinberger
e79e5dbbdf test(release): align plugin contract assertions 2026-05-15 17:33:28 +01:00
Peter Steinberger
1ba75463a5 test(release): align plugin prerelease contracts 2026-05-15 17:33:28 +01:00
Peter Steinberger
4e6c85d930 refactor: route remaining channel history through window (#82220) 2026-05-15 17:27:00 +01:00
Peter Steinberger
c96795d272 ci(release): use hosted runners for manual release gates 2026-05-15 17:25:32 +01:00
Peter Steinberger
8338412b54 fix: cover per-peer LINE cron recovery (#81704) 2026-05-15 17:22:58 +01:00
許元豪
f3f2c784c4 fix(line): reject lowercased LINE-shaped recipients before push (#81628)
Defense-in-depth safety net for #81628: even with the cron-tool fix in
place, any other code path that ever produces a 33-char LINE-shaped
recipient missing its leading capital (C/U/R) would otherwise hit the
LINE API and return HTTP 400 with no permanent-error signal, causing
delivery-recovery to retry five times before moving the entry to
failed/.

normalizeTarget now throws "Recipient is not a valid LINE id ..." when
the post-strip value looks like a LINE id but the case was lost. The
message matches the existing /recipient is not a valid/i pattern in
delivery-queue-recovery's PERMANENT_ERROR_PATTERNS, so recovery moves
the entry to failed/ on the first attempt instead of silently retrying.

Short fixtures (length < 33) are left alone so existing tests using
"U123", "line:user:1", etc. keep working.
2026-05-15 17:22:58 +01:00
許元豪
ac2e72a8e6 fix(cron): refuse LINE session-key recipient fallback (#81628)
LINE chat ids are case-sensitive (push requires capital C/U/R) but the
session key holds the peer id lowercased for canonical routing. When
cron-tool runs without currentDeliveryContext (delivery-recovery, queue
replay after reply-token expiry), inferDeliveryFromSessionKey was
lifting the lowercased fragment straight into delivery.to, producing a
value LINE rejects with HTTP 400 — the job retried five times silently
and the dashboard reported "delivered" while the LINE group received
nothing.

Refuse the session-key fallback for channel === "line" so the missing
target surfaces explicitly instead of scheduling an undeliverable job.
2026-05-15 17:22:58 +01:00
Peter Steinberger
d5b87672f8 fix(mac): disarm legacy update launchd jobs 2026-05-15 17:20:41 +01:00
Peter Steinberger
cf79689ca1 fix: strip attributed final tags
Fix Gemini/Gemma attributed and self-closing <final> tag leaks across sanitizer, reasoning cleanup, and embedded Pi streaming enforcement.\n\nProof posted in PR body: focused Vitest, formatting, diff check, real Google Gemini/OpenRouter/local Gemma live output.
2026-05-15 17:18:24 +01:00
Peter Steinberger
65dd71d42d fix: preserve cron session transcript rotation (#82200)
* fix: preserve cron session transcript rotation

* chore: refresh pr checks
2026-05-15 17:00:42 +01:00
Peter Steinberger
c6ddb1afb7 fix: preserve media completion message-tool delivery (#82206)
* fix: preserve message-tool media completion delivery

* chore: update generated protocol models
2026-05-15 16:49:52 +01:00
Peter Steinberger
29b5563ccd fix: strip adjacent function response scaffolding (#82155)
Summary:
- Strip adjacent function_response workflow output after stripped XML tool-call scaffolding.
- Cover multiline, compact, dangling, chained, prose-like, and same-line-tail response forms.
- Add regression coverage for the production sanitizeUserFacingText path and the shared assistant-visible-text sanitizer.

Verification:
- node scripts/run-vitest.mjs src/shared/text/assistant-visible-text.test.ts src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts -- --reporter=verbose
- git diff --check origin/main...HEAD
- /Users/steipete/Projects/agent-scripts/skills/codex-review/scripts/codex-review --mode branch --base origin/main --full-access --output /tmp/codex-review-82155-rerun.txt --parallel-tests "node scripts/run-vitest.mjs src/shared/text/assistant-visible-text.test.ts src/agents/pi-embedded-helpers.sanitizeuserfacingtext.test.ts -- --reporter=verbose"
- GitHub Real behavior proof: https://github.com/openclaw/openclaw/actions/runs/25926897171
2026-05-15 16:48:33 +01:00
Peter Steinberger
9c38948700 docs: note sharp libvips install workaround 2026-05-15 16:32:04 +01:00
Peter Steinberger
9ee93e8ea7 docs: document channel turn guardrails
Document the channel-turn media/history guardrails and add a focused regression test for migrated message paths.
2026-05-15 16:27:34 +01:00
Peter Steinberger
4718e6272c docs: add tts command changelog (#82174) 2026-05-15 16:23:38 +01:00
Rui Xu
2204b25f1d fix(tts): preserve command voice delivery decision 2026-05-15 16:23:38 +01:00
Peter Steinberger
5aefc9dda4 refactor: centralize channel turn media facts
Centralize channel-turn media fact shaping in core and route Discord/Slack through the shared helper.
2026-05-15 16:21:06 +01:00
Vincent Koc
1b62168a3a fix(media): reject malformed generated base64 2026-05-15 23:20:46 +08:00
Peter Steinberger
06ec35452f test: deduplicate OpenRouter reasoning replay regression 2026-05-15 16:17:50 +01:00
Peter Steinberger
c5a4d7af41 fix: avoid OpenRouter DeepSeek V4 empty reasoning replay 2026-05-15 16:17:50 +01:00
luyao618
25864ee540 fix(transport): strip empty-string reasoning_content from OpenRouter assistant replay
DeepSeek V4 via OpenRouter injects reasoning_content: "" on assistant
messages that contain tool_calls.  The sanitizer only deleted the field
when it was not a string, so empty strings slipped through and were
replayed on follow-up turns.  OpenRouter rejects the field with an
HTTP 500 Internal Server Error instead of a descriptive 4xx, breaking
every subsequent tool-call turn for the session.

Also strip empty-string reasoning for the same reason.

Closes #82150
2026-05-15 16:17:50 +01:00
Merlin
127156a88a fix(codex): fail fast after quiescent app-server turns
Fix Codex app-server turns that go quiet after the last non-assistant current-turn item completes without turn/completed.\n\nMaintainer proof: focused watchdog regression passed on rebased head, diff whitespace check passed, and local OpenClaw CLI + WebSocket app-server transport proof observed turn/interrupt after the short idle watchdog.\n\nCo-authored-by: funmerlin <funmerlin@users.noreply.github.com>
2026-05-15 16:16:33 +01:00
Peter Steinberger
bbf50a406e fix: keep Discord prompt metadata structured (#82168) 2026-05-15 16:12:11 +01:00
Peter Steinberger
2eee70e0a6 refactor: run prepared Discord and Slack turns
Route Discord and Slack prepared message turns through the core prepared-turn runner directly.

Local proof before landing:
- node scripts/run-vitest.mjs src/channels/turn/kernel.test.ts extensions/discord/src/monitor/message-handler.process.test.ts extensions/slack/src/monitor/message-handler/prepare.test.ts extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental false
- node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental false
- OPENCLAW_TESTBOX_REMOTE_RUN=1 OPENCLAW_VITEST_MAX_WORKERS=1 pnpm check:changed
- codex-review clean after accepted Slack bot-loop history cleanup finding was fixed in core

GitHub checks had no failures; Blacksmith/GitHub runner jobs were still queued when maintainer approved landing based on local proof.
2026-05-15 16:06:22 +01:00
Peter Steinberger
369917ff79 fix: surface cron model override diagnostics 2026-05-15 16:04:49 +01:00
Peter Steinberger
9393be2e4b chore(release): refresh generated release baselines 2026-05-15 15:57:01 +01:00
Peter Steinberger
4780e69352 fix(line): acknowledge webhooks before agent processing 2026-05-15 15:49:36 +01:00
Peter Steinberger
99dfb8291f fix(providers): preserve Kimi MiMo reasoning replay (#82170)
* fix(providers): preserve Kimi MiMo reasoning replay

* chore: rerun provider replay ci
2026-05-15 15:44:34 +01:00
Peter Steinberger
abbfd276ee ci(release): stringify candidate workflow fields 2026-05-15 15:43:43 +01:00
Peter Steinberger
d24a847279 test(doctor): type legacy compaction fixtures (#80645) 2026-05-15 15:33:27 +01:00
Peter Steinberger
76ec830c7a docs: add onboarding i18n changelog (#80645) (thanks @GaosCode) 2026-05-15 15:33:27 +01:00
Peter Steinberger
80b5a0138f test(zalouser): align history expectation after rebase 2026-05-15 15:33:27 +01:00
Peter Steinberger
40789da1ef fix(wizard): narrow setup i18n SDK surface 2026-05-15 15:33:27 +01:00
MrBrain
6472b05fad feat(plugins): localize channel setup wizards 2026-05-15 15:33:27 +01:00
MrBrain
bfc674876d feat(wizard): localize onboarding flows 2026-05-15 15:33:27 +01:00
MrBrain
d8ae3ec4c8 feat(wizard): add cli i18n catalog 2026-05-15 15:33:27 +01:00
Peter Steinberger
492f59e586 ci(release): preserve candidate JSON parse cause 2026-05-15 15:32:17 +01:00
Peter Steinberger
41810a462e fix(discord): suppress link embeds by default
* fix(discord): suppress link embeds by default

* fix(discord): handle missing stream config
2026-05-15 15:22:54 +01:00
Peter Steinberger
1b87ba8ca5 docs(codex): document native compaction behavior 2026-05-15 15:17:12 +01:00
Peter Steinberger
031655b933 fix(doctor): migrate codex compaction config 2026-05-15 15:17:12 +01:00
Peter Steinberger
934fc6ceeb fix(codex): keep app-server compaction native 2026-05-15 15:17:12 +01:00
Peter Steinberger
d61051558b ci(release): harden candidate workflow dispatch lookup 2026-05-15 15:10:34 +01:00
Peter Steinberger
adac07f1d8 ci(release): publish validation manifest on main 2026-05-15 14:55:59 +01:00
Peter Steinberger
c91e20ac0c ci(release): add candidate evidence checklist 2026-05-15 14:54:46 +01:00
Otto Deng
2d91a3b200 fix(gateway/approvals): treat turnSourceTo as optional in chat approval bridge (#82132)
canBridgeNoDeviceChatApprovalFromBackend used matchesRequiredString for
turnSourceTo, which returns false when expected is null. Channels without
a recipient concept (webchat, control-ui) leave turnSourceTo null on both
the approval snapshot and the replay params, so every backend
gateway-client replay was rejected with APPROVAL_CLIENT_MISMATCH after
the approval prompt was answered. turnSourceAccountId and turnSourceThreadId
in the same function already use matchesOptionalString for the same reason;
turnSourceTo was missed when PR #78728 added the helper.

Switch to matchesOptionalString so null-on-both-sides matches. Cross-channel
replay protection is preserved by the existing required turnSourceChannel
and sessionKey checks. Added a regression test asserting webchat replay
with null turnSourceTo is accepted.
2026-05-15 14:51:31 +01:00
Peter Steinberger
1e31bd2ac2 fix(codex): time out silent app-server turns 2026-05-15 14:46:33 +01:00
Peter Steinberger
111a17b6e8 chore: publish 2026.5.12 mac appcast 2026-05-15 14:37:36 +01:00
Yash Saliya
d91f58ee25 fix(message-tool): rename type schema property to avoid JSON Schema keyword collision (#78920)
Merged via squash.

Prepared head SHA: 669084aad8
Co-authored-by: YashSaliya <79741768+YashSaliya@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-15 16:29:56 +03:00
Peter Steinberger
f74436dc81 refactor: assemble channel contexts in core 2026-05-15 14:14:02 +01:00
Jerome Xu
8cc1aee9d8 fix(xiaomi): surface MiMo reasoning-only finals (#60304)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-15 14:12:44 +01:00
Peter Steinberger
bc461965a3 fix: document cron runtime plugin preload (#82111) 2026-05-15 14:04:56 +01:00
Peter Steinberger
38e53a89b2 fix(cron): align runtime plugin preload mode 2026-05-15 14:04:56 +01:00
郑苏波 (Super Zheng)
5779d485fd fix(cron): lazily load runtime plugins to fix external channel resolution
Ensure runtime plugins are loaded before resolving cron delivery context,
preventing multi-channel ambiguity errors when using external channels.
Implemented via a lazy facade to preserve fast isolated agent startup.
2026-05-15 14:04:56 +01:00
Peter Steinberger
6de8563827 refactor: centralize channel history window 2026-05-15 13:56:17 +01:00
Peter Steinberger
56303b96d0 fix(slack): clarify finalized draft guard 2026-05-15 13:48:55 +01:00
Neerav Makwana
2b7c150de3 fix(slack): preserve finalized draft after tool warning 2026-05-15 13:48:55 +01:00
Eden
b67bcd93cc fix(twitch): keep account monitor alive until abort (#81853)
Summary:
- Keep Twitch startAccount alive until abort via runStoppablePassiveMonitor.
- Add lifecycle regression coverage and env-gated live Twitch IRC proof.
- Add changelog credit for #60071 / #81853.

Verification:
- pnpm test extensions/twitch/src/plugin.lifecycle.test.ts extensions/twitch/src/plugin.test.ts extensions/twitch/src/twitch-client.test.ts src/gateway/server-channels.test.ts
- pnpm exec oxfmt --check --threads=1 extensions/twitch/src/plugin.ts extensions/twitch/src/plugin.lifecycle.test.ts extensions/twitch/src/plugin.live.test.ts CHANGELOG.md
- pnpm test:live -- extensions/twitch/src/plugin.live.test.ts (skipped without Twitch live credentials)
- codex-review --mode branch --parallel-tests targeted Twitch/gateway tests
- GitHub checks on aea52056c6 green

Fixes #60071.

Co-authored-by: 許元豪 <146086744+edenfunf@users.noreply.github.com>
2026-05-15 13:47:10 +01:00
Peter Steinberger
e0f7dafcea docs: require codex review before landing 2026-05-15 13:41:34 +01:00
Peter Steinberger
2ea0c6c929 docs(slack): align unfurl default docs (#82123) 2026-05-15 13:25:52 +01:00
Kibi
cb695b0986 fix(slack): default unfurl_links to false for outbound messages
Slack link unfurls (inline message previews) are enabled by default
when unfurl_links is not explicitly set in chat.postMessage. This means
bot messages containing Slack message links or URLs automatically expand
into rich preview cards, which can be noisy in channels.

Default unfurl_links to false so outbound messages don't show inline
link previews unless the operator explicitly opts in via:

  channels.slack.unfurlLinks: true

unfurlMedia remains opt-in (only sent when explicitly configured).
2026-05-15 13:25:52 +01:00
Peter Steinberger
b4f6cb29b8 fix(slack): break modal routing import cycle 2026-05-15 13:18:55 +01:00
Peter Steinberger
d89732efca fix(slack): route plugin modal submissions
Co-authored-by: shannon0430 <258282406+shannon0430@users.noreply.github.com>

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>

Co-authored-by: Jin Kim <198280395+jink-ucla@users.noreply.github.com>
2026-05-15 13:18:55 +01:00
Peter Steinberger
cda4689d71 fix(auto-reply): document silent reply fallback fix (#82086) (thanks @taozengabc) 2026-05-15 13:18:16 +01:00
Peter Steinberger
391b4916dc fix(auto-reply): cover surface silent reply fallback 2026-05-15 13:18:16 +01:00
taozengabc
a541aa3b0b fix(auto-reply): honor silentReply policy on group failure-fallback path
Threads the runtime config through buildKnownAgentRunFailureReplyPayload
into resolveExternalRunFailureTextForConversation so the documented
agents.defaults.silentReply / surfaces.<id>.silentReply policy is
consulted before silencing failure copy in groups/channels. Default
policy (group: allow, direct: disallow, internal: allow) preserves the
existing 'groups stay quiet on generic runner failure' behavior; opting
into silentReply.group: disallow now lets the run-failure copy reach
the chat instead of disappearing.

Resolves an internal inconsistency: route-reply.ts already routes
NO_REPLY-style payloads through resolveSilentReplyPolicy(), but the
failure-fallback path in agent-runner-execution.ts hardcoded silence on
chat type alone, ignoring the operator-visible knob.

Refs #82060.
2026-05-15 13:18:16 +01:00
Peter Steinberger
2a02d83e2e refactor: record dropped channel history in turn kernel 2026-05-15 13:06:25 +01:00
Peter Steinberger
8859e89e07 feat: attach recent inbound history images to agent turns (#82068)
* feat: attach recent inbound history images

* fix: bound recent history media downloads

* fix: preserve sticker history media

* fix: enforce history media cap for stickers

* refactor: name agent turn attachments generically

* refactor: share pending history media recording

* fix: gate historical media attachment visibility

* fix: avoid media runtime on text-only turns

* fix: preserve fallback history media selection

* fix: avoid sparse media history index collisions

* fix: skip history images for current non-image media

* test: import history media type directly

* test: satisfy agent media runtime mock lint

* fix: respect mocked Slack media fetches

* fix: settle history media recording races
2026-05-15 12:41:52 +01:00
Peter Steinberger
2d8339529b fix: preserve reasoning_content replay for MiMo proxies 2026-05-15 12:35:44 +01:00
Jim Dawdy
aeb06bf4ef fix(agents): apply MiMo reasoning_content fallback wrapper for unowned proxy providers 2026-05-15 12:35:44 +01:00
Jim Dawdy
795ad845d6 fix(xiaomi): address review findings — remove speculative models, add xiaomi-native to native+nonstandard lists, test host resolution 2026-05-15 12:35:44 +01:00
Jim Dawdy
d00cd314d1 fix(transport): drop compat override for requiresReasoningContentOnAssistantMessages (detection-only field) 2026-05-15 12:35:44 +01:00
Jim Dawdy
7958eb0fc4 test(xiaomi): add MiMo thinking profile, stream wrapper, and reasoning_content injection tests 2026-05-15 12:35:44 +01:00
Jim Dawdy
f97645428e feat(xiaomi): register wrapStreamFn, resolveThinkingProfile, isModernModelRef, and replay hooks 2026-05-15 12:35:44 +01:00
Jim Dawdy
e3ad37c24f feat(xiaomi): add MiMo thinking profile and stream wrapper 2026-05-15 12:35:44 +01:00
Jim Dawdy
0dc34ca171 feat(xiaomi): add providerEndpoints for xiaomi-native and mimo-v2.5 model entries 2026-05-15 12:35:44 +01:00
Jim Dawdy
d4c83edba8 fix(transport): propagate requiresReasoningContentOnAssistantMessages to convertMessages 2026-05-15 12:35:44 +01:00
Jim Dawdy
e6dc6c52fe fix(compat): detect xiaomi-native endpoints, set deepseek thinkingFormat and requiresReasoningContentOnAssistantMessages 2026-05-15 12:35:44 +01:00
Jim Dawdy
215e43aa94 fix(transport): add xiaomi-native to ProviderEndpointClass and manifest endpoint classes 2026-05-15 12:35:44 +01:00
Peter Steinberger
e360e105a3 fix: require web search query schema 2026-05-15 12:32:52 +01:00
Peter Steinberger
f06e9f6358 fix(release): keep TypeScript compiler external 2026-05-15 12:32:33 +01:00
Peter Steinberger
b3d9bef38d [codex] Fix Codex OAuth refresh fallback (#82117)
* fix: fall back to Codex CLI OAuth after refresh failure

* fix: support Codex CLI fallback for named profiles
2026-05-15 12:32:00 +01:00
Peter Steinberger
b6809b5e31 fix(gateway): keep config schema admin scoped 2026-05-15 12:25:31 +01:00
Peter Steinberger
8ff722fe7d docs: update changelog for gateway methods (#82063) 2026-05-15 12:25:31 +01:00
Peter Steinberger
3bedce151e fix(gateway): keep exec approvals policy admin scoped 2026-05-15 12:25:31 +01:00
Peter Steinberger
373f709130 fix(gateway): preserve core method collision guards 2026-05-15 12:25:31 +01:00
Peter Steinberger
a383baac03 test(logging): fix stalled recovery threshold test 2026-05-15 12:25:31 +01:00
Peter Steinberger
93b9223bee fix(plugins): tolerate legacy inspect reports 2026-05-15 12:25:31 +01:00
Peter Steinberger
4aa37c3261 fix(gateway): allow partial method registries 2026-05-15 12:25:31 +01:00
Peter Steinberger
db3c4ba8d3 refactor(gateway): collapse method metadata shims 2026-05-15 12:25:31 +01:00
Peter Steinberger
7c639d4b46 fix(gateway): accept legacy plugin registries 2026-05-15 12:25:31 +01:00
Peter Steinberger
fb7dc43043 fix(gateway): preserve lazy method boundaries 2026-05-15 12:25:31 +01:00
Peter Steinberger
386fbd6594 fix(gateway): preserve advertised method ordering 2026-05-15 12:25:31 +01:00
Peter Steinberger
e4a1032072 style(gateway): avoid method list spread allocations 2026-05-15 12:25:31 +01:00
Peter Steinberger
622728757f refactor(gateway): add method descriptor registry 2026-05-15 12:25:31 +01:00
Ayaan Zaidi
b2d04646c1 ci(mantis): run telegram proof agent faster 2026-05-15 16:54:58 +05:30
Ayaan Zaidi
f04d20f8f9 ci(mantis): allow non-visual telegram proof skips 2026-05-15 16:54:58 +05:30
Peter Steinberger
c0fe7ab34a fix: keep queued system event authority structured
Keep queued system-event owner downgrades as structured runtime metadata while rendering the model-visible prompt as plain `System:` lines.

This preserves least-privilege wakeups for webhook/node/exec/cron/reaction/hook producers, keeps legacy `trusted: false` compatibility for installed plugins and older hosts, and updates representative gateway, agent, cron, plugin, and OpenGrep coverage.
2026-05-15 12:24:27 +01:00
Val Alexander
2ac011b8ae fix(ui): repair chat composer usability
Fix the WebChat composer regression reported in #45656 by focusing the textarea from non-control composer chrome clicks and restoring larger labeled desktop composer controls while preserving compact mobile taps.

Verification:
- pnpm test ui/src/ui/views/chat.test.ts ui/src/ui/chat/run-controls.test.ts ui/src/styles/chat/layout.test.ts
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/ui/views/chat.ts ui/src/ui/views/chat.test.ts ui/src/ui/chat/run-controls.ts ui/src/ui/chat/run-controls.test.ts ui/src/styles/chat/layout.css ui/src/styles/chat/layout.test.ts
- git diff --check origin/main...HEAD
- pnpm changed:lanes --json
- pnpm lint:core
- pnpm ui:build
- gh pr checks 82120 --repo openclaw/openclaw --watch=false
- ClawSweeper review completed successfully: https://github.com/openclaw/clawsweeper/actions/runs/25914298634

Closes #45656
2026-05-15 06:07:12 -05:00
civil
c8d53fdf1b docs: credit STT WAV transcode contributor (#82110)
Credit contributor PR #82110 in the existing Audio/STT changelog entry after the ffmpeg muxer fix landed on main.

Verification:
- /Users/steipete/Projects/agent-scripts/skills/codex-review/scripts/codex-review --mode branch
- node scripts/run-vitest.mjs src/media-understanding/apply.test.ts src/media-understanding/runner.cli-audio.test.ts
- gh pr checks 82110 --repo openclaw/openclaw --watch --interval 10
2026-05-15 12:04:19 +01:00
Peter Steinberger
b2dfa98877 docs: credit OpenRouter reasoning replay fix 2026-05-15 11:59:07 +01:00
Peter Steinberger
3537d8a613 fix: preserve valid completions reasoning replay 2026-05-15 11:59:07 +01:00
sliverp
8bfb943945 fix: strip response-only reasoning fields from OpenAI Completions requests
Prevents providers like OpenRouter from returning HTTP 500 errors when replayed assistant messages include fields such as `reasoning_details`.
2026-05-15 11:59:07 +01:00
Peter Steinberger
a1a6cd6508 refactor: centralize inbound history shaping
Centralize inbound history shaping through shared reply-history helpers and preserve existing channel behavior.
2026-05-15 11:56:38 +01:00
Peter Steinberger
f686bb519f fix: force ffmpeg muxers for staged audio outputs
* fix: force ffmpeg muxers for staged audio outputs

* docs: clarify staged audio changelog
2026-05-15 11:56:12 +01:00
Ayaan Zaidi
f1b92c8885 fix(mantis): publish evidence to r2 (#81845)
* fix(mantis): publish evidence to r2

* ci(mantis): pass r2 artifact credentials

* ci(mantis): pin artifact bucket config

* fix(mantis): link raw evidence index
2026-05-15 16:23:53 +05:30
solodmd
239def7838 perf(skills): cache hydrated resolved skills (#81451)
Merged via squash.

Prepared head SHA: e202d16e50
Co-authored-by: solodmd <51304754+solodmd@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-15 13:48:22 +03:00
Peter Steinberger
cd91bd9a1e docs: document admin HTTP RPC plugin 2026-05-15 11:44:58 +01:00
Peter Steinberger
764cfd5552 feat: add bundled admin HTTP RPC plugin 2026-05-15 11:44:58 +01:00
Peter Steinberger
dfeaf6f7cf refactor: add gateway method dispatch contract 2026-05-15 11:44:58 +01:00
Peter Steinberger
cd9b2c0af4 fix: restore voice media uploads 2026-05-15 11:35:34 +01:00
Peter Steinberger
0e5f4ea18c perf: reuse manifest metadata for read-only model catalogs 2026-05-15 11:24:06 +01:00
Frank Yang
b04e42812e fix(memory): stop watcher write-polling fd pressure (#81802)
Merged via squash.

Prepared head SHA: 623874619b
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Reviewed-by: @frankekn
2026-05-15 18:12:29 +08:00
Peter Steinberger
21b6dcbe37 fix: restore Discord voice Ogg transcoding 2026-05-15 11:01:15 +01:00
Kaspre
44840007d4 fix(agents): scope custom provider baseUrl SSRF trust by origin (#80751)
* fix(agents): scope provider SSRF trust by origin

* fix(provider): preserve explicit private-network deny

* docs(provider): document exact-origin SSRF trust

* test(provider): cover exact-origin SSRF edges

* docs(provider): align local model private-origin guidance

* refactor(ssrf): keep policy merging in infra

* test(ssrf): cover exact-origin trust through guard

* test(ssrf): block sibling private-origin redirects

* fix(provider): keep loopback trust origin-scoped

* fix(provider): block metadata origin trust

* fix(ssrf): keep metadata rebinding blocked

* fix(ssrf): block cloud metadata origins

* fix(ssrf): block ipv6 metadata origins

* fix(ssrf): block embedded metadata origins

* test(ssrf): cover embedded link-local metadata

* test(provider): cover custom anthropic proxy classification

* test(provider): widen transport policy mock

* test(plugin-sdk): assert metadata-IP allowedOrigins entries are rejected

Plugin authors can construct an SsrFPolicy that lists any well-formed
http(s) origin in allowedOrigins. The abuse-resistance lives one layer
deeper, in resolvePinnedHostnameWithPolicy's metadata/link-local block.
Add an SDK-level smoke test asserting that contract directly:

- AWS/Alibaba IMDS IPv4 literals, GCP metadata canonical hostname,
  IPv6 ULA metadata literal, and non-metadata link-local IPv4 entries
  build a policy via ssrfPolicyFromHttpBaseUrlAllowedOrigin and are
  then rejected at resolvePinnedHostnameWithPolicy.
- DNS rebinding from a trusted private DNS origin to a metadata IP is
  rejected even when the request hostname is origin-trusted.

This would fail if the SDK helper or resolveSsrFPolicyForUrl ever
short-circuited past the metadata block.

* chore(docs): regenerate baselines after upstream rebase

upstream/main moved between rebases; the merged source state for the
PR's `src/config/schema.help.ts` change and the upstream plugin-sdk
surface changes both produce different hashes than the committed
baselines, so `config:docs:check` and `plugin-sdk:api:check` would fail.

Regenerated via `pnpm config:docs:gen` + `pnpm plugin-sdk:api:gen` on
Crabbox; both baselines verified with their respective `--check`
generators.

* test(plugin-sdk): assert SSRF blocked error class

* fix(lint): satisfy exact-origin PR lint rules

* docs: clarify custom provider origin trust

* chore(docs): refresh plugin sdk api baseline

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-15 11:00:29 +01:00
Peter Steinberger
778ad09ff2 test(logging): derive diagnostic abort threshold 2026-05-15 10:38:43 +01:00
Peter Steinberger
582f834269 test(sdk): refresh command facts API baseline 2026-05-15 10:38:43 +01:00
Peter Steinberger
fc5349688f test(agents): update command turn prompt snapshots 2026-05-15 10:38:43 +01:00
Peter Steinberger
3b1497789c refactor(channels): derive command turns from turn facts 2026-05-15 10:38:43 +01:00
Pavan Kumar Gondhi
b9fbc57bbd Bind shell script operands after combined options [AI] (#81882)
* fix: bind shell script operands after combined options

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-15 14:55:37 +05:30
Pavan Kumar Gondhi
238b0fc76f fix(canvas): validate snapshot response formats [AI] (#81881)
* fix: validate canvas snapshot formats

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-15 14:51:38 +05:30
Peter Steinberger
e30be460e1 fix: shorten stalled Codex recovery window 2026-05-15 10:19:37 +01:00
Pavan Kumar Gondhi
eb1e6099d2 Constrain provider catalog entry paths [AI] (#81884)
* fix: constrain provider catalog entries to plugin root

* addressing review-skill

* docs: add changelog entry for PR merge
2026-05-15 14:48:24 +05:30
Pavan Kumar Gondhi
d656087b31 Require canonical node platform IDs [AI] (#81880)
* fix: require canonical node platform ids

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* fix: require consistent node platform metadata

* addressing review-skill

* addressing codex review

* fix: complete root-cause handling

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-15 14:46:46 +05:30
Peter Steinberger
df70ed2b9c fix: force message through empty allowlists 2026-05-15 10:16:27 +01:00
Peter Steinberger
63ad5b4f97 fix: send structured message attachments 2026-05-15 10:16:27 +01:00
Peter Steinberger
3fd4b02eb5 fix: track message attachment aliases 2026-05-15 10:16:27 +01:00
Peter Steinberger
24e88bcdd1 fix: narrow forced message tool inclusion 2026-05-15 10:16:27 +01:00
Peter Steinberger
8650f4ba19 fix: force message tool for source delivery mode 2026-05-15 10:16:27 +01:00
Peter Steinberger
3b2fb9e63d fix: use message mediaUrl attachment hints 2026-05-15 10:16:27 +01:00
Peter Steinberger
9bad29261d fix: preserve forced message tool allowlists 2026-05-15 10:16:27 +01:00
Peter Steinberger
55322d7301 fix: deliver generated media as structured attachments 2026-05-15 10:16:27 +01:00
Peter Steinberger
9d51d2a8b8 docs: credit protocol validator lazy compile (#82064) 2026-05-15 10:16:19 +01:00
samzong
5121f30d2d fix(gateway): lazy compile protocol validators
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-15 10:16:19 +01:00
Val Alexander
28f59a9124 fix(ui): align chat header controls
Summary:
- Align WebChat desktop header controls to a compact 44px header and 36px control rhythm.
- Replace the auto-scroll text dropdown with an icon toggle that keeps tooltip, title, aria-label, and pressed state.
- Lay out mobile chat action icons as a five-column full-width grid.

Verification:
- git diff --check origin/main...HEAD
- pnpm changed:lanes --json
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/ui/app-render.helpers.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/styles/layout.css ui/src/styles/layout.mobile.css ui/src/styles/chat/layout.css ui/src/styles/chat/layout.test.ts ui/src/styles/layout.mobile.test.ts
- pnpm lint:core
- pnpm test ui/src/styles/chat/layout.test.ts ui/src/styles/layout.mobile.test.ts ui/src/ui/app-render.helpers.browser.test.ts
- pnpm ui:build
- Browser proof at desktop 1200x760 and mobile 390x844
- Exact-head GitHub CI green for a25444c5fa
2026-05-15 04:03:34 -05:00
Peter Steinberger
ec9d56601a test: add Gemini subagent stress e2e 2026-05-15 10:01:29 +01:00
Peter Steinberger
b180b8ae48 fix: strip workflow function responses from replies 2026-05-15 09:57:44 +01:00
clawsweeper[bot]
a099acc557 fix: update Azure OpenAI API version default to preview (#82072)
Summary:
- The branch changes the Azure OpenAI Responses transport default API version from `2024-12-01-preview` to `preview`, updates the focused unit assertion, and adds a changelog entry.
- Reproducibility: yes. The source PR provides live Azure curl/OpenClaw commands showing dated defaults fail w ...  `api-version=preview` succeeds, and current main still resolves an unset env var to the old dated default.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: update DEFAULT_AZURE_OPENAI_API_VERSION to 2025-04-01-preview (i…
- PR branch already contained follow-up commit before automerge: fix: use preview literal for AZURE_OPENAI_API_VERSION
- PR branch already contained follow-up commit before automerge: fix: repair Azure API version PR diff and tests
- PR branch already contained follow-up commit before automerge: fix: keep Azure image API version default
- PR branch already contained follow-up commit before automerge: fix: update Azure OpenAI API version default to preview

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

Prepared head SHA: d7062f162f
Review: https://github.com/openclaw/openclaw/pull/82072#issuecomment-4458291270

Co-authored-by: Leo Ge <116452300+leoge007@users.noreply.github.com>
Co-authored-by: leoge007 <leoge@users.noreply.github.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
2026-05-15 08:42:36 +00:00
Peter Steinberger
06e79b2762 fix: harden response format forwarding 2026-05-15 09:40:06 +01:00
lellansin
8503418274 feat(gateway): forward response format params 2026-05-15 09:40:06 +01:00
Peter Steinberger
be166b9ae4 fix(agent): retry empty anthropic-compatible replies 2026-05-15 08:52:10 +01:00
Val Alexander
930852af29 feat(agents): support per-agent bootstrap profiles
Summary:\n- Add optional per-agent bootstrap profile overrides for contextInjection, bootstrapMaxChars, and bootstrapTotalMaxChars.\n- Resolve per-agent bootstrap profile settings before agents.defaults and thread the resolved session agent through embedded, compact, CLI, and /context diagnostic paths.\n- Update schema/help/docs/changelog plus focused runtime, schema, and /context regression coverage.\n\nVerification:\n- Local focused auto-reply tests and formatter checks passed.\n- Local pnpm check:changed passed before landing follow-ups.\n- Local Node 24 pnpm check:test-types passed after merging latest main into the PR branch.\n- GitHub PR state CLEAN at 0ff12062840f42daf2666c5fabb127c3f7631669.\n- ClawSweeper re-review completed successfully with no actionable repair finding.\n\nFixes #69966.
2026-05-15 02:42:21 -05:00
Peter Steinberger
64d4f99d26 refactor(auto-reply): centralize command turn context
* refactor(auto-reply): centralize command turn context

* fix(channels): narrow command turn context literals

* fix(auto-reply): preserve command auth on refinalize

* fix(auto-reply): keep command turn context sdk-compatible

* fix(auto-reply): route structured command turns before reply setup

* test(cli): type stale launchd job mock
2026-05-15 08:41:09 +01:00
Peter Steinberger
f4d90eb36a test: guard Telegram grammY type imports 2026-05-15 08:38:44 +01:00
Val Alexander
5f89cabeb5 fix(macos): harden screen.snapshot validation and payload bounds
Fixes #68181.

Rejects malformed macOS screen.snapshot params before capture, sanitizes capture failures, and bounds inline base64 snapshot responses against the projected node.invoke.result frame size.

Supersedes #68186.
2026-05-15 02:27:33 -05:00
Peter Steinberger
66ba611f5b docs: update changelog for discord config fixes 2026-05-15 08:23:31 +01:00
Gio Della-Libera
6623444f8d fix(discord): report unresolved token refs at startup (#82009)
Treat configured-but-unresolved Discord token refs as configured so gateway startup reaches the explicit SecretRef resolution error instead of silently classifying the account as unconfigured. Also cover runtime snapshot resolution for active Discord token refs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-15 08:22:47 +01:00
Peter Steinberger
7acbb2260c fix(mac): surface stale updater launchd jobs 2026-05-15 08:20:55 +01:00
Gio Della-Libera
0dc8552cb3 fix(config): preserve numeric patch object keys (#81999)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-15 08:20:08 +01:00
Peter Steinberger
bea597b2d6 fix(discord): clear failed partial preview finals 2026-05-15 08:12:51 +01:00
Peter Steinberger
1458829822 fix: serialize stale auth shadow repair 2026-05-15 08:10:44 +01:00
Val Alexander
396d5b26da docs: record sidebar markdown copy fix 2026-05-15 02:07:42 -05:00
tikitoki
e1d69bc433 fix(ui): enable sidebar markdown code copying
Summary:
- Add the existing delegated markdown code-block copy handler to the Control UI chat sidebar container.
- Fix sidebar-rendered markdown code copy buttons that previously emitted no clipboard write because `.chat-sidebar` sits outside `.chat-thread`.

Verification:
- Unpatched current `origin/main` (`b24a6d2cbd636b0b39b732c962d58e574c748abe`) + temporary regression assertion: `pnpm test ui/src/ui/views/chat.test.ts -t "chat sidebar markdown copy"` failed with 0 `navigator.clipboard.writeText` calls.
- PR patch applied onto current `origin/main` + same temporary regression assertion: `pnpm test ui/src/ui/views/chat.test.ts -t "chat sidebar markdown copy"` passed, 1 test passed and 32 skipped.
- Live PR state before merge: `MERGEABLE`, `CLEAN`, head `2e04e981e992b32920476edc648009ddff7976d0`.
- Duplicate sweep found no same-failure duplicate PR/issue.
- Security check clear: UI event binding only; no dependency, workflow, auth, secret, network, or command-execution surface changes.

Known proof gap:
- No full browser walkthrough was run; the focused jsdom proof covers the exact DOM delegation boundary.

Thanks @tikitoki.
2026-05-15 02:05:04 -05:00
Peter Steinberger
b24a6d2cbd fix(control-ui): rotate service worker cache per build (#82050) 2026-05-15 07:59:29 +01:00
github-actions[bot]
925861f9b3 chore(ui): refresh fa control ui locale 2026-05-15 06:56:27 +00:00
github-actions[bot]
aff30f9671 chore(ui): refresh nl control ui locale 2026-05-15 06:56:20 +00:00
github-actions[bot]
fa43ed33d8 chore(ui): refresh th control ui locale 2026-05-15 06:56:01 +00:00
github-actions[bot]
7c39d0d60c chore(ui): refresh vi control ui locale 2026-05-15 06:55:52 +00:00
github-actions[bot]
c1eb1ba7cd chore(ui): refresh pl control ui locale 2026-05-15 06:55:49 +00:00
github-actions[bot]
8e515e5fa8 chore(ui): refresh id control ui locale 2026-05-15 06:55:44 +00:00
github-actions[bot]
d6cb0e5adf chore(ui): refresh ar control ui locale 2026-05-15 06:55:22 +00:00
github-actions[bot]
e5a3e3b357 chore(ui): refresh uk control ui locale 2026-05-15 06:55:16 +00:00
github-actions[bot]
fb87c0b470 chore(ui): refresh tr control ui locale 2026-05-15 06:55:10 +00:00
github-actions[bot]
45c3faeb1e chore(ui): refresh it control ui locale 2026-05-15 06:55:01 +00:00
github-actions[bot]
b521dae2ec chore(ui): refresh fr control ui locale 2026-05-15 06:54:45 +00:00
github-actions[bot]
3f0c875e4c chore(ui): refresh ko control ui locale 2026-05-15 06:54:34 +00:00
github-actions[bot]
9fdd7c56b9 chore(ui): refresh es control ui locale 2026-05-15 06:54:31 +00:00
github-actions[bot]
3a0029a297 chore(ui): refresh ja-JP control ui locale 2026-05-15 06:54:29 +00:00
github-actions[bot]
a1ee350cc9 chore(ui): refresh de control ui locale 2026-05-15 06:54:01 +00:00
github-actions[bot]
3146470ee1 chore(ui): refresh zh-CN control ui locale 2026-05-15 06:53:56 +00:00
github-actions[bot]
c3dc015cac chore(ui): refresh zh-TW control ui locale 2026-05-15 06:53:52 +00:00
github-actions[bot]
599432b5a7 chore(ui): refresh pt-BR control ui locale 2026-05-15 06:53:47 +00:00
Peter Steinberger
65aa6c8a77 test(ci): update installer sync workflow assertion 2026-05-15 07:52:01 +01:00
zhulijin1991
2e2da1f2b9 fix(ci): unblock scheduled and publish checks 2026-05-15 07:52:01 +01:00
Peter Steinberger
1109abc947 fix: align Telegram grammY type imports (#81975) 2026-05-15 07:50:47 +01:00
Peter Steinberger
91f01b7664 fix: document Telegram isolated polling init (#81975) (thanks @neeravmakwana) 2026-05-15 07:50:47 +01:00
Neerav Makwana
de48410384 test(telegram): name isolated init regression
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 07:50:47 +01:00
Neerav Makwana
0beae266da fix(telegram): initialize isolated polling bot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 07:50:47 +01:00
Peter Steinberger
916fc3d09a test: keep update mock persisted hash order 2026-05-15 07:32:29 +01:00
Peter Steinberger
7bc73ded71 test: remove duplicate persisted hash mock keys 2026-05-15 07:32:29 +01:00
Peter Steinberger
9f211bb802 test: align update mocks with persisted config hash 2026-05-15 07:32:29 +01:00
Peter Steinberger
b830beb34b fix: surface update restart and plugin repair guidance 2026-05-15 07:32:29 +01:00
Galin Iliev
0cbd2d3b08 fix(ui): wrap long inline code in chat bubbles (#81931)
Wrap long inline code tokens inside chat bubbles so unbroken paths and identifiers stay within the message bubble.\n\nFixes #81932.
2026-05-14 23:31:45 -07:00
Peter Steinberger
4a188e7ca5 chore: update dependencies 2026-05-15 07:28:28 +01:00
Peter Steinberger
2645492fde test: cover sync clobber snapshot collisions 2026-05-15 07:12:57 +01:00
Kaspre
5734193fdf fix(plugins): keep metadata snapshot memo fresh
* fix(plugins): keep metadata memo freshness

* fix(plugins): keep metadata memo freshness

* fix(plugins): resolve metadata memo review gaps

* fix(plugins): scope metadata memo watches to env

* fix(plugins): tighten metadata memo fingerprint return type

`resolvePersistedRegistryFastMemoFingerprint` was annotated `: unknown`
but always returns object literals (`{ disabled: true }` or
`{ index, npmPackageJson }`). Spreading the unknown-typed result on
line 478 (`...fastFingerprint`) was rejected by tsgo with TS2698, which
cascaded across every check that runs the project compile (build,
tsgo:prod, check:test-types, lint, all node test shards).

Tighten the return type to `Record<string, unknown>` to match the
function's actual return shapes and unblock the spread.

* test(gateway): tolerate ENOENT in sessions.list spy predicate

The `sessions.list configuredAgentsOnly hides disk-discovered
unregistered agent stores` test spies on `fsSync.readFileSync` and
predicates with `fsSync.realpathSync.native(file) === realDiskOnlyStorePath`
for every captured read. The native realpath call throws on missing
files, so any new readFileSync of a path that may not exist (e.g. the
persisted plugin install records probe added in this PR) crashes the
predicate before the assertion runs.

Wrap the predicate in ENOENT tolerance so the test stays robust against
any future readFileSync of files that may not exist on disk.

* fix(plugins): refresh memo from cached registry

* fix(plugins): use high resolution memo fingerprints

* test(plugins): stabilize memo freshness regression

* test(cli): satisfy config mutation mock hash contract

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-15 07:12:31 +01:00
Val Alexander
7289e14dae fix(ui): keep PWA chat controls above iOS home indicator
Fix the active Control UI WebChat composer path so mobile standalone PWA layouts keep the toolbar above the iOS home indicator even when safe-area insets under-report.

- apply the mobile safe-area composer margin in the later-loading chat layout stylesheet
- add a standalone PWA defensive floor for broken zero safe-area reports
- cover the CSS contract with focused regression coverage

Verification:
- corepack pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/styles/chat/layout.css ui/src/styles/chat/layout.test.ts
- git diff --check
- corepack pnpm test ui/src/styles/chat/layout.test.ts ui/src/ui/chat/chat-responsive.browser.test.ts -- --reporter=verbose
- corepack pnpm check:changed
- GitHub CI green on exact head b2b6007f43

Fixes #77408.

Thanks @BunsDev.
2026-05-15 01:04:28 -05:00
samzong
87724c964f refactor(config): split channel schema imports (#82007)
Split generic channel config schema out of the provider schema barrel so OpenClawSchema no longer imports provider-specific channel schemas for generic channel defaults validation.

Co-authored-by: samzong <samzong.lu@gmail.com>
2026-05-15 07:02:02 +01:00
Peter Steinberger
59d2e7686c refactor: centralize live provider drift policy (#82033) 2026-05-15 06:57:00 +01:00
Peter Steinberger
7e9a863423 test(update): model finalize channel rewrite snapshots 2026-05-15 06:55:04 +01:00
Peter Steinberger
c5ca8a17ce docs(skills): add release ci workflow skill 2026-05-15 06:55:04 +01:00
Peter Steinberger
a543d21352 fix(test): give anthropic cache probes more output budget 2026-05-15 06:55:04 +01:00
Peter Steinberger
41992581b8 fix(test): tolerate cache probes with usage-only output 2026-05-15 06:55:04 +01:00
Peter Steinberger
5f8200e6e8 fix(test): stabilize anthropic cache probe output 2026-05-15 06:55:03 +01:00
Peter Steinberger
cc129a0dd3 fix(update): refresh config after package doctor 2026-05-15 06:55:03 +01:00
Peter Steinberger
f1deb53d43 fix(release): unblock full validation 2026-05-15 06:55:03 +01:00
Peter Steinberger
93c799eb16 test(release): tolerate generated Slack scan artifact 2026-05-15 06:55:03 +01:00
Peter Steinberger
942334f97d test(release): update plugin prerelease assertions 2026-05-15 06:55:03 +01:00
Peter Steinberger
cdc9a380d1 docs: update changelog for canvas lazy-load (#82001) 2026-05-15 06:54:28 +01:00
samzong
a4cd482488 refactor(canvas): lazy-load startup modules
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-15 06:54:28 +01:00
Peter Steinberger
510628ca6f fix: refine clobber snapshot rotation (#82012) 2026-05-15 06:48:03 +01:00
Kaspre
57e699a09a fix(config): rotate clobber snapshots at cap 2026-05-15 06:48:03 +01:00
Peter Steinberger
de18f77737 refactor(cron): centralize agent phase watchdog state 2026-05-15 06:42:45 +01:00
Peter Steinberger
1713930bbe fix(opencode-go): strip Kimi reasoning payloads 2026-05-15 06:42:19 +01:00
alexph-dev
d471540ceb fix: harden telegram html fallback text (#81764)
Harden Telegram HTML parse fallback so plain-text retries render readable labels and links instead of raw anchors.

Co-authored-by: Sam (OpenClaw) <sam.kpg5stars@gmail.com>
2026-05-15 06:40:17 +01:00
Peter Steinberger
c462e68df7 fix: repair stale auth shadows and status plugin failures 2026-05-15 06:39:38 +01:00
Peter Steinberger
4d28450312 refactor: share channel status read model
Share channel status read-model helpers across channels list and status-all.
2026-05-15 06:39:18 +01:00
Peter Steinberger
aedcfa76a4 fix(cron): classify dispatch milestones for watchdog (#81871) 2026-05-15 06:27:04 +01:00
Sam (OpenClaw)
11984c7997 fix(cron): treat attempt dispatch as execution start 2026-05-15 06:27:04 +01:00
Peter Steinberger
42f6d90917 fix(telegram): share API request timeout wrapper 2026-05-15 06:17:06 +01:00
Baris Albayrak
1139777765 fix(whatsapp): mark text slash commands as command turns
* fix(whatsapp): mark text slash commands as command turns

* fix(ci): clear PR 81972 gates

* fix(msteams): wrap graph JSON parse errors

* docs: add WhatsApp slash command changelog

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-15 06:13:38 +01:00
B.K.
22a0ca9e3b fix: hand off managed update run self-updates
Route managed LaunchAgent package self-updates through the post-exit CLI handoff path and persist handoff helper failures through the update restart sentinel so agent-invoked updates cannot stay pending indefinitely.

Add handoff ownership guards for stale helpers, atomic helper sentinel writes, and regression coverage for unrelated and newer pending sentinels.

Fixes #81894.

Co-authored-by: B.K. <bandark@mac.com>
2026-05-15 06:12:57 +01:00
Peter Steinberger
7db44b979f test: tolerate provider account drift in live CI 2026-05-15 06:07:58 +01:00
Peter Steinberger
b672be59ae fix(channels): prefer runtime status in channel list (#82016) 2026-05-15 05:42:10 +01:00
Peter Steinberger
7e7ce53e5a docs(changelog): fold 2026.5.9 into 2026.5.12 2026-05-15 05:40:25 +01:00
Peter Steinberger
4505a88d88 fix(agents): preserve fallback trace truth 2026-05-15 05:13:35 +01:00
Peter Steinberger
dae90067e9 docs: note git installer ref fix (#81875) (thanks @keshavbotagent) 2026-05-15 05:11:35 +01:00
Peter Steinberger
a9aafc84b1 fix: fetch git installer branch refs without tags 2026-05-15 05:11:35 +01:00
Keshav's Bot
b26dcb3390 fix: scope git installer lockfile refresh 2026-05-15 05:11:35 +01:00
Keshav's Bot
36411cde8f fix: let git installer refresh lockfile 2026-05-15 05:11:35 +01:00
Keshav's Bot
e72c849359 fix: make installer pnpm install noninteractive 2026-05-15 05:11:35 +01:00
Keshav's Bot
0d22fbf312 fix: avoid tag fetch for main installer ref 2026-05-15 05:11:35 +01:00
Peter Steinberger
f12e9c41fa fix(codex): inject app-server client factories
Co-authored-by: Benjamin Badejo <ben@benbadejo.com>
2026-05-15 05:03:28 +01:00
Peter Steinberger
0db0979365 fix: harden code mode runtime 2026-05-15 04:16:07 +01:00
Peter Steinberger
204941c03e fix: register code mode worker dependency 2026-05-15 04:16:07 +01:00
Peter Steinberger
bf400c08c3 docs: mark code tool surfaces experimental 2026-05-15 04:16:07 +01:00
Peter Steinberger
8985cd596a fix: refresh code mode after rebase 2026-05-15 04:16:07 +01:00
Peter Steinberger
0844e771a8 feat: add generic code mode runtime 2026-05-15 04:16:07 +01:00
Val Alexander
346a773b18 fix(ui): remove duplicate Usage heading
Remove the local Usage view header now that the shared Control UI shell owns the page title, clean up the obsolete Usage subtitle locale key through the i18n sync pipeline, and add focused render coverage.

Fixes #45709.
Supersedes #67290 and #74238.

Verification:
- node scripts/run-vitest.mjs ui/src/ui/views/usage.test.ts ui/src/ui/views/usage-render-overview.test.ts ui/src/styles/usage.test.ts ui/src/i18n/test/translate.test.ts
- pnpm lint --threads=8
- pnpm ui:i18n:check
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/styles/usage.css ui/src/ui/views/usage.ts ui/src/ui/views/usage.test.ts ui/src/i18n/locales/*.ts
- git diff --check
- node scripts/run-vitest.mjs src/logging/logger-redaction-behavior.test.ts
- GitHub CI run 25895690773 passed after failed-job rerun
- Real behavior proof run 25895689499 passed

Head: f60e501a07
2026-05-14 20:50:44 -05:00
Maple778
2156b204ea fix(ui): align overview session labels
Summary:
- move session display-name resolution into a shared UI helper
- reuse that resolver for Overview recent sessions and chat session controls
- keep Telegram/channel fallback labels from leaking raw compound session keys into Overview

Verification:
- node scripts/run-vitest.mjs ui/src/ui/views/overview.render.test.ts ui/src/ui/app-render.helpers.node.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/ui/app-render.helpers.ts ui/src/ui/chat/session-controls.ts ui/src/ui/session-display.ts ui/src/ui/views/overview-cards.ts ui/src/ui/views/overview.render.test.ts CHANGELOG.md
- pnpm exec oxlint --tsconfig config/tsconfig/oxlint.core.json ui/src/ui/app-render.helpers.ts ui/src/ui/chat/session-controls.ts ui/src/ui/session-display.ts ui/src/ui/views/overview-cards.ts ui/src/ui/views/overview.render.test.ts src/commands/doctor/shared/legacy-config-core-normalizers.ts
- git diff --check origin/main...HEAD
- GitHub CI on 36fd998f66: check, check-lint, checks-node-core-ui, build-artifacts, Real behavior proof all passed
2026-05-14 20:40:41 -05:00
Vincent Koc
695a4f5039 fix(web-search): wrap more provider json 2026-05-15 09:12:31 +08:00
Vincent Koc
d0034e2f99 fix(msteams): guard graph fetches 2026-05-15 09:09:23 +08:00
Vincent Koc
4ce979934f fix(media): wrap malformed provider json 2026-05-15 09:08:34 +08:00
Vincent Koc
f0803c576f fix(memory): wrap malformed remote json 2026-05-15 09:06:24 +08:00
Vincent Koc
31bfe7f084 fix(web-search): wrap malformed provider json 2026-05-15 09:04:20 +08:00
Vincent Koc
8659eabba7 fix(firecrawl): wrap malformed api json 2026-05-15 09:01:39 +08:00
Vincent Koc
9c88241a85 fix(test): satisfy provider web search test types 2026-05-15 08:57:51 +08:00
hclsys
30cfcf21b7 fix(skills): replace generated plugin skill directories 2026-05-15 08:57:03 +08:00
Vincent Koc
60a6945a6e fix(googlechat): wrap malformed api json 2026-05-15 08:56:16 +08:00
Vincent Koc
c98459d9da fix(msteams): wrap malformed api json 2026-05-15 08:52:15 +08:00
Vincent Koc
376a792100 fix(nextcloud-talk): wrap malformed api json 2026-05-15 08:49:50 +08:00
Vincent Koc
ffae8f32d8 fix(xai): wrap malformed tool json 2026-05-15 08:47:41 +08:00
Kevin Lin
acbe461c16 fix(codex): remove spurious migration warnings
Remove spurious Codex migration warnings for expected planned/manual/archive states while preserving real provider warnings.
2026-05-14 17:47:21 -07:00
EvanYao
70ebf4898b fix(config): treat enabled channels as configured 2026-05-15 08:45:22 +08:00
Vincent Koc
380ba7071f fix(brave): wrap malformed search json 2026-05-15 08:44:34 +08:00
Vincent Koc
d16f79f49d fix(providers): add safe json response helper 2026-05-15 08:41:18 +08:00
Vincent Koc
a709927698 fix(codex): hide empty rate-limit buckets
Hide empty Codex rate-limit buckets from account/status output while preserving server-reported usage-limit blocks.
2026-05-15 08:40:29 +08:00
Vincent Koc
9f99464119 fix(deepinfra): wrap malformed video json 2026-05-15 08:36:05 +08:00
Vincent Koc
c589680e95 fix(doctor): honor alternate memory slot owners 2026-05-15 08:33:29 +08:00
Vincent Koc
1d46a2f0b5 fix(comfy): wrap malformed workflow json 2026-05-15 08:32:31 +08:00
Vincent Koc
62375ae860 fix(lint): quiet ollama num_ctx normalizer 2026-05-15 08:29:02 +08:00
Vincent Koc
6e191f0e1e fix(lmstudio): wrap malformed model json 2026-05-15 08:27:55 +08:00
Vincent Koc
d77f428441 fix(tlon): wrap malformed scry json 2026-05-15 08:22:41 +08:00
Vincent Koc
a118e114fe fix(usage): wrap malformed usage json 2026-05-15 08:18:11 +08:00
Shakker
0179efc022 docs: add update finalizer changelog 2026-05-15 01:10:20 +01:00
Shakker
4199034de2 fix: refresh finalize state after doctor 2026-05-15 01:09:06 +01:00
Shakker
92f8c1edac feat: add update finalization command 2026-05-15 01:09:06 +01:00
Vincent Koc
eb07aba973 fix(clawhub): wrap malformed marketplace json 2026-05-15 08:02:13 +08:00
Vincent Koc
77e5a492f2 fix(signal): wrap malformed release metadata 2026-05-15 07:57:07 +08:00
Vincent Koc
c59e900903 fix(tlon): wrap malformed sse json 2026-05-15 07:54:04 +08:00
Vincent Koc
63d72e2191 fix(voice-call): wrap malformed media stream json 2026-05-15 07:50:08 +08:00
Truffle
d7e946eb34 fix(runner): gate surface_error throw on failoverFailure (#70900)
Merged via squash.

Prepared head SHA: b62213339b
Co-authored-by: truffle-dev <260125384+truffle-dev@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-15 02:47:30 +03:00
Val Alexander
eb4e20ca1d fix(plugins): expose effective context budget in hooks
Add optional context budget/source/reference metadata to plugin hook contexts plus llm_output and sanitized model_call_* hook events.

Thread the existing resolved context-window info through Pi embedded runs, CLI harness runs, and Codex app-server hook emission so plugins can observe the effective budget after agent/model/config caps.

Document the metadata and cover the CLI, Pi, Codex app-server, and model-call paths with focused tests.

Fixes #64327.
2026-05-14 17:51:53 -05:00
Josh Lehman
4004c9342d fix: use Codex context windows for OpenAI runtime (#81906)
* fix: use Codex context windows for OpenAI runtime

* test: satisfy status model fixture types

* fix: note Codex context window budget fix
2026-05-14 15:38:50 -07:00
Josh Lehman
9cfb4c747a docs: restore 2026.5.12 changelog section (#81943) 2026-05-14 15:36:04 -07:00
Extra Small
70ed7c9873 fix(control-ui): make log stream height responsive
Summary:
- Replace the fixed 500px Control UI Logs stream cap with a viewport-responsive max-height plus a 200px floor.
- Keep the offset documented inline and add the changelog entry for #53916.

Verification:
- git diff --check origin/main...HEAD
- git merge-tree --name-only origin/main HEAD
- node assertion confirmed `.log-stream` has `max-height: calc(100vh - 280px)`, `min-height: 200px`, and no `max-height: 500px`
- Source path check confirmed `renderLogs` renders the affected `.log-stream` container

Maintainer note:
- Real behavior proof requirement intentionally overridden by maintainer proof comment: https://github.com/openclaw/openclaw/pull/53916#issuecomment-4455196712
2026-05-14 17:21:23 -05:00
Josh Lehman
3f80f889fa fix: align Codex cron bootstrap context (#81822)
* fix: align Codex cron bootstrap context

* fix: address Codex cron review comments

* fix: suppress Codex project docs for lightweight context

* fix: note Codex cron lightweight context
2026-05-14 15:10:42 -07:00
Josh Avant
bcbf4fc35f fix(discord): honor threadName when sending to threads (#81933) 2026-05-14 17:07:29 -05:00
joshavant
3f0a39510b docs changelog for ollama num_ctx fix 2026-05-14 16:53:12 -05:00
Josh Avant
bd0555d5fc fix ollama native num_ctx migration (#81928) 2026-05-14 16:50:57 -05:00
javierdici
f6c00456dc Render provider errors in chat history (#65689)
Merged via squash.

Prepared head SHA: a777c7506e
Co-authored-by: javierdici <131621115+javierdici@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-15 00:48:41 +03:00
Leo Ge
99a6b1c5a8 fix(acpx): surface Codex ACP diagnostics
Surface redacted Codex wrapper stderr for generic ACP internal failures, preserve safe Codex model/provider routing in isolated CODEX_HOME, and cover the ACP parent stream dispatch order.

Co-authored-by: leoge007 <leoge@users.noreply.github.com>
2026-05-14 22:42:28 +01:00
Gio Della-Libera
abf59205fc fix(config): return persisted config write responses (#81445)
Merged via squash.

Prepared head SHA: 8f549e0621
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-15 00:35:15 +03:00
Kevin Lin
079bf99671 docs: consolidate plugin management docs (#81898)
* docs: consolidate plugin management docs

* docs: keep community plugins page discovery-only

* docs: restore clawhub publishing guidance

* docs: keep community publishing checklist
2026-05-14 14:27:50 -07:00
Peter Steinberger
926bf66ee3 fix(skills): sync managed symlink skills as directories 2026-05-14 22:11:01 +01:00
stainlu
cca4f3c63c fix(skills): trust managed skill symlink roots 2026-05-14 22:11:01 +01:00
Peter Steinberger
f8ae0fb1c4 fix: narrow ACP timeout config suppression (#81603) 2026-05-14 22:01:40 +01:00
Peter Steinberger
f9112f0e0a fix: tolerate unsupported ACP timeout hints (#81603) (thanks @qkal) 2026-05-14 22:01:40 +01:00
Qkal
ba61d12c45 docs(plugin-sdk): document Codex helper subpaths 2026-05-14 22:01:40 +01:00
Qkal
82f4297311 fix(acp): tolerate unsupported timeout config hints 2026-05-14 22:01:40 +01:00
Peter Steinberger
1d8d664570 chore(release): prepare 2026.5.14 2026-05-14 21:38:45 +01:00
Peter Steinberger
f6f05c4859 build(clawhub): publish bedrock providers
(cherry picked from commit cbafae60dd)
2026-05-14 21:34:36 +01:00
pashpashpash
1a5548203e Stream Codex preambles in channel progress drafts (#81887)
* codex: stream preambles in progress drafts

* test: update preamble progress PR checks

* test: refresh plugin sdk api baseline
2026-05-15 05:32:42 +09:00
Peter Steinberger
d9ff8cfb01 fix: plan managed npm peer pins with npm
Plan managed npm peer dependency pins from npm's lockfile planner instead of recursively scanning nested node_modules packages, preserving host peer ranges when npm cannot produce a usable root pin.

Also preserves active root-managed OpenClaw host runtimes during npm plugin installs, folding the active-host guard/test from #81632.

Verification:
- codex-review --full-access
- pnpm check:test-types
- pnpm exec oxfmt --check --threads=1 src/infra/npm-managed-root.ts src/infra/npm-managed-root.test.ts src/plugins/install.npm-spec.test.ts CHANGELOG.md test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts && git diff --check
- OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test src/infra/npm-managed-root.test.ts src/plugins/install.npm-spec.test.ts -- --reporter=verbose
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/test-projects.mjs src/plugins/install.npm-spec.e2e.test.ts -- --reporter=verbose
- node scripts/run-vitest.mjs run --config test/vitest/vitest.full-core-support-boundary.config.ts test/scripts/mantis-build-telegram-desktop-proof-evidence.test.ts --reporter=verbose
- GitHub current-head checks: 55 completed, 0 failures; remaining Blacksmith-backed jobs capacity-queued at merge decision time.

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-14 21:25:22 +01:00
Peter Steinberger
6971036043 test: align mantis evidence assertions 2026-05-14 20:56:13 +01:00
Peter Steinberger
21f1b46f8a refactor(clawhub): reuse response body timeout helper 2026-05-14 20:56:13 +01:00
stainlu
86b0a7ddda fix(clawhub): cancel stalled archive body reads 2026-05-14 20:56:13 +01:00
Conan Scott
817dca5ae9 fix(webchat): render tts audio command replies 2026-05-14 20:41:21 +01:00
Peter Steinberger
686b93e5c7 fix: keep command cron turns lightweight 2026-05-14 20:15:44 +01:00
Peter Steinberger
e575325af6 fix(memory): prioritize canonical daily notes 2026-05-14 20:11:47 +01:00
simplyclever914
c404711703 fix: enforce Codex forced OAuth refresh (#80738)
Treat forced OAuth refresh as a hard refresh contract: fallback credentials may be reused only when they changed after the attempted refresh began.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Clever <clever@users.noreply.github.com>
2026-05-14 20:08:14 +01:00
Josh Avant
130c2d5044 Fix Telegram polling lease cleanup on restart (#81890)
* fix(telegram): release stopped polling leases

* docs: add Telegram polling lease changelog
2026-05-14 14:04:34 -05:00
Josh Lehman
f64feab47a fix: prevent codex app-server surrogate stalls 2026-05-14 19:59:23 +01:00
Pavan Kumar Gondhi
386d321634 Bind gateway approval access to requester metadata [AI] (#81380)
* fix: bind approval access to requester metadata

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing claude review

* addressing ci

* fix: complete root-cause handling

* addressing review-skill

* addressing codex review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-14 23:21:34 +05:30
Peter Steinberger
c9b6b0be0e fix(mantis): stop git-backed evidence publishing 2026-05-14 18:34:31 +01:00
Peter Steinberger
59be6d6390 build(deps): route node proxy helpers through proxyline 2026-05-14 18:27:23 +01:00
pashpashpash
28550a798c fix(doctor): respect runtime message tool grants 2026-05-14 17:46:28 +01:00
Josh Avant
d0f22ccf97 Fix gateway handling for undici HTTP2 session teardown (#81838)
* fix: handle undici HTTP2 session teardown

* docs: add gateway HTTP2 changelog entry
2026-05-14 11:36:59 -05:00
SymbolStar
0de6f93805 fix(telegram): reuse sticky IPv4 dispatcher for getMe health check (#76852) (#76856)
Fixes #76852.

Co-authored-by: jindongfu <jindongfu@microsoft.com>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
2026-05-15 00:21:08 +08:00
Ayaan Zaidi
85eb3cda65 fix(telegram): add isolated lane drain changelog (#81849) (thanks @VACInc) 2026-05-14 21:49:23 +05:30
Ayaan Zaidi
52c9860bde refactor(telegram): simplify spooled lane tracking 2026-05-14 21:49:23 +05:30
VACInc
3f132370f4 fix telegram isolated spool lane draining 2026-05-14 21:49:23 +05:30
Mason Huang
83d7ab0d36 fix(changelog): reject bot/app handles as Thanks attribution and require explicit human credit (#81357)
Summary:
- The PR expands forbidden changelog `Thanks` attribution rules for bot/app handles, shares the Node predicate ... ngelog gate, requires explicit human credit for bot/app-authored changelog entries, and adds focused tests.
- Reproducibility: yes. Current main source shows bot/app changelog authors can skip human attribution and bot/app `Thanks` handles are not all rejected; I did not execute tests because this review was read-only.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix: simplify bot changelog credit guard
- PR branch already contained follow-up commit before automerge: fix: share changelog credit attribution rule
- PR branch already contained follow-up commit before automerge: fix: tighten changelog attribution scanning
- PR branch already contained follow-up commit before automerge: test: cover legacy changelog credit exclusions
- PR branch already contained follow-up commit before automerge: fix: express changelog credit exclusions as union sets
- PR branch already contained follow-up commit before automerge: fix: avoid substring changelog credit exclusions

Validation:
- ClawSweeper review passed for head 1e6d0f53ec.
- Required merge gates passed before the squash merge.

Prepared head SHA: 1e6d0f53ec
Review: https://github.com/openclaw/openclaw/pull/81357#issuecomment-4439359411

Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
2026-05-14 15:04:43 +00:00
masonxhuang
1f45b37fe1 feat(secret-scanning): add automated message header to maintainer notifications 2026-05-14 22:28:12 +08:00
Gado
83b8289ee2 feat: WhatsApp status reactions, new emoji categories, self-explanatory defaults (#59077) (#80612)
Merged via squash.

Prepared head SHA: 25e0a7a9fd
Co-authored-by: gado-ships-it <276509604+gado-ships-it@users.noreply.github.com>
Co-authored-by: velvet-shark <126378+velvet-shark@users.noreply.github.com>
Reviewed-by: @velvet-shark
2026-05-14 14:37:23 +02:00
Vincent Koc
74dae6088b fix(mattermost): wrap malformed interaction json 2026-05-14 20:10:41 +08:00
Andrii Furmanets
42b95a9eb1 fix(plugins): harden git ref checkout 2026-05-14 19:56:36 +08:00
Vincent Koc
e692f5c1cf fix(synology-chat): wrap malformed webhook json 2026-05-14 19:53:19 +08:00
Vincent Koc
2d6fd54ebd fix(cli): keep plugin json output parseable
Co-authored-by: Eric Milgram, PhD <4348294+ScientificProgrammer@users.noreply.github.com>
2026-05-14 19:44:38 +08:00
Vincent Koc
8813b79990 fix(openai): wrap malformed embedding batch jsonl 2026-05-14 19:43:34 +08:00
Vincent Koc
d9c6036a8f fix(qqbot): wrap malformed token json 2026-05-14 19:40:46 +08:00
Vincent Koc
2d9ef76d5b fix(bedrock): wrap malformed embedding json 2026-05-14 19:38:11 +08:00
Vincent Koc
1bdb151d0d fix(node-host): wrap malformed invoke params json 2026-05-14 19:35:45 +08:00
Vincent Koc
1b77553115 fix(build): keep externalized plugins out of root dist 2026-05-14 19:34:15 +08:00
Vincent Koc
1fc82347a7 fix(google): wrap malformed sse json 2026-05-14 19:28:13 +08:00
Vincent Koc
ae0cb0ac6f fix(google-meet): wrap malformed browser status json 2026-05-14 19:23:11 +08:00
Vincent Koc
b02de2e948 fix(qa-lab): wrap malformed model catalog json 2026-05-14 19:18:57 +08:00
Vincent Koc
8f7a3cbff3 fix(plugins): repair legacy npm declaration stubs 2026-05-14 19:17:05 +08:00
Vincent Koc
8754094292 fix(gateway): wrap malformed pricing catalog json 2026-05-14 19:15:20 +08:00
Vincent Koc
c96181fdbe fix(foundry): wrap malformed az token json 2026-05-14 19:10:08 +08:00
Vincent Koc
278e3eabf2 fix(realtime): wrap malformed transcription frames 2026-05-14 19:05:46 +08:00
Vincent Koc
f3fecb7218 changelog: cover claude-cli reasoning preview bridge + gating 2026-05-14 19:03:59 +08:00
Vincent Koc
79bd0185f5 fix(voice-call): wrap guarded api json parse 2026-05-14 19:00:54 +08:00
Ayaan Zaidi
02f2e08493 fix(auto-reply): gate claude cli reasoning bridge 2026-05-14 16:29:46 +05:30
Cameron Beeley
f3875ac937 fix(auto-reply): bridge cli assistant text-delta into reasoning preview
Add a CLI-runtime-gated bridge in runAgentTurnWithFallback that subscribes
to `stream: "assistant"` agent-events for the current runId and re-emits
them as reasoning content through `params.opts.onReasoningStream`. Mirrors
the assistant-text bridge from #76914 and the tool-event bridge from #80046:
same Promise-chain serialization + drain, same silentExpected gate, same
unsubscribe pattern at success/catch/finally.

The reply lane is untouched -- `onPartialReply` continues to settle the
final assistant text via #76914. The reasoning lane now reflects the
model's live text output during streaming, which is the only "what is the
model producing right now" signal available for claude-opus-4-7 over
claude-cli (Anthropic suppresses readable thinking_delta events on the
wire for opus-4-7; only thinking content_block + signature_delta arrive).

The bridge is gated on isCliProvider so API/native runtimes that already
get reasoning content from real thinking_delta events do NOT double-receive
text_delta as reasoning.

Tests cover:
- Forwards assistant agent-events to onReasoningStream with correct text
- Respects silentExpected (heartbeat / NO_REPLY runs don't emit)
- Does not fire on the API/native runtime path (gate works)
2026-05-14 16:29:46 +05:30
Vincent Koc
99d7b206fd fix(twilio): wrap malformed api json 2026-05-14 18:57:19 +08:00
Vincent Koc
49e288823c fix(cli): wrap malformed trajectory export requests 2026-05-14 18:52:05 +08:00
Vincent Koc
a1de61bf65 fix(channels): list manifest-only plugins 2026-05-14 18:47:52 +08:00
Vincent Koc
7a65b8a3d5 fix(google-meet): wrap malformed node host params 2026-05-14 18:47:18 +08:00
Val Alexander
348ffe6061 fix(gateway): stop stale control ui auth retry loops
Fixes #72139.

Summary:
- Stop Control UI and Gateway clients from retrying AUTH_TOKEN_MISMATCH forever when no trusted cached device-token retry is queued.
- Keep the bounded trusted device-token retry path intact.
- Cap Control UI chat history rendering by raw tool-output size, including tool_result.content, with bounded estimation to avoid pre-render stalls.

Verification:
- node scripts/run-vitest.mjs ui/src/ui/gateway.node.test.ts src/gateway/client.test.ts ui/src/ui/chat/build-chat-items.test.ts
- node scripts/run-vitest.mjs src/gateway/reconnect-gating.test.ts ui/src/ui/controllers/chat.test.ts ui/src/ui/views/chat.test.ts
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/ui/gateway.ts ui/src/ui/gateway.node.test.ts ui/src/ui/chat/history-limits.ts ui/src/ui/chat/build-chat-items.ts ui/src/ui/chat/build-chat-items.test.ts src/gateway/client.ts src/gateway/client.test.ts
- git diff --check
- PR CI/check graph passed on d9692555ee.
2026-05-14 05:36:09 -05:00
Ayaan Zaidi
095de07135 docs(platforms): link Android Play Store app 2026-05-14 16:04:31 +05:30
Gio Della-Libera
260e1e138b fix(ui): drop unrestorable redacted config placeholders
Summary:
- Sanitize Control UI form-mode config submissions after schema coercion and before config.set/config.apply.
- Drop stale redacted placeholders only when the loaded form also had the redaction sentinel and the original raw config lacks that path.
- Preserve restorable saved secrets and user-entered literal sentinels so the gateway's fail-closed validation remains authoritative.

Verification:
- node scripts/run-vitest.mjs ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts
- pnpm exec oxfmt --check --threads=1 ui/src/ui/controllers/config.ts ui/src/ui/controllers/config/form-utils.ts ui/src/ui/controllers/config.test.ts ui/src/ui/controllers/config/form-utils.node.test.ts docs/web/control-ui.md CHANGELOG.md
- git diff --check origin/main...HEAD
- pnpm check:changed
- GitHub PR checks green on head b35a5b975d
2026-05-14 05:33:20 -05:00
Josh Avant
a2963f51d5 fix(telegram): skip unmentioned group media before download (#81785)
* fix(telegram): skip unmentioned group media before download

* docs(changelog): note telegram require mention media fix
2026-05-14 05:22:24 -05:00
Josh Avant
2b04cedfb1 Fix subagent default model precedence (#81783)
* fix subagent default model precedence

* docs changelog for subagent default fix
2026-05-14 05:19:41 -05:00
Ayaan Zaidi
d25bece9f6 refactor(codex): tighten status rate-limit formatting 2026-05-14 15:45:33 +05:30
Matthew Schleder
724868cec8 docs: add Codex rate-limit changelog entry 2026-05-14 15:45:33 +05:30
Matthew Schleder
6b6538bd13 fix(codex): format status rate limits like usage 2026-05-14 15:45:33 +05:30
Vincent Koc
dbabfc550f fix(telnyx): validate webhook client state base64 2026-05-14 18:08:16 +08:00
Vincent Koc
c822824503 fix(qqbot): validate cron payload base64 2026-05-14 18:04:32 +08:00
Vincent Koc
fe97f1fa4f fix(voice-call): validate realtime media frame base64 2026-05-14 18:00:30 +08:00
Gio Della-Libera
b9dc6d86b8 test(config): refresh plugin schema fixtures 2026-05-14 17:58:27 +08:00
Gio Della-Libera
13c2e245aa fix(config): use plugin channel schemas in dry-run 2026-05-14 17:58:26 +08:00
Vincent Koc
f3f6a866ca fix(msteams): validate inline image base64 2026-05-14 17:57:53 +08:00
joshavant
6ae9c8bead note telegram worker dist fix 2026-05-14 04:56:14 -05:00
joshavant
8ba7927f6e fix telegram ingress worker dist entry 2026-05-14 04:55:39 -05:00
Vincent Koc
84ec355af8 fix(qa-channel): reject malformed inline attachment data 2026-05-14 17:54:55 +08:00
Ayaan Zaidi
23ed804657 fix(telegram): keep plugin slash commands on native path 2026-05-14 15:22:53 +05:30
Vincent Koc
23cfc81bcd fix(file-transfer): validate inline write base64 2026-05-14 17:51:20 +08:00
Vincent Koc
92524fcf98 fix(proxy): reject malformed debug proxy targets 2026-05-14 17:46:10 +08:00
Vincent Koc
a47132734b fix(agents): skip continuation bootstrap preload 2026-05-14 17:42:36 +08:00
Val Alexander
b405c6e640 fix(mac): verify launchd stop releases gateway port
Fixes #73132.

Summary:
- Verify macOS LaunchAgent stop/restart port postconditions before reporting success.
- Resolve the effective gateway port from launchd args, persisted service environment, then caller env.
- Delay degraded fallback success output until the listener port is confirmed released.

Verification:
- node scripts/run-vitest.mjs src/daemon/launchd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/restart-health.test.ts
- pnpm exec oxfmt --check --threads=1 src/daemon/launchd.ts src/daemon/launchd.test.ts CHANGELOG.md
- git diff --check
- Testbox tbx_01krjxf8vrbjwxv3xfdx4770xr: pnpm check:changed
2026-05-14 04:41:45 -05:00
Vincent Koc
c70adb8528 fix(plugins): wrap malformed node proxy payloads 2026-05-14 17:40:38 +08:00
Vincent Koc
6b3998aa40 fix(gateway): ignore malformed host on session routes 2026-05-14 17:35:57 +08:00
Peter Steinberger
365c986a5b docs(models): clarify cli runtime alias comment 2026-05-14 10:35:35 +01:00
Peter Steinberger
ac5674b32c fix(web): keep legacy Brave search fallback provider-owned
- Keep doctor migration as canonical for legacy Brave web-search config.
- Move legacy runtime support into Brave-owned provider config handling.
- Preserve legacy config precedence over ambient BRAVE_API_KEY.

Verification:
- node scripts/run-vitest.mjs run src/secrets/runtime-web-tools.test.ts --maxWorkers=1
- pnpm test extensions/brave -- --maxWorkers=1
- pnpm check:changed via Blacksmith Testbox tbx_01krjwy2gc4d2sxb3hqxcbhhtk / https://github.com/openclaw/openclaw/actions/runs/25852532246
2026-05-14 10:32:55 +01:00
Peter Steinberger
731c8843ff test: update lint suppression allowlist 2026-05-14 10:27:12 +01:00
Peter Steinberger
554dfbd017 docs(ui): add i18n report changelog 2026-05-14 10:27:12 +01:00
Peter Steinberger
4feb4e6623 docs(ui): document i18n report usage 2026-05-14 10:27:12 +01:00
Peter Steinberger
266722500c fix(ui): avoid noisy i18n report locale warnings 2026-05-14 10:27:12 +01:00
samzong
4e76d6e427 fix(ui): harden i18n report filters
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-14 10:27:12 +01:00
samzong
ee9d471865 feat(ui): add i18n baseline report
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-14 10:27:12 +01:00
Vincent Koc
d5abbd29cc changelog: cover @sjf Codex marketplace handling and @scotthuang weixin 2.4.3
- (#81625) Codex migrate delayed marketplace + warning/next-step glyph cleanup. Thanks @sjf.
- (#81730) Weixin bundled catalog bump 2.4.1 -> 2.4.3. Thanks @scotthuang.
2026-05-14 17:26:45 +08:00
Mariano
a5c1956ca1 feat(codex): bind CLI sessions from nodes
Adds node-backed Codex CLI session listing and resume binding for paired nodes, including Windows shim-safe Codex resume spawning, docs, changelog, and focused Codex coverage.

Verification:
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md docs/plugins/codex-harness.md extensions/codex/index.ts extensions/codex/src/command-formatters.ts extensions/codex/src/command-handlers.ts extensions/codex/src/commands.test.ts extensions/codex/src/conversation-binding-data.ts extensions/codex/src/conversation-binding.test.ts extensions/codex/src/conversation-binding.ts extensions/codex/src/node-cli-sessions.ts extensions/codex/src/node-cli-sessions.test.ts
- pnpm run lint:tmp:no-random-messaging
- pnpm run lint:extensions:bundled
- OPENCLAW_VITEST_MAX_WORKERS=4 pnpm test extensions/codex/src/node-cli-sessions.test.ts extensions/codex/src/conversation-binding.test.ts extensions/codex/src/commands.test.ts
- pnpm tsgo:extensions
- git diff --check
- AWS Crabbox focused proof run_a901a61e006f
2026-05-14 11:24:30 +02:00
Ayaan Zaidi
2268ce3a14 docs(changelog): note telegram cron html fix 2026-05-14 14:39:23 +05:30
Ayaan Zaidi
e28d66d531 fix(cli): preserve lazy sender formatting 2026-05-14 14:39:23 +05:30
Ayaan Zaidi
41aee75cd1 test(cli): prove lazy sender preserves html formatting 2026-05-14 14:39:23 +05:30
Peter Steinberger
04605f1670 docs: allow maintainer proof override 2026-05-14 10:08:54 +01:00
Peter Steinberger
a0f35574d0 Remove codex-cli backend and migrate to Codex runtime
Remove the bundled codex-cli backend, migrate legacy codex-cli refs and runtime pins to the Codex app-server runtime, and update live/backend workflow coverage for the supported CLI lanes.
2026-05-14 10:07:18 +01:00
Peter Steinberger
66b98b7294 chore: sync codex review skill 2026-05-14 10:02:14 +01:00
Peter Steinberger
a582fc2d5c chore: tighten codex review skill 2026-05-14 09:58:58 +01:00
Peter Steinberger
beea866a53 chore: add codex review skill 2026-05-14 09:56:13 +01:00
samzong
1d121c1f08 chore(gateway): add startup trace attribution (#81738)
Adds owner-level startup trace attribution for gateway auth, plugin loading, lookup counts, and plugin sidecar services.

Verification:
- node scripts/run-vitest.mjs src/plugins/startup-trace-segment.test.ts src/plugins/services.test.ts src/plugins/loader.test.ts src/gateway/server-startup-config.secrets.test.ts
- pnpm build
- pnpm check

CI override:
- Red checks are unrelated baseline noise. The failed CI shard is src/cli/plugins-install-persist.test.ts, which fails on origin/main 336ba2a2b3 with the same missing resolveIsNixMode mock export. PR #81738 touches gateway/plugin startup trace files and CHANGELOG.md, not the failing CLI plugin install test.

Thanks @samzong.

Co-authored-by: samzong <13782141+samzong@users.noreply.github.com>
2026-05-14 16:50:08 +08:00
Vincent Koc
12b8db34ee fix(browser): handle malformed node proxy payloads 2026-05-14 16:48:28 +08:00
Josh Avant
fd244fd76d Fix Telegram polling ingress under event-loop stalls (#81746)
* fix telegram polling ingress under event-loop stalls

* add changelog for telegram ingress fix
2026-05-14 03:35:06 -05:00
scotthuang
c35634c729 Fix/weixin catalog update 2.4.3 (#81730)
* fix(weixin): upgrade catalog to 2.4.3

* fix(weixin): update catalog integrity for 2.4.3

---------

Co-authored-by: scotthuang <scotthuang@tencent.com>
2026-05-14 03:32:38 -05:00
Vincent Koc
0668f1e003 fix(web): resolve explicit global search providers 2026-05-14 16:29:55 +08:00
Vincent Koc
94f3ecae9a perf(cli): route plugin list json directly 2026-05-14 16:29:21 +08:00
Vincent Koc
641ad418c9 fix(clickclack): skip malformed websocket frames 2026-05-14 16:26:02 +08:00
Eduardo Buitrago
336ba2a2b3 fix(agents): forward explicit per-run timeout to LLM idle watchdog (#79426)
Merged via squash.

Prepared head SHA: 0e6cf9b4d5
Co-authored-by: legolaz8451 <18042830+legolaz8451@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Reviewed-by: @joshavant
2026-05-14 03:24:01 -05:00
Vincent Koc
8717525fbc test(cli): cover parent startup budgets 2026-05-14 16:18:26 +08:00
Sarah Fortune
2f2563314a fix(codex): handle delayed plugin marketplace (#81625) 2026-05-14 01:17:58 -07:00
Jack Storment
b79c41d252 fix(memory): discover slugged daily memory files alongside date-only files
Widen daily memory filename discovery so slugged session-memory files flow through Dreaming, rem-backfill, rem-harness, doctor, and short-term promotion.

Preserve exact slugged source paths during historical seeding and rem-backfill attribution, including multiple files for the same day.

Add regression coverage for slugged ingestion, rem-backfill, rem-harness preview paths, and doctor backfill day extraction.

Fixes #69536.

Co-authored-by: Jack Storment <crazycoder131@gmail.com>
2026-05-14 09:17:44 +01:00
Vincent Koc
31a28eb5ba fix(media): reject malformed redirect locations 2026-05-14 16:16:56 +08:00
Kaspre
f71df80522 perf(plugins): memoize metadata snapshots narrowly 2026-05-14 16:15:50 +08:00
Vincent Koc
f6d0cc6cc3 perf(cli): keep channel option help lightweight 2026-05-14 16:13:28 +08:00
Vincent Koc
db743e4918 fix(voice-call): ignore malformed host for webhook paths 2026-05-14 16:11:29 +08:00
Vincent Koc
462a056210 fix(gateway): ignore malformed host on json routes 2026-05-14 16:06:23 +08:00
Vincent Koc
fe25ed214e refactor(cli): lazy-load devices runtime 2026-05-14 16:02:42 +08:00
Peter Steinberger
3fa9658b39 fix: carry transcript update sequence 2026-05-14 08:59:31 +01:00
samzong
c20224688c fix(gateway): carry transcript update sequence
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-14 08:59:31 +01:00
Vincent Koc
a012411d5e refactor(cli): lazy-load plugins runtime 2026-05-14 15:57:07 +08:00
anagnorisis2peripeteia
bcb9fa42be fix(models): keep CLI runtime providers in /models picker (#81239)
Merged via squash.

Prepared head SHA: 294741d1db
Co-authored-by: anagnorisis2peripeteia <129746152+anagnorisis2peripeteia@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-14 10:52:57 +03:00
Peter Steinberger
3bd47a95a8 test: align release check with external slack package 2026-05-14 08:49:48 +01:00
Peter Steinberger
e17f628a75 test(release): skip externalized slack pack paths 2026-05-14 08:49:00 +01:00
Peter Steinberger
7edcfabf51 fix(build): keep slack dependencies extension-owned 2026-05-14 08:49:00 +01:00
Peter Steinberger
e7ae306aa1 refactor(auth): use fs-safe stale lock recovery 2026-05-14 08:49:00 +01:00
Peter Steinberger
04afd114bb fix(auth): reclaim zombie-owned stale locks 2026-05-14 08:49:00 +01:00
Peter Steinberger
c499ef1a6b fix(auth): preserve non-signalable lock owners 2026-05-14 08:49:00 +01:00
Peter Steinberger
f84d031d38 fix(auth): fail closed on unreadable stale locks 2026-05-14 08:49:00 +01:00
Peter Steinberger
3048ad4731 refactor(infra): centralize stale lock cleanup 2026-05-14 08:49:00 +01:00
Peter Steinberger
ceb3092493 fix(auth): reclaim stale file locks 2026-05-14 08:49:00 +01:00
Vincent Koc
babd25c6b7 refactor(cli): lazy-load models runtime 2026-05-14 15:48:11 +08:00
Peter Steinberger
bfc798bd0b fix(ci): restore main build 2026-05-14 08:38:49 +01:00
Peter Steinberger
32f89760e3 docs: clarify landing recap requirement 2026-05-14 08:37:30 +01:00
Peter Steinberger
11017c93cf build: keep external provider deps out of core dist 2026-05-14 08:29:10 +01:00
Peter Steinberger
643dea2455 fix(mattermost): gate delivery success log 2026-05-14 08:29:07 +01:00
kinjitakabe
6789fe248b fix(mattermost): diagnose silent final-delivery completions
`deliverMattermostReplyPayload` accepted a substantive (non-reasoning) reply
payload, called the shared `deliverTextOrMediaReply`, and dropped its
`"empty"|"text"|"media"` return value on the floor. When the underlying chunker
or media-resolution produced no text and no media to send, the function
returned `Promise<void>` and the caller in `monitor.ts` unconditionally logged
`delivered reply to <channel>` — masking a silent completion where no
Mattermost API send ever happened (the symptom in #80501).

Thread the outcome through the helper, evaluate it against the original
payload to distinguish intentional reasoning suppression from a substantive
payload that vanished, and log a structured `mattermost no-visible-reply`
diagnostic for the substantive-vanished case. The misleading "delivered
reply to" log now only fires on actual visible delivery; reasoning-skipped
payloads correctly stay silent.

No behavior change: visible-delivery decisions, preview-finalization, and the
existing reasoning-suppression contract are untouched. Operators can now grep
the new diagnostic to detect the failure class instead of seeing the agent
appear to go silent.

Fixes #80501.
2026-05-14 08:29:07 +01:00
Josh Avant
10d2f41c83 fix(browser): request admin scope for CLI control (#81716)
* fix(browser): request admin scope for CLI control

* chore(changelog): note browser CLI scope fix
2026-05-14 02:20:14 -05:00
Vincent Koc
b1fc55fded fix(web): honor legacy search api key selection 2026-05-14 15:14:27 +08:00
Vincent Koc
8962d35264 refactor(cli): mark parent help in descriptors 2026-05-14 15:11:33 +08:00
Vincent Koc
d41907a5cb fix(slack): ignore malformed media redirects 2026-05-14 15:10:40 +08:00
Peter Steinberger
b8dccbf310 ci: run package patch guard in pr checks 2026-05-14 08:09:28 +01:00
Mariano Belinky
949012797b fix: reference codex watchdog changelog entry 2026-05-14 08:07:47 +01:00
Mariano Belinky
1aef36b60d fix(codex): keep post-tool watchdog armed 2026-05-14 08:07:47 +01:00
Vincent Koc
1e5641ba82 changelog: cover @sjf migrate trailing-period cleanup (#81705) 2026-05-14 15:03:30 +08:00
Peter Steinberger
0916a19cb5 ci: block new package patches 2026-05-14 07:57:59 +01:00
Vincent Koc
1d5f01500d fix(matrix): tolerate malformed location params 2026-05-14 14:55:52 +08:00
Peter Steinberger
625713091e docs: clarify plugin externalization guidance 2026-05-14 07:53:25 +01:00
Sarah Fortune
d9e999cf4f fix(migrate): drop trailing periods from migrate item messages (#81705) 2026-05-13 23:52:19 -07:00
Peter Steinberger
81b239dc98 build: externalize slack openshell vertex plugins 2026-05-14 07:46:58 +01:00
Vincent Koc
7f05ea60fa changelog: cover Windows sandbox bind, env-marker inference, bodyless media
- (#63074) Security/sandbox: include Windows USERPROFILE in blocked home roots. Thanks @luoyanglang.
- Models config/auth: stop inferring providers from broad env-var name patterns; use structured SecretRefs only. Thanks @sallyom.
- Media fetch: avoid buffering bodyless responses. Thanks @shakkernerd.
2026-05-14 14:46:06 +08:00
Vincent Koc
8ec9bfb31e fix(ci): authenticate performance report publishing 2026-05-14 14:40:20 +08:00
Josh Avant
4e1f59010e fix(gateway): suppress startup liveness warnings (#81699)
* fix(gateway): suppress startup liveness warnings

* docs(changelog): note diagnostic startup grace fix
2026-05-14 01:39:46 -05:00
Vincent Koc
25eef1203a fix(plugins): prefer installed memory tool owners 2026-05-14 14:35:45 +08:00
Vincent Koc
d656cda46d fix(process): normalize Windows child env keys 2026-05-14 14:34:00 +08:00
Peter Steinberger
5479b6b32c build(deps): consume fs-safe 0.2.3 2026-05-14 07:31:40 +01:00
Peter Steinberger
36755e4057 [codex] externalize amazon bedrock providers (#81687)
* build: externalize amazon bedrock providers

* build: skip external plugins in root dist graph

* test: update managed npm override expectation

* build: mark amazon providers external-only
2026-05-14 07:27:40 +01:00
Vincent Koc
6bd19bffd6 changelog: cover @sjf onboarding wizard provider-flag forwarding (#81669) 2026-05-14 14:23:47 +08:00
Vincent Koc
31de033590 fix(hooks): allow dot-prefixed handler paths 2026-05-14 14:23:13 +08:00
Vincent Koc
e064cc98f0 fix(ci): skip locale refresh on invalid provider auth 2026-05-14 14:13:39 +08:00
Sarah Fortune
0a42afae3a fix(onboard): forward provider auth flags through wizard (#81669)
The wizard's applyAuthChoice call dropped provider-specific flag values
like --openai-api-key, only forwarding token/tokenProvider. As a result,
maybeApplyApiKeyFromOption could not honor the flag and onboarding still
prompted "Use existing OPENAI_API_KEY?" when the operator already
passed --openai-api-key alongside an existing env var (e.g. onboard-fast
harnesses that pre-seed --openai-api-key "$OPENAI_API_KEY").

Spread opts into the inner opts bag so provider-specific flag values
reach the provider auth method via ctx.opts. When no flag is passed the
env-confirm prompt still fires unchanged.
2026-05-13 23:12:40 -07:00
pashpashpash
da1ccd3077 fix(replies): preserve rich coalesced block replies (#81689) 2026-05-14 15:10:58 +09:00
Vincent Koc
2ab08c8a19 fix(cli): keep plugin parent help lightweight 2026-05-14 14:09:53 +08:00
Vincent Koc
c635f0087e fix(plugins): preserve dot-prefixed package metadata 2026-05-14 14:08:53 +08:00
Vincent Koc
3b7d01b63f fix(ci): prefer valid locale refresh provider 2026-05-14 14:03:06 +08:00
Vincent Koc
8f612787a8 fix(ci): restore control ui locale refresh 2026-05-14 13:58:27 +08:00
WhatsSkiLL
eefa6ecea0 fix(plugins): discover setup provider env vars (#81542)
Discover provider plugins from setup.providers[].envVars credentials during provider discovery while keeping the deprecated providerAuthEnvVars fallback.

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>
2026-05-14 06:58:05 +01:00
Vincent Koc
9518d12e13 fix(codex): remap dot-prefixed bootstrap context 2026-05-14 13:55:26 +08:00
Peter Steinberger
65ea6fdb49 docs: clarify Codex home isolation 2026-05-14 06:51:57 +01:00
Vincent Koc
af3d9333aa fix(agents): remap dot-prefixed context paths 2026-05-14 13:40:25 +08:00
Vincent Koc
cd42df45d6 fix(telegram): allow dot-prefixed local media 2026-05-14 13:32:29 +08:00
Vincent Koc
3485a907d1 fix(auth): stop Codex OAuth refresh spam
Treat high-confidence app-server OAuth refresh invalidation as terminal auth-profile failure, while keeping entitlement and rate-limit payloads out of re-auth classification.
2026-05-14 13:28:47 +08:00
Vincent Koc
6cac228a0c changelog: cover @sjf migrate selection hint cleanup (#8da06d46f8f) 2026-05-14 13:24:20 +08:00
Vincent Koc
b73d01f13b fix(canvas): reject malformed document paths 2026-05-14 13:23:26 +08:00
samzong
bb8aa0cfe2 [Fix] Throttle agent event fanout (#80335)
Merged via squash.

Prepared head SHA: 5dddb405ad
Co-authored-by: samzong <13782141+samzong@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-05-13 22:21:46 -07:00
Vincent Koc
1fc92ddfb1 fix(cli): preserve multiline table colors 2026-05-14 13:18:08 +08:00
Vincent Koc
284dcc51b8 fix(replies): preserve rich outbound content 2026-05-14 13:17:06 +08:00
Vincent Koc
6cfb62d5aa fix(canvas): harden asset path resolution 2026-05-14 13:15:32 +08:00
Vincent Koc
bc0def52af fix(ci): read sparse package manifests from index 2026-05-14 13:11:42 +08:00
Vincent Koc
ce63b9ca46 fix(plugin-sdk): classify memory core alias 2026-05-14 13:11:42 +08:00
Sarah Fortune
8da06d46f8 fix(migrate): hide per-item hints in Codex skill/plugin selection prompts 2026-05-13 22:05:42 -07:00
Ayaan Zaidi
e44b915dbf docs(changelog): note oauthRef runtime auth fix (#81633) 2026-05-14 10:31:16 +05:30
Ayaan Zaidi
df4aac8f96 fix(auth): accept oauthRef profiles for runtime auth 2026-05-14 10:31:16 +05:30
Vincent Koc
c04bbd3cbb fix(agents): allow dot-prefixed sandbox paths 2026-05-14 12:52:24 +08:00
Vincent Koc
fe89243c3b fix(plugin-sdk): restore memory core alias 2026-05-14 12:50:22 +08:00
Val Alexander
6db2ee6583 fix(ios): restore privacy permission prompts
Restores first-use iOS authorization prompts for Contacts, Calendar, and Reminders by adding the missing usage descriptions, requesting access from `.notDetermined` in the service paths, and adding Settings Privacy & Access status/actions.

Verification:
- `plutil -lint apps/ios/Sources/Info.plist apps/ios/Tests/Info.plist apps/ios/ShareExtension/Info.plist apps/ios/ActivityWidget/Info.plist apps/ios/WatchApp/Info.plist apps/ios/WatchExtension/Info.plist`
- `swiftformat --lint apps/ios/Sources/Permissions/PermissionRequestBridge.swift apps/ios/Sources/Contacts/ContactsService.swift apps/ios/Sources/Calendar/CalendarService.swift apps/ios/Sources/Reminders/RemindersService.swift apps/ios/Sources/Settings/PrivacyAccessSectionView.swift apps/ios/Sources/Settings/SettingsTab.swift apps/ios/Sources/Onboarding/GatewayOnboardingView.swift apps/shared/OpenClawKit/Sources/OpenClawKit/DeepLinks.swift --config config/swiftformat`
- `swiftlint lint --config apps/ios/.swiftlint.yml apps/ios/Sources/Permissions/PermissionRequestBridge.swift apps/ios/Sources/Contacts/ContactsService.swift apps/ios/Sources/Calendar/CalendarService.swift apps/ios/Sources/Reminders/RemindersService.swift apps/ios/Sources/Settings/PrivacyAccessSectionView.swift apps/ios/Sources/Settings/SettingsTab.swift apps/ios/Sources/Onboarding/GatewayOnboardingView.swift apps/ios/Tests/PermissionRequestBridgeTests.swift`
- `git diff --check origin/main...HEAD`
- `rg '<<<<<<<|=======|>>>>>>>' CHANGELOG.md apps/ios apps/shared/OpenClawKit/Sources/OpenClawKit/DeepLinks.swift`
- `pnpm ios:build`
- `xcodebuild test -project apps/ios/OpenClaw.xcodeproj -scheme OpenClaw -destination 'platform=iOS Simulator,name=iPhone 17' -configuration Debug -only-testing:OpenClawTests/PermissionRequestBridgeTests`
- Fresh-erased iPhone 17 simulator proof for Contacts denial/Open Settings, Calendar add-only/full-access upgrade, and Reminders authorization prompts.

Not tested: physical device, or a paired gateway command invocation after onboarding.
2026-05-13 23:45:35 -05:00
Vincent Koc
ca7349b585 fix(media): normalize cross-platform media paths 2026-05-14 12:43:15 +08:00
Val Alexander
dd4c68b525 fix(agents): suppress aborted assistant output
Summary:
- Suppress aborted embedded-run assistant partials, reasoning text, reply directives, and stale previous-assistant fallback output.
- Preserve clean timeout/error payloads, tool/media payloads, and compaction bookkeeping for non-aborted delivery paths.
- Add focused regressions for aborted partial text, reasoning text, stale fallback, and timeout delivery.

Verification:
- git diff --check HEAD~1..HEAD
- PATH=/Users/buns/.nvm/versions/node/v22.22.2/bin:$PATH pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/agents/pi-embedded-runner/run.ts src/agents/pi-embedded-runner/run/payloads.errors.test.ts src/agents/pi-embedded-runner/run/payloads.ts
- PATH=/Users/buns/.nvm/versions/node/v22.22.2/bin:$PATH pnpm test src/agents/pi-embedded-runner/run/payloads.errors.test.ts src/agents/pi-embedded-runner/run/payloads.test.ts -- --reporter=verbose
- PATH=/Users/buns/.nvm/versions/node/v22.22.2/bin:$PATH pnpm test src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts src/auto-reply/reply/agent-runner-execution.test.ts src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts src/auto-reply/reply/get-reply-run-queue.test.ts src/auto-reply/reply/abort.test.ts -- --reporter=verbose
- PATH=/Users/buns/.nvm/versions/node/v22.22.2/bin:$PATH pnpm test src/auto-reply/inbound.test.ts -- --reporter=verbose
- PATH=/Users/buns/.nvm/versions/node/v22.22.2/bin:$PATH pnpm check:changed
- GitHub CI run 25841945093 passed, including checks-node-auto-reply-core-top-level, checks-node-core, and build-artifacts.
- Real behavior proof run 25841947282 passed.

Fixes #48241
Thanks @BunsDev
2026-05-13 23:41:59 -05:00
Vincent Koc
89987df3d5 test(matrix): guard externalized runtime deps 2026-05-14 12:38:17 +08:00
Vincent Koc
b97b5d6f22 changelog: cover three @sjf codex-migrate UX fixes
- humanize MIGRATION_REASON_* codes in conflict-status messaging
- swap migrate glyphs for manual-review (🔍) and archive (📖) items
- split codex-migrate output into preview + result phases
2026-05-14 12:36:45 +08:00
Bek
aa39107261 docs: align Slack docs for socket mode and troubleshooting (#81647) 2026-05-14 00:34:30 -04:00
Vincent Koc
117d2c9f2e changelog: cover Codex MCP, migration binary, and subagent maintenance fixes
- (#81551) Codex app-server MCP server projection, thread rotation, resume resend (jalehman)
- (#81582) Codex migration uses managed codex binary (fuller-stack-dev)
- (#81498) Subagent registry sessions preserved through maintenance (ai-hpc)
2026-05-14 12:31:58 +08:00
Vincent Koc
f5ebe63ecd fix(auto-reply): preserve debounce ordering 2026-05-14 12:29:30 +08:00
Sarah Fortune
2d231cef27 fix(migrate): humanize conflict-status messaging across migrate UI
Replace internal `MIGRATION_REASON_*` codes with natural sentences across the migrate UI.

| Surface | Before | After |
| --- | --- | --- |
| Selection prompt (skill) | `(Codex CLI skill; conflict: target exists)` | `(Codex skill already installed in workspace)` |
| Selection prompt (plugin) | `(openai-curated; conflict: plugin exists)` | `(openai-curated plugin already installed in workspace)` |
| Plan/result row (skill conflict) | `• conflict: gh-address-comments (Copy Codex skill into OpenClaw)` | `⚠️ gh-address-comments (Already installed in workspace.)` |
| Plan/result row (plugin conflict) | `• conflict: <name> (Install Codex plugin into OpenClaw)` | `⚠️ <name> (Already installed in workspace.)` |
2026-05-13 21:25:58 -07:00
rolandrscheel
e4cee2eb69 perf(gateway): cache session list resolver lookups
Refs #75839.\n\nRebases and lands the sessions.list resolver-cache fix from #77187 after maintainer conflict repair. The change keeps cache state scoped to a single sessions.list call and memoizes deterministic per-row resolver work for repeated provider/model tuples.\n\nVerification:\n- pnpm test src/gateway/session-utils.perf.test.ts src/gateway/session-utils.test.ts\n- pnpm exec oxfmt --check --threads=1 src/gateway/session-utils.ts src/gateway/session-utils.perf.test.ts scripts/github/real-behavior-proof-policy.mjs\n- git diff --check HEAD -- CHANGELOG.md scripts/github/real-behavior-proof-policy.mjs src/gateway/session-utils.perf.test.ts src/gateway/session-utils.ts\n- GitHub PR checks: 87 passing, CodeQL neutral, 21 skipped\n\nCo-authored-by: OpenClaw Agent <openclaw-agent@users.noreply.github.com>
2026-05-13 23:20:40 -05:00
Vincent Koc
5b418c3c4f fix(channels): preserve Telegram ordering without blocking follow-ups 2026-05-14 12:19:02 +08:00
Val Alexander
c722ae6a65 fix(control-ui): prevent iOS input zoom
Fixes #64651. Supersedes #64673.

Keeps shared form, config, and usage Control UI text-entry controls at 16px on touch-primary devices while preserving chat composer input sizing, so iOS Safari no longer auto-zooms focused fields.

Verification:
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md ui/src/styles/components.css ui/src/styles/config.css ui/src/styles/usage.css ui/src/styles/chat/layout.test.ts ui/src/styles/components.test.ts ui/src/styles/config.test.ts ui/src/styles/usage.test.ts
- git diff --check
- pnpm test ui/src/styles/chat/layout.test.ts ui/src/styles/components.test.ts ui/src/styles/config.test.ts ui/src/styles/usage.test.ts
- pnpm check:changed
- Playwright WebKit iPhone 12 computed-style proof for all targeted controls at 16px
- GitHub Real behavior proof, CI, and workflow sanity on exact PR head fa0d44a8fd
2026-05-13 23:17:34 -05:00
Val Alexander
5d4a8b0072 fix(agents): make trajectory cleanup timeout configurable
Refs #75839.\n\nAdds OPENCLAW_TRAJECTORY_FLUSH_TIMEOUT_MS and OPENCLAW_AGENT_CLEANUP_TIMEOUT_MS for agent cleanup steps while preserving the 10s default. Includes focused timeout precedence tests, trajectory docs, and changelog coverage.\n\nVerification:\n- pnpm test src/agents/run-cleanup-timeout.test.ts\n- pnpm exec oxfmt --check --threads=1 src/agents/run-cleanup-timeout.ts src/agents/run-cleanup-timeout.test.ts\n- pnpm format:docs:check docs/tools/trajectory.md\n- git diff --check\n- pnpm check:changed\n- GitHub PR checks: 88 passing, CodeQL neutral, 21 skipped
2026-05-13 23:09:56 -05:00
Vincent Koc
5496c0d5b7 docs(testing): clarify pnpm proof routing 2026-05-14 12:09:17 +08:00
Josh Lehman
1ee0d51e92 fix(codex): preserve MCP servers in app-server harness (#81551)
* Plumb bundle MCP config into Codex app server

* fix: align codex mcp thread config with pi

* fix: rotate codex mcp threads when disabled

* fix: scope codex bundle mcp to bundled servers

* fix(codex): resend user MCP config on resume

---------

Co-authored-by: Josh Lehman <phaedrus@Mac.hsd1.ca.comcast.net>
2026-05-13 21:05:20 -07:00
Val Alexander
4935e24c7a fix: reconcile control ui run status cleanup
Fix stale Control UI active-run cleanup across terminal, reconnect, reset, and session-switch paths. Adds shared run lifecycle cleanup, stale compaction/fallback reconciliation, focused tests, and the compact composer run-status chip. Fixes #76874 and #64220; refs #71630. Validated with green PR CI on head 141f07158f and focused local UI tests.
2026-05-13 23:03:45 -05:00
Josh Lehman
aac216d699 fix: route plugin LLM completions through Codex runtime (#81511)
* fix: route plugin LLM completions through Codex runtime

* fix: preserve OpenRouter completion model ids

* fix: allow registry config compat guards
2026-05-13 21:02:28 -07:00
Vincent Koc
3b8ac38ae9 fix(codex): classify app-server auth refresh failures
Classify Codex native/app-server auth refresh logout failures and preserve app-server relogin detail in RPC errors.
2026-05-14 11:56:18 +08:00
Kevin Lin
78644bc6de fix: carry codex migration config through onboarding 2026-05-13 20:50:07 -07:00
Vincent Koc
3da9027770 fix(update): allow update config size drops 2026-05-14 11:47:17 +08:00
Val Alexander
256377c029 feat(ui): add WebChat auto-scroll mode selector
Add a persisted Control UI/WebChat auto-scroll mode setting with near-bottom, always, and off modes. The implementation preserves the current near-bottom behavior by default, keeps manual scroll-to-bottom available when automatic scrolling is off, exposes the selector in desktop and mobile chat controls, syncs i18n fallbacks, and adds focused storage/render/scroll coverage.

Verification:
- pnpm test ui/src/ui/app-settings.test.ts ui/src/ui/views/chat.test.ts ui/src/ui/app-render.helpers.node.test.ts ui/src/ui/app-render.helpers.browser.test.ts ui/src/ui/storage.node.test.ts ui/src/ui/app-scroll.test.ts -- --reporter=verbose
- pnpm check:changed
- pnpm ui:i18n:check
- pnpm ui:build
- PR CI green on head 1b8859c8ba

Fixes #7648.
Fixes #81287.
2026-05-13 22:24:53 -05:00
NVIDIAN
7c5222a195 fix: preserve pending subagent sessions during maintenance (#81498) 2026-05-13 23:19:18 -04:00
pashpashpash
78eb92e622 Route Codex message tool replies back to WebChat and TUI (#81586)
* fix: route internal ui message tool replies

* docs: document reserved codex sdk helpers

* test(gateway): stabilize sessions send agent assertion

* fix(agents): preserve rich internal source replies

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-14 11:55:54 +09:00
Val Alexander
faa443a452 fix(chat/ios): downscale image attachments before send
Resize iOS chat PhotosPicker image attachments through the shared JPEG transcoder before staging/sending. Cap long edge and payload bytes, strip source metadata, preserve previews from processed data, and add focused processor/view-model regression tests.\n\nFixes #68524.\nSupersedes #73710.
2026-05-13 21:44:05 -05:00
Jerry-Xin
61ae9b7193 fix(update): preserve config during update repair
Preserve update-time config state by snapshotting before repair/restart writes, keeping plugin install records available for migration, and blocking unsafe update-time config size drops.

Also documents the Codex reserved SDK subpaths needed by the plugin contract guardrail.

Fixes #80077.

Thanks @Jerry-Xin and @vincentkoc.

Co-authored-by: Jerry-Xin <3401616+Jerry-Xin@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-05-14 10:43:33 +08:00
Jason
3fd64a281f fix: use managed codex binary for source migration (#81582)
* fix: use managed codex binary for source migration

* docs: document codex reserved sdk subpaths
2026-05-13 19:40:54 -07:00
Vincent Koc
c95ccf43c1 fix: sync codex cli package pin 2026-05-14 10:35:18 +08:00
Val Alexander
6a41a54212 fix(macos): harden direct gateway TLS pinning
Summary:
- Require macOS system trust before saving and accepting first-use direct `wss://` gateway TLS pins.
- Honor `gateway.remote.tlsFingerprint` in macOS direct node-mode TLS params.
- Add focused Swift coverage and update remote gateway docs/changelog.

Verification:
- Local: swiftformat --lint on touched Swift files.
- Local: git diff --check HEAD~1..HEAD.
- Local: swift test --package-path apps/shared/OpenClawKit --filter GatewayTLSPinningTests.
- Local: swift test --package-path apps/macos --filter 'MacNodeModeCoordinatorTests|GatewayEndpointStoreTests'.
- Local: PATH=/Users/buns/.nvm/versions/node/v24.13.0/bin:$PATH pnpm docs:list.
- CI: macos-node, macos-swift, check-docs, security-fast, security-scm-fast, security-dependency-audit, Opengrep OSS, and changed-path checks passed on PR head cf383fc047.

Fixes #50642.
Supersedes #50643.
2026-05-13 21:30:22 -05:00
Eduardo Piva
983064f5f8 fix(sessions): report ACP-runtime metadata for ACP-keyed sessions
Report ACP control-plane session runtime metadata from persisted ACP session metadata/backend, and keep ACP-shaped bridge sessions on normal configured model/runtime metadata.

Proof: focused sessions runtime/model-display tests, core prod/test typechecks, touched-file format check, seeded openclaw sessions --json behavior proof, and passing relevant CI. Known unrelated red check: checks-fast-contracts-plugins-d plugin SDK documentation contract for codex helper subpaths.
2026-05-13 19:03:50 -07:00
Sarah Fortune
bce56bacc7 fix(migrate): swap glyphs on manual-review and archive item rows
Manual-review items are kind:"manual" with status:"skipped" so they were rendering with ⏭️, which reads like "done, ignored" — exactly the wrong signal for items that still need user attention. Render with 🔍 instead so the row says "look closer here".

Archive items end up status:"migrated" once written to the report dir, so they were rendering with , which overstates what happened — the file was saved aside, not imported. Render with 📖 so the row reads "filed away".

Skill/plugin/secret/memory rows continue to render with their status glyphs (  ⏭️ ⚠️) unchanged. JSON output (--json) is unaffected.
2026-05-13 18:58:17 -07:00
Vincent Koc
e774b25b2f fix(agents): preserve reply metadata through tool media 2026-05-14 09:54:31 +08:00
pashpashpash
3ce922437f fix: load Codex for selectable OpenAI agent models
Treat selectable configured OpenAI agent models as Codex runtime requirements during plugin auto-enable, startup planning, and doctor install repair.\n\nPR: https://github.com/openclaw/openclaw/pull/81591
2026-05-14 09:51:15 +08:00
Vincent Koc
97ed9b2d82 test(agents): fix live profile lint 2026-05-14 09:19:04 +08:00
Vincent Koc
5923d9e807 fix(plugin-sdk): export codex runtime helpers 2026-05-14 09:19:04 +08:00
Vincent Koc
a504cd0190 test: make root permission assertions deterministic 2026-05-14 08:52:41 +08:00
Peter Steinberger
f3361dc928 test(agents): surface live OpenAI replay auth failures 2026-05-14 01:36:56 +01:00
Val Alexander
52370c5998 feat(ui): add browser-local Control UI text size setting
Adds a bounded browser-local Control UI text size setting in Appearance and Quick Settings, persists it in UiSettings, and applies CSS text-scale variables across chat text, composer input, sidebars, and tool cards while preserving mobile Safari input zoom safety.

Fixes #8547.
Thanks @BunsDev.
2026-05-13 19:18:05 -05:00
Peter Steinberger
0b55317494 test(plugins): isolate capability provider runtime mocks 2026-05-14 01:07:57 +01:00
Peter Steinberger
3225ec43c8 test(plugin-install): align npm peer scan expectations 2026-05-14 00:51:09 +01:00
Peter Steinberger
23446a248b ci(release): fail full validation on child failure 2026-05-14 00:46:22 +01:00
Eduardo Piva
9431d18aaf fix(sessions): classify spawn-child sessions correctly
Classify ACP spawn-child sessions via persisted spawnedBy metadata and share the session kind classifier across sessions/status output.

Verified with Azure Crabbox seeded ACP session-store proof, targeted session/status tests, touched-file lint, build, and green PR CI.
2026-05-13 16:39:04 -07:00
pashpashpash
74860e93fd fix(codex): preserve user home for app-server launches 2026-05-13 16:37:03 -07:00
Peter Steinberger
8046b5e462 docs: add plugin update changelog (#81512) (thanks @JARVIS-Glasses) 2026-05-14 00:25:52 +01:00
JARVIS-Glasses
5214f16e29 fix(update): clear stale plugin refs after failed updates 2026-05-14 00:25:52 +01:00
Vincent Koc
b5c3379097 fix(telegram): clear progress draft before answer 2026-05-14 07:19:00 +08:00
Peter Steinberger
dc7fab4dc5 perf: cache pi model discovery 2026-05-14 00:13:29 +01:00
Peter Steinberger
b10b946b12 docs(clawhub): remove missing security route 2026-05-13 23:57:05 +01:00
이민재
72f50dd127 fix(slack): normalize read timestamp bounds (#81338)
* fix(slack): normalize read timestamp bounds

* fix(slack): document read timestamp bounds fix

* fix(slack): simplify timestamp bounds validation

---------

Co-authored-by: honor2030 <19909783+honor2030@users.noreply.github.com>
Co-authored-by: Altay <altay@hey.com>
2026-05-14 01:52:55 +03:00
Vincent Koc
d08f68dee7 test(e2e): cover root-managed VPS upgrades 2026-05-14 06:50:58 +08:00
Peter Steinberger
25dd30d656 build(whatsapp): keep audio decoder dependency 2026-05-13 23:48:05 +01:00
Peter Steinberger
c654f1f811 test(whatsapp): allow audio runtime dependency 2026-05-13 23:47:03 +01:00
Josh Lehman
6395117142 fix: restore Codex cron automation compatibility (#81510)
* fix: restore Codex cron automation compatibility

* fix: document Codex cron automation restore
2026-05-13 15:34:31 -07:00
Shakker
26da4edbe1 docs: add acp request error changelog 2026-05-13 22:39:24 +01:00
vyctorbrzezowski
c5071a8061 fix(acp): preserve RequestError details 2026-05-13 22:39:24 +01:00
Eduardo Piva
207fb9951d fix(sessions): display ACP runtime sentinel for ACP sessions (#79543)
Display the ACP runtime sentinel for ACP control-plane session rows in openclaw sessions output, while preserving configured model/provider display for direct sessions.

Verified with focused sessions tests, touched-file oxlint, check:test-types, Crabbox after-fix proof, and exact-head GitHub CI.
2026-05-13 14:26:51 -07:00
B.K.
b8ea6097d9 fix(cli): report stale plugin doctor config (#81515)
Merged via squash.

Prepared head SHA: 23bc849abd
Co-authored-by: BKF-Gitty <263413630+BKF-Gitty@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-14 00:03:54 +03:00
vyctorbrzezowski
4d2e708726 fix(memory-lancedb): support cjk auto-capture triggers 2026-05-13 21:49:22 +01:00
Sarah Fortune
6602884b06 test(codex-migrate): stub clack log in migrate mock 2026-05-13 13:29:23 -07:00
Sarah Fortune
b85259c443 test(codex-migrate): cover new preview/result format 2026-05-13 13:29:23 -07:00
Sarah Fortune
49adf206e8 fix(codex-migrate): use String#replace in display name 2026-05-13 13:29:23 -07:00
Sarah Fortune
d7d1fba74b ux(codex-migrate): polish preview/result output
Restructure the migrate codex CLI output:

- Split into separate Before (preview) and After (result) messages
  so each can be tuned independently. Both render through clack's
  log.message so they pick up the standard '|' gutter.
- Group items by kind (Skills, Plugins, Memory, Secrets, Archive,
  Manual review, Other) instead of one flat list. Hide config items
  from display and exclude them from the summary count.
- Drop the internal kind/action tag (e.g. 'manual/manual'), strip
  '<kind>:' id prefixes and trailing ':N' disambiguators, and use
  '•' for bullets.
- Mute parenthetical action text.
- In result mode: replace status text with emoji ( migrated,
   error, ⏭️ skipped, ⚠️ conflict), show '(Migrated)' on success,
  show humanized failure reasons for known codes (plugin_missing,
  marketplace_missing, etc.), say '(Skipped)' for user-deselected
  skill/plugin items but keep the real message on manual-review
  skips. Drop warnings from the result message.
- In preview mode: omit the 'Next' section and move warnings to
  the bottom. Use generic action descriptions ('Copy Codex skill
  into OpenClaw', 'Install Codex plugin into OpenClaw').
- Drop the redundant 'Codex cached plugin bundles remain
  manual-review only.' warning — covered by the source-installed
  warning above it.
2026-05-13 13:29:23 -07:00
Peter Steinberger
cf571c1b58 fix(plugins): scope install scanner to runtime graph 2026-05-13 21:22:37 +01:00
dwc1997
cffae53b43 fix(security): classify broad Windows SIDs as world principals
Carry Windows ACL world-principal classification through @openclaw/fs-safe@0.2.2 so Anonymous Logon, Guests, Interactive, Network, and Local SID/principal variants are treated as world-equivalent in filesystem audit findings.

Also add regression coverage, changelog coverage, a narrow lint cleanup, and a UI test isolation fix needed by the current CI shard.

Co-authored-by: dwc <118101032587@njust.edu.cn>
2026-05-13 15:19:02 -05:00
Kevin Lin
6a23e26a27 docs: consolidate plugin install docs (#81167)
* docs: consolidate plugin install docs

* docs: align plugin getting started page

* snap

* docs: add reusable audit viewer tooling

* docs: add audit viewer doc mode

* docs: add audit viewer diff mode

* docs: strengthen plugin docs audit coverage

* docs: preserve plugin scan order reference

* docs: resolve plugin audit coverage gaps

* docs: strengthen audit line mappings

* docs: narrow plugin docs refactor scope

* docs: preserve plugin audit facts

* docs: keep audit skill local

* docs: remove audit skill from pr

* fix: satisfy plugin scan lint

* docs: address plugin docs review
2026-05-13 13:17:39 -07:00
Peter Steinberger
308b39efd5 docs: document real behavior proof fields 2026-05-13 21:08:17 +01:00
Peter Steinberger
f30c9eff76 docs: refresh clawdtributor update guidance 2026-05-13 21:07:49 +01:00
Peter Steinberger
7c4f607572 docs: refresh config baseline hash 2026-05-13 20:59:11 +01:00
Peter Steinberger
ebd829cffd test: add release qa docker lanes 2026-05-13 20:57:44 +01:00
edge_kase
8237d165e2 feat(acp): add backend provider failover for UNAVAILABLE errors (#69542)
Merged via squash.

Prepared head SHA: 1d4c929ad7
Co-authored-by: kaseonedge <15183881+kaseonedge@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-13 22:52:14 +03:00
狼哥
609187f5f6 fix(security): classify dangerous Windows sandbox binds first (#63074)
Adds Windows USERPROFILE to the sandbox blocked home roots so credential binds are denied even when HOME points at a different shell home.

Verified:
- node scripts/test-projects.mjs src/agents/sandbox/validate-sandbox-security.test.ts
- node scripts/test-projects.mjs src/agents/sandbox/bind-spec.test.ts src/agents/sandbox/host-paths.test.ts src/agents/sandbox/validate-sandbox-security.test.ts
- git diff --check HEAD^ HEAD

Co-authored-by: luoyanglang <hanwanlonga@gmail.com>
2026-05-13 14:42:45 -05:00
AI-HUB
b7d3b74f1c fix(ui): order live chat items by timestamp (#81016)
* fix(ui): order live chat items by timestamp

* fix(ui): stabilize chat timestamp sorting

* test: refresh core lint fixtures

* test: refresh current main guard fixtures

* test: refresh codex prompt snapshots

* test(matrix): keep runtime helper local

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-13 20:30:44 +01:00
Peter Steinberger
439e396262 fix(plugins): allow benign LanceDB runtime shims 2026-05-13 20:24:46 +01:00
Peter Steinberger
1f59031373 test(matrix): keep runtime media mock local 2026-05-13 20:07:10 +01:00
Peter Steinberger
8a406528b4 fix(codex): project user MCP servers into app-server threads
Fixes #80814.

Co-authored-by: kinjitakabe <273844887+kinjitakabe@users.noreply.github.com>
2026-05-13 20:07:10 +01:00
sallyom
d4484158d9 fix: avoid broad provider env marker inference 2026-05-13 15:02:56 -04:00
Josh Lehman
b55d9fa466 fix(codex): rotate incompatible context-engine threads (#81223)
* fix(codex): rotate incompatible context-engine threads

* fix(codex): tighten context-engine sidecar policy

* fix: type context-engine binding policy config

---------

Co-authored-by: Josh Lehman <phaedrus@Mac.hsd1.ca.comcast.net>
2026-05-13 11:50:03 -07:00
Shakker
433bafa55b fix: avoid bodyless media response buffering 2026-05-13 19:38:26 +01:00
Shakker
af6f75f78c docs: credit media fetch retry author 2026-05-13 19:38:26 +01:00
vyctorbrzezowski
e9a9434842 fix(media): retry transient remote media fetches 2026-05-13 19:38:26 +01:00
Peter Steinberger
58bfefbad3 test: add release user journey docker lane 2026-05-13 19:17:57 +01:00
homer-byte
c3e5d85ce1 fix(imessage): avoid visible media placeholder text (#81209)
Keep media-only iMessage sends from delivering visible <media:image> text while preserving a non-visible echo key for self-echo dedupe. Thanks @homer-byte.
2026-05-13 09:03:05 -07:00
Ayaan Zaidi
ddd79e51ba docs(changelog): note agent session bootstrap 2026-05-13 21:29:21 +05:30
Ayaan Zaidi
652af36d17 test(gateway): prove agent session bootstrap 2026-05-13 21:29:21 +05:30
Ayaan Zaidi
2d3f3de235 fix(gateway): bootstrap agent sessions before send 2026-05-13 21:29:21 +05:30
homer-byte
1d6e5f7a3e fix(imessage): make inbound image attachments readable by agents (#78580)
Stage native iMessage inbound attachments into managed media and convert HEIC/HEIF images to JPEG before dispatch. Thanks @homer-byte.
2026-05-13 08:35:52 -07:00
Peter Steinberger
58591c37a4 fix(tui): emit v4 embedded chat deltas
(cherry picked from commit a6d878376b)
2026-05-13 16:28:12 +01:00
Peter Steinberger
64ba5e2ae3 docs: add inline comment guidance 2026-05-13 16:13:49 +01:00
Peter Steinberger
f441a569ea docs: update changelog for OpenAI OAuth prompt (#81301) (thanks @rubencu) 2026-05-13 16:13:35 +01:00
Rubén Cuevas
83549774cd fix(openai): clarify remote Codex OAuth prompt 2026-05-13 16:13:35 +01:00
Peter Steinberger
48fb4bade8 docs: credit Telegram group fix contributor (#81030) 2026-05-13 16:09:13 +01:00
kinjitakabe
ab719c2f82 fix(telegram/groups): treat empty accounts.<id>.groups: {} as unspecified in single-account setups
`mergeTelegramAccountConfig` and the generic `resolveChannelGroups` both used
`accountGroups ?? channelConfig.groups` to fall back to root group allowlists,
which only catches the `undefined` case. An explicit empty `{}` survives
nullish coalescing and overrides the root allowlist with an empty allowlist,
which then pairs with the default `groupPolicy: "allowlist"` to silently
deny every group update — the symptom reported in #79427.

Treat an explicit empty `{}` the same as undefined for fallback purposes in
single-account setups (one or zero configured accounts). Multi-account setups
keep current semantics so per-account explicit-empty groups still scope
disable a single account without affecting its siblings. The explicit way to
block all groups for any account remains `groupPolicy: "disabled"`, which
this PR does not touch.

Fixes #79427.
2026-05-13 16:09:13 +01:00
Peter Steinberger
d540512d00 fix(gateway): satisfy node registry lint 2026-05-13 16:06:37 +01:00
Peter Steinberger
babd48b6cd docs(changelog): note v4 chat delta protocol 2026-05-13 16:06:37 +01:00
Peter Steinberger
a6497b1759 fix(gateway): avoid duplicate v4 deltas 2026-05-13 16:06:37 +01:00
Peter Steinberger
150bebcd0c fix(gateway): require v4 chat deltas 2026-05-13 16:06:37 +01:00
samzong
63724ddcfd fix(sdk): preserve replayed chat snapshots 2026-05-13 16:06:37 +01:00
samzong
10315ce215 fix(gateway): add incremental chat delta payloads 2026-05-13 16:06:37 +01:00
Vincent Koc
2a67a7f65e fix(plugins): prune managed peers on uninstall 2026-05-13 22:53:58 +08:00
Peter Steinberger
0513b285ef docs: update crabbox skill guidance 2026-05-13 15:46:50 +01:00
Pavan Kumar Gondhi
418d7afb33 gateway: pass Talk session scope to resolver [AI] (#81379)
* fix: pass talk session visibility scope

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing claude review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 20:09:03 +05:30
Peter Steinberger
4d8aec8210 fix(plugins): attribute runtime config deprecations (#81425) (thanks @BKF-Gitty)
Co-authored-by: BKF-Gitty <bandark@mac.com>
2026-05-13 15:37:43 +01:00
Altay
a40499b21a fix(test): isolate auth profile secrets in test state (#81393)
Merged via squash.

Prepared head SHA: fde8787cb7
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-13 17:34:45 +03:00
Peter Steinberger
210c7c1b85 fix: preserve SGLang reasoning replay (#81091) 2026-05-13 15:28:07 +01:00
AI-HUB
51cd3cddeb fix(sglang): preserve reasoning replay history 2026-05-13 15:28:07 +01:00
Shakker
402b0df3b6 fix: preserve owned plugin dependencies during peer repair 2026-05-13 15:26:40 +01:00
Shakker
f4cb20300f fix: harden managed plugin peer recovery 2026-05-13 15:26:40 +01:00
Shakker
6e5042cd62 fix: avoid rescanning repaired plugin peers 2026-05-13 15:26:40 +01:00
Shakker
18ca285ed6 fix: preserve managed plugin peer dependencies 2026-05-13 15:26:40 +01:00
Peter Steinberger
1c28e4a0bb test: add docker live subagent announce proof 2026-05-13 15:21:37 +01:00
Peter Steinberger
0b8ee4616d fix(github-copilot): support Gemini image understanding
Fixes Copilot image understanding by exchanging OAuth tokens for Copilot API tokens, routing Copilot Gemini image requests through Chat Completions, and sending the prompt in user content with Copilot vision headers.

Real behavior proof:
- Old Responses route with real Copilot key reproduced `400 model gemini-3.1-pro-preview does not support Responses API`.
- Fixed route with the same real Copilot key returned `Cat`.
- Final CLI live smoke returned `ok: true` and `text: Cat` for `github-copilot/gemini-3.1-pro-preview`.

Verification:
- pnpm test src/media-understanding/image.test.ts extensions/github-copilot/models.test.ts extensions/github-copilot/stream.test.ts src/agents/pi-hooks/compaction-safeguard.test.ts -- --reporter=verbose
- pnpm check:changed via Blacksmith Testbox tbx_01krgt56pqmft8txekt017wke6, Actions run https://github.com/openclaw/openclaw/actions/runs/25803926150, exit 0.

Refs #80393, #80442.

Co-authored-by: Yang Haoyu <150496764+afunnyhy@users.noreply.github.com>
2026-05-13 15:20:27 +01:00
Peter Steinberger
6160e7a411 fix(gateway): hide unapproved node surfaces
Co-authored-by: samzong <samzong.lu@gmail.com>
2026-05-13 15:13:44 +01:00
Peter Steinberger
53d007bc87 refactor(media): centralize bounded remote downloads
Co-authored-by: samzong <samzong.lu@gmail.com>
2026-05-13 15:04:49 +01:00
Peter Steinberger
218156447c docs: add config mutation changelog 2026-05-13 15:00:07 +01:00
Peter Steinberger
ab3d61813a fix: rebase synthetic browser profiles 2026-05-13 15:00:07 +01:00
Peter Steinberger
23344fdb61 fix: avoid stale config mutation rebases 2026-05-13 15:00:07 +01:00
Peter Steinberger
756379b11d refactor: centralize config mutations 2026-05-13 15:00:07 +01:00
Peter Steinberger
c4c0b65b80 fix: rebase browser profile mutations 2026-05-13 15:00:07 +01:00
Peter Steinberger
ec998d1e95 fix: clean current dependency checks 2026-05-13 15:00:07 +01:00
Peter Steinberger
07c5e2465b fix: handle rebased config mutation races 2026-05-13 15:00:07 +01:00
Peter Steinberger
743cbc2f13 fix: mark slack channel system events untrusted 2026-05-13 15:00:07 +01:00
Peter Steinberger
66cce180c3 test: align config mutation mocks 2026-05-13 15:00:07 +01:00
Peter Steinberger
f3327ac30b fix: clean production config mutation checks 2026-05-13 15:00:07 +01:00
Peter Steinberger
2fe39ce949 refactor: rebase runtime config writes 2026-05-13 15:00:07 +01:00
Peter Steinberger
fb3aa155be fix: remove redundant config clone casts 2026-05-13 15:00:07 +01:00
Peter Steinberger
2e983e47df fix: serialize config mutation writes 2026-05-13 15:00:07 +01:00
Peter Steinberger
488a3d8e52 fix(ci): refresh stale metadata ownership 2026-05-13 14:59:47 +01:00
Peter Steinberger
5ac6b600de docs(channels): document bot loop protection 2026-05-13 14:59:47 +01:00
Peter Steinberger
4785a073d6 feat(channels): add generic bot loop protection 2026-05-13 14:59:47 +01:00
Peter Steinberger
d00e9eba65 docs: add ds4 provider guide 2026-05-13 14:45:34 +01:00
Peter Steinberger
96c0309db9 test: fix queue settings session fixtures 2026-05-13 14:24:45 +01:00
Peter Steinberger
714f62f976 test: add live subagent steering proof 2026-05-13 14:24:45 +01:00
Peter Steinberger
3cef9a65d3 fix: use in-process subagent announce handoff 2026-05-13 14:24:45 +01:00
stain lu
f1381b5312 fix(telegram): limit startup probes (#80986)
## Summary

- Limit Telegram startup `getMe` probes to two concurrent accounts.
- Add regression coverage for queued startup and queued abort behavior.
- Document the multi-account startup bound and add changelog credit.

## Verification

- `pnpm exec oxfmt --check --threads=1 CHANGELOG.md docs/channels/telegram.md extensions/telegram/src/channel.ts extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/startup-probe-limiter.ts`
- `node scripts/format-docs.mjs --check docs/channels/telegram.md`
- `git diff --check HEAD~1..HEAD`
- `env OPENCLAW_TEST_HEAVY_CHECK_LOCK_HELD=1 OPENCLAW_VITEST_MAX_WORKERS=1 pnpm --config.manage-package-manager-versions=false test extensions/telegram/src/channel.gateway.test.ts src/gateway/server-channels.test.ts`
- `env OPENCLAW_TSGO_HEAVY_CHECK_LOCK_HELD=1 pnpm --config.manage-package-manager-versions=false run tsgo:extensions`
- `env OPENCLAW_TSGO_HEAVY_CHECK_LOCK_HELD=1 pnpm --config.manage-package-manager-versions=false run tsgo:extensions:test`
- GitHub CI mostly green on `2d389e1010742efa884eacea520afd588d0b898f`; `check-test-types` red in unrelated `src/auto-reply/reply/queue/settings.test.ts` outside this PR's diff.

Co-authored-by: stainlu <stainlu@newtype-ai.org>
2026-05-13 14:23:32 +01:00
Pavan Kumar Gondhi
b17e77a22b Require approval for setup-code device pairing [AI] (#81292)
* fix: require approval for setup-code bootstrap pairing

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 18:48:44 +05:30
Peter Steinberger
05bef5db20 docs: update changelog for docker setup path fix (#81105) 2026-05-13 14:13:57 +01:00
brokemac79
3cf296185f fix(docker): pin setup cli container paths 2026-05-13 14:13:57 +01:00
Jason
70df2b8fe2 feat: steer mid-turn prompts by default (#77023)
Summary:
- Default active-run queueing to steer while preserving explicit followup/collect modes.
- Keep `/steer` fallback behavior and migrate retired queue steering config.
- Await Codex app-server steering acceptance so rejected/aborted steering can fall back safely.
- Route active subagent announcements through intentional acceptance-aware steering, with legacy queue helpers deprecated for delivery decisions.

Verification:
- git diff --check
- rg -n "^(<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|)" CHANGELOG.md docs src extensions || true
- pnpm test src/agents/subagent-announce-dispatch.test.ts src/agents/subagent-announce-delivery.test.ts src/agents/pi-embedded-runner/runs.test.ts src/agents/subagent-announce.format.e2e.test.ts src/agents/subagent-announce.test.ts
- pnpm test src/auto-reply/reply/commands-steer.test.ts src/auto-reply/reply/queue/settings.test.ts src/auto-reply/reply/queue-policy.test.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts src/auto-reply/reply/get-reply-run.media-only.test.ts extensions/codex/src/app-server/run-attempt.test.ts -- -t "queued steering|explicit all-mode steering|flushes pending default queued steering|rejects queued steering|resolveActiveRunQueueAction|resolveQueueSettings|handleSteerCommand"

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-13 14:00:11 +01:00
Peter Steinberger
1c5c72ea24 docs: update changelog for chat action overlap (#81244) 2026-05-13 13:54:30 +01:00
JARVIS-Glasses
3b7181a38b fix(ui): prevent chat actions overlapping replies 2026-05-13 13:54:06 +01:00
Peter Steinberger
4e34c1aa47 fix(channel): refresh wecom onboarding install (#80390) (thanks @brokemac79) 2026-05-13 13:52:05 +01:00
brokemac79
f2cbe9ecc5 fix(channel): refresh wecom onboarding install 2026-05-13 13:52:05 +01:00
Peter Steinberger
dfead3198d ci: make testbox session shutdown non-blocking 2026-05-13 13:50:44 +01:00
Peter Steinberger
852f88f1e7 ci: guard optional website installer file 2026-05-13 13:35:54 +01:00
Peter Steinberger
694ca50e97 Revert "refactor: move runtime state to SQLite"
This reverts commit f91de52f0d.
2026-05-13 13:33:38 +01:00
Peter Steinberger
3de5979bdc ci: fix website installer sync git add 2026-05-13 13:31:39 +01:00
Peter Steinberger
d1fdd6e186 fix(installer): honor git install versions 2026-05-13 13:17:29 +01:00
Peter Steinberger
f91de52f0d refactor: move runtime state to SQLite
* refactor: remove stale file-backed shims

* fix: harden sqlite state ci boundaries

* refactor: store matrix idb snapshots in sqlite

* fix: satisfy rebased CI guardrails

* refactor: store current conversation bindings in sqlite table

* refactor: store tui last sessions in sqlite table

* refactor: reset sqlite schema history

* refactor: drop unshipped sqlite table migration

* refactor: remove plugin index file rollback

* refactor: drop unshipped sqlite sidecar migrations

* refactor: remove runtime commitments kv migration

* refactor: preserve kysely sync result types

* refactor: drop unshipped sqlite schema migration table

* test: keep session usage coverage sqlite-backed

* refactor: keep sqlite migration doctor-only

* refactor: isolate device legacy imports

* refactor: isolate push voicewake legacy imports

* refactor: isolate remaining runtime legacy imports

* refactor: tighten sqlite migration guardrails

* test: cover sqlite persisted enum parsing

* refactor: isolate legacy update and tui imports

* refactor: tighten sqlite state ownership

* refactor: move legacy imports behind doctor

* refactor: remove legacy session row lookup

* refactor: canonicalize memory transcript locators

* refactor: drop transcript path scope fallbacks

* refactor: drop runtime legacy session delivery pruning

* refactor: store tts prefs only in sqlite

* refactor: remove cron store path runtime

* refactor: use cron sqlite store keys

* refactor: rename telegram message cache scope

* refactor: read memory dreaming status from sqlite

* refactor: rename cron status store key

* refactor: stop remembering transcript file paths

* test: use sqlite locators in agent fixtures

* refactor: remove file-shaped commitments and cron store surfaces

* refactor: keep compaction transcript handles out of session rows

* refactor: derive transcript handles from session identity

* refactor: derive runtime transcript handles

* refactor: remove gateway session locator reads

* refactor: remove transcript locator from session rows

* refactor: store raw stream diagnostics in sqlite

* refactor: remove file-shaped transcript rotation

* refactor: hide legacy trajectory paths from runtime

* refactor: remove runtime transcript file bridges

* refactor: repair database-first rebase fallout

* refactor: align tests with database-first state

* refactor: remove transcript file handoffs

* refactor: sync post-compaction memory by transcript scope

* refactor: run codex app-server sessions by id

* refactor: bind codex runtime state by session id

* refactor: pass memory transcripts by sqlite scope

* refactor: remove transcript locator cleanup leftovers

* test: remove stale transcript file fixtures

* refactor: remove transcript locator test helper

* test: make cron sqlite keys explicit

* test: remove cron runtime store paths

* test: remove stale session file fixtures

* test: use sqlite cron keys in diagnostics

* refactor: remove runtime delivery queue backfill

* test: drop fake export session file mocks

* refactor: rename acp session read failure flag

* refactor: rename acp row session key

* refactor: remove session store test seams

* refactor: move legacy session parser tests to doctor

* refactor: reindex managed memory in place

* refactor: drop stale session store wording

* refactor: rename session row helpers

* refactor: rename sqlite session entry modules

* refactor: remove transcript locator leftovers

* refactor: trim file-era audit wording

* refactor: clean managed media through sqlite

* fix: prefer explicit agent for exports

* fix: use prepared agent for session resets

* fix: canonicalize legacy codex binding import

* test: rename state cleanup helper

* docs: align backup docs with sqlite state

* refactor: drop legacy Pi usage auth fallback

* refactor: move legacy auth profile imports to doctor

* refactor: keep Pi model discovery auth in memory

* refactor: remove MSTeams legacy learning key fallback

* refactor: store model catalog config in sqlite

* refactor: use sqlite model catalog at runtime

* refactor: remove model json compatibility aliases

* refactor: store auth profiles in sqlite

* refactor: seed copied auth profiles in sqlite

* refactor: make auth profile runtime sqlite-addressed

* refactor: migrate hermes secrets into sqlite auth store

* refactor: move plugin install config migration to doctor

* refactor: rename plugin index audit checks

* test: drop auth file assumptions

* test: remove legacy transcript file assertions

* refactor: drop legacy cli session aliases

* refactor: store skill uploads in sqlite

* refactor: keep subagent attachments in sqlite vfs

* refactor: drop subagent attachment cleanup state

* refactor: move legacy session aliases to doctor

* refactor: require node 24 for sqlite state runtime

* refactor: move provider caches into sqlite state

* fix: harden virtual agent filesystem

* refactor: enforce database-first runtime state

* refactor: rename compaction transcript rotation setting

* test: clean sqlite refactor test types

* refactor: consolidate sqlite runtime state

* refactor: model session conversations in sqlite

* refactor: stop deriving cron delivery from session keys

* refactor: stop classifying sessions from key shape

* refactor: hydrate announce targets from typed delivery

* refactor: route heartbeat delivery from typed sqlite context

* refactor: tighten typed sqlite session routing

* refactor: remove session origin routing shadow

* refactor: drop session origin shadow fixtures

* perf: query sqlite vfs paths by prefix

* refactor: use typed conversation metadata for sessions

* refactor: prefer typed session routing metadata

* refactor: require typed session routing metadata

* refactor: resolve group tool policy from typed sessions

* refactor: delete dead session thread info bridge

* Show Codex subscription reset times in channel errors (#80456)

* feat(plugin-sdk): consolidate session workflow APIs

* fix(agents): allow read-only agent mount reads

* [codex] refresh plugin regression fixtures

* fix(agents): restore compaction gateway logs

* test: tighten gateway startup assertions

* Redact persisted secret-shaped payloads [AI] (#79006)

* test: tighten device pair notify assertions

* test: tighten hermes secret assertions

* test: assert matrix client error shapes

* test: assert config compat warnings

* fix(heartbeat): remap cron-run exec events to session keys (#80214)

* fix(codex): route btw through native side threads

* fix(auth): accept friendly OpenAI order for Codex profiles

* fix(codex): rotate auth profiles inside harness

* fix: keep browser status page probe within timeout

* test: assert agents add outputs

* test: pin cron read status

* fix(agents): avoid Pi resource discovery stalls

Co-authored-by: dataCenter430 <titan032000@gmail.com>

* fix: retire timed-out codex app-server clients

* test: tighten qa lab runtime assertions

* test: check security fix outputs

* test: verify extension runtime messages

* feat(wake): expose typed sessionKey on wake protocol + system event CLI

* fix(gateway): await session_end during shutdown drain and track channel + compaction lifecycle paths (#57790)

* test: guard talk consult call helper

* fix(codex): scale context engine projection (#80761)

* fix(codex): scale context engine projection

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* chore: align Codex projection changelog

* chore: realign Codex projection changelog

* fix: isolate Codex projection patch

---------

Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
Co-authored-by: Josh Lehman <josh@martian.engineering>

* refactor: move agent runtime state toward piless

* refactor: remove cron session reaper

* refactor: move session management to sqlite

* refactor: finish database-first state migration

* chore: refresh generated sqlite db types

* refactor: remove stale file-backed shims

* test: harden kysely type coverage

# Conflicts:
#	.agents/skills/kysely-database-access/SKILL.md
#	src/infra/kysely-sync.types.test.ts
#	src/proxy-capture/store.sqlite.test.ts
#	src/state/openclaw-agent-db.test.ts
#	src/state/openclaw-state-db.test.ts

* refactor: remove cron store path runtime

* refactor: keep compaction transcript handles out of session rows

* refactor: derive embedded transcripts from sqlite identity

* refactor: remove embedded transcript locator handoff

* refactor: remove runtime transcript file bridges

* refactor: remove transcript file handoffs

* refactor: remove MSTeams legacy learning key fallback

* refactor: store model catalog config in sqlite

* refactor: use sqlite model catalog at runtime

# Conflicts:
#	docs/cli/secrets.md
#	docs/gateway/authentication.md
#	docs/gateway/secrets.md

* fix: keep oauth sibling sync sqlite-local

# Conflicts:
#	src/commands/onboard-auth.test.ts

* refactor: remove task session store maintenance

# Conflicts:
#	src/commands/tasks.ts

* refactor: keep diagnostics in state sqlite

* refactor: enforce database-first runtime state

* refactor: consolidate sqlite runtime state

* Show Codex subscription reset times in channel errors (#80456)

* fix(codex): refresh subscription limit resets

* fix(codex): format reset times for channels

* Update CHANGELOG with latest changes and fixes

Updated CHANGELOG with recent fixes and improvements.

* fix(codex): keep command load failures on codex surface

* fix(codex): format account rate limits as rows

* fix(codex): summarize account limits as usage status

* fix(codex): simplify account limit status

* test: tighten subagent announce queue assertion

* test: tighten session delete lifecycle assertions

* test: tighten cron ops assertions

* fix: track cron execution milestones

* test: tighten hermes secret assertions

* test: assert matrix sync store payloads

* test: assert config compat warnings

* fix(codex): align btw side thread semantics

* fix(codex): honor codex fallback blocking

* fix(agents): avoid Pi resource discovery stalls

* test: tighten codex event assertions

* test: tighten cron assertions

* Fix Codex app-server OAuth harness auth

* refactor: move agent runtime state toward piless

* refactor: move device and push state to sqlite

* refactor: move runtime json state imports to doctor

* refactor: finish database-first state migration

* chore: refresh generated sqlite db types

* refactor: clarify cron sqlite store keys

* refactor: remove stale file-backed shims

* refactor: bind codex runtime state by session id

* test: expect sqlite trajectory branch export

* refactor: rename session row helpers

* fix: keep legacy device identity import in doctor

* refactor: enforce database-first runtime state

* refactor: consolidate sqlite runtime state

* build: align pi contract wrappers

* chore: repair database-first rebase

* refactor: remove session file test contracts

* test: update gateway session expectations

* refactor: stop routing from session compatibility shadows

* refactor: stop persisting session route shadows

* refactor: use typed delivery context in clients

* refactor: stop echoing session route shadows

* refactor: repair embedded runner rebase imports

# Conflicts:
#	src/agents/pi-embedded-runner/run/attempt.tool-call-argument-repair.ts

* refactor: align pi contract imports

* refactor: satisfy kysely sync helper guard

* refactor: remove file transcript bridge remnants

* refactor: remove session locator compatibility

* refactor: remove session file test contracts

* refactor: keep rebase database-first clean

* refactor: remove session file assumptions from e2e

* docs: clarify database-first goal state

* test: remove legacy store markers from sqlite runtime tests

* refactor: remove legacy store assumptions from runtime seams

* refactor: align sqlite runtime helper seams

* test: update memory recall sqlite audit mock

* refactor: align database-first runtime type seams

* test: clarify doctor cron legacy store names

* fix: preserve sqlite session route projections

* test: fix copilot token cache test syntax

* docs: update database-first proof status

* test: align database-first test fixtures

* docs: update database-first proof status

* refactor: clean extension database-first drift

* test: align agent session route proof

* test: clarify doctor legacy path fixtures

* chore: clean database-first changed checks

* chore: repair database-first rebase markers

* build: allow baileys git subdependency

* chore: repair exp-vfs rebase drift

* chore: finish exp-vfs rebase cleanup

* chore: satisfy rebase lint drift

* chore: fix qqbot rebase type seam

* chore: fix rebase drift leftovers

* fix: keep auth profile oauth secrets out of sqlite

* fix: repair rebase drift tests

* test: stabilize pairing request ordering

* test: use source manifests in plugin contract checks

* fix: restore gateway session metadata after rebase

* fix: repair database-first rebase drift

* fix: clean up database-first rebase fallout

* test: stabilize line quick reply receipt time

* fix: repair extension rebase drift

* test: keep transcript redaction tests sqlite-backed

* fix: carry injected transcript redaction through sqlite

* chore: clean database branch rebase residue

* fix: repair database branch CI drift

* fix: repair database branch CI guard drift

* fix: stabilize oauth tls preflight test

* test: align database branch fast guards

* test: repair build artifact boundary guards

* chore: clean changelog rebase markers

---------

Co-authored-by: pashpashpash <nik@vault77.ai>
Co-authored-by: Eva <eva@100yen.org>
Co-authored-by: stainlu <stainlu@newtype-ai.org>
Co-authored-by: Jason Zhou <jason.zhou.design@gmail.com>
Co-authored-by: Ruben Cuevas <hi@rubencu.com>
Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
Co-authored-by: Shakker <shakkerdroid@gmail.com>
Co-authored-by: Kaspre <36520309+Kaspre@users.noreply.github.com>
Co-authored-by: dataCenter430 <titan032000@gmail.com>
Co-authored-by: Kaspre <kaspre@gmail.com>
Co-authored-by: pandadev66 <nova.full.stack@outlook.com>
Co-authored-by: Eva <admin@100yen.org>
Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
Co-authored-by: Josh Lehman <josh@martian.engineering>
Co-authored-by: jeffjhunter <support@aipersonamethod.com>
2026-05-13 13:15:12 +01:00
Peter Steinberger
0a9f7afb66 fix(agents): surface memory-flush errors safely
Refs #80755.
Replaces #80884.

Verification:
- pnpm test src/plugins/contracts/extension-runtime-dependencies.contract.test.ts src/auto-reply/reply/agent-runner-memory.test.ts
- pnpm changed:lanes --json
- git diff --check
- node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.scripts.json scripts/generate-plugin-inventory-doc.mjs scripts/deadcode-unused-files.allowlist.mjs
- pnpm deadcode:unused-files
- pnpm check:changed via Blacksmith Testbox tbx_01krgjhyx965k8ew4qg9nxq8yn
- GitHub CI on PR #81387 head 695f694b70

Co-authored-by: kinjitakabe <273844887+kinjitakabe@users.noreply.github.com>
2026-05-13 12:56:09 +01:00
Peter Steinberger
c796b96d34 docs: add changelog for Claude CLI reseed (#80934) (thanks @bitloi) 2026-05-13 12:54:40 +01:00
bitloi
dd8aa1dcce fix: reseed Claude CLI session context on rotation closes #80905 2026-05-13 12:54:40 +01:00
Jason
ce31fc91e1 Allow pnpm source updates to build OpenClaw (#81294)
Merged via squash.

Prepared head SHA: 4815d5a8c9
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-13 14:30:08 +03:00
Pavan Kumar Gondhi
af42260440 Require explicit browser device pairing [AI] (#81289)
* fix: require explicit pairing for browser-origin device sessions

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 16:49:24 +05:30
Pavan Kumar Gondhi
96fba91b3a Require Control UI pairing before proxy-scoped access [AI] (#81288)
* fix: require control ui device pairing for proxy auth

* addressing review-skill

* fix: cover proxy control ui unbound scopes

* docs: add changelog entry for PR merge
2026-05-13 16:48:39 +05:30
Peter Steinberger
5f8e1dd399 feat(telegram): support web app presentation buttons
Refs #81356
Co-authored-by: Jamil Zakirov <jamil@zakirov.com>
2026-05-13 12:08:29 +01:00
Peter Steinberger
b4d148e21a fix: harden telegram localized command menus (#81351) (thanks @jzakirov) 2026-05-13 11:59:21 +01:00
Jamil Zakirov
97df0bc55a feat(telegram): localized command menu descriptions
Consume `descriptionLocalizations` from plugin command specs and
register per-locale command menus via Telegram `setMyCommands`
`language_code` parameter. Follows the same pattern already used
by the Discord extension.
2026-05-13 11:59:21 +01:00
Peter Steinberger
ca4672458c docs: stop referencing shell profile secrets 2026-05-13 11:55:14 +01:00
Peter Steinberger
0832343197 fix(discord): quiet fatal realtime voice startup failures 2026-05-13 11:51:43 +01:00
Peter Steinberger
74a809a1cd ci: grant dependency awareness pull request writes 2026-05-13 11:45:33 +01:00
Peter Steinberger
1bc45af1db ci: tolerate dependency awareness read-only tokens 2026-05-13 11:45:33 +01:00
Peter Steinberger
46f7750c63 fix: narrow plugin SDK hook type exports 2026-05-13 11:40:37 +01:00
Jamil Zakirov
68c77bb55d feat(plugin-sdk): export plugin hook types
Add `openclaw/plugin-sdk/types` entrypoint that re-exports plugin hook
types, so external plugins can import typed hook interfaces without
reaching into internal paths.

Also export `resolveActiveEmbeddedRunSessionId` from
`agent-harness-runtime` for session resolution in embedded runs.
2026-05-13 11:40:25 +01:00
Pavan Kumar Gondhi
26c7da2d02 Harden trusted-proxy source validation [AI] (#81290)
* fix: reject local-interface trusted-proxy peers

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-13 16:10:11 +05:30
Jamil Zakirov
b7572cc384 feat(plugins): expose tools in LLM input hook event
Add optional `tools` array to `PluginHookLlmInputEvent` so plugin
hooks receive the full LLM call context, not just prompt and history.
2026-05-13 11:38:32 +01:00
Vincent Koc
65e37017b6 revert(cli): remove global root refusal (#81370) 2026-05-13 18:34:46 +08:00
Peter Steinberger
9f46e9cb85 refactor(provider): share operation timeout resolvers 2026-05-13 11:26:30 +01:00
Peter Steinberger
bd326cdd5e fix(provider): retry post status and download deadlines 2026-05-13 11:26:30 +01:00
Peter Steinberger
8b0b4ea82f fix(provider): retry google rest status failures 2026-05-13 11:26:30 +01:00
Peter Steinberger
af021aac8d fix(provider): preserve retry deadlines 2026-05-13 11:26:30 +01:00
Peter Steinberger
47ba73de27 fix(provider): type minimax retry helper 2026-05-13 11:26:30 +01:00
Peter Steinberger
86ee352138 fix(provider): avoid nested transcription retries 2026-05-13 11:26:30 +01:00
Peter Steinberger
ecdad948b5 refactor(provider): centralize transient retry stages 2026-05-13 11:26:30 +01:00
Peter Steinberger
9741bbe2c1 fix(provider): retry top-level network codes 2026-05-13 11:26:29 +01:00
Peter Steinberger
635f6e0d0e fix(provider): tag timeout aborts for retry 2026-05-13 11:26:29 +01:00
Peter Steinberger
b150e23a60 fix(provider): keep abort retries timeout-scoped 2026-05-13 11:26:29 +01:00
Peter Steinberger
2e3c49b161 fix(provider): dedupe transient retry policy 2026-05-13 11:26:29 +01:00
sqsge
f20054ba79 fix(provider): add opt-in transient retries for provider execution 2026-05-13 11:26:29 +01:00
Peter Steinberger
27e5d49fe5 build(whatsapp): keep audio deps external 2026-05-13 11:21:17 +01:00
Peter Steinberger
1e8e004361 build(pnpm): restore exotic subdependency blocking 2026-05-13 11:21:17 +01:00
Peter Steinberger
85f9276624 build(whatsapp): externalize whatsapp plugin 2026-05-13 11:21:17 +01:00
Peter Steinberger
49ccd4e080 docs: quote clawdtributor skill description 2026-05-13 11:20:33 +01:00
Peter Steinberger
7c89fb455b docs: tighten clawdtributor skill trigger 2026-05-13 11:18:31 +01:00
Peter Steinberger
09a490de17 docs: add clawdtributor triage skill 2026-05-13 11:16:34 +01:00
Peter Steinberger
a15559b8d0 fix: normalize array tool schemas (#81217) (thanks @JARVIS-Glasses) 2026-05-13 11:04:13 +01:00
JARVIS-Glasses
392b23c01e fix(agents): normalize array tool schemas 2026-05-13 11:04:13 +01:00
Peter Steinberger
2cae5e92a6 test: dedupe codex user input mock read 2026-05-13 10:58:25 +01:00
Peter Steinberger
16c5d5b87b test: dedupe codex subagent mirror mock reads 2026-05-13 10:57:08 +01:00
Peter Steinberger
453019a2c7 test: dedupe codex compact mock reads 2026-05-13 10:55:45 +01:00
Peter Steinberger
fe19d9fea8 test: dedupe codex schema mock read 2026-05-13 10:54:10 +01:00
Peter Steinberger
a661b7b04c test: dedupe feishu cleanup mock reads 2026-05-13 10:52:29 +01:00
Peter Steinberger
db6bb6d329 test: dedupe zalo pairing mock read 2026-05-13 10:51:10 +01:00
Peter Steinberger
c115b126d2 test: dedupe codex client mock reads 2026-05-13 10:49:47 +01:00
Peter Steinberger
48c8aa11f8 test: dedupe codex context engine mock read 2026-05-13 10:48:18 +01:00
Sarah Fortune
aae173a1c9 fix(plugins): raise default install scan file limit to 25k (#81361) 2026-05-13 02:47:13 -07:00
Peter Steinberger
62adbe0b80 test: dedupe codex binding mock helper 2026-05-13 10:45:51 +01:00
Peter Steinberger
80190249ec test: dedupe nostr mock call helper 2026-05-13 10:44:22 +01:00
Peter Steinberger
95901042d4 fix(config): normalize gemini subagent model writes 2026-05-13 10:42:08 +01:00
Jesse Merhi
6c92324c5f Revert "Check ClawHub trust before plugin installs (#81307)" (#81363)
This reverts commit 87eb450047.
2026-05-13 19:34:18 +10:00
Peter Steinberger
060768ef75 test: dedupe gateway run loop mock read 2026-05-13 10:33:35 +01:00
Peter Steinberger
a9215ef2d4 test: dedupe command secret target mock read 2026-05-13 10:28:56 +01:00
Peter Steinberger
578d723b48 test: dedupe daemon cli mock read 2026-05-13 10:25:54 +01:00
Peter Steinberger
b1db684aca test: dedupe command secret gateway mock read 2026-05-13 10:23:44 +01:00
Peter Steinberger
5904e2027f test: dedupe node cli mock read 2026-05-13 10:20:51 +01:00
Peter Steinberger
06b8cd4565 test: tighten core test mock fixtures 2026-05-13 10:18:35 +01:00
Peter Steinberger
2e6d34d2c9 test: dedupe matrix devices mock read 2026-05-13 10:13:47 +01:00
Peter Steinberger
321c996af8 test: dedupe matrix logger mock read 2026-05-13 10:12:05 +01:00
Peter Steinberger
0fa30e790c docs: clarify cluster close policy 2026-05-13 10:08:17 +01:00
Mason Huang
0eeafbdce2 docs(changelog): credit Ziy1-Tan for transcript redaction (#81343)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-13 17:06:17 +08:00
Peter Steinberger
7c3e4dbf94 test: dedupe whatsapp audio mock read 2026-05-13 10:02:45 +01:00
Peter Steinberger
3a44d88d09 test: dedupe litellm image mock read 2026-05-13 10:00:10 +01:00
Peter Steinberger
383ebe723b test: dedupe canvas tool mock read 2026-05-13 09:56:50 +01:00
Peter Steinberger
5bb2c5e454 test: dedupe canvas cli mock read 2026-05-13 09:54:55 +01:00
Peter Steinberger
f02b715f2b test: dedupe qqbot image mock reads 2026-05-13 09:51:51 +01:00
Peter Steinberger
898a5aae21 test: dedupe line signature mock read 2026-05-13 09:48:41 +01:00
Peter Steinberger
c1700a5c9f test: dedupe imessage action mock read 2026-05-13 09:45:26 +01:00
Peter Steinberger
ffb2dcc2e6 test: dedupe imessage retry mock reads 2026-05-13 09:43:20 +01:00
Peter Steinberger
1d331bcfc5 test: fix telegram transcript mock type 2026-05-13 09:39:19 +01:00
Peter Steinberger
6cd2059749 test: dedupe line rich menu mock reads 2026-05-13 09:35:04 +01:00
Peter Steinberger
33655ee290 test: dedupe line lifecycle mock read 2026-05-13 09:32:43 +01:00
clawsweeper[bot]
faaa7efef0 fix(security): inline redact into appendSessionTranscriptMessage (#79645)
Merged via squash.

Prepared head SHA: da91ab6cf1
Co-authored-by: app/clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-05-13 16:31:04 +08:00
Peter Steinberger
5ef9207813 test: dedupe mattermost retry mock read 2026-05-13 09:30:56 +01:00
Peter Steinberger
c8ddf71989 test: dedupe qa runtime mock read 2026-05-13 09:28:16 +01:00
Peter Steinberger
6c2e0bdc0c test: dedupe matrix action mock read 2026-05-13 09:25:59 +01:00
Peter Steinberger
06e04291e0 test: dedupe signal reply mock reads 2026-05-13 09:24:08 +01:00
Peter Steinberger
b693173e0d test: dedupe synology webhook mock read 2026-05-13 09:22:14 +01:00
Ayaan Zaidi
f7e9d80536 docs(changelog): credit idle timeout fallback fix (#80449) (thanks @jimdawdy-hub) 2026-05-13 13:51:51 +05:30
Ayaan Zaidi
a7ae889ae5 test(agents): cover idle timeout fallback during tools 2026-05-13 13:51:51 +05:30
Jim Dawdy
a6e4132a8c fix: preserve timeout reason after idle-only profile rotations
Addresses Codex P3 review finding: when shouldRotateAssistant fires on
idleTimedOut alone (timedOut=false), mergeRetryFailoverReason was passed
timedOut: params.timedOut (false), so the accumulated retry reason did
not record 'timeout'. Pass timedOut || idleTimedOut so the timeout reason
survives idle-only rotations and downstream fallback_model receives the
correct reason.
2026-05-13 13:51:51 +05:30
Jim Dawdy
b3ef14dbfc fix: address code review findings
- failover-policy.test.ts: move 4 new it() blocks inside describe()
  (they were orphaned outside the block and would not execute)
- run.ts: add idleTimedOut to the assistantFailoverDecision call site
  (missing required field caused TypeScript error and reproduced the freeze
  for the initial-decision code path in the outer loop)
- assistant-failover.ts: treat idleTimedOut same as timedOut in
  markFailedProfile to avoid incorrect profile failure recording
- assistant-failover.ts: add warn log when idle timeout rotates a profile
- assistant-failover.ts: extend resolveAssistantFailoverErrorMessage to
  accept idleTimedOut so surface_error emits "LLM request timed out."
  instead of the generic "LLM request failed."
2026-05-13 13:51:51 +05:30
Jim Dawdy
5ca95b2012 fix(agents): escalate LLM idle timeout to model fallback after profile rotation
When the LLM idle watchdog fires (model produced no tokens for N seconds),
idleTimedOut is set in handleAssistantFailover but was never passed into
resolveRunFailoverDecision. As a result, shouldRotateAssistant saw neither
failoverReason nor timedOut (the run-budget timeout) set, returned false,
and the decision fell through to continue_normal -- the agent silently froze
without surfacing an error or advancing the fallback chain.

Fixes #76877 (regression since 2026.4.24).

Changes:
- failover-policy.ts: add idleTimedOut to AssistantDecisionParams; include it
  in shouldRotateAssistant and reason selection in resolveRunFailoverDecision
- assistant-failover.ts: pass idleTimedOut into resolveRunFailoverDecision
- failover-policy.test.ts: 4 new cases for idle timeout path; update existing
  assistant stage cases with the new required field (idleTimedOut: false)
2026-05-13 13:51:51 +05:30
Peter Steinberger
ba17ddaef3 test: dedupe mattermost route mock read 2026-05-13 09:19:41 +01:00
Peter Steinberger
99f81f10e3 test: dedupe qqbot websocket mock read 2026-05-13 09:17:48 +01:00
Peter Steinberger
9ac275a8bf test: dedupe line download mock read 2026-05-13 09:16:20 +01:00
Peter Steinberger
1dc678393f test: dedupe huggingface provider mock read 2026-05-13 09:15:12 +01:00
Peter Steinberger
4e1f92641c test: dedupe tavily client mock reads 2026-05-13 09:13:34 +01:00
Peter Steinberger
9d13203d15 test: dedupe ollama setup mock reads 2026-05-13 09:12:26 +01:00
Peter Steinberger
6648950862 test: dedupe irc inbound mock read 2026-05-13 09:11:22 +01:00
Peter Steinberger
0f7b1c5414 test: dedupe clickclack inbound mock reads 2026-05-13 09:10:17 +01:00
Peter Steinberger
6ad1c7f3b7 test: dedupe discord listener mock read 2026-05-13 09:08:57 +01:00
Ayaan Zaidi
95a105334b docs(changelog): note worktree heavy-check locks (#80734) (thanks @samzong) 2026-05-13 13:38:52 +05:30
Ayaan Zaidi
25cda2b24c test(scripts): simplify worktree lock setup 2026-05-13 13:38:52 +05:30
samzong
94aae40c28 feat(scripts): allow worktree heavy-check locks
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-13 13:38:52 +05:30
Peter Steinberger
64ff396593 test: dedupe discord webhook mock read 2026-05-13 09:06:09 +01:00
Josh Avant
bd4db5ee62 Add dependency release safety evidence and PR awareness (#81325)
* test: cover dependency pin guard

* build: add dependency vulnerability gate

* build: add dependency risk report

* build: add dependency drift reports

* build: include dependency ownership surface evidence

* build: rename dependency report commands

* build: respect release age exclusions in risk report

* build: clarify transitive risk accounting

* build: remove transitive risk exception registry

* build: clarify transitive risk signal wording

* ci: attach dependency evidence to release preflight

* ci: extract dependency release evidence generator

* build: rename ownership surface dependency report

* ci: clarify release evidence naming

* build: clarify recently published risk report

* build: reorder transitive risk report sections

* build: fix ownership surface pluralization

* ci: surface dependency changes on PRs

* ci: harden dependency change awareness

* ci: use dependency changed PR label

* build: fix dependency report lint

* docs: add dependency safety changelog
2026-05-13 03:05:09 -05:00
Peter Steinberger
b9b7ffc8cd test: dedupe memory search mock read 2026-05-13 09:04:40 +01:00
Peter Steinberger
f2bd20351f test: dedupe llm task mock read 2026-05-13 09:03:18 +01:00
Peter Steinberger
abd45b1763 test: dedupe zalo reply mock read 2026-05-13 08:59:31 +01:00
Peter Steinberger
96752f9804 test: dedupe tlon guarded fetch mock read 2026-05-13 08:57:52 +01:00
Peter Steinberger
22411e17cb fix(cli): normalize Gemini config mutation refs 2026-05-13 08:56:02 +01:00
Peter Steinberger
954407ab74 test: dedupe outbound matrix mock read 2026-05-13 08:43:35 +01:00
Peter Steinberger
edce338e32 test: dedupe cron model override last mock read 2026-05-13 08:41:20 +01:00
Peter Steinberger
cf11d16b43 fix(agents): make subagent task delivery visible
Co-authored-by: stainlu <stainlu@newtype-ai.org>
2026-05-13 08:40:27 +01:00
Peter Steinberger
17fe41a4b9 test: dedupe heartbeat stability mock read 2026-05-13 08:38:57 +01:00
Peter Steinberger
e2ced4cb53 test: dedupe command status mock read 2026-05-13 08:36:19 +01:00
Lellansin Huang
78e03e3004 fix(gateway): forward OpenAI sampling params
- Forward temperature and top_p through OpenAI-compatible chat and responses gateway paths.
- Return OpenAI-compatible 400 errors for invalid sampling params and provider validation failures instead of collapsing them to 500s.
- Add regression coverage and changelog credit.

Co-authored-by: lellansin <lellansin@gmail.com>
2026-05-13 08:35:48 +01:00
Peter Steinberger
b0c817ee9d test: dedupe discord sdk mock read 2026-05-13 08:32:31 +01:00
Peter Steinberger
27af4f618e test: dedupe inbound reply mock read 2026-05-13 08:30:05 +01:00
Peter Steinberger
52a02ab310 test: dedupe acp runtime mock read 2026-05-13 08:27:26 +01:00
Peter Steinberger
34ce85a83d test: dedupe heartbeat commitment mock read 2026-05-13 08:24:24 +01:00
Peter Steinberger
a95a317425 test: dedupe cron tts mock read 2026-05-13 08:22:07 +01:00
Peter Steinberger
40e8782400 test: dedupe cron skills snapshot mock read 2026-05-13 08:20:12 +01:00
Peter Steinberger
d97f72633c test: dedupe plugin approval mock read 2026-05-13 08:18:31 +01:00
Peter Steinberger
49e34f2b7b docs: update crabbox cross-platform skill 2026-05-13 08:16:47 +01:00
Peter Steinberger
f5be0d1406 fix: make codex harness live test portable 2026-05-13 08:16:47 +01:00
Peter Steinberger
984981832e test: dedupe cron model preflight mock read 2026-05-13 08:16:07 +01:00
Peter Steinberger
718476ccc5 test: dedupe cron model override mock read 2026-05-13 08:13:55 +01:00
Peter Steinberger
9ade25d985 test: dedupe isolated cron fallback mock read 2026-05-13 08:11:55 +01:00
Peter Steinberger
62f9024361 test: dedupe isolated cron session mock read 2026-05-13 08:09:59 +01:00
Peter Steinberger
1ae9d8227a test: dedupe cron enqueue mock read 2026-05-13 08:07:09 +01:00
Peter Steinberger
f706d3c322 test: dedupe approval route mock read 2026-05-13 08:05:28 +01:00
Peter Steinberger
4a97da8b47 test: dedupe scheduled turn mock read 2026-05-13 08:03:52 +01:00
Peter Steinberger
b6fcb63d75 test: dedupe session attachment mock read 2026-05-13 08:01:55 +01:00
Peter Steinberger
4c7ce0ad91 test: dedupe web search provider mock read 2026-05-13 07:59:34 +01:00
Peter Steinberger
81811e55a7 test: dedupe provider runtime mock read 2026-05-13 07:58:05 +01:00
Peter Steinberger
0bd3d7c2ed test: dedupe plugin runtime mock read 2026-05-13 07:56:44 +01:00
Peter Steinberger
d29225fde4 test: dedupe plugin install path mock read 2026-05-13 07:54:50 +01:00
Peter Steinberger
57027e35db test: dedupe metadata registry mock read 2026-05-13 07:53:22 +01:00
Peter Steinberger
15481dab26 test: dedupe plugin uninstall mock read 2026-05-13 07:51:59 +01:00
Sarah Fortune
a197e31abb feat(migrate): suppress plan log on embedding + add "Accept recommended" affordance (#81219)
Two related improvements to the interactive `openclaw migrate <provider>`
flow, both surfaced by the onboarding post-install migration prompt that
landed in #81192.

1. `suppressPlanLog?: boolean` on `MigrateCommonOptions`
   (`src/commands/migrate/types.ts`). When set, `migratePlanCommand`
   skips the up-front `runtime.log(formatMigrationPlan(plan))` dump.
   The interactive Codex selection picker and the "Apply this migration
   now?" confirm still run. Wired from the wizard helper at
   `src/wizard/setup.post-install-migration.ts` so that path no longer
   shows the plan dump after the user has already confirmed at the
   wizard prompt.

2. New "Accept recommended" sentinel row at the top of both Codex
   selection pickers, with "Toggle all on" and "Toggle all off" moved
   to the bottom. The cursor starts on "Accept recommended" so pressing
   Enter at the default position submits the picker's `initialValues`
   (the recommended set) — matching the visual state of the checkboxes.

   Implemented in `skill-selection-prompt.ts`:
   - Enter on the Accept sentinel sets `prompt.value` to
     `opts.initialValues` and lets clack submit.
   - Space on the Accept sentinel snaps `prompt.value` to
     `opts.initialValues` so the visible checkboxes flip to the
     recommended state. The user can then Enter to commit or continue
     toggling individual rows. The Accept row itself is never persisted
     in the submitted value list.

   The existing Enter handler for "Toggle all on" / "Toggle all off"
   stays unchanged.

3. Removed the "Skip for now" sentinel entirely. It was a single-
   keystroke trap: with the picker cursor wrapping from Accept to Skip
   via up-arrow (or via accidental down-arrows), Enter on Skip wiped
   `prompt.value` to `[MIGRATION_SELECTION_SKIP]` and abandoned the
   whole migration — including any items the user had already
   confirmed in the previous picker. To exit without migrating, users
   now navigate to "Toggle all off" (or use the `a` / `i` keyboard
   shortcuts) to clear the selection; the apply phase then sees no
   planned work and skips itself via the existing
   `shouldSkipCodexApplyAfterInteractiveSelection` path.

   Cleanup spans `migrate/selection.ts` (constants, `{ action: "skip" }`
   variant, and the reconcile/resolve SKIP branches),
   `migrate.ts` (the picker option rows and the
   `if (selection.action === "skip")` handler blocks in both pickers),
   and the corresponding tests.

4. Plugin selection hint relabelled from "Activate every recommended
   plugin" to "Migrate every recommended plugin" so it matches the
   skill hint and the prompt's own verb ("Migrate ... into this agent
   now?").

Tests:

- `src/commands/migrate/skill-selection-prompt.test.ts` — Accept
  sentinel cases (Enter and Space + Enter both submit initialValues);
  Skip-related test removed; Skip row dropped from the picker fixture.
- `src/commands/migrate/selection.test.ts` — Skip-related sub-
  assertions trimmed from the resolve/reconcile tests; the
  "skip + toggle-off precedence" test renamed to "toggle-off precedence
  over toggle-on" and Skip cases removed.
- `src/commands/migrate.test.ts` — four Skip-driven scenarios removed
  (plugin-only skip, both-pickers skip, skip-skills-continue-to-plugins,
  Codex subscription warning + skip).
- `src/wizard/setup.post-install-migration.test.ts` — call-args
  assertion expects the new `suppressPlanLog` option.

Verification:

- `pnpm lint` clean
- `pnpm tsgo:core` + `pnpm tsgo:core:test` clean
- Touched test suites green (migrate 32/32, selection 17/17,
  skill-selection-prompt 6/6, setup.post-install-migration 10/10).
2026-05-12 23:51:19 -07:00
Peter Steinberger
96b49f0b93 test: dedupe plugin service mock read 2026-05-13 07:50:21 +01:00
Peter Steinberger
10663e4ba2 test: dedupe plugin lifecycle mock read 2026-05-13 07:48:52 +01:00
Peter Steinberger
86dfc78d97 test: dedupe npm pack temp dir mock read 2026-05-13 07:46:07 +01:00
Peter Steinberger
8ebb18416a test: dedupe shell env exec mock read 2026-05-13 07:44:38 +01:00
Peter Steinberger
e898ea67b4 test: dedupe marketplace command mock read 2026-05-13 07:42:52 +01:00
Peter Steinberger
23856156e2 test: dedupe inbound claim log mock read 2026-05-13 07:41:24 +01:00
Peter Steinberger
21aaa9ed81 test: dedupe google video download mock read 2026-05-13 07:39:14 +01:00
Peter Steinberger
6b4333ae6b test: dedupe xiaomi speech fetch mock read 2026-05-13 07:37:35 +01:00
Peter Steinberger
3bc433c179 fix(config): normalize per-agent Gemini preview refs 2026-05-13 07:35:56 +01:00
Jesse Merhi
87eb450047 Check ClawHub trust before plugin installs (#81307)
Merged via squash.

Prepared head SHA: 273fd7c20e
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Reviewed-by: @jesse-merhi
2026-05-13 16:31:52 +10:00
Peter Steinberger
cf68115e6e test: dedupe synology client mock reads 2026-05-13 07:25:03 +01:00
Peter Steinberger
ef78fc9534 test: dedupe synology route mock read 2026-05-13 07:23:36 +01:00
Ayaan Zaidi
8879c671e3 docs(changelog): note Telegram polling stall fix 2026-05-13 11:53:00 +05:30
Ayaan Zaidi
56873b6065 fix(telegram): detect polling stalls from getUpdates 2026-05-13 11:53:00 +05:30
Peter Steinberger
7899b70c18 test: dedupe whatsapp close mock read 2026-05-13 07:21:41 +01:00
Peter Steinberger
0b4f0129df test: dedupe qwen video request mock reads 2026-05-13 07:19:44 +01:00
Peter Steinberger
63ee74109e test: dedupe ollama embedding fetch mock read 2026-05-13 07:18:13 +01:00
Peter Steinberger
4cf6971130 test: dedupe gradium tts fetch mock read 2026-05-13 07:15:45 +01:00
Peter Steinberger
dd127ba0ba test: dedupe google image fetch mock read 2026-05-13 07:14:29 +01:00
Peter Steinberger
6932c66ffe test: dedupe minimax speech fetch mock reads 2026-05-13 07:12:39 +01:00
Peter Steinberger
7e1e4c5f78 test: dedupe memory wiki cli mock read 2026-05-13 07:11:04 +01:00
Peter Steinberger
6ced971cf1 test: dedupe minimax image fetch mock reads 2026-05-13 07:09:24 +01:00
Peter Steinberger
b430270429 test: dedupe copilot model fetch mock reads 2026-05-13 07:07:56 +01:00
Peter Steinberger
29ac94b0e4 test: dedupe device pair qr mock read 2026-05-13 07:06:34 +01:00
Ayaan Zaidi
bfbb9c6f9f docs(changelog): note ACP Claude timeout fix (#80812) (thanks @sxxtony) 2026-05-13 11:35:36 +05:30
Ayaan Zaidi
a146bf03db refactor(acpx): distill ACP command detection 2026-05-13 11:35:36 +05:30
sxxtony
bf8f5d991c fix(acp): drop unsupported timeout config option for claude-agent-acp
`runtime-options.buildRuntimeConfigOptionPairs` translated
`AcpSessionRuntimeOptions.timeoutSeconds` into a
`session/set_config_option(configId: "timeout")` pair on every turn. Both the
control plane (`AcpSessionManager.applyManagerRuntimeControls`) and the ACPX
wrapper (`AcpxRuntime.setConfigOption`) sit between that pair and the backend:

- The control plane validates pairs against the backend's advertised
  config-option keys and throws `ACP_BACKEND_UNSUPPORTED_CONTROL` for any
  pair the backend did not advertise. claude-agent-acp does not advertise a
  `timeout` alias.
- The wrapper then forwards remaining pairs to the delegate. The Codex ACP
  command was already short-circuited there; every other command, including
  claude-agent-acp, fell through.

Net effect on the reporter's scenario:
`sessions_spawn({ runtime:"acp", agentId:"claude", timeoutSeconds: 60 })`
failed at the control-plane validation with `ACP_BACKEND_UNSUPPORTED_CONTROL`
(and, had it reached the wire, claude-agent-acp would have answered
`-32603 Internal error / Unknown config option: timeout`, surfacing as
`ACP_TURN_FAILED: Internal error`).

Fix two layers:

1. Control plane (`src/acp/control-plane/runtime-options.ts`): add
   `isTimeoutConfigOptionAdvertised(advertisedConfigOptionKeys)` and gate the
   timeout pair on it. When advertised keys are unknown (`undefined` or
   empty), keep emitting the pair — this preserves current behavior for
   backends that have not produced a capability list yet. When advertised
   keys are present but exclude every alias in
   `RUNTIME_CONFIG_OPTION_ALIASES.timeoutSeconds`, skip the pair. The
   per-turn timeout is still enforced in-process via
   `AcpSessionManager.resolveTurnTimeoutMs` in `manager.core.ts`.

2. ACPX wrapper (`extensions/acpx/src/runtime.ts`): hoist the Codex
   `timeout` / `timeout_seconds` suppression so it also applies to
   claude-agent-acp commands. Add `isClaudeAcpCommand` mirroring
   `isCodexAcpCommand` (package spec, binary, generated wrapper script).
   This layer is defense in depth — relevant when callers reach the wrapper
   without going through `applyManagerRuntimeControls`, or when advertised
   keys are not yet known.

Coverage:

- `src/acp/control-plane/runtime-options.test.ts` (new) asserts:
  - the timeout pair is omitted when advertised keys exclude every alias,
  - the pair is kept when `timeout` or `timeout_seconds` is advertised,
  - the pair is kept when advertised keys are unknown,
  - model/thinking emission is unaffected.
- `extensions/acpx/src/runtime.test.ts` flips the previous
  `forwards timeout config controls for non-Codex ACP agents` test, which
  codified the buggy behavior, into a suppression assertion. Adds a
  positive `still forwards non-timeout config controls for claude-agent-acp`
  test and an `isClaudeAcpCommand` detector test.

Closes #81127
2026-05-13 11:35:36 +05:30
Peter Steinberger
50cb5ae089 test: dedupe openrouter stream mock read 2026-05-13 07:05:03 +01:00
Peter Steinberger
6a589017ca test: dedupe memory wiki gateway mock reads 2026-05-13 07:03:45 +01:00
Peter Steinberger
3945fd5812 test: dedupe tokenjuice mock read 2026-05-13 07:02:06 +01:00
Peter Steinberger
53032505bd test: dedupe memory lancedb provider assertion 2026-05-13 07:00:59 +01:00
Peter Steinberger
b8727202a5 test: dedupe inworld tts mock read 2026-05-13 06:59:47 +01:00
Peter Steinberger
7de4c47da2 test: dedupe qa credential lease mock read 2026-05-13 06:57:56 +01:00
Peter Steinberger
2a931b5906 test: dedupe google meet oauth mock read 2026-05-13 06:56:44 +01:00
Peter Steinberger
be343e3134 test: dedupe zalouser pairing mock reads 2026-05-13 06:55:30 +01:00
Peter Steinberger
0e3347cba6 test: dedupe reply flow mock read 2026-05-13 06:54:15 +01:00
Peter Steinberger
dccb382283 test: dedupe hook security mock read 2026-05-13 06:51:28 +01:00
Peter Steinberger
134461723e test: dedupe session hook mock read 2026-05-13 06:49:45 +01:00
Peter Steinberger
4a6e46152a test: dedupe sandbox media mock read 2026-05-13 06:48:05 +01:00
Peter Steinberger
6de17fcb75 test: dedupe exec host mock read 2026-05-13 06:46:29 +01:00
Peter Steinberger
560679a2ad test: dedupe outbound channel mock read 2026-05-13 06:45:08 +01:00
Peter Steinberger
af21973ea2 test: dedupe outbound send mock read 2026-05-13 06:43:10 +01:00
Peter Steinberger
07ffc2b955 test: dedupe outbound media mock read 2026-05-13 06:41:47 +01:00
Peter Steinberger
2b5d9bb47c test: dedupe cron owner auth mock read 2026-05-13 06:39:53 +01:00
Peter Steinberger
cd993f4584 test: dedupe cron fast mode mock read 2026-05-13 06:38:15 +01:00
Peter Steinberger
210f606be8 test: dedupe lmstudio stream mock read 2026-05-13 06:36:48 +01:00
Peter Steinberger
93233b2c6b test: dedupe azure speech mock reads 2026-05-13 06:35:12 +01:00
Peter Steinberger
f513c3f0dd test: dedupe qa manual lane mock reads 2026-05-13 06:32:35 +01:00
Peter Steinberger
b21630d6d1 test: dedupe memory watcher mock reads 2026-05-13 06:30:58 +01:00
Peter Steinberger
61268e8117 test: dedupe memory search mock read 2026-05-13 06:29:31 +01:00
Peter Steinberger
df9c9adeff test: dedupe mantle anthropic mock read 2026-05-13 06:27:58 +01:00
Peter Steinberger
87109e5fb5 test: dedupe anthropic vertex mock reads 2026-05-13 06:26:33 +01:00
Peter Steinberger
a282bdc601 test: dedupe openai image mock reads 2026-05-13 06:25:08 +01:00
Peter Steinberger
7bb2153fb2 test: dedupe openai tts mock reads 2026-05-13 06:23:44 +01:00
Peter Steinberger
30af076000 test: dedupe doctor registry mock read 2026-05-13 06:21:35 +01:00
homer-byte
ba1f4271e8 fix(imessage): keep pasted links without preview media (#79374)
Thanks @homer-byte.
2026-05-12 22:20:44 -07:00
Peter Steinberger
a123cddb4b test: dedupe channel module mock read 2026-05-13 06:19:57 +01:00
Ayaan Zaidi
8fe196e28b docs(changelog): add diagnostic lane PR reference 2026-05-13 10:48:46 +05:30
Ayaan Zaidi
d571f21c66 docs(changelog): note diagnostic lane fix 2026-05-13 10:48:46 +05:30
Ayaan Zaidi
3d3a2399b5 fix(logging): track reply runs in diagnostics 2026-05-13 10:48:46 +05:30
Peter Steinberger
5a10326612 test: dedupe node media log mock read 2026-05-13 06:17:56 +01:00
Peter Steinberger
934198b9a5 test: dedupe mcp channel mock read 2026-05-13 06:16:31 +01:00
Peter Steinberger
b25f657394 test: dedupe fetch timeout mock read 2026-05-13 06:15:29 +01:00
Peter Steinberger
6715ac526e test: dedupe plugin cli mock reads 2026-05-13 06:13:46 +01:00
Peter Steinberger
0b0539af17 test: dedupe outbound send mock read 2026-05-13 06:12:32 +01:00
Peter Steinberger
5a2dfac674 test: dedupe cli utility mock read 2026-05-13 06:11:23 +01:00
Peter Steinberger
6af82efcad test: dedupe feishu chat mock reads 2026-05-13 06:10:09 +01:00
Peter Steinberger
54c633db36 test: dedupe feishu docx mock reads 2026-05-13 06:09:06 +01:00
Peter Steinberger
73e0c51a5a test: dedupe vydra fetch mock reads 2026-05-13 06:07:49 +01:00
Peter Steinberger
832f91adbc test: dedupe gateway devices mock read 2026-05-13 06:06:21 +01:00
Peter Steinberger
8d50c3bc05 test: dedupe gateway tools mock reads 2026-05-13 06:05:23 +01:00
Peter Steinberger
2e7036e85c test: dedupe gateway sessions mock read 2026-05-13 06:04:18 +01:00
Peter Steinberger
f9157fcf82 test: dedupe gateway drain mock read 2026-05-13 06:03:11 +01:00
Peter Steinberger
5c67c93ac9 test: dedupe brave fetch mock read 2026-05-13 06:01:48 +01:00
Gio Della-Libera
f141a086fc fix(update): suppress handoff newer-config warning (#81235)
Merged via squash.

Prepared head SHA: 61a5c975bf
Co-authored-by: giodl73-repo <giodl@microsoft.com>
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Reviewed-by: @galiniliev
2026-05-12 22:01:21 -07:00
Peter Steinberger
94fdc56b64 test: dedupe cron ops mock read 2026-05-13 06:00:25 +01:00
Peter Steinberger
2c3582ad0b test: dedupe cron service mock reads 2026-05-13 05:58:16 +01:00
Peter Steinberger
8fd0f9965e test: dedupe google chat mock reads 2026-05-13 05:56:42 +01:00
Pavan Kumar Gondhi
39bcd1e088 fix(plugins): scan installed dependency runtime code [AI] (#81066)
* fix: scan installed plugin dependency code

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 10:26:24 +05:30
Peter Steinberger
06c3318bba test: dedupe cli plugin registry mock read 2026-05-13 05:55:05 +01:00
Peter Steinberger
77f08d095d test: dedupe models cli mock read 2026-05-13 05:54:01 +01:00
Peter Steinberger
c27eca08e3 test: dedupe plugin timeout mock read 2026-05-13 05:52:55 +01:00
Peter Steinberger
2597d6d6d4 test: dedupe runtime web tools mock read 2026-05-13 05:51:45 +01:00
Pavan Kumar Gondhi
6c918ca85f Inherit tool restrictions for delegated sessions [AI] (#80979)
* fix: inherit tool restrictions for delegated sessions

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing review-skill

* addressing codex review

* addressing claude review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 10:21:36 +05:30
Peter Steinberger
aba7652b76 test: dedupe echo transcript mock read 2026-05-13 05:50:33 +01:00
Peter Steinberger
5ce26962c5 test: dedupe daemon restart mock read 2026-05-13 05:49:16 +01:00
Peter Steinberger
30f09cc54c test: dedupe daemon lifecycle mock read 2026-05-13 05:48:12 +01:00
Peter Steinberger
277ad4a71b fix: guard link understanding fetches 2026-05-13 05:47:36 +01:00
Peter Steinberger
d3b16ddec8 docs: note baileys install policy 2026-05-13 05:47:36 +01:00
Peter Steinberger
266e72149b test: dedupe daemon config guard mock read 2026-05-13 05:47:11 +01:00
Peter Steinberger
27e47ae8e6 test: dedupe daemon install mock read 2026-05-13 05:46:18 +01:00
Peter Steinberger
7f8ce2dfd6 test: dedupe daemon service mock read 2026-05-13 05:44:49 +01:00
Peter Steinberger
1eeec9e183 test: dedupe exec approval mock read 2026-05-13 05:43:52 +01:00
Peter Steinberger
54dd6e6da2 test: dedupe cli help mock read 2026-05-13 05:42:52 +01:00
Ayaan Zaidi
a820bda89d docs(changelog): credit telegram offset fix (#80671) (thanks @sxxtony) 2026-05-13 10:12:31 +05:30
Ayaan Zaidi
306b51011f fix(telegram): handle legacy rotated offsets 2026-05-13 10:12:31 +05:30
sxxtony
cb93c0f8f5 fix(telegram): factor offset rotation handling into typed surfaces
Builds on the prior commit by introducing the typed surfaces the rest of
the plugin (and `openclaw doctor`-style consumers) can reuse:

- `inspectTelegramUpdateOffset` returns a discriminated union
  (`absent | valid | rotated`) so callers can act on the rotation event
  without re-implementing the bot-id / fingerprint comparison.
  `readTelegramUpdateOffset` is now a thin adapter over it.
- `TelegramOffsetRotationReason` is exported as a named type alias so
  downstream code can switch over it exhaustively.
- New `TelegramOffsetRotationHandler` class encapsulates the
  "log warning + delete stale file" side effect that the monitor needs at
  startup, plus a `createTelegramOffsetRotationHandler` factory and a
  pure `formatTelegramOffsetRotationMessage` helper used to keep the
  wording consistent.
- `monitor.ts` now constructs the handler once per polling startup
  instead of inlining the closure, and the new surfaces are re-exported
  through `monitor-polling.runtime.ts`.

Unit coverage:
  pnpm test extensions/telegram/src/update-offset-store.test.ts \
            extensions/telegram/src/offset-rotation-handler.test.ts \
            extensions/telegram/src/monitor.test.ts
2026-05-13 10:12:31 +05:30
sxxtony
290d3879eb fix(telegram): detect same-bot token rotation via fingerprinted offset state
Closes #80653.

Persist a non-reversible SHA-256 fingerprint of the bot token alongside the
bot id in the long-poll update offset store (version 3). On read, treat the
persisted offset as stale when the fingerprint diverges from the current
token, even when the bot id still matches. This covers the BotFather
`/revoke` case where the bot id is unchanged but the secret rotates -- the
in-process update tracker would otherwise silently skip any new updates
whose `update_id` is `<=` the restored watermark.

The legacy v2 (bot-id-only) layout still parses, and offsets are preserved
when the bot id matches so existing installs don't lose a watermark on
upgrade; the next persistence upgrades the file to v3 and enables rotation
detection going forward.

`readTelegramUpdateOffset` now reports each rotation through a new
`onRotationDetected` callback. `monitor.ts` uses it to log a clear warning
naming the previous/new bot id and the discarded offset, and to delete the
stale file rather than waiting for the first update to overwrite it.

Acceptance suites pass:
  pnpm test extensions/telegram/src/update-offset-store.test.ts \
            extensions/telegram/src/bot-update-tracker.test.ts \
            extensions/telegram/src/monitor.test.ts \
            extensions/telegram/src/bot.create-telegram-bot.test.ts \
            extensions/telegram/src/token.test.ts \
            extensions/telegram/src/polling-lease.test.ts
2026-05-13 10:12:31 +05:30
Peter Steinberger
9850cb5057 test: dedupe media understanding mock read 2026-05-13 05:41:53 +01:00
Peter Steinberger
11919c8a97 test: dedupe launchd handoff mock read 2026-05-13 05:40:55 +01:00
Peter Steinberger
4e8d9d26a9 test: dedupe wizard install plan mock read 2026-05-13 05:39:57 +01:00
Gio Della-Libera
14170f1be8 fix(commitments): write json output to stdout (#81215)
Merged via squash.

Prepared head SHA: 4a8d3bb51b
Co-authored-by: giodl73-repo <235387111+giodl73-repo@users.noreply.github.com>
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Reviewed-by: @galiniliev
2026-05-12 21:38:43 -07:00
Peter Steinberger
84f4bc6ca4 test: dedupe plugin uninstall mock read 2026-05-13 05:35:45 +01:00
Peter Steinberger
2ffad5c18a test: dedupe commitments mock read 2026-05-13 05:33:37 +01:00
Peter Steinberger
5592132f56 test: dedupe foundry provider mock read 2026-05-13 05:31:55 +01:00
Peter Steinberger
e643890176 test: dedupe task store mock reads 2026-05-13 05:30:29 +01:00
Pavan Kumar Gondhi
3d93174c43 browser: enforce navigation checks for act interactions [AI] (#81070)
* fix: apply browser navigation policy to act interactions

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 09:59:36 +05:30
Peter Steinberger
0d3b6d8ff6 test: dedupe cli registration mock reads 2026-05-13 05:29:02 +01:00
rendrag-git
8831754f5c fix: resolve custom provider env markers 2026-05-13 00:27:39 -04:00
rendrag-git
2269ec727f fix: list self-hosted runtime wildcard models 2026-05-13 00:27:39 -04:00
rendrag-git
3b361cf51c fix: discover self-hosted provider wildcards 2026-05-13 00:27:39 -04:00
Peter Steinberger
0c5bbdaad0 test: dedupe plugin install mock read 2026-05-13 05:27:34 +01:00
Peter Steinberger
e68dfa511e test: dedupe gateway hook mock read 2026-05-13 05:26:13 +01:00
Pavan Kumar Gondhi
17fa101c16 Validate node exec event provenance [AI] (#81071)
* fix: validate node exec event provenance

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing claude review

* addressing ci

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 09:56:09 +05:30
Peter Steinberger
d643d64194 test: dedupe memory dreaming mock read 2026-05-13 05:25:01 +01:00
Peter Steinberger
8560bd845c test: dedupe realtime talk mock read 2026-05-13 05:23:45 +01:00
Peter Steinberger
98e6519878 test: dedupe acp permission mock read 2026-05-13 05:22:13 +01:00
Peter Steinberger
a840f3e775 test: dedupe message hooks mock read 2026-05-13 05:21:06 +01:00
Peter Steinberger
ac7b406d9d test: dedupe acp startup mock reads 2026-05-13 05:19:52 +01:00
Peter Steinberger
bc6fd1fe79 test: dedupe acp stop reason mock reads 2026-05-13 05:18:48 +01:00
Peter Steinberger
39f6dc7108 test: dedupe realtime websocket mock read 2026-05-13 05:17:42 +01:00
Peter Steinberger
33152f4162 test: dedupe provider env mock read 2026-05-13 05:16:18 +01:00
Peter Steinberger
3f590b4828 test: dedupe chat controller mock read 2026-05-13 05:15:18 +01:00
Peter Steinberger
8748ce9f57 test: dedupe system run mock read 2026-05-13 05:14:13 +01:00
Peter Steinberger
7b86539be2 test: dedupe auto reply helper mock read 2026-05-13 05:13:15 +01:00
Peter Steinberger
89a8047e18 test: dedupe heartbeat ack mock read 2026-05-13 05:11:46 +01:00
Peter Steinberger
d377c78aa3 test: dedupe heartbeat subagent mock read 2026-05-13 05:10:39 +01:00
Peter Steinberger
875dffca9e test: dedupe heartbeat tool mock reads 2026-05-13 05:09:36 +01:00
NVIDIAN
ecc48c6d86 fix(config): reject auto-managed meta.lastTouched* paths in config set/unset (#80856)
Merged via squash.

Prepared head SHA: a574312f5c
Co-authored-by: ai-hpc <183861985+ai-hpc@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-05-13 12:09:25 +08:00
Peter Steinberger
6a9e1a7aad test: dedupe tui shell mock read 2026-05-13 05:08:31 +01:00
Peter Steinberger
6912af6d83 test: dedupe proxy validation mock read 2026-05-13 05:07:36 +01:00
Peter Steinberger
4f7a6cebbc test: dedupe windows restart mock read 2026-05-13 05:06:40 +01:00
Peter Steinberger
401d2c6acc test: dedupe ssh config mock read 2026-05-13 05:05:47 +01:00
Peter Steinberger
ef44aa71d3 test: dedupe ssrf dispatcher mock read 2026-05-13 05:04:50 +01:00
Peter Steinberger
a6160b99d9 test: dedupe tui launch mock read 2026-05-13 05:03:53 +01:00
Peter Steinberger
b26db874a3 test: dedupe heartbeat reply mock read 2026-05-13 05:02:58 +01:00
Peter Steinberger
bc92f73ffb test: dedupe heartbeat prefix mock read 2026-05-13 05:02:01 +01:00
Peter Steinberger
02d2c1fee2 test: dedupe heartbeat typing mock read 2026-05-13 05:01:00 +01:00
Peter Steinberger
d7a6656913 test: dedupe transcript mock read 2026-05-13 04:58:43 +01:00
Peter Steinberger
ce712f503f test: dedupe run main mock read 2026-05-13 04:57:39 +01:00
Peter Steinberger
09116464b6 test: dedupe message lifecycle mock read 2026-05-13 04:56:24 +01:00
Peter Steinberger
69f7269e7d test: dedupe message send mock read 2026-05-13 04:55:34 +01:00
Peter Steinberger
abc2f57768 test: dedupe approval gateway mock read 2026-05-13 04:54:36 +01:00
Peter Steinberger
0cd0e57e9c test: dedupe npm root mock read 2026-05-13 04:53:42 +01:00
Peter Steinberger
e202231d56 test: dedupe security audit mock read 2026-05-13 04:52:25 +01:00
Peter Steinberger
65c056d7e2 test: dedupe sessions mock read 2026-05-13 04:51:24 +01:00
Peter Steinberger
45b0c92b3a test: dedupe plugin policy mock read 2026-05-13 04:50:28 +01:00
Peter Steinberger
5ca5c59de2 test: dedupe container target mock read 2026-05-13 04:49:36 +01:00
Peter Steinberger
20ec18807c test: dedupe batch http mock read 2026-05-13 04:48:40 +01:00
Peter Steinberger
06045b578a test: dedupe crestodian mock read 2026-05-13 04:47:44 +01:00
Peter Steinberger
23edebbaed test: dedupe audio transcode mock read 2026-05-13 04:46:31 +01:00
Peter Steinberger
f57c500034 test: dedupe custom theme mock reads 2026-05-13 04:45:33 +01:00
Peter Steinberger
b52a36d6e0 test: dedupe memory cli mock reads 2026-05-13 04:44:08 +01:00
Peter Steinberger
58cebd63c1 test: dedupe acp spawn mock reads 2026-05-13 04:43:00 +01:00
Peter Steinberger
53342ee5f3 test: dedupe live model switch mock reads 2026-05-13 04:42:04 +01:00
Peter Steinberger
6afe7f12b1 test: dedupe cli runner mock reads 2026-05-13 04:40:54 +01:00
Peter Steinberger
596f7a5cda test: dedupe pty fallback mock reads 2026-05-13 04:39:58 +01:00
Peter Steinberger
2cd936366b test: dedupe compaction summary mock reads 2026-05-13 04:39:08 +01:00
Peter Steinberger
36088884ac test: dedupe mcp transport mock reads 2026-05-13 04:38:19 +01:00
Peter Steinberger
3cfbc9e234 test: dedupe restart recovery mock reads 2026-05-13 04:36:36 +01:00
Peter Steinberger
c31874fe87 test: dedupe extra params mock reads 2026-05-13 04:35:34 +01:00
Peter Steinberger
6405977c03 test: dedupe context maintenance mock reads 2026-05-13 04:33:51 +01:00
Peter Steinberger
48e4a38655 test: dedupe prompt cache mock reads 2026-05-13 04:32:52 +01:00
Peter Steinberger
06d15572d3 test: dedupe runner cron mock reads 2026-05-13 04:31:58 +01:00
Peter Steinberger
6a14c838ca test: dedupe media handler mock reads 2026-05-13 04:30:55 +01:00
Peter Steinberger
92c84bbee4 test: dedupe acp lifecycle mock reads 2026-05-13 04:29:54 +01:00
Peter Steinberger
280d7931c1 test: dedupe memory dreaming mock reads 2026-05-13 04:28:50 +01:00
Peter Steinberger
5db2bf75c4 test: dedupe memory qmd mock reads 2026-05-13 04:27:38 +01:00
Peter Steinberger
f6d093e75e test: dedupe embedded subscribe flush mock reads 2026-05-13 04:25:31 +01:00
Peter Steinberger
9831b28dd7 test: dedupe before-tool-call e2e mock reads 2026-05-13 04:23:34 +01:00
Peter Steinberger
9eed27a9b8 test: dedupe before-tool-call mock reads 2026-05-13 04:21:55 +01:00
Peter Steinberger
47f31dd15d test: dedupe ui bootstrap mock reads 2026-05-13 04:20:35 +01:00
Peter Steinberger
d534c15b0a test: dedupe ui gateway mock reads 2026-05-13 04:19:08 +01:00
Peter Steinberger
936989a88b test: dedupe codex projector mock reads 2026-05-13 04:17:31 +01:00
Peter Steinberger
01fc684502 test: dedupe discord component mock reads 2026-05-13 04:16:05 +01:00
Peter Steinberger
32103aa3fd test: dedupe feishu doc mock reads 2026-05-13 04:14:38 +01:00
Peter Steinberger
da23f4572d test: dedupe matrix handler mock reads 2026-05-13 04:13:25 +01:00
Peter Steinberger
a08a38d4d9 test: dedupe mattermost monitor mock reads 2026-05-13 04:11:41 +01:00
Peter Steinberger
e566e817fb test: dedupe openai codex mock reads 2026-05-13 04:10:17 +01:00
Peter Steinberger
efc3e072a4 test: dedupe qqbot adapter mock reads 2026-05-13 04:09:05 +01:00
Peter Steinberger
a4514860e5 test: dedupe telegram command mock reads 2026-05-13 04:06:53 +01:00
Peter Steinberger
a5f5504b0d test: dedupe telegram monitor mock reads 2026-05-13 04:05:30 +01:00
pashpashpash
3688c47f1f Trust installed Codex for its private task runtime (#81206)
* fix(codex): trust installed codex task runtime

* fix(codex): keep private runtime alias packaged
2026-05-12 20:04:45 -07:00
Peter Steinberger
85eb8d47d4 test: dedupe vydra provider mock reads 2026-05-13 04:04:12 +01:00
Peter Steinberger
e1f24786f4 test: dedupe whatsapp login mock reads 2026-05-13 04:02:31 +01:00
Peter Steinberger
12f36b9a5a test: dedupe whatsapp allowlist mock reads 2026-05-13 04:01:19 +01:00
Peter Steinberger
a37c201776 test: dedupe whatsapp monitor mock reads 2026-05-13 03:59:43 +01:00
Rubén Cuevas
d4998d7b88 fix(plugins): retry npm alias override installs (#80539)
* fix(plugins): retry npm alias override installs

* fix(onboarding): space install retry warning

* fix(onboarding): shorten retry progress label

* docs(changelog): note npm alias install retry

---------

Co-authored-by: pashpashpash <nik@vault77.ai>
2026-05-12 19:58:21 -07:00
Peter Steinberger
38e1d68d7a test: dedupe discord process mock reads 2026-05-13 03:58:10 +01:00
Peter Steinberger
3375473e2b test: dedupe matrix cli mock reads 2026-05-13 03:56:49 +01:00
Peter Steinberger
b3260b1d15 test: dedupe telegram media mock reads 2026-05-13 03:55:27 +01:00
Peter Steinberger
889c1d7c15 test: dedupe whatsapp media mock reads 2026-05-13 03:54:10 +01:00
Peter Steinberger
eeecb48775 test: dedupe browser tool mock reads 2026-05-13 03:52:46 +01:00
Peter Steinberger
7159dab78d test: dedupe codex approval mock reads 2026-05-13 03:50:11 +01:00
Peter Steinberger
2edb8dede8 test: dedupe matrix send mock reads 2026-05-13 03:48:40 +01:00
Peter Steinberger
b8a27720f2 test: dedupe telegram gateway mock reads 2026-05-13 03:47:20 +01:00
Peter Steinberger
1f02abe381 fix(update): make pnpm preflight resolution deterministic 2026-05-13 03:46:33 +01:00
Peter Steinberger
f1ddaf46c7 ci: avoid pnpm prompts in live docker tests 2026-05-13 03:46:33 +01:00
Peter Steinberger
130b9bb2c1 test: dedupe browser cli mock reads 2026-05-13 03:45:26 +01:00
Peter Steinberger
ff7beea3da test: dedupe feishu routing mock reads 2026-05-13 03:43:41 +01:00
Peter Steinberger
cb613022ff test: dedupe telegram send mock reads 2026-05-13 03:42:22 +01:00
Peter Steinberger
4c663056d9 test: dedupe qa matrix mock reads 2026-05-13 03:40:17 +01:00
Peter Steinberger
6b77b8d978 test: dedupe discord voice mock reads 2026-05-13 03:37:28 +01:00
Peter Steinberger
a20d253819 test: dedupe active memory mock reads 2026-05-13 03:35:41 +01:00
Peter Steinberger
a06b735f32 test: dedupe provider fetch mock reads 2026-05-13 03:32:22 +01:00
Peter Steinberger
52ce64302f test: dedupe ssh spawn mock reads 2026-05-13 03:31:20 +01:00
Peter Steinberger
1296211c2e test: dedupe auto reply dispatch mock reads 2026-05-13 03:30:15 +01:00
Peter Steinberger
6b0b29fd04 test: dedupe reply media mock reads 2026-05-13 03:29:15 +01:00
Peter Steinberger
a6886d3fc4 test: dedupe durable delivery mock reads 2026-05-13 03:28:07 +01:00
Peter Steinberger
4ce9ff7845 test: dedupe exec policy mock reads 2026-05-13 03:26:58 +01:00
Peter Steinberger
d1ddb68d37 test: dedupe mcp cli mock reads 2026-05-13 03:25:53 +01:00
Peter Steinberger
91bae4baa5 test: dedupe nodes cli mock reads 2026-05-13 03:23:24 +01:00
Peter Steinberger
d8111ea65b test: dedupe setup cli mock reads 2026-05-13 03:21:50 +01:00
Peter Steinberger
48013bb259 test: dedupe qr cli mock reads 2026-05-13 03:20:26 +01:00
Peter Steinberger
00a01d1a39 test: dedupe security cli mock reads 2026-05-13 03:19:01 +01:00
Peter Steinberger
597c69036d test: dedupe cron retry mock reads 2026-05-13 03:17:40 +01:00
Peter Steinberger
9287aa5ef7 test: dedupe channel setup mock reads 2026-05-13 03:16:21 +01:00
Peter Steinberger
b2da3e0a02 test: dedupe embeddings http mock reads 2026-05-13 03:15:02 +01:00
Peter Steinberger
950831d6d1 test: dedupe gateway discovery mock reads 2026-05-13 03:13:55 +01:00
Marcus Castro
81a3de1d9d fix(whatsapp): drain debounced inbound before close (#81246)
* fix(whatsapp): drain debounced inbound before close

* docs(changelog): note WhatsApp debounce close drain
2026-05-12 23:13:38 -03:00
Peter Steinberger
ccf58b069d test: dedupe restart sentinel mock reads 2026-05-13 03:12:38 +01:00
Peter Steinberger
4f1549a6ae test: dedupe gateway reload mock reads 2026-05-13 03:11:19 +01:00
Peter Steinberger
cbf6d5cfe2 test: dedupe fetch guard mock reads 2026-05-13 03:08:34 +01:00
Peter Steinberger
4fdd71d186 test: dedupe transport ready mock reads 2026-05-13 03:07:27 +01:00
Peter Steinberger
74bbac994d test: dedupe git install mock reads 2026-05-13 03:06:23 +01:00
Peter Steinberger
661aa45eeb test: dedupe optional plugin tool mock reads 2026-05-13 03:05:15 +01:00
Peter Steinberger
fc09643aa2 test: dedupe tui command mock reads 2026-05-13 03:04:11 +01:00
Peter Steinberger
784b6cf2da test: dedupe dispatch config mock reads 2026-05-13 03:02:58 +01:00
WhatsSkiLL
e0f6f78b02 fix(gateway): clarify invalid config recovery hints
Closes #40652.

Thanks @JARVIS-Glasses.
2026-05-12 19:01:59 -07:00
Peter Steinberger
7cb596c807 test: dedupe model fallback mock reads 2026-05-13 03:01:37 +01:00
Peter Steinberger
b8bbe0e1e4 test: dedupe embedded reasoning mock reads 2026-05-13 02:59:52 +01:00
Peter Steinberger
46aa0ff9d0 test: dedupe embedded subscribe mock reads 2026-05-13 02:58:29 +01:00
Peter Steinberger
8f37126df7 test: dedupe session status mock reads 2026-05-13 02:57:13 +01:00
Peter Steinberger
919c8f1da5 test: dedupe models config mock reads 2026-05-13 02:56:04 +01:00
Peter Steinberger
191e9b68d7 test: dedupe compaction safeguard mock reads 2026-05-13 02:54:59 +01:00
Pavan Kumar Gondhi
a3fda2ada9 Limit hook CLI tool authority [AI] (#81065)
* fix: limit hook cli tool authority

* docs: add changelog entry for PR merge
2026-05-13 07:24:41 +05:30
Peter Steinberger
ac3aaad70c test: dedupe message tool mock reads 2026-05-13 02:53:44 +01:00
Peter Steinberger
6ace272a4b test: dedupe tts command mock reads 2026-05-13 02:52:35 +01:00
Peter Steinberger
9b4568c78f test: dedupe channel kernel mock reads 2026-05-13 02:51:21 +01:00
Pavan Kumar Gondhi
1c85eff9b1 Require admin scope for node device token management [AI] (#81067)
* fix: require admin for node device token management

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing claude review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-13 07:20:35 +05:30
Peter Steinberger
e2965b5f96 test: dedupe openresponses mock reads 2026-05-13 02:50:18 +01:00
Peter Steinberger
0e9ebe0a92 test: dedupe gateway agent mock reads 2026-05-13 02:49:13 +01:00
Peter Steinberger
dfd63a2145 test: dedupe gateway watch tmux mock reads 2026-05-13 02:48:11 +01:00
Peter Steinberger
cc6da043bd test: dedupe apns http2 mock reads 2026-05-13 02:47:01 +01:00
Pavan Kumar Gondhi
b7e0decf0c Restrict chat sender allowlist matching [AI] (#80898)
* fix: restrict chat sender allowlist matching

* fix: restrict chat sender allowlist matching

* addressing codex review

* fix: complete sender allowlist root cause

* addressing codex review

* addressing codex review

* fix: complete root-cause handling

* addressing review-skill

* addressing codex review

* addressing review-skill

* addressing codex review

* addressing codex review

* fix: complete chat sender allowlist handling

* addressing codex review

* fix: complete root-cause handling

* addressing codex review

* fix: complete root-cause handling

* addressing codex review

* fix: cover sender matcher conversation target opt-in

* addressing review-skill

* addressing codex review

* fix: require explicit chat target sender matching

* addressing review-skill

* addressing codex review

* addressing codex review

* fix: require explicit chat target sender matching

* addressing codex review

* fix: require explicit chat target sender matching

* addressing codex review

* addressing codex review

* fix: require explicit chat target sender matching

* docs: add changelog entry for PR merge
2026-05-13 07:16:27 +05:30
Peter Steinberger
e3a4280788 test: dedupe fetch auth mock reads 2026-05-13 02:44:01 +01:00
Peter Steinberger
73ae1decdf test: dedupe tts contract mock reads 2026-05-13 02:42:04 +01:00
Peter Steinberger
0adc4ed0e7 test: dedupe agent command delivery mock reads 2026-05-13 02:39:43 +01:00
Peter Steinberger
90ea70b63b test: dedupe reply tag mock reads 2026-05-13 02:38:21 +01:00
Peter Steinberger
50f38cc0de test: dedupe subagent announce mock reads 2026-05-13 02:36:59 +01:00
Peter Steinberger
f507f52e19 test: dedupe cron hook prompt reads 2026-05-13 02:35:37 +01:00
Peter Steinberger
a5668efb7a test: dedupe cron session identity mock reads 2026-05-13 02:34:11 +01:00
Peter Steinberger
f9b3733f77 test: dedupe chat abort authorization mock reads 2026-05-13 02:31:53 +01:00
Peter Steinberger
c456e6fa97 test: dedupe chat abort persistence mock reads 2026-05-13 02:30:26 +01:00
Peter Steinberger
e3916e2606 test: dedupe plugin provider mock reads 2026-05-13 02:28:33 +01:00
Peter Steinberger
d0b3b1e1a4 test: dedupe soft chunk reply reads 2026-05-13 02:26:28 +01:00
Peter Steinberger
b7741b6f8c test: dedupe model fallback mock reads 2026-05-13 02:25:06 +01:00
Peter Steinberger
f537b06e8d test: dedupe gateway tool mock reads 2026-05-13 02:23:20 +01:00
Peter Steinberger
4aedf91028 test: dedupe followup runner mock reads 2026-05-13 02:22:08 +01:00
Peter Steinberger
9307df225d test: dedupe chat directive mock reads 2026-05-13 02:20:46 +01:00
Peter Steinberger
e7f6dfa925 test: dedupe incomplete turn attempt reads 2026-05-13 02:18:43 +01:00
Peter Steinberger
e17e881653 test: dedupe gateway plugin mock reads 2026-05-13 02:17:03 +01:00
Peter Steinberger
a9f34bf1f5 test: dedupe config cli log payload reads 2026-05-13 02:15:39 +01:00
Peter Steinberger
5e44f53c5b test: dedupe gateway cron mock reads 2026-05-13 02:13:28 +01:00
Peter Steinberger
e64a9a0507 test: dedupe update cli mock reads 2026-05-13 02:11:06 +01:00
Peter Steinberger
caa7b8a81d test: dedupe media reply mock reads 2026-05-13 02:09:23 +01:00
Peter Steinberger
dd923d9752 test: clear command mock call at usage 2026-05-13 02:07:53 +01:00
Peter Steinberger
5ad3f7adaa test: dedupe command helper mock reads 2026-05-13 02:05:55 +01:00
Peter Steinberger
28b19f4c66 test: dedupe command mock call reads 2026-05-13 02:04:09 +01:00
Peter Steinberger
38bab38ce7 fix: normalize per-agent gemini config refs 2026-05-13 02:02:54 +01:00
Peter Steinberger
bd8e986bb2 test: dedupe doctor security mock read 2026-05-13 01:57:55 +01:00
Peter Steinberger
6014aa5688 test: dedupe channels config write mock read 2026-05-13 01:56:32 +01:00
Peter Steinberger
019dd6282e test: dedupe status json mock read 2026-05-13 01:55:06 +01:00
Peter Steinberger
b5290d0692 test: dedupe agents delete mock read 2026-05-13 01:53:17 +01:00
Peter Steinberger
45f0f4a5ea test: dedupe channel doctor mock read 2026-05-13 01:52:05 +01:00
Peter Steinberger
c36089c417 test: dedupe launchctl note mock read 2026-05-13 01:50:52 +01:00
Peter Steinberger
05ea6054e3 test: dedupe channels status mock read 2026-05-13 01:49:06 +01:00
Peter Steinberger
bf16038b5c test: dedupe models forward mock read 2026-05-13 01:47:52 +01:00
Peter Steinberger
367c600849 test: dedupe doctor memory mock reads 2026-05-13 01:46:13 +01:00
Peter Steinberger
068e6e0291 test: dedupe auth choice install mock read 2026-05-13 01:44:36 +01:00
Peter Steinberger
832ab4787c test: dedupe models status mock read 2026-05-13 01:43:24 +01:00
Peter Steinberger
60f53f5d58 test: dedupe models list mock read 2026-05-13 01:41:59 +01:00
Peter Steinberger
a32c2e6cf5 test: dedupe status report mock read 2026-05-13 01:40:19 +01:00
Peter Steinberger
856b3efeba test: dedupe empty allowlist mock read 2026-05-13 01:39:02 +01:00
Peter Steinberger
c2b46b1331 test: dedupe channels config mock read 2026-05-13 01:37:53 +01:00
Peter Steinberger
0904357eb9 test: dedupe auth choice provider mock read 2026-05-13 01:36:27 +01:00
Peter Steinberger
97c8944eeb test: dedupe dashboard links mock read 2026-05-13 01:35:25 +01:00
Peter Steinberger
02ddaafd99 test: dedupe local daemon mock read 2026-05-13 01:34:22 +01:00
Peter Steinberger
00c99972df test: dedupe channels logs mock read 2026-05-13 01:32:59 +01:00
Peter Steinberger
ccd51b40dd test: dedupe oauth tls mock read 2026-05-13 01:31:59 +01:00
Peter Steinberger
963207d265 test: dedupe bootstrap size mock read 2026-05-13 01:30:54 +01:00
Peter Steinberger
8504029d73 test: dedupe configure daemon mock read 2026-05-13 01:29:36 +01:00
Peter Steinberger
e92806278d test: dedupe local auth choice mock read 2026-05-13 01:28:37 +01:00
Peter Steinberger
74171908cb test: dedupe configure gateway mock read 2026-05-13 01:27:35 +01:00
Sarah Fortune
d06f0a0ee7 fix(install): don't abort install.ps1 when git writes to stderr (#80834)
PowerShell 7+ honors $ErrorActionPreference=Stop for native commands,
so git's normal progress line ("From https://...") on stderr during
`git pull --rebase` would turn into a terminating error and abort the
installer immediately after a fresh clone — before pnpm install/build
ever runs. The existing `2>$null` redirects the display but the error
record is still generated.

Wrap the git status / pull calls in try/catch so the pull stays
best-effort and the rest of the installer can proceed. Reproduced on
Windows 11 ARM under PowerShell 7.x with -InstallMethod git.
2026-05-12 17:26:30 -07:00
Peter Steinberger
31ea86bf7d test: dedupe agents identity mock read 2026-05-13 01:25:54 +01:00
Peter Steinberger
003782a521 test: dedupe channels list mock read 2026-05-13 01:24:51 +01:00
Peter Steinberger
3356aafe3a test: dedupe status json mock read 2026-05-13 01:23:49 +01:00
Peter Steinberger
532fea836b test: dedupe flows mock read 2026-05-13 01:22:28 +01:00
Peter Steinberger
ccb9c68487 test: dedupe sandbox mock read 2026-05-13 01:21:33 +01:00
Peter Steinberger
48eb4e39b2 test: dedupe api key mock read 2026-05-13 01:20:16 +01:00
Peter Steinberger
5f5a0cf916 test: dedupe models shared mock read 2026-05-13 01:19:16 +01:00
Peter Steinberger
945d46c2b7 test: dedupe daemon install mock read 2026-05-13 01:18:11 +01:00
Sarah Fortune
e7c9e84a42 feat(onboard): add --skip-hooks flag (#81220) 2026-05-12 17:17:26 -07:00
Peter Steinberger
373fb93693 test: dedupe status runtime mock read 2026-05-13 01:16:00 +01:00
Peter Steinberger
57863c6009 test: dedupe doctor claude mock read 2026-05-13 01:14:18 +01:00
sallyom
f65251d0ec docs: note tool result detail redaction 2026-05-12 20:13:26 -04:00
nimbleenigma
277eb16652 fix: redact persisted tool result details
Refresh PR #80444 on current upstream main.
2026-05-12 20:13:26 -04:00
Peter Steinberger
250c26d02c test: dedupe backup verify mock read 2026-05-13 01:12:49 +01:00
Peter Steinberger
bf92aa7bc0 test: dedupe doctor browser mock read 2026-05-13 01:11:45 +01:00
Peter Steinberger
c6249e4809 test: dedupe doctor transcript mock read 2026-05-13 01:10:22 +01:00
Peter Steinberger
fccee9485c test: dedupe status service mock read 2026-05-13 01:09:16 +01:00
Peter Steinberger
4b33ade05e test: dedupe doctor auth mock read 2026-05-13 01:08:06 +01:00
Peter Steinberger
cf77ad5025 test: dedupe backup mock read 2026-05-13 01:06:38 +01:00
Peter Steinberger
9147a53274 fix: normalize nested gemini preview config ids 2026-05-13 01:05:25 +01:00
Peter Steinberger
f8953d94bd test: dedupe nodes tool mock read 2026-05-13 01:01:32 +01:00
Peter Steinberger
b8c0edf91c test: dedupe gateway tool mock read 2026-05-13 00:59:30 +01:00
Peter Steinberger
6d631d3adf test: dedupe cron tool mock read 2026-05-13 00:58:26 +01:00
Peter Steinberger
93a81865f0 test: dedupe embedded subscribe warning read 2026-05-13 00:56:52 +01:00
Peter Steinberger
5147d2849f test: dedupe coding tools mock read 2026-05-13 00:55:45 +01:00
Peter Steinberger
8830527536 test: dedupe model catalog mock read 2026-05-13 00:54:38 +01:00
Peter Steinberger
30442d9e4e test: dedupe pi project settings mock read 2026-05-13 00:53:31 +01:00
sallyom
14a9bb98b7 fix(config-audit): guard scrub rename after temp write
Signed-off-by: sallyom <somalley@redhat.com>
2026-05-12 19:52:52 -04:00
YB0y
432b94989b fix(config-audit): scrub pre-redactor argv values from historical config-audit.jsonl entries (#80777)
PR #75095 added `redactConfigAuditArgv` so newly-written entries in
`~/.openclaw/logs/config-audit.jsonl` mask token-shaped values, but the
audit log has no rotation, retention, or one-shot scrub. Users who ran
`openclaw config set <path> <secret-value>` between commit `748d6821d2`
(audit added 2026-02-14) and `a853c5e8c2` (redactor merged 2026-05-01)
still have plaintext Slack, Telegram, gateway, etc. tokens sitting in
`config-audit.jsonl` at rest after upgrading.

Add `scrubConfigAuditLog` in `src/config/io.audit.ts` that reads the
audit log, rewrites every record's `argv` / `execArgv` fields through
the existing forward redactor, and writes the file back atomically
(`*.scrub.tmp` + rename, mode 0o600). Idempotent — already-masked
entries pass through unchanged. Malformed lines are preserved verbatim
and counted as `skipped` so the scrub never destroys forensic content
it cannot understand. Concurrent-append guard: re-stat the audit log
immediately before rename and abort (no on-disk change) if the file
grew during the scrub, so a parallel appendConfigAuditRecord call is
never overwritten by the rename swap. Wire into the doctor health flow
as `runConfigAuditScrubHealth`: scan-only on a normal `openclaw doctor`
(prints the count and suggests `--fix`); rewrite atomically on
`openclaw doctor --fix` with a "rotate any credentials" note; print a
"stop the gateway and rerun" hint on the abort path. No plaintext
backup file is produced; file mode and parent dir mode are preserved.

Per repo CLAUDE.md ("Legacy config repair: doctor/fix paths, not
startup/load-time core migrations") the scrub is gated to `--fix`
and runs only when the user opts in.

Verified:
- pnpm install --frozen-lockfile
- pnpm test src/config/io.audit.test.ts
- pnpm test src/commands/doctor-config-flow.test.ts
- pnpm tsgo:core:test
- pnpm exec oxfmt --check --threads=1 src/config/io.audit.ts src/config/io.audit.test.ts src/commands/doctor-config-audit-scrub.ts src/flows/doctor-health-contributions.ts

Closes #80777
2026-05-12 19:52:52 -04:00
Peter Steinberger
9ae29c8bb1 test: dedupe pi tools schema mock read 2026-05-13 00:52:27 +01:00
Sarah Fortune
48529f1a96 feat(onboard): offer codex migration after harness install (#81192)
Add a post-install seam so the wizard can prompt the user to import their
existing Codex CLI state (skills, archived config/hooks, advisory cached
plugins) through the existing `openclaw migrate codex` flow once the
harness plugin is in place. Fires on both fresh installs and repair runs;
the user can decline at any time.

Trigger sites, both routing through one helper:

- src/plugins/provider-auth-choice.ts: after
  `ensureCodexRuntimePluginForModelSelection` reports `installed: true`,
  dynamically import `offerPostInstallMigrations` and call it before the
  wizard moves on.
- src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.ts:
  same call shape with `nonInteractive: true`, so the helper emits a hint
  line only and never mutates state.

Helper (src/wizard/setup.post-install-migration.ts) is generic, not
Codex-hardcoded — it resolves migration providers via the manifest
`migrationProviders` contract, filters to providers owned by plugins the
caller flags as installed in this onboarding step, runs `provider.detect`,
and on TTY hands accepted runs to `migrateDefaultCommand`. All detect,
prompt, and migrate failures are swallowed so onboarding never aborts on
this optional offer.

Also harden the Codex app-server subprocess lifecycle now that `detect()`
runs from a hotter onboarding path: isolate the plugin-install
`plugin/read` call (extensions/codex/src/migration/apply.ts) and have the
isolated request wait for child exit with a SIGKILL fallback
(extensions/codex/src/app-server/request.ts) so parents are not held open
by an orphaned codex binary.

Tests:

- src/wizard/setup.post-install-migration.test.ts (new, 10 cases)
- src/commands/onboard-non-interactive/local/auth-choice.plugin-providers.test.ts
  extended with hint-call assertions and a not-required-no-offer case.
2026-05-12 16:51:27 -07:00
Peter Steinberger
37237a5129 test: dedupe auth profile mock read 2026-05-13 00:50:55 +01:00
Peter Steinberger
ce21937c97 test: dedupe cli helper mock read 2026-05-13 00:49:56 +01:00
Peter Steinberger
20e2206eac test: dedupe exec followup mock reads 2026-05-13 00:48:42 +01:00
Peter Steinberger
21a46f48d2 test: dedupe pi tool adapter log reads 2026-05-13 00:47:32 +01:00
Peter Steinberger
1ade7a53af test: dedupe cron scope mock reads 2026-05-13 00:43:49 +01:00
Peter Steinberger
f2935ca3ec test: dedupe sandbox manage mock reads 2026-05-13 00:41:53 +01:00
Peter Steinberger
a0833ed20b test: dedupe skills install mock reads 2026-05-13 00:40:42 +01:00
Peter Steinberger
9c3e08b346 test: dedupe subagent announce mock reads 2026-05-13 00:39:10 +01:00
Peter Steinberger
7964a49378 test: dedupe subagent spawn mock reads 2026-05-13 00:37:52 +01:00
Peter Steinberger
5051024366 test: dedupe subagent thread mock reads 2026-05-13 00:36:47 +01:00
Peter Steinberger
b540882703 test: dedupe music generate mock reads 2026-05-13 00:35:16 +01:00
Peter Steinberger
3c27f7428b test: dedupe cf markdown mock reads 2026-05-13 00:33:58 +01:00
Peter Steinberger
3436fc2f72 test: dedupe web search mock reads 2026-05-13 00:32:48 +01:00
Peter Steinberger
caa4cf7f0f test: dedupe web fetch mock reads 2026-05-13 00:31:44 +01:00
Peter Steinberger
0e4f2c53c7 test: dedupe command control mock reads 2026-05-13 00:30:24 +01:00
Peter Steinberger
df7a71afc6 test: dedupe agent runner execution mock reads 2026-05-13 00:29:14 +01:00
Peter Steinberger
b3cc2c17fc test: dedupe secret resolution mock reads 2026-05-13 00:27:20 +01:00
Peter Steinberger
a7b9bce139 test: dedupe acp command mock reads 2026-05-13 00:25:54 +01:00
Peter Steinberger
33419d7d1b test: dedupe commands core mock reads 2026-05-13 00:21:44 +01:00
Peter Steinberger
ba625e2cff test: dedupe models command mock reads 2026-05-13 00:18:15 +01:00
Peter Steinberger
f2b560ff5d test: dedupe session restart mock reads 2026-05-13 00:16:04 +01:00
Peter Steinberger
b46e5ae60c test: dedupe session usage mock reads 2026-05-13 00:13:54 +01:00
Peter Steinberger
0b165f708f test: dedupe subagents focus mock reads 2026-05-13 00:11:14 +01:00
Peter Steinberger
65d801cf8a test: dedupe reply dispatch mock reads 2026-05-13 00:09:13 +01:00
Peter Steinberger
e15cce76c7 test: dedupe get reply mock reads 2026-05-13 00:06:48 +01:00
Peter Steinberger
73e47fc6a9 test: dedupe session lifecycle mock reads 2026-05-13 00:04:44 +01:00
Peter Steinberger
f96cfeeb73 test: dedupe gateway cli mock reads 2026-05-13 00:02:45 +01:00
Peter Steinberger
86c4482c58 test: dedupe message thread mock reads 2026-05-13 00:01:15 +01:00
Peter Steinberger
8998e536fa test: dedupe cli route mock reads 2026-05-12 23:59:23 +01:00
Peter Steinberger
1cd736afd2 test: dedupe update cli mock reads 2026-05-12 23:57:58 +01:00
Peter Steinberger
d3099ff0de test: dedupe agent acp mock reads 2026-05-12 23:55:54 +01:00
Peter Steinberger
73907fdf5c test: dedupe channel setup mock reads 2026-05-12 23:54:01 +01:00
Peter Steinberger
4cd356fa2a test: dedupe channels remove mock reads 2026-05-12 23:52:31 +01:00
Peter Steinberger
87f5fb3ab2 test: dedupe doctor startup note mock reads 2026-05-12 23:51:02 +01:00
Peter Steinberger
6676be413e test: dedupe doctor sandbox mock reads 2026-05-12 23:49:46 +01:00
Peter Steinberger
6769b37c36 test: dedupe doctor workspace mock reads 2026-05-12 23:48:32 +01:00
Peter Steinberger
19599c268c test: dedupe doctor repair mock reads 2026-05-12 23:47:20 +01:00
Peter Steinberger
870e6f0ace test: dedupe doctor migration mock reads 2026-05-12 23:45:42 +01:00
Peter Steinberger
c4d4e5d315 test: dedupe message command mock reads 2026-05-12 23:44:26 +01:00
Peter Steinberger
51886077bd test: dedupe sessions cleanup mock reads 2026-05-12 23:43:09 +01:00
Peter Steinberger
2f21db25b0 test: dedupe status fast json mock reads 2026-05-12 23:41:39 +01:00
Peter Steinberger
afe2e07181 test: dedupe status scan mock reads 2026-05-12 23:40:29 +01:00
Peter Steinberger
b3c74c10c9 test: dedupe cron delivery mock reads 2026-05-12 23:39:09 +01:00
Peter Steinberger
1974e6f7b5 test: dedupe cron heartbeat mock reads 2026-05-12 23:37:55 +01:00
Peter Steinberger
b9d3843aff test: dedupe chat attachment mock reads 2026-05-12 23:36:35 +01:00
Peter Steinberger
73abe9e98a test: dedupe control ui auto root mock reads 2026-05-12 23:35:23 +01:00
Peter Steinberger
8a6c18a08a test: dedupe control ui http mock reads 2026-05-12 23:32:42 +01:00
Peter Steinberger
3779c10f27 test: dedupe managed image mock reads 2026-05-12 23:30:44 +01:00
Peter Steinberger
37d01fdd4a test: dedupe server channels mock reads 2026-05-12 23:29:04 +01:00
Peter Steinberger
55aadd2d48 test: dedupe server close mock reads 2026-05-12 23:27:26 +01:00
Peter Steinberger
85f89442c5 test: dedupe agent create event mock reads 2026-05-12 23:25:35 +01:00
Peter Steinberger
c34559d91d test: dedupe channels status mock reads 2026-05-12 23:24:01 +01:00
Kevin Lin
bc44f3824f fix: improve Codex migration selector enter 2026-05-12 15:23:28 -07:00
Peter Steinberger
ec7962fdc3 test: dedupe diagnostics mock reads 2026-05-12 23:21:48 +01:00
Peter Steinberger
096a331ab2 test: dedupe doctor response mock reads 2026-05-12 23:20:16 +01:00
Peter Steinberger
29ba6f8312 test: dedupe nodes pending mock reads 2026-05-12 23:18:10 +01:00
Peter Steinberger
fd79013b8f test: dedupe plugin approval mock reads 2026-05-12 23:15:29 +01:00
Peter Steinberger
ed3df9cbb8 test: dedupe tools catalog mock reads 2026-05-12 23:13:32 +01:00
Peter Steinberger
5ab28bf164 test: dedupe restart sentinel mock reads 2026-05-12 23:11:46 +01:00
Peter Steinberger
d79d6b2e5c test: dedupe startup log mock reads 2026-05-12 23:10:01 +01:00
Peter Steinberger
2c69c41643 test: dedupe sessions list mock reads 2026-05-12 23:08:25 +01:00
Peter Steinberger
b3ee777664 test: dedupe ws connection mock reads 2026-05-12 23:06:37 +01:00
Peter Steinberger
0768b4f2ad test: dedupe tools invoke mock reads 2026-05-12 23:05:20 +01:00
Peter Steinberger
e8a8675128 test: dedupe install flow mock reads 2026-05-12 23:03:59 +01:00
Peter Steinberger
fc94d7541c test: dedupe fetch guard mock reads 2026-05-12 23:02:32 +01:00
Peter Steinberger
c6ebc1d7e8 test: dedupe apns relay mock reads 2026-05-12 23:00:48 +01:00
Peter Steinberger
a3ff7aa02c test: dedupe run node mock reads 2026-05-12 22:59:34 +01:00
Peter Steinberger
3eaefda824 test: dedupe runtime llm mock reads 2026-05-12 22:57:53 +01:00
Peter Steinberger
d42b3c2b4a test: dedupe web fetch provider mock reads 2026-05-12 22:56:41 +01:00
Peter Steinberger
c9d7ba8690 test: dedupe wired hook error mock reads 2026-05-12 22:55:08 +01:00
Peter Steinberger
413580bef2 test: dedupe qa lab live gateway mock reads 2026-05-12 22:53:58 +01:00
Peter Steinberger
ec2944dc82 test: dedupe qa lab agent process mock reads 2026-05-12 22:52:33 +01:00
Peter Steinberger
65c5c3faf8 test: dedupe git install mock reads 2026-05-12 22:50:20 +01:00
Peter Steinberger
cf1987bbe9 test: dedupe plugin install mock reads 2026-05-12 22:48:58 +01:00
Peter Steinberger
6bd565d9f2 test: dedupe provider runtime mock reads 2026-05-12 22:46:49 +01:00
Peter Steinberger
96b2ef812d test: dedupe qa runner mock reads 2026-05-12 22:44:33 +01:00
Peter Steinberger
af8f3552e4 test: dedupe session maintenance mock reads 2026-05-12 22:42:15 +01:00
Peter Steinberger
9531befca5 test: dedupe heartbeat override mock reads 2026-05-12 22:40:54 +01:00
Peter Steinberger
f469cc69d3 test: dedupe approval handler mock reads 2026-05-12 22:39:17 +01:00
Solomon Neas
48af99ed30 fix(agents/harness): pass tool results through tool-result middleware safely (#78743)
Skip tool-result middleware validation when no handler is registered, and
sanitize incoming tool result `details` (functions, symbols, bigints,
cycles, oversized payloads) before middleware sees them. Tool emitters
legitimately produce raw dependency payloads on `details`, and the
harness owes any registered middleware a JSON-safe view of that payload;
otherwise a no-op middleware (e.g. bundled tokenjuice on the pi runtime)
causes the validator to reject every tool result and silently substitute
a failure sentinel, dropping outbound Discord messages, exec output,
cron results, and any other tool whose payload carries non-serializable
values.
2026-05-12 14:37:06 -07:00
Peter Steinberger
75a2e959b2 test: dedupe sessions thinking mock reads 2026-05-12 22:36:44 +01:00
Edward Abrams
b247b1432f fix(heartbeat): multi-agent cadence — parallel broadcast, per-agent busy check, prompt assembly, connect-timeout, doctor warning (#80470)
* fix(heartbeat): unblock beads cadence — parallel broadcast, agent-scoped busy check, full HEARTBEAT.md prompt, connect-timeout, doctor warning

* docs(changelog): note heartbeat cadence fixes

* fix(heartbeat): address review feedback

* fix(heartbeat): append HEARTBEAT.md directives to commitment-only task dispatch (review feedback)

* docs(changelog): extend heartbeat fix entry — commitment-only task dispatch path (review feedback)

* fix(heartbeat): clear connect timer on synchronous baseFn throw (review feedback)

When the provider stream function passed to streamWithIdleTimeout throws

synchronously during setup, the connect watchdog timer was left armed

and could fire onIdleTimeout later with a stale error, keeping the

process open past the real failure. Wrap the synchronous baseFn(...)

invocation in a try/catch that clears the connect timer before

rethrowing, and add a regression test that asserts onIdleTimeout is

not invoked after the synchronous throw.

* docs(changelog): note round-4 heartbeat fix (review feedback)

Bump the heartbeat fixes list from six to seven and document the

synchronous-baseFn-throw connect-timer cleanup added in the prior

commit.

* fix(heartbeat): honor omitted doctor target (review feedback)

* fix(heartbeat): merge doctor heartbeat defaults (review feedback)

Teach the heartbeat session-target doctor warning to enumerate the same agents as the runtime heartbeat runner and merge agents.defaults.heartbeat with per-agent overrides before checking pinned sessions.

Add regression coverage for default-only heartbeat.session pins and explicit agent heartbeat entries that inherit the default session.

Validation:
- pnpm test src/commands/doctor-heartbeat-session-target.test.ts
- pnpm tsgo:core
- pnpm tsgo:core:test
- pnpm config:schema:check
- pnpm exec oxlint src/commands/doctor-heartbeat-session-target.ts src/commands/doctor-heartbeat-session-target.test.ts
- pnpm exec oxfmt --check src/commands/doctor-heartbeat-session-target.ts src/commands/doctor-heartbeat-session-target.test.ts
- git diff --check

Beads: openclaw-8zp

* test(heartbeat): avoid redundant doctor assertion (review feedback)

The CI lint shard flags the non-null assertion in the heartbeat doctor regression test. Keep the same test setup while using an explicit guard so the test still narrows the fixture before mutating the heartbeat entry.

Validation:
- pnpm exec oxlint src/commands/doctor-heartbeat-session-target.test.ts
- pnpm test src/commands/doctor-heartbeat-session-target.test.ts
- pnpm tsgo:core:test
- git diff --check

Beads: openclaw-8zp

* docs(config): refresh baseline after heartbeat branch update

* fix(heartbeat): narrow doctor session warnings (review feedback)
2026-05-12 14:36:25 -07:00
Peter Steinberger
aef80a2940 test: dedupe gateway startup mock reads 2026-05-12 22:35:08 +01:00
Peter Steinberger
ae9b7041ef test: dedupe gateway push mock reads 2026-05-12 22:33:51 +01:00
Peter Steinberger
041906e2d5 test: dedupe models auth-status mock reads 2026-05-12 22:29:35 +01:00
Peter Steinberger
efb404b14f test: dedupe agents mutate mock reads 2026-05-12 22:27:00 +01:00
Peter Steinberger
2d4ac9a7f5 test: dedupe gateway aux mock reads 2026-05-12 22:24:34 +01:00
Peter Steinberger
de8022ba0e test: dedupe chat abort mock reads 2026-05-12 22:21:48 +01:00
Peter Steinberger
0428a6dd6f test: dedupe status scan mock reads 2026-05-12 22:20:02 +01:00
Shakker
67ead6ec0e test: payload error text output 2026-05-12 22:19:49 +01:00
Shakker
73723368b8 test: loop compaction log output 2026-05-12 22:19:14 +01:00
Shakker
d1c2ea0cba test: alert incomplete turn warnings 2026-05-12 22:18:39 +01:00
Shakker
369d252317 test: maintain context event output 2026-05-12 22:17:51 +01:00
Shakker
ed1d2db3da test: emit fs bridge script output 2026-05-12 22:17:25 +01:00
Peter Steinberger
46bd83498e test: dedupe models scan mock reads 2026-05-12 22:17:00 +01:00
Shakker
482a05a542 test: hide gh config home hint 2026-05-12 22:16:46 +01:00
Shakker
a5912b92f7 test: quarantine dangerous skill warnings 2026-05-12 22:16:02 +01:00
Shakker
4754b585f4 test: deliver command error output 2026-05-12 22:15:27 +01:00
Shakker
342d697276 test: single default account warning output 2026-05-12 22:14:59 +01:00
Peter Steinberger
8b6328d791 test: dedupe provider catalog mock reads 2026-05-12 22:14:50 +01:00
Shakker
6630766e7e test: disambiguate acp log output 2026-05-12 22:14:11 +01:00
Shakker
71d2e41bb0 test: bundle daemon secret warnings 2026-05-12 22:13:20 +01:00
Peter Steinberger
daffccddb6 test: dedupe doctor locks mock reads 2026-05-12 22:13:00 +01:00
Shakker
bb10e2b22d test: stringify daemon install warnings 2026-05-12 22:12:33 +01:00
Shakker
3653a231cc test: fuse auth choice error output 2026-05-12 22:12:04 +01:00
Shakker
a0f5cac723 test: dedicate gh config hint output 2026-05-12 22:11:35 +01:00
Peter Steinberger
77fb105aad test: dedupe configure wizard mock reads 2026-05-12 22:11:16 +01:00
Shakker
f9c87de73f test: condense gateway mismatch notes 2026-05-12 22:10:56 +01:00
Shakker
736b8c676b test: coalesce capability cli errors 2026-05-12 22:10:25 +01:00
Shakker
c4d26b9e0c test: compress plugin uninstall logs 2026-05-12 22:10:00 +01:00
Shakker
3cfcaf80d0 test: unify daemon status log assertions 2026-05-12 22:09:35 +01:00
Shakker
6e8d0605c3 test: concatenate cron list logs 2026-05-12 22:08:58 +01:00
Peter Steinberger
b51a7cb35e test: dedupe channel setup mock reads 2026-05-12 22:08:43 +01:00
Shakker
171d3e4fa2 test: assemble sandbox command output 2026-05-12 22:08:23 +01:00
Shakker
102cdd8d32 test: aggregate completion timeout logs 2026-05-12 22:07:47 +01:00
Solomon Neas
314903417f fix(memory-core): prevent staged dream candidates from leaking into MEMORY.md (#68774)
* fix(memory-core): prevent staged dream candidates from leaking into MEMORY.md

* fix(memory-core): correct PromotionComponents shape in dream-fence test fixture
2026-05-12 14:07:43 -07:00
Peter Steinberger
706699bd24 test: dedupe agents bind mock reads 2026-05-12 22:06:56 +01:00
Shakker
e156b4299c test: token gateway install warnings 2026-05-12 22:05:36 +01:00
Peter Steinberger
fd3f654f20 test: dedupe cli program mock reads 2026-05-12 22:05:30 +01:00
Shakker
6d91d60615 test: onboard search provider notes 2026-05-12 22:04:49 +01:00
Shakker
881878da39 test: spare state integrity files 2026-05-12 22:03:54 +01:00
Peter Steinberger
4472066237 test: dedupe gateway cli mock reads 2026-05-12 22:03:46 +01:00
Shakker
726ecc4987 test: prompt auth choice messages 2026-05-12 22:02:49 +01:00
Shakker
e6c09b90cb test: fetch claude usage urls 2026-05-12 22:02:20 +01:00
Peter Steinberger
a8dd5653ee test: dedupe exec approvals cli mock reads 2026-05-12 22:02:03 +01:00
Shakker
5959a99646 test: queue outbound log text 2026-05-12 22:01:40 +01:00
Shakker
201dd735a0 test: log diagnostic messages 2026-05-12 22:00:59 +01:00
Peter Steinberger
0d4f4bab94 test: dedupe config cli mock reads 2026-05-12 22:00:36 +01:00
Shakker
d4c9aaf53a test: image agent log filenames 2026-05-12 22:00:18 +01:00
Shakker
c0f2e20660 test: hook gateway event text 2026-05-12 21:59:43 +01:00
Shakker
ac3f06fd4f test: rebase update runner commands 2026-05-12 21:59:11 +01:00
Peter Steinberger
d1e53c9488 test: dedupe acp cli mock reads 2026-05-12 21:58:47 +01:00
Shakker
4fd15fcce2 test: ping health snapshot urls 2026-05-12 21:58:35 +01:00
y471823206
3b9796ce9b Handle generic provider internal errors (#49401)
Merged via squash.

Prepared head SHA: 492caa49a9
Co-authored-by: y471823206 <2311651347@qq.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-12 23:58:27 +03:00
Shakker
2ed2fbb55d test: service gateway doctor notes 2026-05-12 21:57:56 +01:00
Peter Steinberger
87d8545c97 test: dedupe media get-reply mock reads 2026-05-12 21:57:18 +01:00
Shakker
ed20e5e10c test: present command output text 2026-05-12 21:57:00 +01:00
Shakker
bf9fd2cfcd test: secret gateway warning text 2026-05-12 21:55:55 +01:00
Peter Steinberger
f3b5dc80f9 test: dedupe agent runner misc mock reads 2026-05-12 21:55:29 +01:00
Shakker
168bb4fac8 test: note wizard finalize calls 2026-05-12 21:55:01 +01:00
Shakker
71cdb6ab9a test: display cli output text 2026-05-12 21:54:12 +01:00
Shakker
016852186d test: observe config warning text 2026-05-12 21:53:17 +01:00
Shakker
9ff2627b7d test: squelch signal client logs 2026-05-12 21:52:38 +01:00
Shakker
c80152eadd test: canonicalise plugin discovery paths 2026-05-12 21:52:03 +01:00
Peter Steinberger
712ceabb40 test: dedupe agent runner memory mock reads 2026-05-12 21:51:44 +01:00
Shakker
559a744594 test: offer slack monitor text 2026-05-12 21:50:13 +01:00
Shakker
cee32280c6 test: weave matrix message assertions 2026-05-12 21:49:38 +01:00
Peter Steinberger
8792341cf6 test: dedupe trigger handling mock reads 2026-05-12 21:49:26 +01:00
Shakker
9456cc850a test: signal plugin warning text 2026-05-12 21:48:49 +01:00
Shakker
8d5623acc8 test: search tui no matches output 2026-05-12 21:48:07 +01:00
Shakker
f7646f9fde test: shutter browser tab cleanup urls 2026-05-12 21:47:37 +01:00
Peter Steinberger
98ca0858f4 test: dedupe web guarded fetch mock reads 2026-05-12 21:47:12 +01:00
Shakker
f8ceffde7c test: watch memory path assertions 2026-05-12 21:46:57 +01:00
Shakker
9656cd365b test: erase discord progress labels 2026-05-12 21:46:17 +01:00
Shakker
c716a30a58 test: block discord picker nav ids 2026-05-12 21:45:49 +01:00
Peter Steinberger
1fe4e9a8f0 test: dedupe video tool mock reads 2026-05-12 21:45:39 +01:00
Shakker
ad882f681d test: hush discord provider logs 2026-05-12 21:45:04 +01:00
Shakker
5396510370 test: point media wav argument 2026-05-12 21:43:55 +01:00
Peter Steinberger
9be1be8f1e test: dedupe sessions send a2a mock reads 2026-05-12 21:43:49 +01:00
Shakker
693c775a7f test: tag provider unit assertions 2026-05-12 21:42:48 +01:00
Peter Steinberger
1725b4ae49 test: dedupe workspace skills warning mock reads 2026-05-12 21:42:02 +01:00
Shakker
40b3236415 test: probe qa lab message snapshots 2026-05-12 21:41:42 +01:00
Shakker
8930897220 test: fasten active memory log lines 2026-05-12 21:40:48 +01:00
Kevin Lin
233d65f09d docs: split plugin docs navigation
Split plugin docs navigation into reader-intent groups.
2026-05-12 13:40:12 -07:00
Peter Steinberger
d71a2427c0 test: dedupe skills install command mock reads 2026-05-12 21:40:00 +01:00
Shakker
05c83c7bd4 test: steady whatsapp status assertions 2026-05-12 21:38:32 +01:00
Peter Steinberger
22f6be52ee test: dedupe provider transport policy mock reads 2026-05-12 21:38:21 +01:00
Shakker
6890ef4952 test: reserve telegram fallback assertions 2026-05-12 21:37:25 +01:00
Peter Steinberger
4ef0d45a91 test: dedupe pi subscribe tool result mock reads 2026-05-12 21:36:45 +01:00
Shakker
2f306546ab test: cradle memory dreaming assertions 2026-05-12 21:36:21 +01:00
Shakker
22235e85de test: caption feishu streaming updates 2026-05-12 21:35:36 +01:00
Peter Steinberger
9cdb59ec4f test: dedupe pi message handler mock reads 2026-05-12 21:35:10 +01:00
Shakker
97a991d037 test: screen ollama setup request probes 2026-05-12 21:34:42 +01:00
Peter Steinberger
a330cba9f8 test: dedupe pi compaction log mock reads 2026-05-12 21:33:42 +01:00
Shakker
f0c016c212 test: dodge msteams graph shares 2026-05-12 21:32:50 +01:00
Shakker
b97d07683a test: heal matrix doctor changes 2026-05-12 21:32:17 +01:00
Peter Steinberger
05a2fed3b7 test: dedupe pi usage reporting mock reads 2026-05-12 21:32:14 +01:00
Shakker
c90635d023 test: vault dreaming repair archives 2026-05-12 21:31:40 +01:00
Shakker
2eba3dabb7 test: reject slack download image content 2026-05-12 21:31:03 +01:00
Peter Steinberger
188bbe92e5 test: dedupe pi failover warning mock reads 2026-05-12 21:30:50 +01:00
Shakker
178a50e017 test: triage telegram status issues 2026-05-12 21:30:11 +01:00
Shakker
70817ed5fa test: locate signal config issues 2026-05-12 21:29:39 +01:00
Peter Steinberger
5dd5dc3bcc test: dedupe embedded pi runner mock reads 2026-05-12 21:29:25 +01:00
Shakker
b5cb5fa711 test: score memory wiki lint codes 2026-05-12 21:28:56 +01:00
Shakker
c1bfc7b3de test: deny googlechat body reads 2026-05-12 21:28:20 +01:00
Shakker
a76bebd2e6 test: etch discord status patches 2026-05-12 21:27:50 +01:00
Peter Steinberger
95e9b87d69 test: dedupe pi lsp windows spawn mock reads 2026-05-12 21:27:30 +01:00
Shakker
5c56ac7efd test: advertise bonjour warning checks 2026-05-12 21:26:42 +01:00
Peter Steinberger
d286e16a37 test: dedupe browser plugin tools mock reads 2026-05-12 21:26:05 +01:00
Shakker
4cfbfc73e0 test: splice matrix notice bodies 2026-05-12 21:25:33 +01:00
Shakker
1b645b21fc test: joiner synology warning checks 2026-05-12 21:25:03 +01:00
Shakker
dbf5b213af test: mute telegram account warning scan 2026-05-12 21:24:26 +01:00
Peter Steinberger
4091be857d test: dedupe implicit provider discovery mock reads 2026-05-12 21:24:07 +01:00
Shakker
d20ba302f8 test: partition bundled entry prefixes 2026-05-12 21:23:47 +01:00
Kevin Lin
eba73e593a build(canvas): stop tracking a2ui bundle hash (#81141) 2026-05-12 13:23:12 -07:00
Shakker
fd8ba6ae63 test: survey slack message schema props 2026-05-12 21:22:27 +01:00
Peter Steinberger
8f4941fd12 test: dedupe model catalog visibility mock reads 2026-05-12 21:22:09 +01:00
Shakker
2b2d696f89 test: vet telegram markdown chunks 2026-05-12 21:21:46 +01:00
Shakker
7fa771b665 test: ground memory lancedb hook checks 2026-05-12 21:21:01 +01:00
Peter Steinberger
db529f7517 test: dedupe cli runner supervisor capture mock reads 2026-05-12 21:20:54 +01:00
Shakker
0659780b21 test: sift openai catalog ids 2026-05-12 21:19:44 +01:00
Peter Steinberger
b36b0de04e test: dedupe bash exec runtime mock reads 2026-05-12 21:19:36 +01:00
Shakker
b7afe26a54 test: surface plugin registry diagnostics 2026-05-12 21:18:39 +01:00
Peter Steinberger
f3a03e1870 test: dedupe acp spawn mock reads 2026-05-12 21:18:20 +01:00
Shakker
33e5f29d0a test: bar codex computer use setup calls 2026-05-12 21:17:56 +01:00
Shakker
97e44aca75 test: recount codex plugin refresh calls 2026-05-12 21:17:19 +01:00
Peter Steinberger
346cc29fc2 test: dedupe acp spawn parent stream mock reads 2026-05-12 21:16:41 +01:00
Shakker
650b145686 test: delineate acp spawn relay calls 2026-05-12 21:16:10 +01:00
Shakker
fed2b9f132 test: stipulate hermes migration warnings 2026-05-12 21:15:01 +01:00
Shakker
bebb36caa5 test: affirm codex native auth calls 2026-05-12 21:13:33 +01:00
Peter Steinberger
ad1947732d test: dedupe signal container fetch reads 2026-05-12 21:13:22 +01:00
Shakker
8cc5870b49 test: sharpen codex migration warnings 2026-05-12 21:12:27 +01:00
Peter Steinberger
4b81881700 test: dedupe qa channel inbound mock reads 2026-05-12 21:11:05 +01:00
Peter Steinberger
86bcd179a7 test: dedupe openai realtime keychain reads 2026-05-12 21:09:35 +01:00
Shakker
6c44a6b21f test: elide run main null guard 2026-05-12 21:07:14 +01:00
Peter Steinberger
2f33554ed4 test: dedupe mattermost slash log reads 2026-05-12 21:07:04 +01:00
Shakker
116282a2c0 test: summon sandbox docker create 2026-05-12 21:05:44 +01:00
Peter Steinberger
c299249b4f test: dedupe matrix media failure mock reads 2026-05-12 21:05:11 +01:00
Shakker
75001adc7e test: carry matrix chunk config 2026-05-12 21:04:17 +01:00
Peter Steinberger
fd75588190 test: dedupe matrix profile mock reads 2026-05-12 21:03:11 +01:00
Shakker
cd98df601c test: compel uninstall plan params 2026-05-12 21:02:16 +01:00
Kevin Lin
9ff5250792 fix(codex): gate migration on app readiness (#80815)
* fix(codex): gate migration on app readiness

* fix(codex): preserve source auth during migration

* fix(codex): isolate migration source app probes

* docs(codex): align migration readiness reasons

* docs(codex): remove stale auth-required source reason

* fix(codex): narrow native auth profile resolver input

* fix: clarify codex migration subscription gating

* refactor: simplify codex migration subscription gate

* fix: make codex app verification optional

* docs: clarify codex app inventory cache

* test: avoid map spread in migration test
2026-05-12 13:01:22 -07:00
Shakker
5c4a723f7c test: demand gateway agent payloads 2026-05-12 21:01:00 +01:00
Peter Steinberger
a1d7fb1273 test: dedupe lmstudio setup mock reads 2026-05-12 21:00:54 +01:00
Shakker
044b4175b3 test: winnow config validation issues 2026-05-12 20:59:14 +01:00
Peter Steinberger
2e45a8ff44 test: dedupe line webhook payload reads 2026-05-12 20:59:10 +01:00
Peter Steinberger
b499d8f60c test: dedupe gradium speech fetch reads 2026-05-12 20:57:38 +01:00
Shakker
a814173e74 test: lone plugin allow warning 2026-05-12 20:56:24 +01:00
Peter Steinberger
de235b96f0 test: dedupe feishu reaction mock reads 2026-05-12 20:55:42 +01:00
Shakker
9b9e73ad59 test: stack missing plugin warnings 2026-05-12 20:54:57 +01:00
Shakker
af20c89e83 test: weigh codex turn results 2026-05-12 20:53:50 +01:00
Peter Steinberger
bc26023b7e test: dedupe feishu comment mock reads 2026-05-12 20:53:45 +01:00
Shakker
3e425dde0d test: mine compaction branch messages 2026-05-12 20:52:19 +01:00
Peter Steinberger
eb46fa15ae test: dedupe feishu bot menu mock reads 2026-05-12 20:51:45 +01:00
Shakker
b428427108 test: carve overflow timeout payloads 2026-05-12 20:51:05 +01:00
Shakker
7c5b3283d6 test: supply codex auth profile store 2026-05-12 20:49:47 +01:00
Peter Steinberger
6a012282a4 test: dedupe discord monitor mock reads 2026-05-12 20:49:44 +01:00
Shakker
046d6fc0ae test: seek cron list log text 2026-05-12 20:48:33 +01:00
Shakker
8f55f0d38c test: collect status reaction emojis 2026-05-12 20:47:45 +01:00
Peter Steinberger
9b52daf595 test: dedupe diffs browser mock reads 2026-05-12 20:47:25 +01:00
Shakker
3a37bb717c test: account plugin repair outcomes 2026-05-12 20:46:39 +01:00
Shakker
c5a227163e test: report plugin repair records 2026-05-12 20:44:51 +01:00
Peter Steinberger
c3399806b3 test: dedupe heartbeat ghost reminder mock reads 2026-05-12 20:44:43 +01:00
Shakker
8423884a51 test: negate realtime response events 2026-05-12 20:43:33 +01:00
Shakker
ee40ce6d4b test: ledger session runtime options 2026-05-12 20:42:28 +01:00
Peter Steinberger
906dd432cf test: dedupe exec approval mock reads 2026-05-12 20:41:37 +01:00
Shakker
a455edc2b1 test: stamp task registry exact records 2026-05-12 20:40:52 +01:00
Peter Steinberger
652a56fc74 test: dedupe startup migration log reads 2026-05-12 20:39:27 +01:00
Shakker
ed4c287bf3 test: clinch forced realtime barge-in 2026-05-12 20:38:21 +01:00
Shakker
5768d55db8 test: trail realtime barge-in events 2026-05-12 20:37:25 +01:00
Peter Steinberger
3f26f3ddfd test: dedupe gateway update mock reads 2026-05-12 20:36:55 +01:00
Shakker
0452ad6d1a test: plumb doctor peer link repair call 2026-05-12 20:36:26 +01:00
Shakker
9623bb0af7 test: peg idle timeout stream args 2026-05-12 20:35:17 +01:00
Shakker
b60ae89aa4 test: settle plugin repair noops 2026-05-12 20:33:52 +01:00
Peter Steinberger
d18bbfe7ae test: dedupe gateway config reload mock reads 2026-05-12 20:33:34 +01:00
Shakker
ea7f74ffc9 test: idle disabled plugin repair results 2026-05-12 20:31:00 +01:00
Peter Steinberger
1b9603e7c1 test: dedupe whatsapp session mock reads 2026-05-12 20:30:06 +01:00
Shakker
ba54c0e060 test: unlock synology schema passthrough 2026-05-12 20:29:12 +01:00
Shakker
81fe17c4a6 test: regularize codex collab statuses 2026-05-12 20:27:32 +01:00
Shakker
a5aadea756 test: persist codex collab terminal message 2026-05-12 20:26:56 +01:00
Peter Steinberger
1993b2a40c test: dedupe openrouter media mock reads 2026-05-12 20:26:40 +01:00
Shakker
354bb11702 test: originate codex collab task payloads 2026-05-12 20:26:01 +01:00
Shakker
108507f6a2 test: terminate codex subagent statuses 2026-05-12 20:24:55 +01:00
Shakker
5f68002509 test: shadow codex subagent task payloads 2026-05-12 20:24:10 +01:00
Shakker
f0e381d6e9 test: transmit context ingest identity 2026-05-12 20:22:57 +01:00
Shakker
886e9223c9 test: rotate compaction context rows 2026-05-12 20:21:53 +01:00
Shakker
dacb8cf08a test: profile openrouter media descriptor 2026-05-12 20:20:09 +01:00
Shakker
f58515431e test: draft browser think command 2026-05-12 20:19:18 +01:00
Shakker
58bb7a50ef test: declare openrouter stt request 2026-05-12 20:18:19 +01:00
Peter Steinberger
ce085e5fa8 test: dedupe gateway client mock reads 2026-05-12 20:17:49 +01:00
Shakker
d8a2d1aaa9 test: relay gateway bridge payloads 2026-05-12 20:17:17 +01:00
Shakker
0ad0ff32fe test: pipe googlechat webhook limits 2026-05-12 20:16:11 +01:00
Shakker
0d9c38ffdf test: measure msteams upload options 2026-05-12 20:15:09 +01:00
Shakker
f6ee35fc86 test: decode tool card raw payload 2026-05-12 20:13:51 +01:00
Shakker
2eb302db1f test: imprint openrouter stt payloads 2026-05-12 20:13:10 +01:00
Peter Steinberger
82882ddf1a test: dedupe gateway boot mock reads 2026-05-12 20:12:52 +01:00
Shakker
b3ea131d51 test: box codex activation diagnostics 2026-05-12 20:11:54 +01:00
Shakker
975fd2a038 test: collate feishu doc descendants 2026-05-12 20:11:13 +01:00
Shakker
288eee88b1 test: sieve usage cache card 2026-05-12 20:10:20 +01:00
Peter Steinberger
acef9920df test: dedupe tasks command log reads 2026-05-12 20:09:55 +01:00
Shakker
5782d3441e test: clamp googlemeet cli registrations 2026-05-12 20:09:38 +01:00
Shakker
d14fa499a6 test: marshal gateway chat responses 2026-05-12 20:08:19 +01:00
Peter Steinberger
d356f84801 test: dedupe models list registry reads 2026-05-12 20:05:56 +01:00
Shakker
2ff3514037 test: portray channel status rows 2026-05-12 20:04:47 +01:00
Shakker
17dd725150 test: broadcast node pairing payloads 2026-05-12 20:03:29 +01:00
Peter Steinberger
513c717cd3 test: dedupe gateway status mock reads 2026-05-12 20:02:55 +01:00
Shakker
d05624aa3c test: assay exec command analysis fields 2026-05-12 20:02:02 +01:00
Shakker
d3f959a83a test: verbalize partial reply chunks 2026-05-12 20:01:19 +01:00
Peter Steinberger
91ae344c19 test: dedupe channels add mock reads 2026-05-12 20:00:04 +01:00
Shakker
383485e785 test: articulate node pairing requests 2026-05-12 19:59:47 +01:00
Shakker
b60f785777 test: certify bootstrap approval status 2026-05-12 19:58:41 +01:00
Shakker
4071fc6288 test: excise tool result details exactly 2026-05-12 19:57:57 +01:00
Peter Steinberger
0dbe2e9e12 test: dedupe nodes approval timeout mock reads 2026-05-12 19:57:38 +01:00
Shakker
c9d28775ec test: reprise optional install retry 2026-05-12 19:56:38 +01:00
Shakker
a0a91f8028 test: unwrap cmd transport argv 2026-05-12 19:55:54 +01:00
Shakker
d7f7a71981 test: purify health probe snapshots 2026-05-12 19:55:08 +01:00
Peter Steinberger
c964da8d58 test: dedupe daemon install mock reads 2026-05-12 19:54:55 +01:00
Shakker
129b147871 test: qualify model auth checker options 2026-05-12 19:54:32 +01:00
Shakker
b304155f66 test: confine respawn bridge options 2026-05-12 19:53:38 +01:00
Shakker
94c46c606a test: reflect side alias events 2026-05-12 19:52:59 +01:00
Peter Steinberger
a3534aedae test: dedupe channel auth mock reads 2026-05-12 19:52:39 +01:00
Shakker
69ea7b115d test: encase discovery log calls 2026-05-12 19:52:08 +01:00
Shakker
bb692899ab test: linearize launchd command calls 2026-05-12 19:51:23 +01:00
Shakker
f634799b45 test: capsize tool location traversal 2026-05-12 19:50:35 +01:00
Shakker
a263c4c58f test: ordinalize ledger replay chunks 2026-05-12 19:49:42 +01:00
Peter Steinberger
57db08504d test: dedupe sessions spawn hook reads 2026-05-12 19:49:17 +01:00
Shakker
e523183e46 test: schematize session mode requests 2026-05-12 19:49:00 +01:00
Shakker
492336414d test: thread media-only inbound context 2026-05-12 19:47:45 +01:00
Shakker
fdcd83da08 test: inscribe command config writes 2026-05-12 19:46:59 +01:00
Peter Steinberger
44f2cc71d5 test: dedupe subagent steer restart mock reads 2026-05-12 19:46:05 +01:00
Shakker
24e8a28057 test: forward daemon probe timeouts exactly 2026-05-12 19:45:50 +01:00
Shakker
b7cd7cb914 test: pinpoint session target discovery 2026-05-12 19:45:11 +01:00
Shakker
1e4155eb2e test: truncate acp deliveries exactly 2026-05-12 19:44:32 +01:00
Peter Steinberger
1f8c0dfc64 test: dedupe subagent orphan recovery mock reads 2026-05-12 19:44:14 +01:00
Shakker
061ef36397 test: disallow elevated allowlist failures 2026-05-12 19:43:58 +01:00
Shakker
008a837e5e test: retrieve cron jobs exactly 2026-05-12 19:42:39 +01:00
Peter Steinberger
85dbd478a6 test: dedupe subagent announce mock reads 2026-05-12 19:42:18 +01:00
Shakker
8e5e326de2 test: flag suppressed model refs 2026-05-12 19:41:50 +01:00
Peter Steinberger
71aec03dd9 test: dedupe ssh sandbox mock reads 2026-05-12 19:39:52 +01:00
Shakker
fa8965a4de test: singularize union validation issues 2026-05-12 19:39:00 +01:00
Peter Steinberger
ff64d8dde7 test: dedupe capability cli mock reads 2026-05-12 19:37:37 +01:00
Shakker
7901e7a454 test: enact launchd stop calls 2026-05-12 19:37:01 +01:00
Shakker
c5dd54431d test: script scheduled restart calls 2026-05-12 19:35:25 +01:00
Peter Steinberger
48e7f24565 test: dedupe cron gateway mock reads 2026-05-12 19:35:01 +01:00
Shakker
ebaa674bdc test: purge stale proof labels 2026-05-12 19:33:02 +01:00
Peter Steinberger
973e978aee test: dedupe session repair log reads 2026-05-12 19:32:49 +01:00
Shakker
b32e870e38 test: revisit active reaction calls 2026-05-12 19:31:49 +01:00
Peter Steinberger
2416fdece9 test: dedupe model diagnostic hook reads 2026-05-12 19:30:55 +01:00
Shakker
97207192b5 test: timeline status reaction cleanup 2026-05-12 19:30:32 +01:00
Shakker
50dd00ade6 test: chronicle turn record failure 2026-05-12 19:29:14 +01:00
Peter Steinberger
6398836079 test: dedupe embedded subscribe final filter reads 2026-05-12 19:29:04 +01:00
Shakker
d6bde4994c test: wrap blockquote style ir 2026-05-12 19:27:59 +01:00
Shakker
8483659477 test: slot ci dependency shard 2026-05-12 19:27:03 +01:00
Shakker
c54a3e6f78 test: rank boundary check guards 2026-05-12 19:26:26 +01:00
Peter Steinberger
8cd6e8ee42 test: dedupe embedded subscribe block reply reads 2026-05-12 19:26:17 +01:00
Shakker
14cd8193db test: position prerelease liveish check 2026-05-12 19:24:55 +01:00
Peter Steinberger
b5dc9a578b test: dedupe exec host followup mock reads 2026-05-12 19:24:11 +01:00
Shakker
e75c63fb08 test: furnish status json payload 2026-05-12 19:23:49 +01:00
Shakker
8a8cb1b8d5 test: concretize video override normalization 2026-05-12 19:22:39 +01:00
Shakker
f2ce07cd67 test: serialize config tuple baseline 2026-05-12 19:21:58 +01:00
Peter Steinberger
0ab328c915 test: dedupe exec approval mock reads 2026-05-12 19:21:15 +01:00
Shakker
ceaa5c08d6 test: crystallize blockquote spacing 2026-05-12 19:20:37 +01:00
Shakker
6dbe3b187c test: delimit command span formatting 2026-05-12 19:19:30 +01:00
Shakker
6e79a06d50 test: encompass beta verifier args 2026-05-12 19:18:40 +01:00
Peter Steinberger
ef8e6650ae test: dedupe anthropic transport mock reads 2026-05-12 19:17:27 +01:00
Shakker
7fd1f5c73c test: omit opus build allowlist 2026-05-12 19:17:08 +01:00
Shakker
52cbb7de33 test: literalize media fetch redaction 2026-05-12 19:16:12 +01:00
Shakker
ff580f2fb6 test: bracket file context output 2026-05-12 19:14:57 +01:00
Peter Steinberger
fc28f9376e test: dedupe compaction safeguard mock reads 2026-05-12 19:14:36 +01:00
Shakker
364212c6c0 test: summarize skill frontmatter exactly 2026-05-12 19:13:58 +01:00
Shakker
0d0832c24d test: compare provider index previews 2026-05-12 19:11:32 +01:00
Shakker
5ce8410041 test: disclose custom acp backend hint 2026-05-12 19:11:32 +01:00
Shakker
1f4cf100e8 test: compose waiting status message 2026-05-12 19:11:32 +01:00
Peter Steinberger
66421d413f test: dedupe maintenance cli mock reads 2026-05-12 19:10:46 +01:00
Shakker
b5706597c1 test: reproduce memory ingest page 2026-05-12 19:09:31 +01:00
Shakker
23725bf11f test: sequence zai model ids 2026-05-12 19:09:31 +01:00
Peter Steinberger
d548adb610 test: tighten channel catalog mock assertions 2026-05-12 19:08:47 +01:00
Shakker
ce6ba9a263 test: warn on shared agent dirs 2026-05-12 19:06:20 +01:00
Shakker
c22ea053d1 test: merge tuple doc metadata 2026-05-12 19:05:55 +01:00
Shakker
99a976e527 test: demonstrate raw redaction output 2026-05-12 19:05:16 +01:00
Shakker
796126912d test: scrub auth state warning 2026-05-12 19:04:30 +01:00
Shakker
50420d9e8f test: map runtime channel capabilities 2026-05-12 19:04:30 +01:00
Peter Steinberger
63a44ed310 test: dedupe system cli mock reads 2026-05-12 19:04:19 +01:00
Shakker
1bd0455072 test: index shell env expected keys 2026-05-12 19:02:27 +01:00
Shakker
ea4c365a4c test: phrase deferred followup tools 2026-05-12 19:02:27 +01:00
Shakker
493b2c918c test: catalog core tool profiles 2026-05-12 19:02:27 +01:00
Peter Steinberger
06938c9117 test: dedupe tool context guard mock reads 2026-05-12 19:01:54 +01:00
Shakker
e0841015e3 test: constrain typing mode issue paths 2026-05-12 19:00:01 +01:00
Shakker
9d9816b307 test: read qa workspace marker 2026-05-12 19:00:01 +01:00
Shakker
8ba6d3e207 test: show openai default allowlist 2026-05-12 19:00:01 +01:00
Shakker
8d71a42294 test: echo optional channel setup hint 2026-05-12 19:00:01 +01:00
Peter Steinberger
ad3ce47224 test: dedupe live model switch mock reads 2026-05-12 18:58:04 +01:00
Shakker
806d1f3cca test: identify logging size issue 2026-05-12 18:57:20 +01:00
Shakker
5497371ff0 test: pin e2e vitest setup 2026-05-12 18:57:04 +01:00
Shakker
ae571575f8 test: pin live vitest setup 2026-05-12 18:56:52 +01:00
Shakker
6abe2526d0 test: preserve discord gateway fallback log 2026-05-12 18:56:09 +01:00
Shakker
174e7ddffd test: name google setup entries 2026-05-12 18:56:08 +01:00
Shakker
6e562f5163 test: order telegram updates 2026-05-12 18:56:08 +01:00
Shakker
eecbc596b3 test: detail audit surface summary 2026-05-12 18:56:08 +01:00
Peter Steinberger
3d70d037aa test: dedupe embedded subscribe lifecycle mock reads 2026-05-12 18:55:45 +01:00
Shakker
ac9cddf353 test: print cli parse errors 2026-05-12 18:54:06 +01:00
Shakker
133fe11618 test: arrange cli failure lines 2026-05-12 18:54:06 +01:00
Shakker
c34a982f87 test: resolve docs links exactly 2026-05-12 18:54:06 +01:00
Peter Steinberger
c2bbb73e18 test: dedupe setup registry mock reads 2026-05-12 18:53:38 +01:00
Shakker
29a087be5a test: transcribe sherpa usage output 2026-05-12 18:52:29 +01:00
Shakker
a231036436 test: mark table block ir text 2026-05-12 18:52:14 +01:00
Shakker
7194be8fb8 test: capture docker enoent guidance 2026-05-12 18:51:58 +01:00
Shakker
3a2220f0a5 test: enumerate persisted auth channels 2026-05-12 18:51:23 +01:00
Shakker
8554e851af test: list pdf tool registration 2026-05-12 18:51:23 +01:00
Shakker
068bbb474b test: spell qwen doctor hint 2026-05-12 18:51:23 +01:00
Peter Steinberger
5d68e645ce test: dedupe overflow compaction mock reads 2026-05-12 18:51:19 +01:00
Shakker
3eeab53b80 test: state discord voice contract 2026-05-12 18:50:02 +01:00
Shakker
61903a2f08 test: outline qa markdown report 2026-05-12 18:49:48 +01:00
Shakker
e7c1d10f1d test: seal matrix logger redaction 2026-05-12 18:49:37 +01:00
Shakker
2bd58b5cfa test: distinguish allowed value summaries 2026-05-12 18:48:37 +01:00
Shakker
2e7cf45ed2 test: mirror btw inline rows 2026-05-12 18:48:37 +01:00
Shakker
83bf5ce4f3 test: require subagent wait guidance 2026-05-12 18:48:37 +01:00
Peter Steinberger
6861d8a6d7 test: dedupe subagent lifecycle mock reads 2026-05-12 18:48:06 +01:00
Shakker
542ee2f77b test: fix browser tab error guidance 2026-05-12 18:47:21 +01:00
Shakker
4b4adc767a test: specify markdown table fallback 2026-05-12 18:47:21 +01:00
Shakker
cc9197e51e test: nail daemon runtime status text 2026-05-12 18:47:20 +01:00
Peter Steinberger
4b41e591fe test: dedupe directory cli mock reads 2026-05-12 18:46:03 +01:00
Shakker
f054295e48 test: bind matrix mention html output 2026-05-12 18:45:40 +01:00
brokemac79
58700db5ff fix(gateway): suppress heartbeat tool events in webchat (#80378) 2026-05-12 10:45:16 -07:00
Shakker
45cf560f4e test: tighten matrix markdown html basics 2026-05-12 18:44:47 +01:00
Shakker
b2f6e06e13 test: verify sidebar status label 2026-05-12 18:43:42 +01:00
Peter Steinberger
4d74353064 test: dedupe auth profile runtime mock reads 2026-05-12 18:43:28 +01:00
Shakker
2a95f2cd48 test: assert markdown fallback structure 2026-05-12 18:42:48 +01:00
Peter Steinberger
052724416b test: dedupe btw mock reads 2026-05-12 18:40:39 +01:00
Shakker
864eb07d44 test: lock browser slash imports 2026-05-12 18:39:39 +01:00
Shakker
e2f512ce49 test: localize copy code markup 2026-05-12 18:38:01 +01:00
Shakker
dd75205d9f test: encode remaining www autolinks 2026-05-12 18:37:02 +01:00
Shakker
1611539b03 test: freeze unsafe markdown links 2026-05-12 18:36:03 +01:00
Peter Steinberger
4339a18657 test: dedupe attempt execution mock reads 2026-05-12 18:35:56 +01:00
Shakker
bd3d1fbb58 test: define markdown structural blocks 2026-05-12 18:34:21 +01:00
Shakker
62fff1f738 test: specify basic markdown rendering 2026-05-12 18:33:32 +01:00
Peter Steinberger
3c8bf48bb5 test: dedupe gateway usage mock reads 2026-05-12 18:33:17 +01:00
Shakker
ffc7d88473 test: codify markdown code blocks 2026-05-12 18:32:23 +01:00
Shakker
ad4bc5f80d test: capture unsafe markdown sanitizing 2026-05-12 18:31:00 +01:00
Peter Steinberger
7d9232a9a9 test: dedupe codex command mock reads 2026-05-12 18:30:47 +01:00
Shakker
77233877ac test: describe markdown image output 2026-05-12 18:29:43 +01:00
Shakker
fafe11bc67 test: escape task details exactly 2026-05-12 18:29:01 +01:00
Shakker
c60308239f test: detail task list markdown 2026-05-12 18:28:02 +01:00
Peter Steinberger
b5f2e4b5bb test: complete auto reply mock call helpers 2026-05-12 18:27:15 +01:00
Shakker
a043e7b7b3 test: spell escaped html output 2026-05-12 18:26:45 +01:00
Shakker
119dd0ee57 test: pin protocol CJK link rendering 2026-05-12 18:25:26 +01:00
Shakker
7d7d5809ab test: leave plain domains unlinked 2026-05-12 18:24:01 +01:00
clawsweeper[bot]
81cd5028a5 ci: add missing extension and channel labels to labeler.yml (#81095)
Summary:
- This PR adds `.github/labeler.yml` changed-file rules for 22 bundled plugin directories that currently have no dedicated labeler entry.
- Reproducibility: not applicable. as a CI metadata PR rather than a product bug. The gap is source-verifiable ...  with current-main `.github/labeler.yml`, which shows the added plugin paths exist and are unlabeled today.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

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

Prepared head SHA: eef42948d3
Review: https://github.com/openclaw/openclaw/pull/81095#issuecomment-4432997258

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: bing <33149547+bing0901@users.noreply.github.com>
2026-05-12 17:23:35 +00:00
Peter Steinberger
cab7c4536e test: avoid mutating grouped render params 2026-05-12 18:23:28 +01:00
Peter Steinberger
bce0e9e0be test: dedupe cli runner spawn mock reads 2026-05-12 18:23:28 +01:00
Shakker
8536340e89 test: fence www autolink boundaries 2026-05-12 18:23:09 +01:00
Shakker
1a6b1aeb9d test: preserve quoted www autolinks 2026-05-12 18:22:06 +01:00
Shakker
6ddc2b5f49 test: fix www autolink suffix output 2026-05-12 18:21:14 +01:00
Shakker
8f10a86842 test: render basic www autolinks exactly 2026-05-12 18:20:02 +01:00
Shakker
d267880017 test: anchor slash command refreshes 2026-05-12 18:18:56 +01:00
Peter Steinberger
cae1263198 test: dedupe feishu reply dispatcher mock reads 2026-05-12 18:18:26 +01:00
Shakker
9fa1d9bf36 test: parse assistant media metadata urls 2026-05-12 18:17:38 +01:00
Shakker
5cefebd352 test: trace stored attachment previews 2026-05-12 18:16:54 +01:00
Shakker
038a968e36 test: color context notice exactly 2026-05-12 18:15:57 +01:00
Shakker
df6bc365bf test: quote websocket constructor errors 2026-05-12 18:15:06 +01:00
Shakker
94dc1e32c2 test: name update mismatch banner 2026-05-12 18:14:08 +01:00
Peter Steinberger
797ce4c05c test: dedupe slack slash mock reads 2026-05-12 18:13:53 +01:00
Shakker
d161053caa test: define dreaming error states 2026-05-12 18:13:24 +01:00
Shakker
d08a407610 test: state agent tool errors 2026-05-12 18:12:47 +01:00
Shakker
b881243dc6 test: spell out chat controller errors 2026-05-12 18:12:06 +01:00
Shakker
1d31583e0d test: pin gateway close messages 2026-05-12 18:11:12 +01:00
Shakker
49029cbdcc test: specify chat attachment transcript 2026-05-12 18:10:38 +01:00
Peter Steinberger
1e3a7548d9 test: dedupe update cli mock reads 2026-05-12 18:10:15 +01:00
Shakker
46ca9cf9c4 test: trim mismatched thinking defaults 2026-05-12 18:08:31 +01:00
Shakker
7b4fd3d67a test: alias slash commands exactly 2026-05-12 18:07:06 +01:00
Peter Steinberger
0f390fc820 test: dedupe telegram bot mock reads 2026-05-12 18:06:03 +01:00
Shakker
362ebc9c4f test: export chat markdown exactly 2026-05-12 18:04:50 +01:00
Shakker
5d9f16a093 test: tally performance event buffer 2026-05-12 18:03:41 +01:00
Shakker
378fff4330 test: nest session option labels 2026-05-12 18:02:52 +01:00
Peter Steinberger
78e9717d9b test: dedupe whatsapp send mock reads 2026-05-12 18:02:40 +01:00
Shakker
a390424442 test: sign gateway auth payloads 2026-05-12 18:01:27 +01:00
Peter Steinberger
c3c4510942 test: dedupe agent event mock reads 2026-05-12 18:00:04 +01:00
Shakker
cb0de89ef4 test: prune stored gateway scopes 2026-05-12 17:59:05 +01:00
Shakker
63c0f2894e test: chain channel save recovery 2026-05-12 17:58:08 +01:00
Shakker
cd34b0ce54 test: line model picker options 2026-05-12 17:57:23 +01:00
Peter Steinberger
df89ad90d8 test: dedupe voice call mock reads 2026-05-12 17:57:15 +01:00
Shakker
e5e1e7b489 test: derive custom theme colors 2026-05-12 17:56:03 +01:00
Shakker
35af092508 test: total usage helper tools 2026-05-12 17:55:18 +01:00
Shakker
a407eba98c test: engrave tool card payloads 2026-05-12 17:54:20 +01:00
Peter Steinberger
c4b106bcfe test: dedupe node wake mock calls 2026-05-12 17:53:56 +01:00
Shakker
fe46705640 test: zero config form unsupported paths 2026-05-12 17:53:04 +01:00
Shakker
8829fcaaf0 test: print tool helper previews 2026-05-12 17:52:07 +01:00
Shakker
44b7f5bceb test: table navigation metadata 2026-05-12 17:51:08 +01:00
Shakker
10f166a0fd test: sketch dreaming scene rows 2026-05-12 17:50:07 +01:00
Galin Iliev
4b28312bd8 fix(azure):Drain split provider stream frames (#80927)
Merged via squash.

Prepared head SHA: 03a7e1fec3
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Reviewed-by: @galiniliev
2026-05-12 09:49:51 -07:00
Shakker
8d823a98c0 test: summarize peak error rows 2026-05-12 17:48:32 +01:00
Peter Steinberger
103664dd23 test: dedupe control ui response reads 2026-05-12 17:48:27 +01:00
pashpashpash
36b9da5c91 Keep Codex media tools backed by auth profiles (#81059)
* fix(codex): pass auth profiles to dynamic tools

* fix: bump protobufjs past advisory range
2026-05-13 01:46:21 +09:00
Shakker
6053532bd2 test: checkpoint sessions compaction text 2026-05-12 17:45:50 +01:00
Peter Steinberger
43316c2909 test: dedupe qa matrix mock calls 2026-05-12 17:44:26 +01:00
Peter Steinberger
6a5290e49e test: dedupe migrate mock calls 2026-05-12 17:38:47 +01:00
Shakker
65b608388a test: pare voice option exclusions 2026-05-12 17:37:42 +01:00
Shakker
687f4be9ec test: stage dreaming scene buttons 2026-05-12 17:36:55 +01:00
Shakker
9cbfc843a1 test: recite dream diary prose 2026-05-12 17:36:14 +01:00
Shakker
230be4e91c test: cleanse login raw errors 2026-05-12 17:35:05 +01:00
Peter Steinberger
6a099e5971 test: dedupe model picker mock calls 2026-05-12 17:34:46 +01:00
Shakker
07f68b1b4d test: diagnose login connection guidance 2026-05-12 17:33:57 +01:00
Shakker
63563713c6 test: pair login context guidance 2026-05-12 17:33:21 +01:00
Shakker
505aa38079 test: prescribe login auth guidance 2026-05-12 17:32:33 +01:00
Shakker
fe04523211 test: option session override selects 2026-05-12 17:31:32 +01:00
Shakker
5f081c8cd5 test: column sessions table 2026-05-12 17:30:39 +01:00
Peter Steinberger
05fabfbc9c test: dedupe google meet mock calls 2026-05-12 17:29:52 +01:00
Shakker
b98e97210b test: unhide raw config body 2026-05-12 17:29:15 +01:00
Shakker
bfc5d99828 test: flatten malformed config values 2026-05-12 17:28:45 +01:00
Shakker
ddfa97eba2 test: arrange config tabs 2026-05-12 17:27:32 +01:00
Shakker
2cb8a0c4fb test: retain cron advanced labels 2026-05-12 17:26:49 +01:00
Shakker
d7dfd4a8b2 test: navigate cron run links 2026-05-12 17:26:02 +01:00
Peter Steinberger
a8bc83edf4 test: dedupe diagnostics otel mock calls 2026-05-12 17:25:57 +01:00
Shakker
3aeec2e4a4 test: wire cron suggestion lists 2026-05-12 17:25:00 +01:00
Shakker
5681cfd839 test: distinguish cron delivery options 2026-05-12 17:24:14 +01:00
Shakker
641eaeecf3 test: gather localized selectors 2026-05-12 17:23:27 +01:00
Shakker
706b9a2ef7 test: announce slash option exactly 2026-05-12 17:22:34 +01:00
Shakker
637afd6a11 test: sequence thinking option labels 2026-05-12 17:21:06 +01:00
Shakker
a728e6aaf6 test: expect config section titles 2026-05-12 17:19:26 +01:00
Peter Steinberger
6cfb532afd test: dedupe feishu drive mock calls 2026-05-12 17:19:17 +01:00
Shakker
0c5e33480e test: honor wildcard raw redaction 2026-05-12 17:18:20 +01:00
Shakker
3589827635 test: disclose raw redaction state 2026-05-12 17:17:48 +01:00
Shakker
c630aa3488 test: prove config reveal reset 2026-05-12 17:17:08 +01:00
Shakker
16f2b22b33 test: mask config raw secrets 2026-05-12 17:14:49 +01:00
Shakker
b5f8e4c18a test: notice raw mode lockout 2026-05-12 17:13:34 +01:00
Peter Steinberger
72d9ea3b76 test: dedupe matrix send mock calls 2026-05-12 17:13:20 +01:00
Shakker
628eeda84a test: limit scoped config labels 2026-05-12 17:12:41 +01:00
Shakker
ae773272ac test: clear config diff panel 2026-05-12 17:12:00 +01:00
Shakker
0918f3823b test: open config diff rows 2026-05-12 17:11:07 +01:00
Shakker
1f1a5c205c test: quote theme importer hints 2026-05-12 17:09:59 +01:00
Shakker
adb8d553e4 test: mark imported theme metadata 2026-05-12 17:09:19 +01:00
Peter Steinberger
3598938458 test: dedupe openresponses mock calls 2026-05-12 17:09:07 +01:00
Shakker
c5574eb796 test: redact secret ref input 2026-05-12 17:08:23 +01:00
Shakker
c967410bed test: unpack device pairing rows 2026-05-12 17:07:34 +01:00
Shakker
87a4da89e3 test: badge agent tool provenance 2026-05-12 17:05:43 +01:00
Shakker
9be8d38f95 test: freeze exec approval expiry 2026-05-12 17:04:46 +01:00
Peter Steinberger
c0e287f3c1 test: dedupe embedded attempt mock calls 2026-05-12 17:04:11 +01:00
Shakker
e15bb302e0 test: translate exec approval chrome 2026-05-12 17:03:22 +01:00
Shakker
4fe36dc608 test: inventory cron filter options 2026-05-12 17:02:20 +01:00
Shakker
9808fd6802 test: localize talk button title 2026-05-12 17:01:21 +01:00
Shakker
a230aefb40 test: itemize login failure panel 2026-05-12 17:00:24 +01:00
Peter Steinberger
8c6dd5bddc test: dedupe outbound delivery mock calls 2026-05-12 16:59:51 +01:00
Shakker
9076ce0a7d test: outline cron advanced controls 2026-05-12 16:56:32 +01:00
Shakker
24fa9ba6a4 test: expose cron edit controls 2026-05-12 16:55:20 +01:00
Shakker
a5557d1fb5 test: index cron validation status 2026-05-12 16:54:47 +01:00
Peter Steinberger
4f1bee9f8b test: dedupe telegram send mock calls 2026-05-12 16:54:31 +01:00
Ayaan Zaidi
4272ce1597 chore(voice-call): note Telnyx realtime PR (#81024) (thanks @dynamite-bud) 2026-05-12 21:23:50 +05:30
Ayaan Zaidi
665c29d4dc fix(voice-call): bind Telnyx realtime streams to issued calls 2026-05-12 21:23:50 +05:30
Rudra
148e5467b5 fix: align Telnyx stream lifecycle parsing with carrier docs
Two parsing bugs caught by Codex review on the Telnyx Media Streaming
PR:

Lifecycle webhook event names had a stray `call.` prefix that never
matched Telnyx's documented event types. Telnyx surfaces stream
lifecycle as `streaming.started` and `streaming.stopped` (no prefix);
stream errors arrive as `{event:"error"}` JSON frames over the
WebSocket, not as carrier webhooks. Drop the bogus
`call.streaming.failed` case from the webhook parser and add a new
`error` frame kind to the StreamFrameAdapter union so the realtime
handler can log failures instead of silently dropping them.

Telnyx WebSocket frames carry `stream_id` at the top level of the
envelope and `call_control_id` inside the `start` object; the
Telnyx adapter was reading `start.stream_id` (always undefined) and
defaulting `providerCallId` to the constructor-supplied value
regardless of what the carrier sent. Read both fields from the
documented locations and fall back to the constructor providerCallId
only when the carrier frame omits them.

Tests updated to reflect the carrier-documented frame shapes; new
fixture covers `{event:"error"}` round-trip through the adapter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:23:50 +05:30
Rudra
b28e3b378e test: cover Telnyx Media Streaming for voice-call realtime
Adds tests across the touched surface: StreamFrameAdapter for both
Twilio (with streamSid) and Telnyx (without), the generalized
RealtimeAudioPacer carrying both envelopes, Telnyx provider
dial-time and answer-action streaming params with the
call.streaming.failed -> call.error mapping, manager
streamSessionIssuer wiring for Telnyx outbound, and the widened
realtime + telnyx config gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:23:50 +05:30
Rudra
bb1b075118 feat: add Telnyx Media Streaming for voice-call realtime
Wires bidirectional PCMU WebSocket audio for Telnyx so realtime
providers (OpenAI Realtime, etc.) can drive Telnyx calls the same
way they drive Twilio. Telnyx attaches Media Streaming at dial
time and answer-action time per the documented canonical patterns
(no actions/streaming_start call needed).

New StreamFrameAdapter abstraction owns provider-shaped frame
parsing and outbound serialization, so realtime-handler.ts stays
carrier-agnostic. RealtimeAudioPacer is generalized to accept any
serializer. The provider-twilio realtime gate widens to accept
telnyx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:23:50 +05:30
Shakker
a517434261 test: read cron error bodies 2026-05-12 16:52:13 +01:00
Shakker
a665c004c1 test: scope cron history subtitle 2026-05-12 16:51:12 +01:00
Shakker
f1569b4afd test: read cron due metadata 2026-05-12 16:50:21 +01:00
Shakker
d0c2cce07e test: name stale cron job 2026-05-12 16:49:13 +01:00
Shakker
d6a65e928b test: tabulate cron delivery fields 2026-05-12 16:48:10 +01:00
Shakker
0aed7c5090 test: select localized welcome copy 2026-05-12 16:47:04 +01:00
Shakker
80c615daee test: bind pairing hint commands 2026-05-12 16:45:47 +01:00
Peter Steinberger
cb957fe0d2 test: dedupe telegram delivery mock calls 2026-05-12 16:44:58 +01:00
Shakker
4b4b8d9305 test: rely on context detail text 2026-05-12 16:43:54 +01:00
Shakker
23a4d5298d test: target chat detail labels 2026-05-12 16:42:57 +01:00
Shakker
ec082a7790 test: route chat loading assertions 2026-05-12 16:41:42 +01:00
Peter Steinberger
fcd1073b72 test: dedupe auto-reply dispatch mock calls 2026-05-12 16:41:33 +01:00
Shakker
7d208f3a5d test: scope localized agent refresh 2026-05-12 16:39:47 +01:00
Shakker
678cd504e8 test: order advanced review controls 2026-05-12 16:38:36 +01:00
Shakker
aef22e659b test: pin wiki preview truncation 2026-05-12 16:37:09 +01:00
Shakker
34e69362d9 test: read parsed dream entry 2026-05-12 16:36:21 +01:00
Shakker
aac9c9bc96 test: specify diary empty states 2026-05-12 16:35:32 +01:00
Shakker
4941c919d9 test: detail wiki enablement cta 2026-05-12 16:34:42 +01:00
Shakker
44001b7d25 test: extract diary insight fields 2026-05-12 16:33:56 +01:00
Peter Steinberger
e215dfcadf test: dedupe outbound matrix mock calls 2026-05-12 16:33:49 +01:00
Shakker
b0cdb5b3ce test: normalize dreaming status detail 2026-05-12 16:32:57 +01:00
Shakker
2174cabcbe test: anchor live canvas preview 2026-05-12 16:31:39 +01:00
Shakker
19a70d98b1 test: separate visible canvas rows 2026-05-12 16:30:52 +01:00
Shakker
4289e4c834 test: locate hidden canvas details 2026-05-12 16:30:07 +01:00
Peter Steinberger
5e009ed142 test: dedupe subagent announce mock calls 2026-05-12 16:29:54 +01:00
Shakker
a46fa1d952 test: describe canvas embed frame 2026-05-12 16:29:23 +01:00
Shakker
ba23d9ac71 test: resolve document media link 2026-05-12 16:28:19 +01:00
Peter Steinberger
2379da6cf1 test: dedupe qa matrix cli mock calls 2026-05-12 16:27:30 +01:00
Shakker
263d7cbf27 test: recheck media retry state 2026-05-12 16:22:45 +01:00
Shakker
52a958727b test: verify platform media checks 2026-05-12 16:22:12 +01:00
Peter Steinberger
c5135c1efd test: dedupe qa matrix message body mock calls 2026-05-12 16:22:00 +01:00
Shakker
f56a091607 test: identify blocked media fields 2026-05-12 16:21:09 +01:00
Gavin Zeng
a7f1c7b672 fix(exec): skip heartbeat wake for subagent sessions (#66749)
Merged via squash.

Prepared head SHA: 86bf841519
Co-authored-by: ggzeng <20488795+ggzeng@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-05-12 18:21:03 +03:00
Shakker
3c8ff0af26 test: separate same-origin media state 2026-05-12 16:20:24 +01:00
Shakker
372ed1e5e4 test: differentiate media auth refresh 2026-05-12 16:19:54 +01:00
Shakker
ca87dabac0 test: trace local media ticket cards 2026-05-12 16:19:17 +01:00
Shakker
565e612a5b test: confirm assistant media surfaces 2026-05-12 16:18:35 +01:00
Peter Steinberger
d24254ef5f test: dedupe telegram bot mock call 2026-05-12 16:17:54 +01:00
Shakker
4a5009f8d1 test: bind tool catalog warning 2026-05-12 16:15:17 +01:00
Peter Steinberger
730cbb356f test: dedupe bonjour advertiser mock calls 2026-05-12 16:15:03 +01:00
Peter Steinberger
7b52b60051 test: dedupe codex side question mock calls 2026-05-12 16:13:08 +01:00
Shakker
7058b5a859 test: structure sessions empty states 2026-05-12 16:12:56 +01:00
Shakker
81ba006442 test: narrow runtime filter result 2026-05-12 16:12:24 +01:00
Shakker
e1ebe46d12 test: scope identity filter rows 2026-05-12 16:11:35 +01:00
Peter Steinberger
250e16d3c9 test: dedupe codex conversation mock calls 2026-05-12 16:11:24 +01:00
Shakker
8a2dae7050 test: select compaction disclosure 2026-05-12 16:10:52 +01:00
Shakker
e40fa869da test: inspect session details fields 2026-05-12 16:10:12 +01:00
Peter Steinberger
b2d8a92f48 test: dedupe feishu docx mock calls 2026-05-12 16:09:16 +01:00
Shakker
4dd0231ecc test: parse grouped tool outputs 2026-05-12 16:08:11 +01:00
Pavan Kumar Gondhi
9ac4272b35 fix: harden safe-bin argument validation [AI] (#80999)
* fix: reject shell expansion in safe-bin tokens

* fix: complete safe-bin shell payload handling

* addressing codex review

* addressing ci

* addressing ci

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-12 20:37:58 +05:30
Peter Steinberger
186de9daa0 test: dedupe feishu outbound mock calls 2026-05-12 16:06:08 +01:00
Shakker
cbb73134ef test: expand grouped tool blocks 2026-05-12 16:05:05 +01:00
Peter Steinberger
fdb2d3a083 test: dedupe googlechat auth mock calls 2026-05-12 16:04:22 +01:00
Shakker
78c0ba016c test: query run control buttons 2026-05-12 16:04:04 +01:00
Shakker
45b68a2c20 test: label session filter field 2026-05-12 16:03:06 +01:00
Peter Steinberger
fa0c23c8ba test: dedupe googlechat target mock calls 2026-05-12 16:02:29 +01:00
Shakker
6390733519 test: read grouped meta spans 2026-05-12 16:02:14 +01:00
Shakker
af5f6a3276 test: place delete confirms exactly 2026-05-12 16:01:26 +01:00
Shakker
2030a6390c test: catalogue agent tool details 2026-05-12 16:00:29 +01:00
Peter Steinberger
7121791735 test: dedupe matrix client mock calls 2026-05-12 15:59:47 +01:00
Shakker
188fa93862 test: address agent tabs directly 2026-05-12 15:59:31 +01:00
Shakker
a20a213daa test: find quick settings rows 2026-05-12 15:58:50 +01:00
Pavan Kumar Gondhi
a5dce367ce fix: scan plugin runtime entries during install [AI] (#80998)
* fix: scan plugin runtime entries during install

* addressing review-skill

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 20:28:40 +05:30
Peter Steinberger
b076215e82 test: dedupe memory search mock calls 2026-05-12 15:57:57 +01:00
Shakker
33ca27f4f6 test: parse tool card raw details 2026-05-12 15:57:32 +01:00
Shakker
c423ef2e34 test: split tool card block checks 2026-05-12 15:56:38 +01:00
Shakker
44de39a1df test: filter config form tag labels 2026-05-12 15:56:01 +01:00
Peter Steinberger
b28714307d test: dedupe minimax speech mock calls 2026-05-12 15:55:38 +01:00
Shakker
166361c5eb test: frame markdown sidebar slots 2026-05-12 15:55:13 +01:00
Shakker
c77f199fd6 test: resolve lazy view text 2026-05-12 15:53:58 +01:00
Peter Steinberger
f3d5a9926f test: dedupe nostr inbound mock calls 2026-05-12 15:53:31 +01:00
Shakker
151de16001 test: render side result slots 2026-05-12 15:52:50 +01:00
Shakker
4a83448662 test: shape context notice controls 2026-05-12 15:52:05 +01:00
Peter Steinberger
cb8b7ff891 test: dedupe ollama embedding mock calls 2026-05-12 15:51:45 +01:00
Shakker
449da806bd test: name session source toggles 2026-05-12 15:51:16 +01:00
Peter Steinberger
7a9613e66b test: dedupe openai tts mock calls 2026-05-12 15:49:59 +01:00
Peter Steinberger
49d42bea6e test: dedupe openrouter video mock calls 2026-05-12 15:48:23 +01:00
Shakker
b0cd70f021 test: grade session status badges 2026-05-12 15:47:13 +01:00
Peter Steinberger
360b0769db test: dedupe qqbot websocket mock calls 2026-05-12 15:46:33 +01:00
Peter Steinberger
67ac7ee200 test: dedupe signal client mock calls 2026-05-12 15:45:01 +01:00
Shakker
94e7678be4 test: expand preview class checks 2026-05-12 15:44:49 +01:00
Shakker
8c134178d6 test: isolate mount fallback elements 2026-05-12 15:44:14 +01:00
Shakker
b8db4fc859 test: preserve focus shell classes 2026-05-12 15:43:31 +01:00
Peter Steinberger
cc736fdf1c test: dedupe signal monitor mock calls 2026-05-12 15:43:14 +01:00
Shakker
b80f5c2ea5 test: lock mobile controls classes 2026-05-12 15:42:56 +01:00
Shakker
3e1360cfea test: map navigation shell classes 2026-05-12 15:42:20 +01:00
Shakker
b14f91bd86 test: require config action buttons 2026-05-12 15:41:03 +01:00
Peter Steinberger
7c8d32211d test: dedupe speech tts mock calls 2026-05-12 15:40:41 +01:00
Peter Steinberger
094f6d83c7 test: dedupe telegram dispatch mock calls 2026-05-12 15:38:59 +01:00
Shakker
859977e5d8 test: define custom theme style sync 2026-05-12 15:38:07 +01:00
Shakker
14a95bffb5 test: capture tool card action class 2026-05-12 15:37:28 +01:00
Peter Steinberger
26afc763b3 test: dedupe telegram command menu mock calls 2026-05-12 15:37:11 +01:00
Shakker
7c2c91a0fa test: track divider dragging class 2026-05-12 15:35:39 +01:00
Shakker
b9e0babe04 test: match chat avatar initials 2026-05-12 15:34:59 +01:00
Shakker
10e6d7eb3e test: spell out agent tool classes 2026-05-12 15:34:04 +01:00
Shakker
24f0ae7937 test: list active quick profile classes 2026-05-12 15:33:16 +01:00
Peter Steinberger
f4ae21cb0a test: dedupe telegram channel post mock calls 2026-05-12 15:33:06 +01:00
Shakker
3fdb2b78c5 test: pin chat status indicators 2026-05-12 15:32:41 +01:00
Shakker
1dbf788619 test: enumerate chat control classes 2026-05-12 15:31:29 +01:00
Peter Steinberger
2bfbe25239 test: dedupe telegram fetch mock calls 2026-05-12 15:30:17 +01:00
Shakker
13111d8e27 test: verify mount fallback copy 2026-05-12 15:29:21 +01:00
Shakker
ffbeb53838 test: target lazy view states 2026-05-12 15:28:31 +01:00
Shakker
98f72eda21 test: tighten context notice text 2026-05-12 15:27:50 +01:00
Shakker
8e068bc72c test: locate config tag result 2026-05-12 15:27:06 +01:00
Peter Steinberger
684e13c7fd test: dedupe vydra fetch mock calls 2026-05-12 15:26:51 +01:00
Shakker
646ef0c78f test: anchor config hint label 2026-05-12 15:26:06 +01:00
Peter Steinberger
f6418812ef test: dedupe whatsapp media cap mock calls 2026-05-12 15:24:54 +01:00
Peter Steinberger
99f9b78bcd test: dedupe whatsapp process mock calls 2026-05-12 15:22:22 +01:00
Shakker
26df0e4782 test: pin cron run filters 2026-05-12 15:22:06 +01:00
Shakker
ac3bf79d9d test: assert debug callout class 2026-05-12 15:21:16 +01:00
Shakker
3b2735f3ee test: check dreaming tab labels 2026-05-12 15:20:41 +01:00
Peter Steinberger
4e3b952b70 test: dedupe feishu comment mock calls 2026-05-12 15:19:46 +01:00
Peter Steinberger
a34d45e2a1 test: dedupe feishu media mock calls 2026-05-12 15:17:31 +01:00
Peter Steinberger
ca2523f9d5 test: dedupe line download mock calls 2026-05-12 15:14:46 +01:00
Peter Steinberger
185ace0155 test: dedupe synology chat http mock calls 2026-05-12 15:12:36 +01:00
Peter Steinberger
2298889cb9 test: dedupe telegram session metadata mock calls 2026-05-12 15:09:56 +01:00
Pavan Kumar Gondhi
b6a94d4ef9 Require auth for sandbox browser CDP relay [AI] (#81002)
* fix: require auth for sandbox browser cdp relay

* addressing review-skill

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 19:37:32 +05:30
Peter Steinberger
ed2a451363 test: dedupe whatsapp audio mock calls 2026-05-12 15:06:58 +01:00
Pavan Kumar Gondhi
65d7232218 fix: detect carried exec command forms [AI] (#81000)
* fix: detect carried inline exec forms

* addressing review-skill

* addressing codex review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 19:36:04 +05:30
Peter Steinberger
64b7be436c test: dedupe export session write mock calls 2026-05-12 15:04:54 +01:00
Pavan Kumar Gondhi
731af9c96b Reject truncated exec approval commands [AI] (#81001)
* fix: reject truncated exec approval commands

* docs: add changelog entry for PR merge
2026-05-12 19:33:42 +05:30
Peter Steinberger
8d41e4d53f test: dedupe daemon install mock calls 2026-05-12 15:02:28 +01:00
Pavan Kumar Gondhi
50f4440c96 Enforce inline shell wrapper payload matching [AI] (#80978)
* fix: enforce inline shell wrapper payload matching

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing claude review

* addressing claude review

* fix: complete shell wrapper allowlist handling

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 19:30:18 +05:30
Peter Steinberger
b1131cddbd test: dedupe claude doctor note mock calls 2026-05-12 14:59:03 +01:00
Peter Steinberger
bf4ab7ecf0 test: dedupe models list runtime mock calls 2026-05-12 14:57:30 +01:00
Peter Steinberger
07748507cc test: dedupe chat directive mock calls 2026-05-12 14:55:53 +01:00
Shakker
086aec8d85 test: compare inherited session keys 2026-05-12 14:55:13 +01:00
Shakker
5f83ddba9f test: match session identity cells 2026-05-12 14:54:26 +01:00
Shakker
313df5814d test: locate markdown preview label 2026-05-12 14:53:38 +01:00
Peter Steinberger
3b7fdb3033 test: dedupe heartbeat tool response mock calls 2026-05-12 14:52:21 +01:00
Shakker
e101ee184b test: preserve localized agent tabs 2026-05-12 14:51:51 +01:00
Shakker
e21efc6ccc test: check active tool profile state 2026-05-12 14:50:37 +01:00
Peter Steinberger
e2c32806c1 test: dedupe anthropic vertex stream mock calls 2026-05-12 14:50:30 +01:00
Shakker
806a3bce68 test: list whatsapp action buttons 2026-05-12 14:49:27 +01:00
Shakker
9bfa2d031f test: order quick identity titles 2026-05-12 14:48:56 +01:00
Peter Steinberger
3b45ad6960 test: dedupe matrix device mock calls 2026-05-12 14:48:14 +01:00
Peter Steinberger
a45b96fd88 test: dedupe matrix message mock calls 2026-05-12 14:46:43 +01:00
Shakker
eea3e2c0f7 test: record assistant avatar source fields 2026-05-12 14:45:53 +01:00
Peter Steinberger
bfb595b5ce test: dedupe memory narrative mock calls 2026-05-12 14:45:02 +01:00
Peter Steinberger
fce4f10e96 test: dedupe ollama web search mock calls 2026-05-12 14:43:10 +01:00
Peter Steinberger
33568988a6 test: dedupe status scan mock calls 2026-05-12 14:39:18 +01:00
Peter Steinberger
f1ce79ba6c test: dedupe server channel startup mock calls 2026-05-12 14:36:57 +01:00
Peter Steinberger
89cd10157b test: dedupe tools catalog respond calls 2026-05-12 14:34:45 +01:00
Peter Steinberger
1e543fa844 test: dedupe gateway post attach mock calls 2026-05-12 14:32:29 +01:00
Peter Steinberger
cf924fd1e8 test: dedupe heartbeat reply body mock calls 2026-05-12 14:29:12 +01:00
Peter Steinberger
10c09d9b73 test: dedupe bedrock mantle stream mock calls 2026-05-12 14:26:38 +01:00
Peter Steinberger
8f645dba24 test: dedupe browser registration mock calls 2026-05-12 14:24:31 +01:00
Shakker
d08072285c test: bind clawhub detail dialog text 2026-05-12 14:24:15 +01:00
Shakker
4116f8cedf test: target clawhub result fields 2026-05-12 14:22:57 +01:00
Shakker
6f46d12778 test: isolate agent skills tab count 2026-05-12 14:21:42 +01:00
Peter Steinberger
997c28c50c test: dedupe feishu monitor cleanup mock calls 2026-05-12 14:20:45 +01:00
Shakker
831eebfadd test: verify debug security callout text 2026-05-12 14:19:27 +01:00
Peter Steinberger
3303b2fc05 test: dedupe matrix monitor mock calls 2026-05-12 14:18:27 +01:00
Shakker
67267cb2ad test: scope cache hit overview assertion 2026-05-12 14:17:02 +01:00
Peter Steinberger
85e0137472 test: dedupe qa credential lease fetch calls 2026-05-12 14:15:54 +01:00
Shakker
322d9be225 test: tighten sqlite-vec error contracts 2026-05-12 14:15:23 +01:00
Peter Steinberger
fad2484477 fix: canonicalize qualified gemini pro preview refs 2026-05-12 14:12:35 +01:00
Peter Steinberger
45a8a25947 test: dedupe telegram media e2e mock calls 2026-05-12 14:07:05 +01:00
Peter Steinberger
d9f2b64be1 test: dedupe tlon guarded fetch calls 2026-05-12 14:04:38 +01:00
Peter Steinberger
37c38d1756 test: dedupe whatsapp session mock calls 2026-05-12 14:02:47 +01:00
Shakker
d26ab41372 test: require exact http failures 2026-05-12 14:01:56 +01:00
Peter Steinberger
7665b3926c test: dedupe configure auth allowlist calls 2026-05-12 13:59:05 +01:00
Peter Steinberger
a1cae45654 test: dedupe talk handler mock calls 2026-05-12 13:57:06 +01:00
Peter Steinberger
076bf848a1 test: dedupe heartbeat ghost mock calls 2026-05-12 13:54:24 +01:00
Peter Steinberger
8ecdd353ef test: dedupe approval forwarder mock calls 2026-05-12 13:52:24 +01:00
Shakker
e14b54596f test: name default local embedding model 2026-05-12 13:51:13 +01:00
Peter Steinberger
8aca690939 test: dedupe health snapshot mock calls 2026-05-12 13:50:28 +01:00
Peter Steinberger
5ec4573604 test: dedupe codex elicitation mock calls 2026-05-12 13:48:28 +01:00
Peter Steinberger
db79b1cc5e test: dedupe ollama setup mock calls 2026-05-12 13:46:26 +01:00
Peter Steinberger
4b2a502c5b test: dedupe heartbeat reply mock calls 2026-05-12 13:44:30 +01:00
Peter Steinberger
9b07f80559 test: dedupe node event mock calls 2026-05-12 13:40:28 +01:00
Peter Steinberger
fe0e2e6f41 test: dedupe telegram native command mock calls 2026-05-12 13:38:34 +01:00
Shakker
1c44d31aab test: map multilingual query tokens 2026-05-12 13:37:38 +01:00
Peter Steinberger
14b871efd9 test: dedupe codex registration mock calls 2026-05-12 13:36:21 +01:00
Peter Steinberger
e6551e63ba test: dedupe auto-reply delivery mock calls 2026-05-12 13:34:16 +01:00
Peter Steinberger
88714d6803 fix: normalize oauth auth-result config patches 2026-05-12 13:31:42 +01:00
Shakker
a538e58075 test: anchor consult runtime prompt 2026-05-12 13:31:03 +01:00
Shakker
fa97442740 test: freeze voice consult prompt 2026-05-12 13:30:00 +01:00
Shakker
31bdbfe59b test: codify usage chart sizing 2026-05-12 13:28:59 +01:00
Peter Steinberger
0a028a3a8a test: dedupe openai http agent mock calls 2026-05-12 13:22:36 +01:00
Bob
fe79efc31b fix: surface silent model fallback failures (#80917)
Merged via squash.

Prepared head SHA: 59be6e2db5
Co-authored-by: dutifulbob <261991368+dutifulbob@users.noreply.github.com>
Co-authored-by: osolmaz <2453968+osolmaz@users.noreply.github.com>
Reviewed-by: @osolmaz
2026-05-12 15:19:10 +03:00
Shakker
9c125e821f test: enumerate config preset defaults 2026-05-12 13:18:26 +01:00
Peter Steinberger
7187d2754e test: dedupe matrix group history mock calls 2026-05-12 13:18:08 +01:00
Shakker
9e09dfe512 test: parse talk file log fields 2026-05-12 13:17:21 +01:00
Peter Steinberger
258002917b test: dedupe whatsapp delivery mock calls 2026-05-12 13:16:05 +01:00
Shakker
3b5e189125 test: quantify fallback error allocation 2026-05-12 13:15:38 +01:00
Peter Steinberger
8e848919e7 test: dedupe zalo group gating mock calls 2026-05-12 13:14:08 +01:00
Shakker
0746fda37c test: specify session export content 2026-05-12 13:13:20 +01:00
Shakker
c3c72a7cfb test: assert peak error summaries 2026-05-12 13:10:26 +01:00
clawsweeper[bot]
d44553dade fix(gateway): wire max_completion_tokens/max_tokens through openai-http (#81013)
Summary:
- The branch adds Chat Completions token-cap fields to the Gateway request type, forwards them as agent stream parameters, and documents/tests the behavior.
- Reproducibility: yes. Source inspection gives a high-confidence current-main path: send `max_completion_toke ... tokens` to `/v1/chat/completions` and observe that the current handler never sets `streamParams.maxTokens`.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(gateway): wire max_completion_tokens/max_tokens through openai-http

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

Prepared head SHA: a9c39f7d4a
Review: https://github.com/openclaw/openclaw/pull/81013#issuecomment-4430303959

Co-authored-by: Bingsen <dingheng.huang@urbanic.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
2026-05-12 12:08:07 +00:00
Shakker
be7ca5d828 test: lock qmd backend collections 2026-05-12 13:07:56 +01:00
Peter Steinberger
04ee5985c4 test: dedupe control plane response mock calls 2026-05-12 13:06:58 +01:00
Shakker
66f16b81b9 test: pin query expansion expectations 2026-05-12 13:05:53 +01:00
Peter Steinberger
e9431e2dd4 test: dedupe codex run attempt hook mock calls 2026-05-12 13:04:34 +01:00
Peter Steinberger
c9ec1dea71 test: dedupe codex shared client mock calls 2026-05-12 13:01:48 +01:00
Peter Steinberger
f7f9312c7a test: dedupe matrix replies send mock calls 2026-05-12 12:59:22 +01:00
Peter Steinberger
756f9bb2f1 test: dedupe usage sessions mock calls 2026-05-12 12:57:39 +01:00
Peter Steinberger
5940d0d4b1 test: dedupe codex approval gateway mock calls 2026-05-12 12:55:50 +01:00
Peter Steinberger
3c82b144bb test: dedupe mattermost send mock calls 2026-05-12 12:53:52 +01:00
Peter Steinberger
32d5cd9a28 test: dedupe channels list log mock calls 2026-05-12 12:50:26 +01:00
Peter Steinberger
6d10e7d784 test: dedupe gateway hook run mock calls 2026-05-12 12:48:42 +01:00
Peter Steinberger
632c1bc0ba test: dedupe brave fetch mock calls 2026-05-12 12:45:31 +01:00
Super Zheng
4223dd2886 fix: enable native require fast path on Windows for plugin-sdk root alias (#80878)
Merged via squash.

Prepared head SHA: 87446445b6
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-05-12 04:43:55 -07:00
Super Zheng
a92d5fe77d feat(agents): make run loop retry limits configurable in openclaw.json (#80661)
Merged via squash.

Prepared head SHA: d595d51a5a
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-05-12 04:43:12 -07:00
Peter Steinberger
8a051395b7 test: dedupe matrix handler send mock calls 2026-05-12 12:42:04 +01:00
Super Zheng
380daf2f50 feat(gateway): inject isHeartbeat into agent event broadcast payload (#80610)
Merged via squash.

Prepared head SHA: cb254108a1
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-05-12 04:41:14 -07:00
Peter Steinberger
4e29ee516b test: dedupe slack interaction mock calls 2026-05-12 12:39:58 +01:00
Ayaan Zaidi
f506ced2b3 docs(changelog): note onboarding auth fix (#80913) (thanks @rubencu) 2026-05-12 17:08:18 +05:30
Ayaan Zaidi
a6faeecf52 refactor(onboard): simplify model auth candidates 2026-05-12 17:08:18 +05:30
Rubén Cuevas
9600646449 test(onboard): type model check auth mocks 2026-05-12 17:08:18 +05:30
Rubén Cuevas
379ba2e8ae fix(onboard): short-circuit model auth check 2026-05-12 17:08:18 +05:30
Rubén Cuevas
31eaa106c5 fix(onboard): accept Codex auth in model check 2026-05-12 17:08:18 +05:30
Peter Steinberger
74fbbf503f test: dedupe matrix approval mock calls 2026-05-12 12:37:16 +01:00
Peter Steinberger
ed53339f8f test: dedupe mcp transport fetch mock calls 2026-05-12 12:34:57 +01:00
Peter Steinberger
dc0ebdfef8 test: guard codex command mock calls 2026-05-12 12:31:16 +01:00
Peter Steinberger
275acdaeba test: guard feishu reply dispatcher mock calls 2026-05-12 12:29:09 +01:00
Peter Steinberger
0c6cc68eb3 test: guard slack slash mock calls 2026-05-12 12:27:12 +01:00
Peter Steinberger
75f5d6d9b5 test: guard auto reply media mock calls 2026-05-12 12:24:20 +01:00
Peter Steinberger
3e3057509b test: dedupe models auth status mock calls 2026-05-12 12:22:21 +01:00
Peter Steinberger
837cb8f5b0 test: dedupe doctor memory note assertions 2026-05-12 12:20:31 +01:00
Ayaan Zaidi
3718ef1985 docs(agents): distill PR routing guidance 2026-05-12 16:50:29 +05:30
Rubén Cuevas
3fe2c0e71f docs: clarify PR workflow gitcrawl fallback 2026-05-12 16:50:29 +05:30
Peter Steinberger
50c31707fa test: dedupe tools effective mock calls 2026-05-12 12:18:49 +01:00
Peter Steinberger
30c17fed20 test: guard whatsapp send api mock calls 2026-05-12 12:16:20 +01:00
Peter Steinberger
3a4c97c291 test: guard server chat agent event mock calls 2026-05-12 12:14:15 +01:00
Peter Steinberger
8846a2a89f test: guard voice call mock calls 2026-05-12 12:12:14 +01:00
Ayaan Zaidi
5abb4b18c8 fix(telegram): simplify context boundary plumbing 2026-05-12 16:40:42 +05:30
VACInc
afd7339bd2 fix telegram context session start boundary 2026-05-12 16:40:42 +05:30
VACInc
b31afcbc17 fix telegram context reset boundary 2026-05-12 16:40:42 +05:30
Peter Steinberger
d3e39f0c94 test: dedupe models status log parsing 2026-05-12 12:10:08 +01:00
Peter Steinberger
1e5b12ae73 test: guard node invoke wake mock calls 2026-05-12 12:08:05 +01:00
Peter Steinberger
efacb91818 test: guard control ui http mock calls 2026-05-12 12:06:00 +01:00
Ayaan Zaidi
1675b2ff30 docs(changelog): mention docker auth profile key mount (#80991) 2026-05-12 16:35:53 +05:30
Ayaan Zaidi
c025291df7 docs(docker): document auth profile key mount 2026-05-12 16:35:53 +05:30
Ayaan Zaidi
c3e3146639 fix(docker): persist auth profile key mount 2026-05-12 16:35:53 +05:30
Pavan Kumar Gondhi
3aeb55b5e7 fix(node-pairing): replace changed pending requests [AI] (#80894)
* fix: replace changed node pairing requests

* fix: replace changed node pairing requests

* addressing codex review

* addressing codex review

* addressing ci

* fix: complete node pairing permission handling

* addressing review-skill

* addressing codex review

* addressing codex review

* addressing ci

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 16:33:55 +05:30
Peter Steinberger
3013369e99 test: guard migrate command mock calls 2026-05-12 12:03:52 +01:00
Pavan Kumar Gondhi
1b22384c11 Rate limit Google Chat webhook requests [AI] (#80974)
* fix: rate limit google chat webhook requests

* addressing claude review

* addressing ci

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 16:31:28 +05:30
Peter Steinberger
a943e4b766 test: guard model picker mock calls 2026-05-12 12:00:08 +01:00
Peter Steinberger
eb422fe44b test: guard diagnostics otel mock calls 2026-05-12 11:58:43 +01:00
Peter Steinberger
69298b18cf test: guard feishu drive mock calls 2026-05-12 11:57:20 +01:00
Pavan Kumar Gondhi
8c9dbe3e71 fix(feishu): normalize webhook rate-limit client keys [AI] (#80975)
* fix: normalize Feishu webhook rate limit keys

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 16:26:12 +05:30
Peter Steinberger
636636ca92 test: guard google meet mock calls 2026-05-12 11:56:05 +01:00
Peter Steinberger
7625a8b6d6 test: guard openresponses mock calls 2026-05-12 11:54:29 +01:00
Peter Steinberger
f82b9adfb1 test: guard matrix send mock calls 2026-05-12 11:52:11 +01:00
Peter Steinberger
0586da70db test: guard telegram bot core mock calls 2026-05-12 11:50:44 +01:00
Peter Steinberger
4ea089b7fe test: guard auto-reply dispatch mock calls 2026-05-12 11:45:09 +01:00
Peter Steinberger
aa9799320d test: guard telegram bot mock calls 2026-05-12 11:42:50 +01:00
Pavan Kumar Gondhi
2d00bedc1e fix(auth): prevent bootstrap pairing scope changes [AI] (#80976)
* fix: prevent bootstrap pairing scope changes before redemption

* docs: add changelog entry for PR merge
2026-05-12 16:11:35 +05:30
Peter Steinberger
abd2ba1fe0 test: guard telegram send mock calls 2026-05-12 11:40:13 +01:00
Peter Steinberger
a12caa8b86 test: guard outbound delivery mock calls 2026-05-12 11:38:39 +01:00
Peter Steinberger
4bc47a3a75 test: guard telegram delivery mock calls 2026-05-12 11:37:03 +01:00
Pavan Kumar Gondhi
5ef8d1ab5e Validate Control UI loopback retry endpoints [AI] (#80900)
* fix: validate loopback retry endpoints

* fix: validate loopback retry endpoints

* docs: add changelog entry for PR merge
2026-05-12 16:06:00 +05:30
Pavan Kumar Gondhi
fd12a48ee1 Harden exported markdown link rendering [AI] (#80902)
* fix: sanitize exported markdown links

* fix: sanitize exported markdown links

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 16:05:19 +05:30
Pavan Kumar Gondhi
da6f32bedf fix(gateway): honor minimal discovery mode for wide-area DNS-SD [AI] (#80903)
* fix: respect discovery mode for wide-area cli path

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-12 16:03:50 +05:30
Peter Steinberger
d164f8cc74 test: guard qa matrix mock call assertions 2026-05-12 11:31:18 +01:00
Pavan Kumar Gondhi
889afc7c31 slack: enforce reaction notification policy [AI] (#80907)
* fix: enforce slack reaction notification policy

* addressing claude review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 16:00:44 +05:30
Pavan Kumar Gondhi
652f5f9b10 Enforce gateway command scopes by caller context [AI] (#80891)
* fix: enforce gateway command scopes by caller context

* fix: enforce gateway command scopes by caller context

* addressing codex review

* addressing claude review

* addressing claude review

* addressing ci

* docs: add changelog entry for PR merge
2026-05-12 15:59:22 +05:30
Peter Steinberger
be5483f240 test: guard core mock call assertions 2026-05-12 11:29:16 +01:00
Pavan Kumar Gondhi
a4da627da1 Enforce Slack plugin approval button authorization [AI] (#80899)
* fix: enforce slack plugin approval button authorization

* fix: enforce slack plugin approval button authorization

* addressing codex review

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-12 15:56:24 +05:30
Peter Steinberger
97b9d77196 test: guard extension runtime mock calls 2026-05-12 11:24:21 +01:00
Ayaan Zaidi
485e04266c docs(changelog): note telegram html rendering fix (#80977) 2026-05-12 15:54:01 +05:30
Ayaan Zaidi
f6adc78f06 fix(telegram): keep durable html unsanitized 2026-05-12 15:54:01 +05:30
Ayaan Zaidi
b480b29dc7 fix(telegram): preserve supported html replies 2026-05-12 15:54:01 +05:30
Pavan Kumar Gondhi
de47989731 Recognize PowerShell -ec inline commands [AI] (#80893)
* fix: recognize PowerShell -ec inline command flag

* fix: recognize PowerShell -ec inline command flag

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* addressing codex review

* fix: recognize PowerShell encoded command prefixes

* addressing review-skill

* addressing review-skill

* addressing codex review

* addressing codex review

* docs: add changelog entry for PR merge
2026-05-12 15:53:10 +05:30
Pavan Kumar Gondhi
6e498a1f62 fix(qqbot): authorize approval button callbacks [AI] (#80892)
* fix: authorize qqbot approval buttons

* fix: authorize qqbot approval buttons

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 15:51:13 +05:30
Peter Steinberger
2ec1a27c9f test: guard extension channel mock calls 2026-05-12 11:19:53 +01:00
Peter Steinberger
6a230a108a test: guard extension messaging mock calls 2026-05-12 11:15:37 +01:00
Peter Steinberger
ea05be12b4 test: guard extension provider mock calls 2026-05-12 11:11:04 +01:00
Shakker
7bb2d20303 test: remove duplicate gateway startup case 2026-05-12 11:09:49 +01:00
Peter Steinberger
04139a7d44 test: guard extension app mock calls 2026-05-12 11:07:04 +01:00
Peter Steinberger
7215945b06 test: guard gateway infra mock calls 2026-05-12 11:03:37 +01:00
Peter Steinberger
7a9f770a63 test: guard command model mock calls 2026-05-12 11:00:43 +01:00
Pavan Kumar Gondhi
47eb2d48d4 Scrub streamable MCP redirect headers [AI] (#80906)
* fix: scrub streamable mcp redirect headers

* addressing review-skill

* addressing codex review

* addressing claude review

* docs: add changelog entry for PR merge
2026-05-12 15:28:54 +05:30
Peter Steinberger
e196a43694 test: guard auto reply runner mock calls 2026-05-12 10:58:34 +01:00
Peter Steinberger
81b7d670cd test: guard cron infra ui mock calls 2026-05-12 10:56:25 +01:00
Peter Steinberger
067666df90 test: guard gateway call assertions 2026-05-12 10:53:58 +01:00
Ayaan Zaidi
99598284c1 docs(changelog): credit matrix runtime install fix (#80876) (thanks @kinjitakabe) 2026-05-12 15:22:10 +05:30
Ayaan Zaidi
0792223a87 refactor(matrix): simplify dependency availability check 2026-05-12 15:22:10 +05:30
kinjitakabe
760501fc38 fix(matrix): stop runtime npm install from parent-derived cwd
`ensureMatrixSdkInstalled` previously derived an install `cwd` via fixed
two-segment traversal from `import.meta.url` and spawned `npm install`
(or `pnpm install`) when Matrix packages were missing. Under the
externalized plugin layout the derived path is a scope directory like
`<config>/npm/node_modules/@openclaw`, so npm walks up to the managed
project root and prunes undeclared siblings. Under the legacy bundled
layout it would target `<global-prefix>/lib/node_modules` and could
delete unrelated global CLIs.

Matrix is now a pure availability check: if any required package fails
to resolve, it throws an actionable error pointing the operator at the
supported repair commands (`openclaw plugins update matrix`,
`openclaw doctor --fix`). This matches extensions/AGENTS.md:
"Runtime never installs deps; install/update/doctor are repair points."

The exported signature stays backwards-compatible (all params optional;
`confirm` and `runtime` are accepted but ignored). `resolveMissingMatrixPackages`
gains an optional `resolveFn` seam for testability, mirroring the existing
`ensureMatrixCryptoRuntime` injection pattern.

Fixes #80758.
2026-05-12 15:22:10 +05:30
Peter Steinberger
067e83d121 test: guard command call assertions 2026-05-12 10:50:38 +01:00
Pavan Kumar Gondhi
aeb1ba9a53 fix(memory-wiki): require admin scope for ingest [AI] (#80897)
* fix: require admin scope for wiki ingest

* fix: require admin scope for wiki ingest

* docs: add changelog entry for PR merge

* docs: add changelog entry for PR merge
2026-05-12 15:19:43 +05:30
Pavan Kumar Gondhi
c3f1f0c315 memory-wiki: require write scope for Obsidian search [AI] (#80904)
* fix: require write scope for obsidian search

* docs: add changelog entry for PR merge
2026-05-12 15:18:07 +05:30
Peter Steinberger
768637a595 test: guard auto reply command mock calls 2026-05-12 10:47:16 +01:00
Shakker
163eb08a34 test: require minimax voice catalog 2026-05-12 10:45:45 +01:00
Ayaan Zaidi
47698133f6 fix(matrix): land markdown table default (#80890) (thanks @kinjitakabe) 2026-05-12 15:15:05 +05:30
Ayaan Zaidi
8841a82f5c fix(matrix): clean markdown table default PR 2026-05-12 15:15:05 +05:30
kinjitakabe
09a2d6e571 fix(matrix): default markdown tables to bullets across Matrix clients
Matrix outbound markdown was hitting the shared `resolveMarkdownTableMode`
"code" fallback for every send because the Matrix channel plugin never
declared `defaultMarkdownTableMode` in its `messaging` block at
`extensions/matrix/src/channel.ts:452`. Tables were emitted as
`<pre><code>` fenced blocks across every Matrix client.

This change declares `defaultMarkdownTableMode: "bullets"`, matching the
Signal and WhatsApp precedent at `extensions/signal/src/shared.ts:111`
and `extensions/whatsapp/src/shared.ts:261`. The choice matches the
cross-client compatibility profile the issue filer surveyed:
Element X iOS squashes HTML `<table>` and Element X Android drops cell
text entirely (element-hq/element-x-android#1551), while bullet lists
render cleanly across every Matrix client. Operators wanting the
previous fenced-code rendering can set `channels.matrix.markdown.tables:
"code"` explicitly; clients that do render real tables can opt in with
`channels.matrix.markdown.tables: "off"` (markdown-it's `table` rule is
already enabled by default through the markdown-it default preset, so
raw markdown tables flow through to native HTML tables on that path).

Docs and the changelog entry list Matrix alongside Signal and WhatsApp
as a bullet-default channel.

Fixes #78990.
2026-05-12 15:15:05 +05:30
Peter Steinberger
9d4081b839 test: guard core support mock calls 2026-05-12 10:43:53 +01:00
Peter Steinberger
138421b6c6 test: guard gateway session mock calls 2026-05-12 10:39:47 +01:00
Peter Steinberger
a68b4a5606 test: guard gateway mock calls 2026-05-12 10:36:44 +01:00
Peter Steinberger
17237fc44f test: align release validation expectations 2026-05-12 10:32:29 +01:00
Peter Steinberger
17863b0612 test: guard status command mock calls 2026-05-12 10:31:29 +01:00
Shakker
dc70841f8b test: assert imessage reaction context 2026-05-12 10:29:47 +01:00
Peter Steinberger
7a8d86be27 test: guard doctor command mock calls 2026-05-12 10:29:04 +01:00
Peter Steinberger
b37a71f2af test: guard command mock calls 2026-05-12 10:26:20 +01:00
Shakker
f093033ee8 test: pin silent reply fallback text 2026-05-12 10:23:29 +01:00
Peter Steinberger
8e045f6670 test: guard auto reply mock calls 2026-05-12 10:22:53 +01:00
Peter Steinberger
b42227e476 test: guard whatsapp mock calls 2026-05-12 10:19:51 +01:00
Shakker
54bbf40add test: pin invalid-config restart guidance 2026-05-12 10:17:17 +01:00
Peter Steinberger
22667fb096 test: guard messaging extension mock calls 2026-05-12 10:16:36 +01:00
Shakker
43332ce3fa test: check post-core helper calls 2026-05-12 10:15:22 +01:00
Shakker
3c47ab331e test: check post-core warning payloads 2026-05-12 10:14:08 +01:00
Shakker
10372bd23e test: check delivery retry backoff 2026-05-12 10:12:59 +01:00
Shakker
fcfa2617a8 test: check plugin payload failures 2026-05-12 10:11:43 +01:00
Peter Steinberger
cce9a9ef2a test: guard mixed extension mock calls 2026-05-12 10:10:52 +01:00
Shakker
135071b33f test: check media read roots 2026-05-12 10:08:06 +01:00
Peter Steinberger
1e46929d3e test: guard matrix mock calls 2026-05-12 10:07:36 +01:00
Peter Steinberger
b3ded351e3 test: guard extension provider mock calls 2026-05-12 10:04:45 +01:00
Shakker
dbbb7f0aaf test: check skills json formatting 2026-05-12 10:01:24 +01:00
Peter Steinberger
a765668e63 test: guard extension one-hit mock calls 2026-05-12 10:00:29 +01:00
Peter Steinberger
7965342425 test: guard subagent announce mock calls 2026-05-12 09:57:19 +01:00
Peter Steinberger
20319d6909 test: guard embedded attempt mock calls 2026-05-12 09:54:18 +01:00
Peter Steinberger
e3c674d64b test: guard cli runner mock calls 2026-05-12 09:51:50 +01:00
Peter Steinberger
98bf4ed640 test: guard agent cli attempt mock calls 2026-05-12 09:50:11 +01:00
Peter Steinberger
ce67f75930 test: guard agent eight-hit mock calls 2026-05-12 09:48:23 +01:00
Peter Steinberger
e4498e0cd5 test: guard agent seven-hit mock calls 2026-05-12 09:45:55 +01:00
Shakker
db30000220 test: check logs follow notices 2026-05-12 09:45:01 +01:00
Peter Steinberger
2b295a5679 test: guard agent six-hit mock calls 2026-05-12 09:43:16 +01:00
Peter Steinberger
69f3ac80df test: guard agent five-hit mock calls 2026-05-12 09:40:35 +01:00
Peter Steinberger
2afca35577 test: guard agent four-hit mock calls 2026-05-12 09:34:12 +01:00
Shakker
dda4632d38 test: check progress log output 2026-05-12 09:29:45 +01:00
Peter Steinberger
be911a1d74 test: guard remaining three-hit mock calls 2026-05-12 09:27:45 +01:00
Shakker
9cc4827e9b test: check qmd update defaults 2026-05-12 09:27:28 +01:00
Peter Steinberger
521ac5da42 test: guard embedded three-hit mock calls 2026-05-12 09:25:20 +01:00
Shakker
c920053005 test: check startup memory stat failure 2026-05-12 09:25:09 +01:00
Peter Steinberger
ac017fa443 test: guard agent model config mock calls 2026-05-12 09:22:10 +01:00
Shakker
f34faf2f1c test: check diagnostics metric payloads 2026-05-12 09:20:29 +01:00
Peter Steinberger
d2ae92ad1f test: guard agent three-hit mock calls 2026-05-12 09:18:40 +01:00
Peter Steinberger
48576e7225 test: guard subagent mock calls 2026-05-12 09:15:36 +01:00
Peter Steinberger
80a9072c9e test: guard sandbox skills mock calls 2026-05-12 09:13:33 +01:00
Peter Steinberger
c6cfd12228 test: guard before tool call mock calls 2026-05-12 09:11:08 +01:00
Peter Steinberger
6252f2a097 test: guard agent two-hit mock calls 2026-05-12 09:06:01 +01:00
Peter Steinberger
e16b80a829 test: guard remaining agent mock calls 2026-05-12 09:03:39 +01:00
Peter Steinberger
e024362c20 test: guard agent utility mock calls 2026-05-12 09:00:38 +01:00
Peter Steinberger
ee40b9bbbd test: guard embedded subscribe mock calls 2026-05-12 08:58:04 +01:00
Peter Steinberger
16adcc75b0 test: guard embedded runner mock calls 2026-05-12 08:55:12 +01:00
Peter Steinberger
cb059e4006 test: guard agent runtime mock calls 2026-05-12 08:52:32 +01:00
Peter Steinberger
96288dd19c test: guard agent harness mock calls 2026-05-12 08:50:03 +01:00
Peter Steinberger
e78d0d505d test: guard agent cli mock calls 2026-05-12 08:47:34 +01:00
Peter Steinberger
7d75bffa17 fix: reuse package entry validation in update smoke 2026-05-12 08:44:00 +01:00
Peter Steinberger
be7ac231b8 test: guard agent auth bash mock calls 2026-05-12 08:42:59 +01:00
Peter Steinberger
cf885c25df test: guard pdf tool mock calls 2026-05-12 08:40:12 +01:00
Mariano
d728ff8183 fix(codex): release quiet completed app-server turns (#80776)
Merged via squash.

Prepared head SHA: 59baf4110b

Reviewed-by: @mbelinky
2026-05-12 09:39:09 +02:00
Peter Steinberger
6812215d4b test: guard message tool mock calls 2026-05-12 08:37:14 +01:00
Peter Steinberger
0fbbba0c6f ci: keep main push checks running 2026-05-12 08:35:36 +01:00
Peter Steinberger
a815ab9476 test: guard pdf provider mock calls 2026-05-12 08:34:47 +01:00
Peter Steinberger
8ee024df39 test: guard agent tool call assertions 2026-05-12 08:32:40 +01:00
Peter Steinberger
8c22d5aaaf test: guard agent image mock calls 2026-05-12 08:30:54 +01:00
Peter Steinberger
808ce04cc1 test: guard agent web mock calls 2026-05-12 08:29:21 +01:00
Peter Steinberger
815af80363 test: raise macos update smoke heap 2026-05-12 08:28:28 +01:00
Peter Steinberger
84b0c6240b test: guard agent tool mock calls 2026-05-12 08:27:13 +01:00
Peter Steinberger
1b964fac30 test: guard cron tool mock calls 2026-05-12 08:25:04 +01:00
Peter Steinberger
0b69446562 test: guard agent tool mock calls 2026-05-12 08:22:13 +01:00
Peter Steinberger
2a43e26b19 test: guard model catalog mock calls 2026-05-12 08:19:29 +01:00
Peter Steinberger
2feab20368 test: guard update cli mock calls 2026-05-12 08:17:33 +01:00
Peter Steinberger
da7f9a6267 test: guard runtime capture mock calls 2026-05-12 08:15:26 +01:00
Peter Steinberger
5ed2a9a4e2 test: guard config cli mock calls 2026-05-12 08:14:03 +01:00
Peter Steinberger
3d37afd3d2 test: guard capability cli mock calls 2026-05-12 08:12:14 +01:00
Peter Steinberger
ced66da8e1 test: guard exec approvals mock calls 2026-05-12 08:09:53 +01:00
Peter Steinberger
c070ea3974 test: guard gateway cli mock calls 2026-05-12 08:08:49 +01:00
Peter Steinberger
81d973e09d test: guard daemon cli mock calls 2026-05-12 08:07:34 +01:00
Peter Steinberger
af632f4d9e fix: raise update build heap 2026-05-12 08:06:44 +01:00
Peter Steinberger
aba8b00af3 test: guard program help mock calls 2026-05-12 08:05:29 +01:00
B.K.
109493bcdd fix(update): mandatory post-core plugin convergence before gateway restart
Summary:
- validate active plugin payloads, including openclaw.extensions entry files, after core package updates
- treat corrupt active install records without installPath as convergence failures
- prevent managed gateway recovery restart when post-core plugin convergence fails

Verification:
- CI=true pnpm test src/cli/update-cli/plugin-payload-validation.test.ts src/cli/update-cli/post-core-plugin-convergence.test.ts src/cli/update-cli.test.ts src/commands/doctor/shared/missing-configured-plugin-install.test.ts src/commands/doctor/shared/update-phase.test.ts
- CI=true pnpm check:changed
- PR checks green for 2afa84dffe
2026-05-12 08:02:10 +01:00
Peter Steinberger
e7ba2f9b0d test: guard maintenance mock calls 2026-05-12 08:01:40 +01:00
Peter Steinberger
a978f0fe36 test: guard nodes basic mock calls 2026-05-12 07:59:24 +01:00
Peter Steinberger
14042cff90 test: guard nodes media mock calls 2026-05-12 07:56:48 +01:00
Peter Steinberger
00d0d4bd19 test: guard nodes approval mock calls 2026-05-12 07:53:20 +01:00
Peter Steinberger
04a868b98d fix: skip metadata for build-excluded bundled plugins
Fix bundled plugin metadata copying to follow the build-entry set, so build-excluded plugins like QQ Bot do not leave stale dist metadata advertising missing runtime files.

Verification:
- pnpm test src/plugins/copy-bundled-plugin-metadata.test.ts test/scripts/bundled-plugin-build-entries.test.ts
- git diff --check
- pnpm openclaw gateway status --deep
- CI run 25718250461
- CodeQL run 25718250402
- CodeQL Critical Quality run 25718250418
- Real behavior proof run 25718290985
2026-05-12 07:51:11 +01:00
Peter Steinberger
a676366200 test: guard command secret target mock calls 2026-05-12 07:49:19 +01:00
Alex Naidis
a290cd633f fix(doctor): repair managed plugin peer links
Repair managed npm plugin OpenClaw peer links across doctor, install, and update flows.

- relink `peerDependencies.openclaw` packages under managed npm roots during doctor repair
- make read-only doctor preview broken peer links with a `doctor --fix` hint
- reject target plugin installs when their own peer link cannot be repaired, without blocking unrelated installs for stale sibling packages
- preserve update warning behavior for unrepairable package-local `node_modules`

Verification:
- `pnpm test src/plugins/plugin-peer-link.test.ts src/plugins/install.test.ts src/plugins/install.npm-spec.test.ts src/plugins/update.test.ts src/commands/doctor-plugin-registry.test.ts src/commands/doctor/repair-sequencing.test.ts -- --reporter=verbose`
- `pnpm exec oxfmt --check --threads=1 ...`
- `git diff --check`
- Crabbox/Testbox `tbx_01krde1jx199rnpm2rv1rdcj76`: focused tests + `pnpm check:changed`, exit 0
- Real CLI proof in PR body: read-only `openclaw doctor` warning plus `openclaw doctor --fix` symlink repair

Thanks @TheCrazyLex.
2026-05-12 07:49:08 +01:00
Peter Steinberger
ee1a278aea test: guard directory cli mock calls 2026-05-12 07:46:44 +01:00
Peter Steinberger
e7e3e903bf test: guard plugins list mock calls 2026-05-12 07:44:05 +01:00
Peter Steinberger
d40ffd95b0 test: guard plugin registry mock calls 2026-05-12 07:42:27 +01:00
Peter Steinberger
abb4f96b81 test: guard proxy cli mock calls 2026-05-12 07:40:36 +01:00
Peter Steinberger
bd3c2e75ca test: guard qr cli mock calls 2026-05-12 07:39:18 +01:00
Peter Steinberger
5908826599 test: guard command secret mock calls 2026-05-12 07:36:47 +01:00
Peter Steinberger
f863447fe1 test: guard cli route mock calls 2026-05-12 07:33:28 +01:00
Peter Steinberger
4f7ce2aa6f docs: capture crabbox before-after proof learnings 2026-05-12 07:33:24 +01:00
Peter Steinberger
a4784c955e build: refresh canvas a2ui bundle hash 2026-05-12 07:31:57 +01:00
Peter Steinberger
dd0c34f5df test: guard cli utils mock calls 2026-05-12 07:31:37 +01:00
Peter Steinberger
3b82156dff test: guard node cli mock calls 2026-05-12 07:29:54 +01:00
Peter Steinberger
3d93d127f3 test: guard gateway run mock calls 2026-05-12 07:28:41 +01:00
Zennn
39005e6aa7 Fix TUI exit after gateway disconnect (#75381)
* fix(tui): exit after gateway disconnect

* test(gateway): avoid uuid lint false positive

* test(extensions): avoid core ansi helper imports

* test: fix strip ansi helper conflicts

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-12 07:27:54 +01:00
Peter Steinberger
14cb165ddd test: guard acp cli mock calls 2026-05-12 07:27:12 +01:00
Peter Steinberger
a12b9444f1 test: guard system cli mock calls 2026-05-12 07:26:05 +01:00
Peter Steinberger
af0345f824 fix: harden dev update validation 2026-05-12 07:25:36 +01:00
Peter Steinberger
65df09647c test: guard plugins update mock calls 2026-05-12 07:23:49 +01:00
Peter Steinberger
131c415de0 test: guard models cli mock calls 2026-05-12 07:22:36 +01:00
Peter Steinberger
dad240eecd test: guard gateway run loop mock calls 2026-05-12 07:20:43 +01:00
Peter Steinberger
5a432aacd7 test: guard gateway register mock calls 2026-05-12 07:19:14 +01:00
Gabriel
53fedc7084 refactor: unify stableStringify implementations (#80457)
Centralize agent stable serialization for cache tracing, models config fingerprinting, and tool-loop hashing.

Adds focused coverage for sorted keys, true cycles, repeated references, cache-trace edge types, and circular tool-call hashing.

Verification:
- pnpm test src/agents/stable-stringify.test.ts src/agents/tool-loop-detection.test.ts src/agents/cache-trace.test.ts -- --reporter=verbose
- OPENCLAW_TESTBOX=0 pnpm check:changed
- GitHub CI: https://github.com/openclaw/openclaw/actions/runs/25716851500
- Real behavior proof: https://github.com/openclaw/openclaw/actions/runs/25717047037

Co-authored-by: Gabriel Piss <gabriel@gabeos.dev>
2026-05-12 07:18:53 +01:00
Peter Steinberger
976593bc5c test: guard program smoke mock calls 2026-05-12 07:17:42 +01:00
Peter Steinberger
acd8236ef2 test: guard channel auth mock calls 2026-05-12 07:15:51 +01:00
Peter Steinberger
7411396dbc test: guard tts contract mock calls 2026-05-12 07:14:25 +01:00
Peter Steinberger
f71aa4504a test: guard scheduled turn mock calls 2026-05-12 07:11:58 +01:00
Peter Steinberger
f6d787cc5c build: hard-pin dependency specs 2026-05-12 07:10:13 +01:00
Peter Steinberger
525e0267b1 test: guard session attachment mock calls 2026-05-12 07:09:31 +01:00
Kaspre
e30e4d1cfa test(extensions): narrow post-rebase type assertions 2026-05-12 07:08:38 +01:00
Kaspre
5375281974 fix(plugins): load untracked TS source plugins 2026-05-12 07:08:38 +01:00
Peter Steinberger
f285e53d5b test: guard runtime index mock calls 2026-05-12 07:06:58 +01:00
Peter Steinberger
6bdfb39937 test: guard runtime llm mock calls 2026-05-12 07:05:44 +01:00
Peter Steinberger
cccbfbf85c test: guard metadata registry mock calls 2026-05-12 07:04:36 +01:00
Peter Steinberger
e00f7dc0bf test: guard marketplace mock calls 2026-05-12 07:03:32 +01:00
Neerav Makwana
0ac4837878 fix(media): default terminal QR to full-block output (#77820)
Avoid node-qrcode compact (small) terminal mode, which emits a dense
ANSI final row that breaks scanning on some terminals.

Covers WhatsApp/Feishu login flows and the pairing QR CLI path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 07:03:12 +01:00
Peter Steinberger
5b1d1eac12 test: guard wired hook mock calls 2026-05-12 07:02:19 +01:00
Peter Steinberger
469da5b111 test: guard install path mock calls 2026-05-12 07:01:15 +01:00
Peter Steinberger
18ead60fc1 test: guard web fetch provider mock calls 2026-05-12 07:00:06 +01:00
Peter Steinberger
433634066c test: guard plugin install mock calls 2026-05-12 06:57:58 +01:00
Peter Steinberger
0c2068fddb test: guard provider runtime mock calls 2026-05-12 06:56:44 +01:00
Shakker
2dc6b76f47 test: check qmd probe cleanup 2026-05-12 06:54:26 +01:00
Peter Steinberger
7917632e01 fix: preserve subagent session picker order (#78623) 2026-05-12 06:53:51 +01:00
chinar-amrutkar
595cc5d0dc Control UI/sessions: fix subagent nesting label prefix and ordering
- Strip "Subagent: " prefix before adding "└─ " prefix
- Insert child sessions immediately after their parent in the dropdown list
2026-05-12 06:53:51 +01:00
chinar-amrutkar
1f1817a904 Control UI/sessions: nest subagent sessions under parent with visual prefix
Subagent sessions now appear in the session picker dropdown with a "└─ "
prefix and are linked to their parent via the parentKey field when the
parent session is also present in the session list.

Fixes #77628
2026-05-12 06:53:51 +01:00
Peter Steinberger
0eb50f9f8d test: guard module loader cache mock calls 2026-05-12 06:52:40 +01:00
Shakker
e657bff6a3 test: count group runtime loads 2026-05-12 06:52:29 +01:00
Peter Steinberger
2dc0072547 build: refresh canvas a2ui bundle hash 2026-05-12 06:51:48 +01:00
Peter Steinberger
7b71987627 test: guard git install mock calls 2026-05-12 06:51:09 +01:00
remdev
a3e534c677 fix(openrouter): address stt review follow-ups
Map `.mp4` filename fallback to `m4a` so audio attachments with missing MIME resolve correctly, and fix changelog attribution formatting flagged in PR review.
2026-05-12 06:50:12 +01:00
remdev
f756b9a6f1 fix(openrouter): normalize stt mime parsing 2026-05-12 06:50:12 +01:00
remdev
5c87b692cb feat(openrouter): add inbound audio STT support 2026-05-12 06:50:12 +01:00
Peter Steinberger
0543448df8 test: guard channel catalog mock calls 2026-05-12 06:49:41 +01:00
Shakker
28adb8efb0 test: count directory cli calls 2026-05-12 06:49:21 +01:00
Peter Steinberger
0eceaefda9 test: guard setup registry mock calls 2026-05-12 06:47:54 +01:00
Shakker
5e5094a7b6 test: count compaction followup replies 2026-05-12 06:47:14 +01:00
Peter Steinberger
ce7e7a2834 fix: normalize oauth default model patches 2026-05-12 06:45:15 +01:00
Shakker
a90f65cf2a test: check acp session metadata writes 2026-05-12 06:45:08 +01:00
Shakker
2dd79fb8dc test: count followup delivery calls 2026-05-12 06:42:51 +01:00
Shakker
042a8f106e test: count inline tool execution 2026-05-12 06:41:01 +01:00
Peter Steinberger
5aede953ad test: guard channel send and stat overloads 2026-05-12 06:37:52 +01:00
Shakker
842cadda26 test: count inline action cleanup 2026-05-12 06:35:10 +01:00
Peter Steinberger
c98698aa0e chore: release 2026.5.12-beta.1 2026-05-12 06:33:41 +01:00
Shakker
9ba23d1804 test: check config write metadata 2026-05-12 06:32:17 +01:00
Peter Steinberger
f55491b208 chore: update dependencies 2026-05-12 06:31:48 +01:00
Peter Steinberger
26cc9bf2ef test: guard update cli mock calls 2026-05-12 06:31:29 +01:00
Shakker
b88965efc0 test: count plugin registry lookup 2026-05-12 06:30:33 +01:00
Peter Steinberger
b066819dda test: guard cron heartbeat target mock calls 2026-05-12 06:29:21 +01:00
Shakker
f36079b5af test: check plugin config mutation calls 2026-05-12 06:29:11 +01:00
Peter Steinberger
3f5557f92b test: guard plugin sdk mock calls 2026-05-12 06:26:47 +01:00
Peter Steinberger
6d35fb81d4 test: guard plugin sdk acp mock call 2026-05-12 06:23:28 +01:00
Shakker
b33951591e test: count typing signaler calls 2026-05-12 06:22:25 +01:00
Peter Steinberger
71c8d2405d build: forward-port release packaging fixes 2026-05-12 06:21:10 +01:00
Peter Steinberger
1ed83d0ed2 test: use renamed pi ai package
(cherry picked from commit 3c51059ae4)
2026-05-12 06:21:10 +01:00
Peter Steinberger
2e8f8f8b3a fix: keep release fast pretag check branch-safe
(cherry picked from commit 5a14f7b500)
2026-05-12 06:21:10 +01:00
Peter Steinberger
38593cc8fc fix: preserve beta verifier parse errors
(cherry picked from commit 454f6ed402)
2026-05-12 06:21:10 +01:00
Peter Steinberger
a4acd33097 ci: speed up beta release verification
(cherry picked from commit 7ca9b58a27)
2026-05-12 06:21:09 +01:00
Altay
db4c72c53d fix(ci): keep Docker patch smoke on pnpm workspace config
(cherry picked from commit c501d4b923)
2026-05-12 06:21:09 +01:00
Peter Steinberger
abb5fc6522 build: refresh generated protocol models
(cherry picked from commit b8b948e208)
2026-05-12 06:21:09 +01:00
scoootscooob
294cdf973b fix: reread config on in-process gateway restart (#80161)
* fix: reread config on in-process gateway restart

* fix: refresh swift protocol model

(cherry picked from commit 537bcada37)
2026-05-12 06:21:09 +01:00
Peter Steinberger
d86cf646fc ci: skip OpenAI install tool smoke
(cherry picked from commit 50f229c0f6)
2026-05-12 06:21:09 +01:00
Peter Steinberger
50f62beb8a ci: use faster OpenAI model for installer proof
(cherry picked from commit d05ed07260)
2026-05-12 06:21:09 +01:00
Peter Steinberger
9297e1c0e9 ci: parallelize OpenAI installer proof turns
(cherry picked from commit 690eb73520)
2026-05-12 06:21:09 +01:00
Peter Steinberger
25e513e078 fix(agents): preserve OpenAI event streams
(cherry picked from commit 5d8b500929)
2026-05-12 06:21:09 +01:00
Peter Steinberger
2682d5efab test(agents): type stream setup timeout mock
(cherry picked from commit 5157ee268f)
2026-05-12 06:21:09 +01:00
Peter Steinberger
40db71b320 fix(agents): cap provider setup timeout
(cherry picked from commit 575ee22448)
2026-05-12 06:21:09 +01:00
Peter Steinberger
19a3962f9a fix(agents): abort timed out stream setup
(cherry picked from commit dccf55ffb6)
2026-05-12 06:21:09 +01:00
Peter Steinberger
a7668e8257 fix(agents): enforce idle timeout during stream setup
(cherry picked from commit 7d5cccaef4)
2026-05-12 06:21:09 +01:00
Peter Steinberger
c0b443aa9f ci: use current OpenAI model for release smokes
(cherry picked from commit 72ffd3a464)
2026-05-12 06:21:09 +01:00
Shakker
fab8657f85 test: count followup cleanup signals 2026-05-12 06:20:45 +01:00
Ayaan Zaidi
ca9489b43a docs(changelog): note read eof offset fix (#75536) (thanks @vyctorbrzezowski) 2026-05-12 10:50:42 +05:30
Ayaan Zaidi
3c9c91fb35 fix(agents): treat read offsets past eof as empty 2026-05-12 10:50:42 +05:30
Peter Steinberger
2d69e3227a test: guard daemon install mock calls 2026-05-12 06:20:11 +01:00
Shakker
d68d8e6b2d test: count dispatch idle marker 2026-05-12 06:18:37 +01:00
Peter Steinberger
4f67eaee68 test: guard proxy validation mock call 2026-05-12 06:18:07 +01:00
Shakker
91f01917ca test: count realtime voice callbacks 2026-05-12 06:16:51 +01:00
Peter Steinberger
1e7d5d6201 test: guard fetch ssrf mock calls 2026-05-12 06:15:37 +01:00
Peter Steinberger
651c62040f test: guard daemon install integration mock call 2026-05-12 06:13:55 +01:00
Ayaan Zaidi
c3f310cc14 fix(agents): land post-compaction workspace refresh (#75532) (thanks @vyctorbrzezowski) 2026-05-12 10:42:46 +05:30
vyctorbrzezowski
d5c67d712e fix(agents): use run workspace for post-compaction context 2026-05-12 10:42:46 +05:30
Peter Steinberger
8b51d89d60 test: guard daemon lifecycle mock call 2026-05-12 06:12:16 +01:00
Shakker
354a6ddefd test: check minted gateway token format 2026-05-12 06:11:09 +01:00
Peter Steinberger
3c66de8010 test: guard daemon probe mock calls 2026-05-12 06:10:24 +01:00
Ayaan Zaidi
16cfc83643 ci(mantis): fix telegram run wait before checkout 2026-05-12 10:39:27 +05:30
Peter Steinberger
b859e0f2ba test: guard cron delivery dispatch mock call 2026-05-12 06:08:53 +01:00
Shakker
bec7217630 test: count compaction summary calls 2026-05-12 06:08:33 +01:00
Peter Steinberger
bf7e3ff94d test: guard cron model override mock call 2026-05-12 06:07:19 +01:00
Peter Steinberger
42aa65dcb4 test: guard cron skills snapshot mock call 2026-05-12 06:06:08 +01:00
Shakker
30083c796b test: check compaction auth lookup 2026-05-12 06:06:00 +01:00
Peter Steinberger
71f04eedbc test: guard cron model preflight mock call 2026-05-12 06:04:50 +01:00
Peter Steinberger
b7dfacd9bb test: guard cron payload fallback mock call 2026-05-12 06:03:40 +01:00
Shakker
48e62b7757 test: check orphan repair reply 2026-05-12 06:03:33 +01:00
Ayaan Zaidi
ef9a820949 docs(changelog): credit active memory Telegram DM fix (#75533) (thanks @vyctorbrzezowski) 2026-05-12 10:32:12 +05:30
Ayaan Zaidi
4b40daf0ee test(active-memory): clean threaded DM coverage 2026-05-12 10:32:12 +05:30
vyctorbrzezowski
1ee29fb0ae fix(active-memory): classify threaded telegram dms 2026-05-12 10:32:12 +05:30
Peter Steinberger
21fe98a77c test: tighten core mock call helpers 2026-05-12 06:01:12 +01:00
Peter Steinberger
c860104b22 test: guard cron interim retry mock calls 2026-05-12 05:58:34 +01:00
Shakker
6fdcb10480 test: check subagent announce dispatch 2026-05-12 05:58:21 +01:00
Peter Steinberger
d2a9b8405c test: guard daemon service mock call 2026-05-12 05:57:16 +01:00
Shakker
e6b32e6609 test: check compaction branch summary input 2026-05-12 05:56:35 +01:00
Peter Steinberger
e89d1b2593 test: guard ssrf dispatcher mock call 2026-05-12 05:56:05 +01:00
Peter Steinberger
8084cbc345 test: guard daemon restart mock call 2026-05-12 05:55:10 +01:00
Shakker
724e7dba0a test: check tool search controls 2026-05-12 05:54:02 +01:00
Peter Steinberger
e4a5dd9c91 test: guard doctor gateway mock call 2026-05-12 05:53:50 +01:00
Shakker
e3c9675e87 test: check context engine session keys 2026-05-12 05:51:23 +01:00
Peter Steinberger
503eee14a0 test: guard cron session key mock calls 2026-05-12 05:50:57 +01:00
Peter Steinberger
5efd4b8e88 test: guard status summary mock calls 2026-05-12 05:47:57 +01:00
Shakker
b62750ac7e test: check node media payloads 2026-05-12 05:44:51 +01:00
Peter Steinberger
29d478f866 test: guard plugin hooks mock call 2026-05-12 05:44:37 +01:00
Peter Steinberger
92a4bb6c33 test: guard plugin lifecycle mock calls 2026-05-12 05:43:04 +01:00
Peter Steinberger
ed6db3cd23 test: guard plugin services mock call 2026-05-12 05:41:21 +01:00
Andy Ye
7624b0d16d fix(imessage): surface Full Disk Access probe failures
Preserve canonical iMessage Full Disk Access probe failures through non-sensitive health snapshots and status output, promote imsg denial banners to the public remediation message, and add a narrow audit exception for the reviewed Mistral advisory false-positive.
2026-05-11 21:41:08 -07:00
Shakker
a6892a5af3 test: check sanitized bootstrap files 2026-05-12 05:40:48 +01:00
Peter Steinberger
3e1a3e1a36 test: guard cron ops mock calls 2026-05-12 05:39:31 +01:00
Peter Steinberger
900aa25efd test: guard doctor platform notes mock calls 2026-05-12 05:37:57 +01:00
Peter Steinberger
93c5e0c4e0 test: guard tui event mock call 2026-05-12 05:36:29 +01:00
Shakker
58becd8d8e test: check partial reply payloads 2026-05-12 05:35:44 +01:00
Peter Steinberger
91bdeaeea9 test: guard commands info mock call 2026-05-12 05:34:36 +01:00
Peter Steinberger
d7f6bf3693 test: guard gateway status mock calls 2026-05-12 05:33:08 +01:00
Shakker
7e5730921a test: isolate gateway start mock calls 2026-05-12 05:32:19 +01:00
Peter Steinberger
1e894369a0 test: guard auto-reply dispatch mock call 2026-05-12 05:31:20 +01:00
Peter Steinberger
b4b4a77f47 test: guard sdk status mock call 2026-05-12 05:30:01 +01:00
Shakker
6a36ba034e test: count plugin uninstall side effects 2026-05-12 05:28:51 +01:00
Peter Steinberger
66190a890c test: guard cli run-main mock call 2026-05-12 05:27:41 +01:00
Peter Steinberger
10d590a666 test: guard optional tool mock calls 2026-05-12 05:26:27 +01:00
Shakker
ef99cc670e test: check scoped command secret targets 2026-05-12 05:25:10 +01:00
Peter Steinberger
4fe8f98faa test: guard reply media mock calls 2026-05-12 05:24:34 +01:00
Peter Steinberger
74d7c3254b test: guard gateway shutdown mock calls 2026-05-12 05:23:26 +01:00
Shakker
e8f3b48555 test: count subagent registry persistence 2026-05-12 05:22:06 +01:00
Peter Steinberger
a786d8dfcb test: guard inbound claim logger mock calls 2026-05-12 05:20:50 +01:00
Peter Steinberger
ff7e6c7fb3 test: guard container spawn mock call 2026-05-12 05:19:12 +01:00
sallyom
e1795256d5 fix(docker): avoid external Dockerfile frontend pull
Signed-off-by: sallyom <somalley@redhat.com>
2026-05-12 00:19:04 -04:00
Peter Steinberger
9677da3dd6 test: guard usage command mock calls 2026-05-12 05:17:24 +01:00
Shakker
5638ace844 test: tighten cli output assertions 2026-05-12 05:16:58 +01:00
Peter Steinberger
ff54363dd4 test: guard channel loader jiti mock call 2026-05-12 05:15:49 +01:00
Peter Steinberger
be233081e2 test: guard session hook mock calls 2026-05-12 05:14:05 +01:00
Shakker
e35bc01ade test: count cli command calls 2026-05-12 05:13:33 +01:00
Peter Steinberger
78fd1f18c5 test: guard status usage mock calls 2026-05-12 05:11:36 +01:00
Peter Steinberger
35174ea046 test: guard plugin doctor jiti mock call 2026-05-12 05:10:19 +01:00
Peter Steinberger
17fd01e228 test: guard exec approval delivery mock calls 2026-05-12 05:09:05 +01:00
Peter Steinberger
0756f7501a test: guard exec policy config mock call 2026-05-12 05:07:27 +01:00
Shakker
3c430f10e6 test: count owned tool hook calls 2026-05-12 05:07:20 +01:00
Peter Steinberger
b56f68fedc test: guard cron enqueue mock calls 2026-05-12 05:06:07 +01:00
Peter Steinberger
39b6f06661 test: guard acp manager mock calls 2026-05-12 05:04:35 +01:00
Shakker
49cef49ff9 test: count model switch side effects 2026-05-12 05:04:25 +01:00
Peter Steinberger
43793f6e52 test: guard acp startup mock calls 2026-05-12 05:03:11 +01:00
Peter Steinberger
54f0ab2e73 test: guard acp stop reason mock call 2026-05-12 05:01:57 +01:00
Shakker
43eb72b27a test: count compaction hook calls 2026-05-12 05:01:32 +01:00
Peter Steinberger
31e33b029b test: guard acp permission relay mock call 2026-05-12 04:59:13 +01:00
Shakker
5c65a22c8c test: count gateway lock release 2026-05-12 04:58:02 +01:00
Peter Steinberger
3d8f8c8fcc test: guard outbound media mock calls 2026-05-12 04:57:27 +01:00
Peter Steinberger
43cb4d0447 fix: normalize gemini auth login default 2026-05-12 04:56:08 +01:00
Shakker
79f7fc6e19 test: guard downgrade update path 2026-05-12 04:55:15 +01:00
Shakker
187b4a6b79 test: assert indexed tagline 2026-05-12 04:52:12 +01:00
Peter Steinberger
897bc1c355 test: guard exec host socket mock calls 2026-05-12 04:49:33 +01:00
Shakker
bb817002cc test: count update follow-up calls 2026-05-12 04:49:01 +01:00
Peter Steinberger
7fd5d45ae4 test: guard shell env mock calls 2026-05-12 04:48:31 +01:00
Peter Steinberger
f34b1a4958 test: guard tui shell mock call 2026-05-12 04:46:56 +01:00
Peter Steinberger
afc05f85b7 test: guard message hook mock calls 2026-05-12 04:45:49 +01:00
Shakker
9f61642ba9 test: count prompt readline close 2026-05-12 04:45:41 +01:00
Peter Steinberger
02eccba8e6 test: guard channel status plugin mock call 2026-05-12 04:44:45 +01:00
Peter Steinberger
24f23cffe9 test: guard acp lifecycle mock calls 2026-05-12 04:43:50 +01:00
Shakker
23cc8f37b4 test: count restart helper unrefs 2026-05-12 04:43:07 +01:00
Peter Steinberger
b5eb214e4e test: guard launchd handoff mock calls 2026-05-12 04:42:36 +01:00
Peter Steinberger
e9d13cba0a test: guard session store write mock call 2026-05-12 04:41:22 +01:00
Peter Steinberger
c7d34ffee8 test: guard transcript update mock call 2026-05-12 04:40:17 +01:00
Shakker
4ebca4c314 test: count plugin install enable calls 2026-05-12 04:39:10 +01:00
Shakker
250b35691f test: count plugin install config reads 2026-05-12 04:36:27 +01:00
Peter Steinberger
352a394bcc test: guard plugin cleanup timeout mock call 2026-05-12 04:35:10 +01:00
Shakker
f9f232d8fb test: count plugin install refreshes 2026-05-12 04:33:35 +01:00
Peter Steinberger
51e83c4d23 test: guard configure gateway mock call 2026-05-12 04:32:39 +01:00
Peter Steinberger
315cfa47b4 test: guard backup verify mock call 2026-05-12 04:31:44 +01:00
Shakker
77138281ea test: count formatted bundled skills 2026-05-12 04:30:57 +01:00
Peter Steinberger
dc3654b544 test: guard backup registration mock call 2026-05-12 04:29:58 +01:00
Peter Steinberger
bf71a896d8 test: guard status registration mock call 2026-05-12 04:28:58 +01:00
Shakker
5cca9bad0d test: count secrets configure prompt 2026-05-12 04:28:15 +01:00
Peter Steinberger
c49ffedc1f test: guard plugin policy cli mock call 2026-05-12 04:27:47 +01:00
Peter Steinberger
3b85a4ba79 test: guard browser doctor mock call 2026-05-12 04:26:27 +01:00
Peter Steinberger
bf2b40866d test: guard agent runtime config mock calls 2026-05-12 04:25:34 +01:00
Shakker
366b5cf738 test: count channel login calls 2026-05-12 04:25:28 +01:00
Peter Steinberger
2b705957bb test: guard device pairing doctor mock calls 2026-05-12 04:24:38 +01:00
Shakker
fd05a6e9dd test: count routed plugin registry loads 2026-05-12 04:22:54 +01:00
Peter Steinberger
16ce9c1618 test: guard channel send mock calls 2026-05-12 04:22:10 +01:00
Peter Steinberger
6a1ae65b5c test: guard channel lifecycle mock calls 2026-05-12 04:21:01 +01:00
Shakker
d6e63ee3b2 test: count plugin uninstall planning 2026-05-12 04:19:18 +01:00
Peter Steinberger
f468f0f61f test: guard windows exec mock calls 2026-05-12 04:19:02 +01:00
Peter Steinberger
9433f7984b test: guard plugin uninstall mock call 2026-05-12 04:17:16 +01:00
Shakker
b2f3ae2a14 test: count session status store writes 2026-05-12 04:16:43 +01:00
Peter Steinberger
aac9028f89 test: guard fetch timeout mock calls 2026-05-12 04:16:12 +01:00
Peter Steinberger
339b0e164f fix: normalize gemini provider catalog defaults 2026-05-12 04:14:35 +01:00
Shakker
98c1d1f6f3 test: count fallback rate-limit checks 2026-05-12 04:13:34 +01:00
Shakker
df87c2fc56 test: count final tag reply callbacks 2026-05-12 04:10:42 +01:00
Peter Steinberger
ba152d4b63 test: guard security audit mock calls 2026-05-12 04:09:49 +01:00
Shakker
b14cf842c8 test: count subagent completion retries 2026-05-12 04:08:02 +01:00
Peter Steinberger
daeced9f94 test: reuse plugin cli mock call helper 2026-05-12 04:07:24 +01:00
Peter Steinberger
60ff7b2f69 test: guard heartbeat subagent mock call 2026-05-12 04:06:05 +01:00
Vincent Koc
d6d7b048ff docs(help): correct built-in opus/gpt aliases to match DEFAULT_MODEL_ALIASES 2026-05-12 11:04:19 +08:00
Peter Steinberger
efdd3745aa test: guard windows task restart mock calls 2026-05-12 04:04:09 +01:00
Shakker
f07ac11723 test: count sandbox prune removals 2026-05-12 04:03:56 +01:00
Peter Steinberger
7116cc8a2c test: guard runtime web tools mock arg 2026-05-12 04:02:08 +01:00
Peter Steinberger
8ff3a20390 test: guard status json mock calls 2026-05-12 04:01:13 +01:00
Shakker
a40a6eb91c test: count media handler tool output 2026-05-12 04:01:03 +01:00
Peter Steinberger
2ea90f6f49 test: guard gateway service install mock call 2026-05-12 04:00:02 +01:00
Peter Steinberger
5647846fd7 test: guard channel turn finalize mock calls 2026-05-12 03:58:54 +01:00
Shakker
630bbbdc7c test: count verbose tool result callbacks 2026-05-12 03:57:55 +01:00
Peter Steinberger
b9cd2fcc2b test: guard approval gateway mock call 2026-05-12 03:57:35 +01:00
Peter Steinberger
21a80ced0e test: guard label generator mock calls 2026-05-12 03:56:31 +01:00
Peter Steinberger
64e7cfa668 test: guard doctor transcript mock call 2026-05-12 03:55:17 +01:00
Peter Steinberger
5435480e5f test: guard backup log mock call 2026-05-12 03:54:25 +01:00
Peter Steinberger
14e6f0d62e test: guard heartbeat typing mock call 2026-05-12 03:53:28 +01:00
Shakker
b23b092fcc test: count music completion announcements 2026-05-12 03:52:51 +01:00
Peter Steinberger
928d171001 test: guard doctor auth repair mock call 2026-05-12 03:52:07 +01:00
Peter Steinberger
b7bdb083bb test: guard realtime websocket mock calls 2026-05-12 03:51:05 +01:00
Peter Steinberger
ca95f20c6f test: reuse watch-node mock call guard 2026-05-12 03:50:10 +01:00
Shakker
cb2b399368 test: count media completion announcements 2026-05-12 03:49:11 +01:00
Peter Steinberger
3c562dcaa8 test: guard heartbeat prefix mock call 2026-05-12 03:48:42 +01:00
Peter Steinberger
cbc0f68515 test: guard managed npm root mock call 2026-05-12 03:47:37 +01:00
Peter Steinberger
1b8410adb9 test: guard crestodian rescue mock calls 2026-05-12 03:46:40 +01:00
Peter Steinberger
dd5fd3805b test: guard cron fast-mode mock calls 2026-05-12 03:45:29 +01:00
Shakker
4cb35e4bff test: count exec followup results 2026-05-12 03:44:56 +01:00
Peter Steinberger
71f4b68163 test: guard channel mcp mock call 2026-05-12 03:43:03 +01:00
Shakker
39bd6dab3c test: assert chutes token refresh request 2026-05-12 03:42:12 +01:00
Peter Steinberger
4ef76083c0 test: guard auth choice mock helper 2026-05-12 03:41:51 +01:00
Peter Steinberger
42fff3de8e test: guard provider flow mock calls 2026-05-12 03:40:48 +01:00
Peter Steinberger
6538dc58a3 test: guard sandbox media scp mock call 2026-05-12 03:39:45 +01:00
Shakker
5e0b8cd271 test: count announcement gateway attempts 2026-05-12 03:39:36 +01:00
Peter Steinberger
4c8d01e2a7 test: guard wired hook mock call 2026-05-12 03:38:01 +01:00
Peter Steinberger
e87fd7aa30 fix: normalize google gemini preview config 2026-05-12 03:36:58 +01:00
ai-hpc
7b9282323b fix(doctor): render legacy migration panel as preview when --fix is not passed
loadAndMaybeMigrateDoctorConfig emitted four legacy migration / config-mutation changeLines under a fixed "Doctor changes" panel title even when shouldRepair was false, so a read-only doctor run printed past-tense "Removed agents.defaults.agentRuntime" alongside the "Legacy config keys detected" panel saying the key was still ignored. Centralize the preview-aware title selection in a single emitDoctorChangesPanel helper and route the four emit sites (legacy step, normalized compatibility, plugin auto-enable, channel stale cleanup) through it, so the panel renders as "Doctor changes preview" in non-repair runs and "Doctor changes" with --fix. Mirrors the existing precedent for unknown-config-key emission a few lines below.
2026-05-11 22:36:42 -04:00
Shakker
c098766c9b test: count btw context builds 2026-05-12 03:32:35 +01:00
Peter Steinberger
b4c92f40bd test: guard channel setup mock calls 2026-05-12 03:29:47 +01:00
Shakker
baa11835a0 test: count single-pass compaction summaries 2026-05-12 03:29:34 +01:00
Shakker
28dd756d9f test: count ssh sandbox sessions 2026-05-12 03:26:56 +01:00
Peter Steinberger
c41fd134d0 test: guard realtime talk consult mock call 2026-05-12 03:25:00 +01:00
Peter Steinberger
8cbb2f8027 test: guard plugin tools mock calls 2026-05-12 03:23:36 +01:00
Peter Steinberger
5388428c66 test: guard echo transcript mock call 2026-05-12 03:22:18 +01:00
Shakker
1a1b6d8d88 test: count minimax vlm requests 2026-05-12 03:22:12 +01:00
Peter Steinberger
9fd5cf48a6 test: guard tlon sse mock calls 2026-05-12 03:20:55 +01:00
Peter Steinberger
dea633e7dd test: guard foundry provider mock call 2026-05-12 03:19:53 +01:00
Shakker
53ef9154b8 test: count sandbox bridge shell calls 2026-05-12 03:19:44 +01:00
Peter Steinberger
3c6e0b4a95 test: guard image understanding mock calls 2026-05-12 03:18:01 +01:00
Peter Steinberger
b2f6c29301 test: guard pairing cli mock calls 2026-05-12 03:16:01 +01:00
Peter Steinberger
8bddf0efe1 test: guard voice-call realtime mock calls 2026-05-12 03:14:40 +01:00
Shakker
087f1e060b test: check cli runner fallback calls 2026-05-12 03:13:34 +01:00
Peter Steinberger
0d4e6676dc test: guard voice-call webhook mock calls 2026-05-12 03:12:50 +01:00
Peter Steinberger
899730dad6 test: guard voice-call response mock calls 2026-05-12 03:10:46 +01:00
Shakker
8d4fd26233 test: check exec heartbeat routing 2026-05-12 03:10:37 +01:00
Peter Steinberger
8d35fc2197 test: guard voice-call notify mock calls 2026-05-12 03:09:24 +01:00
sallyom
c7623f706f test: cover timeout after tool media
Signed-off-by: sallyom <somalley@redhat.com>
2026-05-11 22:09:20 -04:00
Dwayne
89f2326c52 style: apply oxlint auto-formatting 2026-05-11 22:09:20 -04:00
Dwayne
db57da50c9 fix: reintroduce partial-fragment drop for clean timeouts 2026-05-11 22:09:20 -04:00
Dwayne
18f4a2d987 fix: surface explicit error on LLM idle timeout to prevent ghost turns 2026-05-11 22:09:20 -04:00
Peter Steinberger
7863643dac test: guard voice-call runtime mock calls 2026-05-12 03:08:10 +01:00
Shakker
8d29fd513c test: check markdown fetch call counts 2026-05-12 03:07:36 +01:00
Peter Steinberger
f55b305077 test: guard voice-call media stream mock calls 2026-05-12 03:05:45 +01:00
Shakker
e18859b342 test: assert thinking tag filtered text 2026-05-12 03:04:49 +01:00
Peter Steinberger
4741b4be19 test: guard cron issue enqueue mock call 2026-05-12 03:02:53 +01:00
Shakker
d3ee2a0c78 test: check synthetic auth discovery calls 2026-05-12 03:02:17 +01:00
Peter Steinberger
31c7ca5075 test: guard cron restart enqueue mock call 2026-05-12 03:01:38 +01:00
Peter Steinberger
e3b56c46f2 test: guard audio transcode mock call 2026-05-12 03:00:30 +01:00
Peter Steinberger
8b6c2bf1af test: guard memory auth mock calls 2026-05-12 02:59:25 +01:00
Shakker
9f821e5634 test: check model catalog auth queries 2026-05-12 02:59:16 +01:00
Peter Steinberger
5d32047354 test: guard tui command mock calls 2026-05-12 02:57:05 +01:00
Shakker
3abb2ee781 test: check read-only auth overlay context 2026-05-12 02:56:11 +01:00
Peter Steinberger
a8216a4ba0 test: guard tui spawn mock call 2026-05-12 02:55:51 +01:00
Peter Steinberger
cc5cdf8f1d test: guard node event mock call 2026-05-12 02:54:51 +01:00
Peter Steinberger
bdb5bd0ffb test: guard commitment telegram send mock call 2026-05-12 02:53:45 +01:00
Peter Steinberger
17b9f7a8e0 test: guard discord reaction monitor mock calls 2026-05-12 02:52:24 +01:00
Shakker
ba93e6f427 test: assert compaction sanitized inputs 2026-05-12 02:51:13 +01:00
Peter Steinberger
6ebc6cad17 test: guard discord webhook fetch mock call 2026-05-12 02:50:29 +01:00
Peter Steinberger
e1cd9275dc test: guard discord message process mock calls 2026-05-12 02:49:19 +01:00
Shakker
2bf827ae35 test: pin compaction safeguard diagnostics 2026-05-12 02:47:59 +01:00
Peter Steinberger
97d9efee37 test: guard discord preflight mock calls 2026-05-12 02:47:41 +01:00
Peter Steinberger
a010277524 test: guard discord model picker mock calls 2026-05-12 02:46:24 +01:00
Shakker
8a58fa0a21 test: assert compaction split merge calls 2026-05-12 02:44:44 +01:00
Peter Steinberger
7f4a17f565 test: guard discord component mock calls 2026-05-12 02:44:31 +01:00
Peter Steinberger
0c4e52a6b3 test: guard discord plugin dispatch mock calls 2026-05-12 02:43:17 +01:00
Peter Steinberger
7dc3e22571 test: guard discord provider proxy mock calls 2026-05-12 02:42:06 +01:00
Shakker
9b1596cf12 test: assert bootstrap warning metadata 2026-05-12 02:41:33 +01:00
Peter Steinberger
22981a2cc4 test: guard discord status-direct mock calls 2026-05-12 02:40:41 +01:00
Peter Steinberger
a3f67c2c6e test: guard discord allow-from mock calls 2026-05-12 02:37:27 +01:00
Peter Steinberger
1c09002027 test: guard discord rest proxy mock calls 2026-05-12 02:36:09 +01:00
Peter Steinberger
88c6255ed8 test: guard discord thread binding api mock calls 2026-05-12 02:34:58 +01:00
Shakker
2b54023d08 test: assert compaction instruction fallbacks 2026-05-12 02:34:01 +01:00
Peter Steinberger
578dcfbcf4 test: guard discord thread title mock calls 2026-05-12 02:33:10 +01:00
Peter Steinberger
2f4fa9cbe2 test: guard discord listener mock calls 2026-05-12 02:32:13 +01:00
Peter Steinberger
411846893c test: guard discord command arg mock calls 2026-05-12 02:31:16 +01:00
Shakker
87d03b1191 test: assert decoded image data url bytes 2026-05-12 02:31:04 +01:00
Peter Steinberger
0611e16e0f test: guard discord thread binding mock calls 2026-05-12 02:29:52 +01:00
Peter Steinberger
a0fb3c1dfd test: guard discord provider mock calls 2026-05-12 02:28:39 +01:00
Shakker
e994c996c2 test: assert cleanup completion follows run end 2026-05-12 02:28:25 +01:00
Peter Steinberger
3cbc889701 test: guard discord provider startup mock calls 2026-05-12 02:26:19 +01:00
Shakker
7517fe5aae test: match compact skill warning count 2026-05-12 02:25:49 +01:00
Peter Steinberger
d970a81138 test: guard discord component mock calls 2026-05-12 02:23:52 +01:00
Shakker
d37a6c32c3 test: assert compaction prune history ids 2026-05-12 02:22:58 +01:00
Peter Steinberger
cbfc14171b test: guard discord message utils mock calls 2026-05-12 02:21:36 +01:00
Peter Steinberger
6e1e6ecb4f test: guard discord reply delivery mock calls 2026-05-12 02:20:16 +01:00
Shakker
8fbb0eefd3 test: assert compaction split layouts 2026-05-12 02:20:13 +01:00
Peter Steinberger
fead3bfc55 test: guard discord action mock calls 2026-05-12 02:19:05 +01:00
Peter Steinberger
14d248fd18 test: guard discord threading starter mock calls 2026-05-12 02:17:41 +01:00
Shakker
2f20e247ca test: reject blank bundled skill metadata 2026-05-12 02:17:21 +01:00
Peter Steinberger
860bf921ed test: guard discord gateway supervisor mock calls 2026-05-12 02:16:34 +01:00
Peter Steinberger
0e28f4f70f test: guard browser tab selection mock calls 2026-05-12 02:15:06 +01:00
Shakker
2013700753 test: assert noop exec completion event 2026-05-12 02:14:59 +01:00
pashpashpash
85bf8cdf8f fix: add message tool delivery hint to inbound context (#80821) 2026-05-12 10:14:55 +09:00
Peter Steinberger
eab88c61e7 test: guard slack tool result mock calls 2026-05-12 02:14:05 +01:00
Peter Steinberger
1894e9f4d7 test: guard msteams attachment mock calls 2026-05-12 02:12:33 +01:00
Shakker
49d7a7a4d0 test: pin stale lock watchdog release count 2026-05-12 02:11:44 +01:00
Peter Steinberger
eb5685cfab test: guard discord send mock calls 2026-05-12 02:10:57 +01:00
Peter Steinberger
3d5fd9cc8f test: guard slack media mock calls 2026-05-12 02:09:06 +01:00
Shakker
94704b7185 test: assert materialized session ids are uuid 2026-05-12 02:08:51 +01:00
Peter Steinberger
bb5761ab03 test: guard msteams reaction mock calls 2026-05-12 02:07:39 +01:00
Peter Steinberger
c192604e36 test: guard slack action mock calls 2026-05-12 02:06:27 +01:00
Peter Steinberger
434d589f3e test: guard msteams authz mock calls 2026-05-12 02:04:25 +01:00
Peter Steinberger
2f21fe51fc test: guard discord outbound mock calls 2026-05-12 02:03:10 +01:00
Shakker
4afbd8ac49 test: assert agent wait timeout cushion 2026-05-12 02:02:54 +01:00
Peter Steinberger
e649cb92c0 test: guard discord gateway mock calls 2026-05-12 02:01:54 +01:00
Peter Steinberger
95b6c10fc7 test: guard browser session mock calls 2026-05-12 02:00:53 +01:00
Shakker
1d3ab90165 test: assert block reply chunk payloads 2026-05-12 02:00:10 +01:00
Sarah Fortune
c8998b71e2 fix(onboarding): use isolated codex app-server client for migration detect (#80822)
discoverInstalledCuratedPlugins acquired the shared Codex app-server client
to issue a one-shot plugin/list RPC against the source CODEX_HOME. The
shared slot kept the spawned child alive with stdio pipes attached to the
onboarding process, so the Node event loop never drained after the wizard
emitted its outro and the CLI appeared to hang.

The discovery RPC has its own one-off startOptions (custom CODEX_HOME,
HOME) that should never be reused for an agent session, so request it as
an isolated client. request.ts closes the child as soon as the call
returns, removing the dependence on process-exit harness disposal and
eliminating the post-onboarding hang.
2026-05-11 17:59:48 -07:00
Peter Steinberger
4bf3016096 test: guard browser batch mock calls 2026-05-12 01:57:53 +01:00
Shakker
905da673e7 test: lock down thinking block reply payload 2026-05-12 01:57:24 +01:00
Peter Steinberger
4bde5b6dfa test: guard browser agent contract mock calls 2026-05-12 01:56:24 +01:00
Peter Steinberger
e07e6c77da test: guard msteams reply dispatcher mock calls 2026-05-12 01:54:54 +01:00
Shakker
06f1cd92ed test: specify embedded approval payloads 2026-05-12 01:53:27 +01:00
Peter Steinberger
fb15b32df2 test: guard msteams oauth mock calls 2026-05-12 01:52:52 +01:00
Peter Steinberger
7857bf0c5c test: guard msteams send mock calls 2026-05-12 01:50:50 +01:00
Shakker
e732c514e2 test: specify read tool text content 2026-05-12 01:49:43 +01:00
Peter Steinberger
6f0b789f81 test: guard discord send thread mock calls 2026-05-12 01:49:25 +01:00
Peter Steinberger
68ac67d7c7 test: guard slack routing mock calls 2026-05-12 01:47:47 +01:00
Peter Steinberger
b77ca2e0ff test: guard slack lazy mock calls 2026-05-12 01:46:34 +01:00
Shakker
be6faa11ec test: specify orphaned media lifecycle order 2026-05-12 01:46:14 +01:00
Peter Steinberger
fccf28910e test: guard msteams graph mock calls 2026-05-12 01:44:46 +01:00
Peter Steinberger
b09733dab2 test: guard browser node host mock calls 2026-05-12 01:42:58 +01:00
Peter Steinberger
402da9610c test: guard slack outbound mock calls 2026-05-12 01:41:57 +01:00
Peter Steinberger
a0288dc4aa test: guard discord channel mock calls 2026-05-12 01:40:46 +01:00
Shakker
9dbae5ca95 test: specify expired auth cooldown reset 2026-05-12 01:40:29 +01:00
Peter Steinberger
bcea977531 test: guard msteams consent mock calls 2026-05-12 01:39:39 +01:00
Peter Steinberger
83154d8470 test: guard browser gateway mock calls 2026-05-12 01:38:09 +01:00
Shakker
e23d7db1f1 test: specify oauth fallback key path 2026-05-12 01:38:02 +01:00
Peter Steinberger
4835ff5ea1 test: guard discord component mock calls 2026-05-12 01:35:24 +01:00
Peter Steinberger
3426b09591 test: guard msteams sdk mock calls 2026-05-12 01:33:59 +01:00
Shakker
8530d03671 test: specify cli transcript path 2026-05-12 01:33:13 +01:00
Peter Steinberger
50ba3abf6b test: guard msteams monitor lifecycle mock calls 2026-05-12 01:31:01 +01:00
Peter Steinberger
85c57a42b4 test: guard browser route reachability mock calls 2026-05-12 01:29:34 +01:00
Peter Steinberger
3b851b41c3 test: guard slack identity fallback mock calls 2026-05-12 01:27:41 +01:00
Shakker
b46475a52b test: specify oauth profile ref ids 2026-05-12 01:27:10 +01:00
Sarah Fortune
e9421bbdec fix(onboarding): treat already-installed codex as success, update in place (#80816)
When `ensureCodexRuntimePluginForModelSelection` ran for a host that
already had `@openclaw/codex` installed under the managed npm root, the
default `mode: "install"` path in `installPluginFromNpmSpec` returned
"plugin already exists" from `ensureInstallTargetAvailable` and the
wizard marked the step as failed.

Now, when the install record points at a real package on disk, route
through the existing `repairCodexRuntimePluginInstallForModelSelection`
flow (which runs `repairMissingPluginInstallsForIds` →
`updateNpmInstalledPlugins`), forward any changes/warnings to the
runtime log, enable the plugin in cfg, and return `installed`.

A fresh install still flows through `ensureOnboardingPluginInstalled`
so the wizard progress UI is unchanged.
2026-05-11 17:26:40 -07:00
Peter Steinberger
5c4f5e0f3a test: guard slack blocks mock calls 2026-05-12 01:26:05 +01:00
Peter Steinberger
133c6a5cf5 test: guard msteams file consent mock calls 2026-05-12 01:24:48 +01:00
Peter Steinberger
8486c69315 test: guard browser chrome mock calls 2026-05-12 01:23:39 +01:00
Shakker
9e77a41fcb test: specify cli auth epoch shape 2026-05-12 01:23:03 +01:00
Peter Steinberger
015bf23fe3 test: guard msteams graph search mock calls 2026-05-12 01:22:11 +01:00
Peter Steinberger
e7397ec81f test: guard slack channel mock calls 2026-05-12 01:21:03 +01:00
Shakker
34cbc131f0 test: specify download escape side effects 2026-05-12 01:19:50 +01:00
Peter Steinberger
598f1eb704 test: guard slack approval mock calls 2026-05-12 01:19:20 +01:00
Peter Steinberger
97870f36fb test: guard msteams user agent mock calls 2026-05-12 01:18:08 +01:00
Peter Steinberger
e5a674a783 test: guard acpx runtime mock calls 2026-05-12 01:16:59 +01:00
Shakker
24e5e373e2 test: specify auth path outputs 2026-05-12 01:16:18 +01:00
Peter Steinberger
8ef408bc5e test: guard browser server launch mock calls 2026-05-12 01:15:28 +01:00
Peter Steinberger
7f8d37bdcc test: guard browser control auth mock calls 2026-05-12 01:14:22 +01:00
Peter Steinberger
9947c50968 test: guard browser snapshot mock calls 2026-05-12 01:13:24 +01:00
Shakker
b96e2a7190 test: specify compaction successor messages 2026-05-12 01:12:32 +01:00
Peter Steinberger
2547f4f1ee test: guard browser download save mock calls 2026-05-12 01:12:12 +01:00
Peter Steinberger
25ac449801 test: guard browser session fallback mock calls 2026-05-12 01:10:57 +01:00
Sarah Fortune
26b2c47feb feat(onboarding): featured provider tier in interactive picker (#80798)
* temp

* fix pnpm lock conflict

* fix(onboarding): clear oxlint findings in auth-choice-prompt
2026-05-11 17:09:32 -07:00
Peter Steinberger
9afdd3ae3b test: guard browser cli mock calls 2026-05-12 01:09:27 +01:00
Shakker
d3678b91e6 test: specify bootstrap file filtering 2026-05-12 01:08:32 +01:00
Peter Steinberger
3029da8ef9 test: guard browser profile mock calls 2026-05-12 01:06:55 +01:00
Peter Steinberger
c4df9c7135 test: guard browser service mock calls 2026-05-12 01:05:53 +01:00
Shakker
04cdba80dc test: require cli spawn arg values 2026-05-12 01:05:39 +01:00
Peter Steinberger
5fca39feeb test: guard browser doctor mock calls 2026-05-12 01:04:41 +01:00
Peter Steinberger
af30c02ca5 test: guard browser loopback mock calls 2026-05-12 01:03:05 +01:00
Shakker
82b335f6e6 test: specify agent wait timeout request 2026-05-12 01:02:51 +01:00
Peter Steinberger
4fed265d05 test: guard browser internal cdp mock calls 2026-05-12 01:01:22 +01:00
Shakker
36534558e8 test: require cli mcp config path 2026-05-12 00:59:37 +01:00
Peter Steinberger
3d9d474c0d test: guard browser cdp mock calls 2026-05-12 00:59:00 +01:00
Peter Steinberger
f6d5d1cc4e test: guard qa lab cli mock calls 2026-05-12 00:57:48 +01:00
Peter Steinberger
065475df83 test: guard signal ingest mock calls 2026-05-12 00:56:41 +01:00
Shakker
5995c1b4a3 test: specify cli image argv 2026-05-12 00:56:22 +01:00
Peter Steinberger
6ac981f044 test: guard zalo lifecycle mock calls 2026-05-12 00:55:27 +01:00
Peter Steinberger
3b15e11052 test: guard zalo startup mock calls 2026-05-12 00:53:59 +01:00
Shakker
0e417981db test: specify deduped image refs 2026-05-12 00:53:18 +01:00
Peter Steinberger
8b5cb16cfb test: guard qa lab web mock calls 2026-05-12 00:52:44 +01:00
Peter Steinberger
f97815a04e test: guard qa lab session mock calls 2026-05-12 00:51:44 +01:00
Peter Steinberger
9b6cc4085f test: guard signal autostart mock calls 2026-05-12 00:50:46 +01:00
Kevin Lin
8954c03231 fix(codex): default plugin destructive actions on (#80792) 2026-05-11 16:50:15 -07:00
Shakker
edd200d517 test: specify message image parser refs 2026-05-12 00:49:32 +01:00
Peter Steinberger
e0c03224e0 test: guard synology chat mock calls 2026-05-12 00:49:13 +01:00
Peter Steinberger
9682e7a034 test: guard slack probe mock calls 2026-05-12 00:48:07 +01:00
Peter Steinberger
2b202ffe7c test: guard slack dispatch mock calls 2026-05-12 00:47:11 +01:00
Shakker
2aec3178e8 test: specify media image parser refs 2026-05-12 00:46:56 +01:00
Peter Steinberger
ce695d7a32 test: guard signal reaction mock calls 2026-05-12 00:45:56 +01:00
Peter Steinberger
35ba1dea85 test: guard discord action mock calls 2026-05-12 00:44:43 +01:00
Shakker
f006e97caa test: specify prompt image path refs 2026-05-12 00:43:56 +01:00
Peter Steinberger
56c26c38be test: guard zalo api mock calls 2026-05-12 00:43:34 +01:00
Peter Steinberger
277ede4b1c test: guard mattermost channel mock calls 2026-05-12 00:42:28 +01:00
Peter Steinberger
ac92277066 test: guard comfy video mock calls 2026-05-12 00:41:06 +01:00
Kevin Lin
7b1c741850 test: stabilize core fast tests (#80803) 2026-05-11 16:40:51 -07:00
Shakker
38f897f0ee test: specify image extension refs 2026-05-12 00:40:26 +01:00
Peter Steinberger
aacfe5b421 test: guard msteams graph mock calls 2026-05-12 00:40:00 +01:00
Peter Steinberger
04b07534b5 test: guard mattermost slash mock calls 2026-05-12 00:38:55 +01:00
Shakker
46ab30a541 test: specify sandbox image load output 2026-05-12 00:38:34 +01:00
Shakker
b516f8f228 test: specify bootstrap truncation counts 2026-05-12 00:36:59 +01:00
Peter Steinberger
a091feae2d test: guard qqbot stt mock calls 2026-05-12 00:36:38 +01:00
Shakker
52e246345c test: specify embedded fence chunks 2026-05-12 00:35:26 +01:00
Peter Steinberger
9086751019 test: guard msteams media mock calls 2026-05-12 00:35:04 +01:00
Peter Steinberger
09f0566008 test: guard twitch setup mock calls 2026-05-12 00:33:52 +01:00
Peter Steinberger
ff37c39bae test: guard kilocode model mock calls 2026-05-12 00:32:20 +01:00
Peter Steinberger
86945dc7c0 test: guard video provider mock calls 2026-05-12 00:31:12 +01:00
Shakker
430e3e1e31 test: specify tool-result char estimates 2026-05-12 00:30:45 +01:00
Peter Steinberger
8577570cf3 test: guard matrix cli mock calls 2026-05-12 00:29:38 +01:00
Shakker
949a196090 test: specify qa mock embeddings 2026-05-12 00:28:24 +01:00
Peter Steinberger
44b09a3c71 test: guard mattermost probe mock calls 2026-05-12 00:28:15 +01:00
Peter Steinberger
8b50587ec7 test: guard slack setup mock calls 2026-05-12 00:27:00 +01:00
Shakker
6cd58ce7b1 test: specify heartbeat bootstrap files 2026-05-12 00:25:59 +01:00
Peter Steinberger
26dd616e2d test: guard xai realtime mock calls 2026-05-12 00:25:50 +01:00
Peter Steinberger
8127103bb3 test: guard memory wiki cli mock calls 2026-05-12 00:24:22 +01:00
Shakker
a8a34c92f3 fix: validate literal tilde exec scripts 2026-05-12 00:23:37 +01:00
Peter Steinberger
f078d90226 test: guard thread ownership mock calls 2026-05-12 00:23:11 +01:00
Peter Steinberger
9a9dc4a47b test: guard webhooks mock calls 2026-05-12 00:21:40 +01:00
Peter Steinberger
c63b72d041 test: guard skill workshop mock calls 2026-05-12 00:20:37 +01:00
Peter Steinberger
225a374d5e test: guard document extract mock calls 2026-05-12 00:19:06 +01:00
Peter Steinberger
00453a9607 test: guard active memory hook mock calls 2026-05-12 00:17:49 +01:00
pashpashpash
3b44dfc367 Make OpenAI auth login use ChatGPT by default (#80790)
* fix(openai): default provider login to ChatGPT auth

* fix(openai): align auth login metadata and fast tests

* fix(openai): prefer setup auth providers for login

* fix(openai): reject unknown explicit auth methods

* fix(line): keep channel entry imports scoped
2026-05-12 08:17:14 +09:00
Peter Steinberger
5c14f159c6 test: guard github copilot mock calls 2026-05-12 00:16:04 +01:00
Shakker
cb9881423d test: specify telegram file-ref chunks 2026-05-12 00:14:45 +01:00
Omar Shahine
d7a9248620 fix(imessage): route inbound tapbacks as reactions
Route inbound iMessage tapbacks as untrusted reaction system events, add reaction notification configuration/docs, and cover reply-cache ownership matching for bot-authored targets.
2026-05-11 16:13:29 -07:00
Peter Steinberger
da97f9f54d test: guard tavily tool mock calls 2026-05-12 00:10:33 +01:00
Shakker
919ba6c70c test: remove redundant telegram command check 2026-05-12 00:10:20 +01:00
Shakker
c0601f955e test: specify telegram model keyboard 2026-05-12 00:08:46 +01:00
Peter Steinberger
f0daf09b02 test: guard google realtime mock calls 2026-05-12 00:07:48 +01:00
Shakker
7cd9e43979 test: specify telegram send action result 2026-05-12 00:06:57 +01:00
Peter Steinberger
fcd0e9d5ad test: guard google speech mock calls 2026-05-12 00:06:16 +01:00
Shakker
cdef959514 test: specify matrix encrypted room request 2026-05-12 00:04:15 +01:00
Peter Steinberger
93b1e7e282 test: guard google provider mock calls 2026-05-12 00:03:56 +01:00
Shakker
e847e0f2dd test: specify telegram command menu registrations 2026-05-12 00:02:33 +01:00
Sarah Fortune
3d5b0cb41b fix(cli/completion): re-apply shell-profile source-line guard (re-#78659) (#80797) 2026-05-11 16:01:00 -07:00
Peter Steinberger
1f167178f2 test: guard messaging provider mock calls 2026-05-12 00:00:46 +01:00
Shakker
25e241e3e2 test: specify signal heading styles 2026-05-12 00:00:18 +01:00
Kevin Lin
f5b0eca12a docs: reorganize tools automation nav (#80116)
* docs: reorganize tools automation nav

* docs: add nav spec glossary terms

* docs: refresh nav spec validation

* docs: keep capabilities nav grouped

* docs: refactor tools overview

* docs: restore tools overview coverage

* add doc refactor skill

* docs: mark refactored docs schema

* docs: remove refactor specs from pr

* docs: rename tools overview header
2026-05-11 15:59:27 -07:00
Shakker
b348cdd1f1 test: specify googlechat capability proof set 2026-05-11 23:58:57 +01:00
Peter Steinberger
459c12eda1 test: guard media provider mock calls 2026-05-11 23:57:23 +01:00
Shakker
12eb320b71 test: specify prometheus exporter startup event 2026-05-11 23:56:48 +01:00
Shakker
5742b39c7b test: specify nested skill discovery cap 2026-05-11 23:55:31 +01:00
Peter Steinberger
7453ba6381 test: guard deepinfra provider mock calls 2026-05-11 23:54:31 +01:00
Shakker
b596c484e4 test: require single oc-path diagnostic 2026-05-11 23:53:16 +01:00
Peter Steinberger
36a4ed5956 test: guard infra process mock calls 2026-05-11 23:52:14 +01:00
Peter Steinberger
995d5ef16f test: guard provider usage mock calls 2026-05-11 23:51:03 +01:00
Peter Steinberger
7c81310b99 test: guard voice call twilio mock calls 2026-05-11 23:49:36 +01:00
Shakker
aef3a39561 test: specify googlechat directory entries 2026-05-11 23:48:52 +01:00
Shakker
424666d5ea test: specify msteams directory entries 2026-05-11 23:47:02 +01:00
Peter Steinberger
b0ee88bc94 test: guard infra net mock calls 2026-05-11 23:46:43 +01:00
Shakker
b4cb08c71a test: require actionable compat text 2026-05-11 23:45:19 +01:00
Peter Steinberger
e3dcb6cf66 test: guard ui gateway mock calls 2026-05-11 23:44:01 +01:00
Shakker
9be43d5a8d test: enumerate no-env model providers 2026-05-11 23:43:46 +01:00
Shakker
f82da6cb42 test: spell stream error sentinel 2026-05-11 23:42:12 +01:00
Peter Steinberger
0b0c43d2e4 test: guard ui sidebar mock calls 2026-05-11 23:41:37 +01:00
Shakker
a1fe0bd91b test: require single plugin tool load 2026-05-11 23:40:51 +01:00
Peter Steinberger
b0946c1a4e test: guard respawn and image mock calls 2026-05-11 23:39:59 +01:00
Shakker
376f93b62b test: match plugin registry inventory 2026-05-11 23:39:34 +01:00
Peter Steinberger
9c9b288ca9 test: guard command setup mock calls 2026-05-11 23:38:10 +01:00
Peter Steinberger
b433e643bb test: guard media understanding mock calls 2026-05-11 23:36:13 +01:00
Shakker
bffa49705e test: preserve NVIDIA provider model 2026-05-11 23:34:34 +01:00
Peter Steinberger
db7a981f4d test: guard chat view mock attachments 2026-05-11 23:33:55 +01:00
Shakker
c1f10e42ef test: compare DeepInfra fallback catalog 2026-05-11 23:33:10 +01:00
Peter Steinberger
5f2bd36180 test: guard realtime talk mock events 2026-05-11 23:32:23 +01:00
Shakker
ddf83d16f7 test: specify Kilo static catalog 2026-05-11 23:31:53 +01:00
Josh Lehman
4bfd7416f0 fix: stabilize code-mode follow-up tool display and replay (#80663)
* fix: project tool-search bridge event display

* fix: keep codex tool progress out of final replies

* fix: preserve tool result pairs on cleanup

* fix: restore tool search display target helper

* fix: keep tool search controls independent

* fix: render bridged tool calls like native tools

* fix: abort timed out tool search bridge calls

* fix: preserve code-mode tool results across display turns

* fix: repair missing code-mode tool results on disk

* fix: expose tool search controls in embedded runs

* docs: add code-mode followups changelog

* fix: update session repair agent-core import

* fix: harden code-mode follow-up repair

* fix: use stable session repair ids

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-11 15:31:35 -07:00
Peter Steinberger
1786d60cf8 test: guard ui controller mock calls 2026-05-11 23:30:37 +01:00
Eva
f7ab8c26b1 fix(codex): scale context engine projection (#80761)
* fix(codex): scale context engine projection

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* fix: document Codex context projection scaling

* chore: align Codex projection changelog

* chore: realign Codex projection changelog

* fix: isolate Codex projection patch

---------

Co-authored-by: Eva (agent) <eva+agent-78055@100yen.org>
Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-05-11 15:29:59 -07:00
Shakker
6a8ef7b6cf test: spell inline provider header model 2026-05-11 23:29:47 +01:00
Peter Steinberger
a51a9631cc test: guard tooling mock call fallbacks 2026-05-11 23:28:57 +01:00
Shakker
df99502a2a test: check OpenAI thinking option values 2026-05-11 23:28:10 +01:00
Peter Steinberger
fceea8caed test: guard proxy fetch mock calls 2026-05-11 23:26:09 +01:00
Shakker
17afb47c4d test: require session slot diagnostics 2026-05-11 23:25:44 +01:00
Shakker
0eafe995bc test: verify voice call command activation 2026-05-11 23:24:33 +01:00
Shakker
2e7794d803 test: check skipped stream chunks exactly 2026-05-11 23:23:16 +01:00
Peter Steinberger
07a732572b test: guard channel command mock calls 2026-05-11 23:22:13 +01:00
Shakker
cc72279b5a test: record priority model refs 2026-05-11 23:21:55 +01:00
Sarah Fortune
ce2eb4c367 fix: Fix the build: annotate provider-http test-helper exports for portable dts (#80781)
* fix: annotate provider-http test-helper exports for portable dts

* ci: retrigger

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:21:44 -07:00
Josh Lehman
24ffd4d2f8 Telegram: keep verbose tool results separate from final answers (#80294)
* Telegram: keep tool progress separate from final answers

* Telegram: separate verbose tool results from final answers

* fix: separate Telegram verbose tool drafts
2026-05-11 15:21:19 -07:00
Peter Steinberger
d3edbaabcb test: guard utility mock call helpers 2026-05-11 23:20:17 +01:00
Peter Steinberger
ccce9aa417 test: guard core mock call reads 2026-05-11 23:18:51 +01:00
Peter Steinberger
920a27aa6f test: guard provider request mock calls 2026-05-11 23:17:09 +01:00
Peter Steinberger
5c59bd6987 test: guard qa and telnyx fetch mock calls 2026-05-11 23:12:57 +01:00
Peter Steinberger
dbf0458d1b test: guard memory lancedb mock calls 2026-05-11 23:11:02 +01:00
Peter Steinberger
b9920447ca test: guard ui chat avatar fetch calls 2026-05-11 23:09:57 +01:00
Peter Steinberger
d7735c607c test: guard tlon upload mock calls 2026-05-11 23:08:43 +01:00
Peter Steinberger
fe1f30bfd6 test: guard zalouser payload mock calls 2026-05-11 23:07:36 +01:00
Peter Steinberger
7d7751edc5 test: guard zalouser send mock calls 2026-05-11 23:06:28 +01:00
Peter Steinberger
c4259b2697 test: guard byteplus video mock calls 2026-05-11 23:05:09 +01:00
Kevin Lin
e0824397b8 docs: add refactor docs skill (#80791) 2026-05-11 15:03:54 -07:00
Peter Steinberger
70818bf252 test: guard mantle discovery mock calls 2026-05-11 23:03:28 +01:00
Peter Steinberger
0ed551eac0 test: guard utility mock call helpers 2026-05-11 23:02:07 +01:00
Peter Steinberger
832a337857 test: guard runway video mock calls 2026-05-11 23:00:50 +01:00
Peter Steinberger
c8e5030d29 test: guard copilot embedding mock calls 2026-05-11 22:58:45 +01:00
Peter Steinberger
b3b692829d test: guard xai mock fetch calls 2026-05-11 22:57:32 +01:00
Peter Steinberger
1923db6dac fix: normalize exact Gemini proxy refs 2026-05-11 22:54:42 +01:00
Shakker
37d018c6d9 test: expand inline provider model rows 2026-05-11 22:51:21 +01:00
Peter Steinberger
21fdc729ac test: guard outbound target calls 2026-05-11 22:49:57 +01:00
Shakker
7b8245a820 test: finish anthropic turn merge row 2026-05-11 22:48:48 +01:00
Shakker
eec0d16458 test: complete backup asset helper 2026-05-11 22:47:10 +01:00
Peter Steinberger
1c03a34813 test: guard outbound media calls 2026-05-11 22:46:23 +01:00
Peter Steinberger
7e97ddcd51 test: guard outbound helper calls 2026-05-11 22:44:35 +01:00
Shakker
db084a8f29 test: spell out agents list rows 2026-05-11 22:44:11 +01:00
Peter Steinberger
60e5804a9d test: guard windows exec spawn call 2026-05-11 22:42:30 +01:00
Shakker
c60a4c9552 test: order sandbox status lookups 2026-05-11 22:41:48 +01:00
Peter Steinberger
c69b58157f test: guard process child adapter calls 2026-05-11 22:41:27 +01:00
Peter Steinberger
ca6a513c55 test: guard process queue calls 2026-05-11 22:40:24 +01:00
Shakker
ad84d5c130 test: expose filtered session row shape 2026-05-11 22:38:40 +01:00
Peter Steinberger
2b90adb45f test: guard infra utility calls 2026-05-11 22:38:32 +01:00
Peter Steinberger
8f730667ce test: guard node host invoke calls 2026-05-11 22:37:00 +01:00
Peter Steinberger
70a0236ccc test: guard process spawn calls 2026-05-11 22:36:06 +01:00
Shakker
31d2d13076 test: fill plugin registry repair records 2026-05-11 22:35:53 +01:00
Peter Steinberger
95752bef68 test: guard group policy warning call 2026-05-11 22:34:48 +01:00
Peter Steinberger
2b2664f17f test: guard logging mock calls 2026-05-11 22:34:04 +01:00
Shakker
ec40e36ada test: verify degraded gateway json 2026-05-11 22:33:16 +01:00
Peter Steinberger
e241aedbcf test: guard secrets channel collector calls 2026-05-11 22:32:29 +01:00
Shakker
f1ccfd87b9 test: define external cli profile envelopes 2026-05-11 22:31:44 +01:00
Peter Steinberger
671f0e653f test: guard task registry calls 2026-05-11 22:31:20 +01:00
Peter Steinberger
fc9b8c94a9 test: guard detached task runtime calls 2026-05-11 22:30:10 +01:00
Shakker
8e793e2bce test: lock cache trace events 2026-05-11 22:29:45 +01:00
Peter Steinberger
41cd36fe6c test: guard media fetch call 2026-05-11 22:29:04 +01:00
Peter Steinberger
0f616dc054 test: guard media understanding calls 2026-05-11 22:28:21 +01:00
Shakker
95fa1bba60 test: detail covered backup assets 2026-05-11 22:27:21 +01:00
Peter Steinberger
ac15f1887f test: guard channel mock calls 2026-05-11 22:27:00 +01:00
Peter Steinberger
597b65e93e test: guard talk consult call helper 2026-05-11 22:24:45 +01:00
Shakker
b5d12bb892 test: shape allowed agents payload 2026-05-11 22:24:01 +01:00
Peter Steinberger
e5fa72c3ce test: guard memory host post json calls 2026-05-11 22:23:55 +01:00
Peter Steinberger
c6eefd9f4d test: guard cron auth profile helper 2026-05-11 22:22:48 +01:00
Peter Steinberger
3f75797de7 test: guard cron skill filter calls 2026-05-11 22:21:53 +01:00
Shakker
0fd1ed9853 test: specify memory append result 2026-05-11 22:21:26 +01:00
Peter Steinberger
f9ba1d6d41 test: guard cron message tool calls 2026-05-11 22:20:10 +01:00
Shakker
c512297f4f test: list refreshed catalog entries 2026-05-11 22:19:16 +01:00
Peter Steinberger
933a597f66 test: guard cron stale enqueue call 2026-05-11 22:18:58 +01:00
Peter Steinberger
a03382181c test: guard cron model override call 2026-05-11 22:17:55 +01:00
Shakker
7a7b2316e1 test: enumerate setup discovery entries 2026-05-11 22:17:23 +01:00
Peter Steinberger
07e3fd5c9c test: guard cron live-session retry call 2026-05-11 22:16:02 +01:00
Shakker
bcc2b8cffa test: place pricing status row 2026-05-11 22:15:34 +01:00
Peter Steinberger
0ce6816ed3 test: guard cron interim retry calls 2026-05-11 22:14:54 +01:00
Shakker
cb12d47513 test: trace task audit finding rows 2026-05-11 22:13:15 +01:00
Peter Steinberger
f8a401d900 test: guard cron fallback requests 2026-05-11 22:13:05 +01:00
Peter Steinberger
53a26dc858 test: guard cron owner auth calls 2026-05-11 22:12:06 +01:00
Shakker
3398369788 test: frame missing channel rows 2026-05-11 22:11:02 +01:00
Peter Steinberger
43ad5ddca0 test: guard cron auth profile call 2026-05-11 22:10:40 +01:00
Peter Steinberger
fdb0b49354 test: guard cron heartbeat requests 2026-05-11 22:09:36 +01:00
Shakker
8dd301c0af test: map task audit json 2026-05-11 22:09:17 +01:00
Peter Steinberger
fe0bb3083e test: guard cron preflight fetch call 2026-05-11 22:08:10 +01:00
Shakker
38a3cf4f01 test: outline approval request payloads 2026-05-11 22:07:16 +01:00
Peter Steinberger
08f176cc6c test: guard talkback consult calls 2026-05-11 22:06:50 +01:00
Peter Steinberger
7eb108abd6 test: centralize talkback timer cleanup 2026-05-11 22:05:35 +01:00
Peter Steinberger
7b21f4d864 test: guard cron due enqueue call 2026-05-11 22:04:23 +01:00
Shakker
44290c7afa test: check external cli reader options 2026-05-11 22:03:57 +01:00
Peter Steinberger
90200d30fd test: guard commitment extractor request 2026-05-11 22:03:20 +01:00
Peter Steinberger
8b112abf61 test: guard cron session mock calls 2026-05-11 22:02:19 +01:00
Shakker
5de295ca84 test: chart os scoped skill status 2026-05-11 22:01:26 +01:00
Peter Steinberger
dc5fedeae0 test: avoid browser tab module reset 2026-05-11 21:59:40 +01:00
Shakker
6e32c06ac5 test: capture media duplicate guidance 2026-05-11 21:58:52 +01:00
Peter Steinberger
82b6885552 test: avoid provider flow module reset 2026-05-11 21:58:10 +01:00
Peter Steinberger
edcb53ec1f test: avoid env module reset 2026-05-11 21:56:41 +01:00
Shakker
ac9732cff4 test: record api error fingerprints 2026-05-11 21:56:29 +01:00
Peter Steinberger
4d68faba62 test: avoid config state module resets 2026-05-11 21:55:27 +01:00
Shakker
8755c1874c test: mirror flow list json 2026-05-11 21:54:36 +01:00
Peter Steinberger
ae304ec688 test: remove stale route reset comment 2026-05-11 21:53:26 +01:00
Sarah Fortune
b05c9c0215 feat(discord): remove harness runtime dropdown from /models picker (#80766)
* feat(discord): remove harness runtime dropdown from /models picker

* ci: retrigger checks
2026-05-11 13:53:21 -07:00
Shakker
cbc620be37 test: cover channels status timeout request 2026-05-11 21:52:43 +01:00
Peter Steinberger
d18e5247fe test: avoid memory fts module resets 2026-05-11 21:51:50 +01:00
Shakker
4dbd5558da test: compare guard redaction messages 2026-05-11 21:51:00 +01:00
Peter Steinberger
95631b1e68 test: avoid media registry module resets 2026-05-11 21:49:38 +01:00
Shakker
ba90ee6b49 test: include transcript update ids 2026-05-11 21:49:26 +01:00
Peter Steinberger
935cf2088d test: dedupe memory lancedb mock harness 2026-05-11 21:47:43 +01:00
Shakker
2959753780 test: match task list json records 2026-05-11 21:47:10 +01:00
Peter Steinberger
1faeb89710 test: use gemini 3.1 in neutral fixtures 2026-05-11 21:45:36 +01:00
Shakker
d0e7df343e test: seal auth list json 2026-05-11 21:44:42 +01:00
Shakker
b9722dcea7 test: verify sandbox json payload 2026-05-11 21:42:40 +01:00
Shakker
5829694fcb test: compare tool mutation keys 2026-05-11 21:41:15 +01:00
Shakker
588ba22db2 test: check router model choices 2026-05-11 21:39:43 +01:00
Peter Steinberger
c4abfa6a9e test: reset telegram message cache directly 2026-05-11 21:39:00 +01:00
Peter Steinberger
b8c3a0b14b test: avoid copilot model module resets 2026-05-11 21:37:05 +01:00
Shakker
fd6059bb28 test: list onboarding hook notes 2026-05-11 21:36:56 +01:00
Peter Steinberger
d865d3a6de test: avoid auth profile module resets 2026-05-11 21:35:41 +01:00
Shakker
010934efe7 test: render oauth tls remediation 2026-05-11 21:34:48 +01:00
Shakker
d0ae1cd07e test: verify repaired session records 2026-05-11 21:32:57 +01:00
Peter Steinberger
00d807c67b test: guard xai live null helper 2026-05-11 21:31:43 +01:00
Shakker
3cb51b258d test: detail transcript redaction output 2026-05-11 21:31:21 +01:00
Peter Steinberger
23b5854fd9 test: guard ui chat null elements 2026-05-11 21:30:46 +01:00
Shakker
68d5a7dc9d test: compare camera image blocks 2026-05-11 21:29:26 +01:00
Peter Steinberger
12227ccf0a test: guard metadata wizard null checks 2026-05-11 21:28:48 +01:00
Shakker
a9fcdf727a test: quote tool policy warnings 2026-05-11 21:27:48 +01:00
Peter Steinberger
07f4b7130f test: guard oc-path null results 2026-05-11 21:27:05 +01:00
Shakker
c6668deb44 test: preserve google cache entry shape 2026-05-11 21:26:34 +01:00
Peter Steinberger
a67507eb04 test: guard chat extension null helpers 2026-05-11 21:25:32 +01:00
Shakker
f7b99c2a7c test: capture session cleanup json 2026-05-11 21:24:49 +01:00
Shakker
8687e29fee test: record model merge outputs 2026-05-11 21:23:28 +01:00
Peter Steinberger
f56fae7b1e test: guard agent runner null helpers 2026-05-11 21:23:01 +01:00
Shakker
50f51a71cb test: catalog stale lock cleanup records 2026-05-11 21:22:02 +01:00
Peter Steinberger
baa2776900 test: guard core agent null helpers 2026-05-11 21:20:59 +01:00
Shakker
e9f760027a test: map turn validation merges 2026-05-11 21:20:21 +01:00
Kevin Lin
d06e85b0aa fix(codex): match connector app approvals by id 2026-05-11 13:19:56 -07:00
Peter Steinberger
6eccb0d3bf test: guard extension helper null checks 2026-05-11 21:18:51 +01:00
Shakker
bbd3ccf8e6 test: describe cli image path reuse 2026-05-11 21:17:27 +01:00
Peter Steinberger
32b8925cfa test: guard core sdk null helpers 2026-05-11 21:16:17 +01:00
Shakker
bff97df6e5 test: show replay tail drops 2026-05-11 21:14:38 +01:00
Peter Steinberger
e7f9f3ba63 test: guard agent tool null helpers 2026-05-11 21:12:24 +01:00
Shakker
30323f37f4 test: outline inline provider records 2026-05-11 21:12:17 +01:00
Peter Steinberger
427372b3f9 test: guard auto reply null helpers 2026-05-11 21:10:16 +01:00
Shakker
2b69b487ac test: name pty hex warnings 2026-05-11 21:08:51 +01:00
Peter Steinberger
e19c7ab95e test: guard cli null helpers 2026-05-11 21:07:53 +01:00
Shakker
e986012043 test: spell out bootstrap file records 2026-05-11 21:06:36 +01:00
Peter Steinberger
ed0aa3784e test: guard infra cron secrets helpers 2026-05-11 21:06:03 +01:00
Shakker
e794b79e23 test: show os scoped skill status 2026-05-11 21:04:30 +01:00
Peter Steinberger
faa74ac1e8 test: guard extension channel helpers 2026-05-11 21:04:13 +01:00
Shakker
eea3f6dc4b test: expose redacted attachment payload 2026-05-11 21:02:15 +01:00
Peter Steinberger
2d0c3750d8 test: guard extension provider helpers 2026-05-11 21:01:56 +01:00
Shakker
9bca3a1325 test: identify media status content 2026-05-11 21:00:32 +01:00
Peter Steinberger
905861c4e0 test: guard command object helpers 2026-05-11 20:59:38 +01:00
Shakker
3eb5070817 test: enumerate agents list details 2026-05-11 20:58:28 +01:00
Peter Steinberger
18c56ef143 test: guard gateway object helpers 2026-05-11 20:57:56 +01:00
Shakker
10492a2559 test: map text transform merges 2026-05-11 20:56:47 +01:00
Peter Steinberger
8604774347 test: guard plugin object helpers 2026-05-11 20:56:22 +01:00
Shakker
1b92d8f8c4 test: spell out thinking option captures 2026-05-11 20:54:45 +01:00
Peter Steinberger
9583c37e8b test: guard cli infra object helpers 2026-05-11 20:53:54 +01:00
Shakker
76468cc145 test: describe channel setup entries 2026-05-11 20:53:14 +01:00
Peter Steinberger
10c2a8a311 test: guard message helper nullish deps 2026-05-11 20:52:29 +01:00
Shakker
911d3e969a test: specify finished process records 2026-05-11 20:51:20 +01:00
Peter Steinberger
5899db7b1c test: consolidate group runtime reset coverage 2026-05-11 20:51:10 +01:00
Peter Steinberger
93dd5e61ba test: guard multiline helper assertions 2026-05-11 20:49:23 +01:00
Shakker
6e1e057e88 test: describe runner payload arrays 2026-05-11 20:49:01 +01:00
Peter Steinberger
63af3bcfdb test: guard remaining truthiness assertions 2026-05-11 20:45:49 +01:00
Shakker
23f8c38ba5 test: define session tool records 2026-05-11 20:45:23 +01:00
Shakker
164031f73f test: specify exec approval shortcut 2026-05-11 20:43:10 +01:00
Shakker
873c436841 test: capture cache trace fingerprints 2026-05-11 20:40:56 +01:00
Peter Steinberger
bad097f34b test: guard agents gateway infra truthiness assertions 2026-05-11 20:40:32 +01:00
Shakker
3049576fce test: record bootstrap signature files 2026-05-11 20:38:55 +01:00
Shakker
e793b65073 test: refine external cli sync helpers 2026-05-11 20:37:07 +01:00
Peter Steinberger
ad907871f9 test: guard core truthiness assertions 2026-05-11 20:35:33 +01:00
Shakker
62c21c4cee test: detail transcript update events 2026-05-11 20:35:06 +01:00
Shakker
0e22935c4a test: verify auth repair messages 2026-05-11 20:32:43 +01:00
Peter Steinberger
0398875044 test: guard ui truthiness assertions 2026-05-11 20:32:04 +01:00
Shakker
c21516372d test: document model probe plans 2026-05-11 20:30:54 +01:00
Peter Steinberger
fc10ac838b fix: normalize nested gemini config refs 2026-05-11 20:29:47 +01:00
Peter Steinberger
3c9fbf7071 test: guard ui tooling assertions 2026-05-11 20:29:47 +01:00
Shakker
b6027cb40e test: exercise command json payloads 2026-05-11 20:28:28 +01:00
Shakker
0961d5c8a8 test: characterize plugin registry repairs 2026-05-11 20:26:41 +01:00
Shakker
2bb4e23ea1 test: describe plugin manifest migrations 2026-05-11 20:24:14 +01:00
Shakker
7def30cbb1 test: cover doctor fallback warnings 2026-05-11 20:22:53 +01:00
Peter Steinberger
4981f8ecbc test: guard agents helper assertions 2026-05-11 20:22:47 +01:00
Shakker
70898621e3 test: inspect command json records 2026-05-11 20:21:08 +01:00
Peter Steinberger
5b4940e41c test: guard auto-reply helper assertions 2026-05-11 20:19:34 +01:00
Shakker
1c9dc55e12 test: check backup asset records 2026-05-11 20:18:44 +01:00
Shakker
02e4e0ccbb test: check agent binding records 2026-05-11 20:17:12 +01:00
Peter Steinberger
5f00135a44 test: guard support helper assertions 2026-05-11 20:16:47 +01:00
Shakker
1461b748d8 test: check task json items 2026-05-11 20:15:32 +01:00
Val Alexander
51b73b39a8 fix(auth): align operator bootstrap scopes
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes #79292.
Supersedes #79314, #79296, #79295.
2026-05-11 14:14:33 -05:00
Shakker
0fa4b2fb46 test: check status json audit shape 2026-05-11 20:13:37 +01:00
Peter Steinberger
a644d5dd46 test: guard gateway helper assertions 2026-05-11 20:13:19 +01:00
Shakker
8e75adebe3 test: specify doctor warning text 2026-05-11 20:11:43 +01:00
Peter Steinberger
6b32f6f283 test: guard cli helper assertions 2026-05-11 20:11:18 +01:00
Shakker
aa2596da8b test: verify safe-bin trust hints 2026-05-11 20:10:03 +01:00
Peter Steinberger
0e82b77857 test: guard plugin loader diagnostics 2026-05-11 20:08:19 +01:00
Shakker
94b0695c98 test: capture codex repair summaries 2026-05-11 20:08:09 +01:00
Peter Steinberger
3dd2c1a8b8 test: guard plugin diagnostic assertions 2026-05-11 20:07:14 +01:00
Shakker
eafdbe885f test: record codex route warnings 2026-05-11 20:06:39 +01:00
Peter Steinberger
866c39daea test: guard plugin helper assertions 2026-05-11 20:05:15 +01:00
Shakker
599144b386 test: verify legacy gateway origins 2026-05-11 20:04:53 +01:00
Peter Steinberger
3b4f7adcd9 test: guard tasks and media assertions 2026-05-11 20:03:37 +01:00
Shakker
becc5f5238 test: check legacy migration notes 2026-05-11 20:03:02 +01:00
Peter Steinberger
f9140b30bf test: guard config diagnostics assertions 2026-05-11 20:02:10 +01:00
Shakker
3431607673 test: cover repair note ordering 2026-05-11 20:01:39 +01:00
Peter Steinberger
fb0c525215 test: guard cron helper assertions 2026-05-11 20:00:46 +01:00
Peter Steinberger
1365b71f02 test: guard infra helper assertions 2026-05-11 19:59:48 +01:00
Shakker
630c9fe531 test: verify legacy validation changes 2026-05-11 19:58:48 +01:00
Peter Steinberger
c3dba18730 test: guard channel record helpers 2026-05-11 19:57:25 +01:00
Shakker
085b2d0727 test: verify plugin cleanup changes 2026-05-11 19:57:03 +01:00
Shakker
0573b231ef test: verify allowlist scan warnings 2026-05-11 19:55:33 +01:00
Peter Steinberger
ad1e6c4485 test: guard telegram helper assertions 2026-05-11 19:55:21 +01:00
Shakker
daad0cc834 test: verify config flow hints 2026-05-11 19:54:03 +01:00
Shakker
9924fff1af test: verify channel migration changes 2026-05-11 19:52:49 +01:00
Peter Steinberger
3240aa7399 test: rely on codex approval event guard 2026-05-11 19:52:45 +01:00
Mariano
8c75ed3eaa Mirror Codex native subagents into task registry (#79512)
Merged via squash.

Prepared head SHA: 75bc96ad74
Co-authored-by: mbelinky <mbelinky@users.noreply.github.com>
Co-authored-by: marianobelinky <63976030+marianobelinky@users.noreply.github.com>
Reviewed-by: @pashpashpash
2026-05-11 20:52:41 +02:00
Shakker
ba03d637ea test: verify skills status note 2026-05-11 19:51:39 +01:00
Peter Steinberger
b1a98701cf test: guard mantle fetch assertion 2026-05-11 19:51:29 +01:00
Peter Steinberger
60bda15223 test: check zalouser warning content 2026-05-11 19:50:38 +01:00
Shakker
6873f07e36 test: verify bootstrap size note 2026-05-11 19:50:21 +01:00
Peter Steinberger
a9a196e325 test: guard discord monitor assertions 2026-05-11 19:49:39 +01:00
Shakker
aab10f5e2d test: verify health formatter lines 2026-05-11 19:49:17 +01:00
Peter Steinberger
60cdb99733 test: guard browser dispatcher assertions 2026-05-11 19:48:44 +01:00
Shakker
06f7adf12a test: verify startup note text 2026-05-11 19:47:50 +01:00
Peter Steinberger
199838616c test: guard signal helper assertions 2026-05-11 19:47:34 +01:00
Shakker
f2bb32f09f test: verify default account warnings 2026-05-11 19:46:31 +01:00
Peter Steinberger
880530dd9f test: guard matrix call assertions 2026-05-11 19:46:12 +01:00
Shakker
d16e28c9e1 test: verify gateway status warning 2026-05-11 19:45:13 +01:00
Peter Steinberger
cd9f0b97f8 test: guard matrix helper assertions 2026-05-11 19:44:42 +01:00
Shakker
4c7bffc3a7 fix: remove OSC payloads from terminal text 2026-05-11 19:44:08 +01:00
Peter Steinberger
0793775a66 test: guard channel provider helpers 2026-05-11 19:41:21 +01:00
Shakker
a091a77dbd test: verify cleanup dry run logs 2026-05-11 19:40:42 +01:00
Peter Steinberger
88673b2fad test: guard gateway runtime assertions 2026-05-11 19:40:00 +01:00
Shakker
9d0669cfa3 test: verify gateway auth diagnostics 2026-05-11 19:39:42 +01:00
Shakker
2e5acf12b8 test: verify doctor repair notes 2026-05-11 19:38:09 +01:00
Peter Steinberger
4b6e1373f6 test: guard extension lookup helpers 2026-05-11 19:38:00 +01:00
Peter Steinberger
c7584d5dc7 test: guard codex relay registrations 2026-05-11 19:36:35 +01:00
AI-HUB
738f78519a fix(browser): skip internal CDP targets (#80629) 2026-05-11 19:36:22 +01:00
Shakker
a9991f0d22 test: verify gateway probe summaries 2026-05-11 19:35:33 +01:00
Peter Steinberger
c741d92d06 test: guard discord qa helpers 2026-05-11 19:34:50 +01:00
AI-HUB
578fad471a docs(subagents): document announce timeout (#75509)
Document agents.defaults.subagents.announceTimeoutMs in the sub-agent and configuration references, and align the exported type comment with the runtime default.

Thanks @akrimm702.

Co-authored-by: AI-HUB <144416483+akrimm702@users.noreply.github.com>
2026-05-11 19:33:50 +01:00
Shakker
4b6798d546 test: verify sessions option errors 2026-05-11 19:33:37 +01:00
Peter Steinberger
fa183bbe0b test: guard core helper assertions 2026-05-11 19:32:41 +01:00
Shakker
174ea9d0e4 test: verify ACP default modes 2026-05-11 19:31:41 +01:00
Peter Steinberger
4fb37c9a2d test: guard browser helper assertions 2026-05-11 19:31:28 +01:00
Peter Steinberger
864f30f868 test: guard provider helper assertions 2026-05-11 19:30:04 +01:00
Shakker
5be22e7781 test: verify Claude session rows 2026-05-11 19:29:41 +01:00
Peter Steinberger
fdd902b25e test: guard send handler mock calls 2026-05-11 19:28:33 +01:00
Shakker
8b53bee24b test: verify channel docs link 2026-05-11 19:28:07 +01:00
Peter Steinberger
ba3459bdf1 test: guard msteams test helpers 2026-05-11 19:26:28 +01:00
Shakker
5dde25c7a9 test: verify ACP error guidance 2026-05-11 19:26:10 +01:00
Shakker
260be33c3e test: verify ACP session detail lines 2026-05-11 19:24:48 +01:00
Peter Steinberger
0322821837 test: guard messaging test helpers 2026-05-11 19:24:44 +01:00
Shakker
6290050645 test: verify service exec command 2026-05-11 19:23:10 +01:00
Peter Steinberger
afac1486bf test: guard voice call test lookups 2026-05-11 19:22:58 +01:00
Shakker
22657f598e test: verify gateway fallback detail 2026-05-11 19:21:52 +01:00
Peter Steinberger
2caa0d6b4f test: guard feishu mock helpers 2026-05-11 19:21:39 +01:00
Shakker
0aee7e4db2 test: verify setup output shape 2026-05-11 19:20:19 +01:00
Peter Steinberger
e17dfb0014 test: guard extension mock helpers 2026-05-11 19:19:27 +01:00
Shakker
dea7ab00df test: verify config advisory body 2026-05-11 19:18:51 +01:00
Shakker
7ee8e0b641 test: cover channel capabilities output 2026-05-11 19:17:22 +01:00
Peter Steinberger
bc92264cd9 test: guard mock lookup helpers 2026-05-11 19:16:35 +01:00
Shakker
cc84606946 test: cover sessions table rows 2026-05-11 19:15:49 +01:00
Shakker
fd82a8c3b4 test: verify gateway SecretRef errors 2026-05-11 19:13:24 +01:00
Peter Steinberger
4da11520c8 test: remove redundant defined guards 2026-05-11 19:13:20 +01:00
Shakker
81db4aca42 test: cover channel diagnostic text 2026-05-11 19:11:46 +01:00
Peter Steinberger
8f1c044e7e test: guard plugin record helpers 2026-05-11 19:10:49 +01:00
Shakker
53f95e25fd test: check remote websocket warning 2026-05-11 19:10:32 +01:00
Peter Steinberger
a2c62b594c test: guard record helper assertions 2026-05-11 19:08:59 +01:00
Shakker
d0edacad5b test: check daemon runtime summary 2026-05-11 19:08:18 +01:00
Peter Steinberger
d8f39ce2ee test: guard remaining mock call helpers 2026-05-11 19:07:15 +01:00
Shakker
4f02ce5242 test: check sandbox explain arrays 2026-05-11 19:06:16 +01:00
Peter Steinberger
a2b36587dd test: guard gateway mock call helpers 2026-05-11 19:05:19 +01:00
Shakker
95950d5522 test: remove duplicate owner checks 2026-05-11 19:04:17 +01:00
Peter Steinberger
03b36f096b test: guard agent helper mock reads 2026-05-11 19:03:16 +01:00
Shakker
e89fb601a7 test: check nested delivery logs 2026-05-11 19:03:01 +01:00
Peter Steinberger
f27bd16cc0 test: guard command mock arg helpers 2026-05-11 19:02:03 +01:00
Shakker
baefffda69 test: check ACP resource link text 2026-05-11 19:01:00 +01:00
Peter Steinberger
c3b9f8cf19 test: guard server cron mock args 2026-05-11 19:00:55 +01:00
Shakker
12ac83c61f test: check browser doctor warning 2026-05-11 18:59:35 +01:00
jesse-merhi
79c2ed9065 feat: make exec command highlighting optional 2026-05-12 03:59:30 +10:00
Peter Steinberger
38de1a7518 test: guard gateway status helper records 2026-05-11 18:59:06 +01:00
Shakker
6748192d64 test: check gateway allowed origins 2026-05-11 18:58:10 +01:00
Peter Steinberger
7f89b074ed test: guard http header mock calls 2026-05-11 18:57:49 +01:00
Peter Steinberger
a346e8c4c5 test: guard skills upload call helper 2026-05-11 18:56:54 +01:00
Shakker
445ca84239 test: check TaskFlow command output 2026-05-11 18:56:41 +01:00
Peter Steinberger
e25283f7c7 test: guard command prompt call helpers 2026-05-11 18:55:42 +01:00
Peter Steinberger
82a243d7b6 test: guard codex record assertions 2026-05-11 18:54:47 +01:00
Shakker
cfeb7703b5 test: check ACP policy messages 2026-05-11 18:54:43 +01:00
Peter Steinberger
0bb4ef5fd3 test: guard context engine mock args 2026-05-11 18:53:24 +01:00
Peter Steinberger
ff5bbac349 test: guard model test record assertions 2026-05-11 18:52:02 +01:00
Peter Steinberger
79d9683afa test: guard compact hook records 2026-05-11 18:50:17 +01:00
Peter Steinberger
6bb5c9f957 test: fail fast on overflow compaction calls 2026-05-11 18:49:23 +01:00
Peter Steinberger
bf8bcae8b2 test: fail fast on google prompt cache calls 2026-05-11 18:48:18 +01:00
Peter Steinberger
ee0760172d test: fix overflow compaction mock call typing (#75117) 2026-05-11 18:47:46 +01:00
Peter Steinberger
b9aee95591 docs: add cron get changelog (#75117) (thanks @samzong) 2026-05-11 18:47:46 +01:00
samzong
380a679313 feat(cron): add direct job lookup
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 18:47:46 +01:00
Peter Steinberger
dc83a10733 test: tighten skip discovery hook assertions 2026-05-11 18:47:16 +01:00
Omar Shahine
efc8641393 fix: add channel status filtering (#80706)
Summary:
- Add `openclaw channels status --channel <name>` filtering through CLI, gateway protocol, and fallback status rendering.
- Document the BlueBubbles-to-iMessage cutover path so operators can probe iMessage without starting both monitors.
- Refresh generated Swift protocol model for the new optional channel status parameter.

Verification:
- `pnpm test src/gateway/server-methods/channels.status.test.ts src/commands/channels.status.command-flow.test.ts src/cli/program/routes.test.ts -- --reporter=verbose`
- `CI=true pnpm check:docs`
- `pnpm protocol:check`
- `git diff --check`
- `node scripts/check-changelog-attributions.mjs`
- CI head `45b27e3866`: focused/docs/protocol shards green locally; GitHub broad/scanner jobs queued for runners at merge attempt time; `Real behavior proof` failure is the maintainer-ignorable external-real-proof complaint.
2026-05-11 18:44:54 +01:00
Peter Steinberger
dca801c6c4 docs: update changelog for node 26 build warning (#78584) 2026-05-11 18:44:29 +01:00
Kelaw - Keshav's Agent
b9ec75fb6f Fix Node 26 build deprecation warnings 2026-05-11 18:44:29 +01:00
Peter Steinberger
3775532a29 test: wait for live model switch cleanup by assertion 2026-05-11 18:42:09 +01:00
Peter Steinberger
1533324a5a test: use immediate for browser websocket close fixtures 2026-05-11 18:41:00 +01:00
Peter Steinberger
ad5549a57b test: use immediate for browser cdp close fixtures 2026-05-11 18:39:43 +01:00
Peter Steinberger
2e7d9e2290 test: use immediate for bash abort turn 2026-05-11 18:38:32 +01:00
Peter Steinberger
07795d57fe test: wait for discord voice tool results by assertion 2026-05-11 18:36:02 +01:00
samzong
df30515315 feat(acp): expose session lineage metadata
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 18:32:46 +01:00
Peter Steinberger
61e787724c test: use immediate for telegram webhook yields 2026-05-11 18:32:20 +01:00
Peter Steinberger
85b668e9ee test: collapse restart sentinel timer retries 2026-05-11 18:30:19 +01:00
Peter Steinberger
36a36d6fde test: use immediate for realtime consult event 2026-05-11 18:29:12 +01:00
Peter Steinberger
3f08c7f0f1 test: wait for acp chat sends by assertion 2026-05-11 18:26:37 +01:00
Peter Steinberger
8d7687663b test: wait for google chat monitor by assertion 2026-05-11 18:25:07 +01:00
Shakker
a66d8ffe75 test: cover CLI spawn cleanup 2026-05-11 18:24:15 +01:00
Peter Steinberger
ef8fd8f2e3 test: use immediate for feishu pending races 2026-05-11 18:24:03 +01:00
Peter Steinberger
309f000341 docs: format Codex harness options 2026-05-11 18:23:00 +01:00
Peter Steinberger
694f40fcee fix: constrain Codex app-server sandbox 2026-05-11 18:23:00 +01:00
Peter Steinberger
68609ea3bd test: use immediate for chat refresh race 2026-05-11 18:22:06 +01:00
Peter Steinberger
b5bae1b96e test: use immediate for settings refresh race 2026-05-11 18:20:22 +01:00
Peter Steinberger
b97edc28da test: wait for ollama pull request by assertion 2026-05-11 18:19:26 +01:00
Shakker
bc7c5d960c test: spell out live probe values 2026-05-11 18:18:51 +01:00
Peter Steinberger
8c4c7280c7 test: wait for acp resolver by assertion 2026-05-11 18:17:17 +01:00
Shakker
2d36be829e test: verify UI request payloads 2026-05-11 18:15:41 +01:00
Peter Steinberger
7d2a8677c7 test: poll provider local service shutdown with vitest 2026-05-11 18:14:53 +01:00
samzong
04002e374b fix(auto-reply): precompile directive regexes
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 18:14:47 +01:00
Shakker
2249af2c95 test: verify agent runtime values 2026-05-11 18:13:39 +01:00
Peter Steinberger
5a1712fac6 test: use expect poll for gateway counter wait 2026-05-11 18:13:34 +01:00
Peter Steinberger
9f625fe5e1 test: wait for node invoke forwarding by assertion 2026-05-11 18:12:05 +01:00
Shakker
ccb6e581d3 test: check context and music options 2026-05-11 18:11:15 +01:00
Peter Steinberger
1c5942abbf test: use vi wait helper in task registry 2026-05-11 18:09:38 +01:00
Shakker
a17277d9b4 test: verify auto-reply payloads 2026-05-11 18:07:29 +01:00
Peter Steinberger
068421b68a test: remove gateway chat history polling loop 2026-05-11 18:06:00 +01:00
Shakker
839e9e970c test: inspect exec approval payloads 2026-05-11 18:04:49 +01:00
Shakker
27e705f7cd test: check auto-reply diagnostics 2026-05-11 18:02:36 +01:00
Peter Steinberger
738f94b290 fix: clarify update warning states 2026-05-11 18:02:05 +01:00
Jerran C.
530b892f06 feat(tools): add per-sender tool policies (#66933)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-11 18:01:39 +01:00
jesse-merhi
2401ece533 fix: resolve wrapper carriers for approval spans 2026-05-12 03:01:12 +10:00
jesse-merhi
1417047ef8 docs: note approval highlight fallback 2026-05-12 03:01:12 +10:00
jesse-merhi
a70d46717c fix: skip windows gateway command spans 2026-05-12 03:01:12 +10:00
jesse-merhi
004367b4ce test: align approval span mock 2026-05-12 03:01:12 +10:00
jesse-merhi
d9be4a3e71 fix: disable non-posix approval highlights 2026-05-12 03:01:12 +10:00
Shakker
a2a32f7d0a test: spell out configure install records 2026-05-11 18:00:33 +01:00
Shakker
d79a585878 test: spell out setup flow notes 2026-05-11 17:59:20 +01:00
Shakker
e5d8a938a1 test: verify gateway HTTP arguments 2026-05-11 17:57:47 +01:00
Shakker
013ef92034 test: check ACP retry calls 2026-05-11 17:56:28 +01:00
Peter Steinberger
1117964ed6 fix: keep music reference fetch timeout scoped 2026-05-11 17:55:56 +01:00
Peter Steinberger
234ebf434f fix: honor configured media timeouts 2026-05-11 17:55:56 +01:00
Shakker
d9491a8a98 test: check auto-reply missing files 2026-05-11 17:54:19 +01:00
Peter Steinberger
177ff5baba test: wait for agent dispatch by assertion 2026-05-11 17:53:47 +01:00
Shakker
f2ab8ef2f2 test: verify infra outbound payloads 2026-05-11 17:52:15 +01:00
Peter Steinberger
d092bf0b17 test: remove discord model picker polling loop 2026-05-11 17:51:37 +01:00
Shakker
cb0c757c83 test: spell out gateway warning output 2026-05-11 17:50:28 +01:00
Peter Steinberger
7b8125989b test: remove qa lab lazy catalog sleep 2026-05-11 17:50:02 +01:00
Peter Steinberger
d65153988d test: remove tool search pending sleep 2026-05-11 17:48:49 +01:00
Peter Steinberger
098469a2a1 test: remove codex pending-state sleeps 2026-05-11 17:47:41 +01:00
Shakker
5b2abf4fba test: spell out doctor preview warnings 2026-05-11 17:46:38 +01:00
Shakker
8412d89544 test: check daemon env warnings 2026-05-11 17:45:31 +01:00
Shakker
a66531e1c2 test: require channel command messages 2026-05-11 17:44:37 +01:00
Shakker
0977067614 test: spell out doctor repair output 2026-05-11 17:43:06 +01:00
Peter Steinberger
cde42bb49c test: remove managed image cache sleep 2026-05-11 17:42:48 +01:00
Peter Steinberger
85255d9906 test: remove ui zero-delay timers 2026-05-11 17:40:33 +01:00
Shakker
bb8a379c55 test: name gateway lifecycle payloads 2026-05-11 17:40:16 +01:00
Shakker
53b1b145f7 test: spell out channel status payloads 2026-05-11 17:38:42 +01:00
Shakker
f95b38baec test: describe cron wake errors 2026-05-11 17:37:35 +01:00
Shakker
cfb516b666 test: verify cli and daemon call shapes 2026-05-11 17:36:20 +01:00
Peter Steinberger
c0b088c08a test: clean up context warmup timing 2026-05-11 17:35:11 +01:00
Shakker
47d02e9bfa test: verify sdk and tool call values 2026-05-11 17:31:59 +01:00
Peter Steinberger
236a36847e test: remove google meet idle pull sleeps 2026-05-11 17:29:59 +01:00
Shakker
cff8e32aa4 test: verify doctor and identity output 2026-05-11 17:29:32 +01:00
Frank Yang
678b2510b2 fix: abort generic no-progress tool loops
Abort generic repeated no-progress tool loops at the configured critical threshold when identical calls keep returning identical outcomes.

Prepared head SHA: 7fa287cd0f
2026-05-12 00:29:10 +08:00
Peter Steinberger
af0b775274 test(gateway): canonicalize reset hook archive path 2026-05-11 17:28:23 +01:00
Peter Steinberger
980dfeaf02 fix(gateway): start shutdown session end emissions concurrently 2026-05-11 17:28:23 +01:00
Peter Steinberger
4f7606f2cc fix(gateway): narrow reply session end reason 2026-05-11 17:28:23 +01:00
pandadev66
376c7aea7f fix(gateway): await session_end during shutdown drain and track channel + compaction lifecycle paths (#57790)
Tighten the shutdown finalizer so it actually waits for plugin handlers
under its bounded budget and so it covers every session lifecycle path,
not just the centralized emitters in `session-reset-service.ts`.

- `drainActiveSessionsForShutdown` previously called
  `emitGatewaySessionEndPluginHook`, which fires `runSessionEnd` as
  fire-and-forget (`void hookRunner.runSessionEnd(...)`). The bounded
  2 s timeout then raced only the synchronous for-loop, so the close
  handler could proceed to subsystem teardown while a database-writing
  `session_end` plugin was still in flight -- the exact ghost-session
  failure this PR is supposed to fix. Inline the emit path: build the
  `buildSessionEndHookPayload` + `resolveStableSessionEndTranscript`
  payload directly in the drain and `await hookRunner.runSessionEnd(...)`
  under the bounded race. A never-resolving handler now surfaces as
  `timedOut=true` and the close handler records `session-end-drain` as
  a warning, but is never blocked.
- The channel reply path in `src/auto-reply/reply/session.ts` and the
  compaction lifecycle helper in `src/auto-reply/reply/session-updates.ts`
  emit `session_start` / `session_end` directly through the global hook
  runner without going through `emitGatewaySessionStartPluginHook`, so
  the shutdown tracker never saw normal channel sessions or rolled-over
  compacted sessions. Wire the tracker `note` / `forget` calls into both
  paths so every public lifecycle emitter participates in the same
  tracker, and so a compacted session is both forgotten (previous id)
  and re-noted (new id) on rollover.

Tests:

- `src/gateway/drain-active-sessions-for-shutdown.test.ts` gains two
  cases: one proves the drain genuinely waits for an in-flight handler
  to settle before returning, the other proves a never-resolving handler
  is cut off at the configured budget with `timedOut=true`.

Refs #57790.
2026-05-11 17:28:23 +01:00
pandadev66
dfa1a11676 fix(gateway): fire typed session_end on shutdown/restart for active sessions (#57790)
`session_end` was only fired when a session was replaced, reset, deleted, or
compacted -- the gateway shutdown/restart paths closed the process without
enumerating active sessions, so downstream `session_end` plugins
(e.g. claude-mem) accumulated ghost rows in `active` state across restarts.
Issue reporter saw 11 orphaned sessions cause 63 timeouts/day from agent
pool exhaustion.

Add an in-memory active-session tracker
(`src/gateway/active-sessions-shutdown-tracker.ts`) populated by
`emitGatewaySessionStartPluginHook` and forgotten unconditionally by
`emitGatewaySessionEndPluginHook` (even when no plugin listens), so any
session that has already been finalized through the normal lifecycle is
never re-fired by the shutdown drain. The close handler then calls a new
`drainActiveSessionsForShutdown({ reason })` in `session-reset-service.ts`
between the `gateway:shutdown`/`gateway:pre-restart` lifecycle hooks and
the subsystem teardown steps; the drain races a bounded 2 s total timeout
so a slow plugin cannot block SIGTERM/SIGINT, surfacing the timeout as a
`session-end-drain` warning on the shutdown result.

Extend `PluginHookSessionEndReason` with `"shutdown"` and `"restart"` so
plugins can distinguish a graceful close from a planned restart; the close
handler picks `restart` when `restartExpectedMs` is set and `shutdown`
otherwise. Update `emitGatewaySessionStartPluginHook` to also accept
`storePath`, `sessionFile`, and `agentId` so the shutdown drain can build
the same `session_end` payload shape the normal lifecycle path emits, and
update the existing call sites in `session-reset-service.ts` and
`server-methods/sessions.ts` to pass those fields through.

Tests:

- `src/gateway/active-sessions-shutdown-tracker.test.ts` (new) -- tracker
  insert/forget/clear semantics, idempotent re-noting, empty-id guard,
  snapshot isolation.
- `src/gateway/drain-active-sessions-for-shutdown.test.ts` (new) -- drain
  fires `session_end` with the right reason for every tracked session,
  skips sessions already finalized via reset/delete/compaction, and still
  forgets sessions even when no `session_end` plugin is registered.
- `src/gateway/server-close.test.ts` -- four new cases covering the
  shutdown/restart drain wiring, the bounded timeout warning, and the
  drain-skipped-when-no-helper case.

Docs:

- `docs/plugins/hooks.md` documents the new `shutdown`/`restart` values
  on `PluginHookSessionEndReason`.
- `docs/automation/hooks.md` documents the post-`gateway:shutdown`
  `session_end` drain step and its bounded execution guarantee.

Fixes #57790.
2026-05-11 17:28:23 +01:00
Shakker
8a8cb6fb30 test: verify command output text 2026-05-11 17:27:29 +01:00
Peter Steinberger
d0347f961c test: wait for qqbot queue drain 2026-05-11 17:26:41 +01:00
Peter Steinberger
c10bbddc2b test(tui): type session key assertion 2026-05-11 17:26:12 +01:00
leonaIee
503cb8d59f fix(auto-reply): keep silent turn errors visible 2026-05-11 17:26:12 +01:00
Peter Steinberger
2a6dfbd034 test: remove discord voice timer flushes 2026-05-11 17:24:33 +01:00
Peter Steinberger
15fa1e546f fix(cron): centralize wake session target resolution 2026-05-11 17:24:30 +01:00
Kaspre
f142bb0d6b test(extensions): type mocked calls explicitly 2026-05-11 17:24:30 +01:00
Kaspre
528ab7ed4d fix(wake): reject subagent session targets 2026-05-11 17:24:30 +01:00
Kaspre
5971f74bf1 fix(cron): strengthen targeted wake routing proof 2026-05-11 17:24:30 +01:00
Kaspre
db4f1fd778 fix(cron): preserve untargeted wake fanout 2026-05-11 17:24:30 +01:00
Kaspre
764bb7fbf7 test(gateway/cron): assert symmetric agentId derivation across enqueue and wake
When `cron.wake` is called with only an agent-prefixed `sessionKey` (no
explicit `agentId`), the gateway cron adapter must derive the same agentId
on both `enqueueSystemEvent` and `requestHeartbeat` so events land in (and
heartbeats fire on) the same agent target. Pre-PR, only `requestHeartbeat`
derived agentId from the key; `enqueueSystemEvent` ran through
`resolveCronSessionKey` with the configured-default agent and was rerouted
to that agent's main session under multi-agent deployments where `main`
exists but is not the default.

The new test exercises the cron-adapter directly via `state.cron.state.deps`
with a multi-agent config (`primary` default + `ops` non-default) and a
`agent:ops:cron:nightly:run:abc-123` foreign-agent session key, asserting
that both call sites resolve the agent target to "ops" rather than falling
back to "primary".

Refs #78687.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:24:30 +01:00
Kaspre
8399ff888f docs(system event): document --session-key timing exception
Codex review on PR #78687 [P3] flagged that the docs say next-heartbeat
"waits for the next scheduled tick" while the patched timer collapses
next-heartbeat+sessionKey to an immediate targeted wake. Add a callout
describing the exception and pointing callers who want delayed delivery
back at the no-session-key path.

Refs #78687.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:24:30 +01:00
Kaspre
fd8d58af05 fix(test): drop unused non-null assertions on mock.calls[0]
Caught by oxlint typescript-eslint(no-unnecessary-type-assertion) in CI.
mock.calls is typed as any[][], so the trailing `!` adds nothing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:24:30 +01:00
Kaspre
072fa9b174 fix(wake): handle relative + agent-prefixed session keys consistently in cron adapter
Address review findings from successive codex rounds:

1. next-heartbeat + sessionKey now fires a targeted immediate wake.
   The regularly-scheduled heartbeat fires for the agent's main session,
   not the supplied sessionKey, so an event queued for a non-main session
   would sit stranded indefinitely; an "event"-intent wake is also
   deferred as not-due by the heartbeat runner and not retried, so
   neither path delivers without an explicit immediate wake.

2. resolveCronWakeTarget now always runs through resolveCronAgent, both
   for agent-prefixed session keys (so non-default agents are honored)
   and relative keys (so the configured default agent is used instead
   of the hardcoded "main" returned by resolveAgentIdFromSessionKey).
   Mirrors the matching fix in the enqueueSystemEvent adapter so wake
   and enqueue resolve to the same target.

3. Generated Swift `WakeParams` models now expose the new optional
   `sessionkey` field (codingKey "sessionKey") in both the macOS and
   shared OpenClawKit copies. Locally regenerated from agent.ts via
   protocol:gen + protocol:gen:swift would have produced this; the
   environment couldn't run the generators (fs-safe transitive
   typecheck errors), so the diff was applied by hand to match what
   pnpm protocol:check would output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:24:30 +01:00
Kaspre
4ddd942f5f feat(wake): expose typed sessionKey on wake protocol + system event CLI
Adds an optional sessionKey to the WakeParamsSchema and threads it through
the gateway wake handler, CronService.wake(), and the underlying timer.wake()
ops so callers can target a specific session for async-task completion
relays instead of always hitting the agent's main session.

Also adds --session-key to `openclaw system event`.

The schema rejects empty/non-string sessionKey at the gateway boundary;
mismatched session keys (a key that does not belong to the resolving agent)
fall back to the agent's main session inside resolveCronSessionKey, which
is the existing safety path.

Refs #52305 (companion to PR #50818, which closes the related cron-run
remap slice at internal enqueue sites). Doesn't depend on #50818.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:24:30 +01:00
Shakker
13bc7037b1 test: verify infra generated values 2026-05-11 17:23:49 +01:00
Peter Steinberger
f57afbbd16 test: remove agent async timer flushes 2026-05-11 17:21:53 +01:00
Shakker
ac478b2c6a test: verify diagnostics and session callbacks 2026-05-11 17:21:03 +01:00
Peter Steinberger
1f43e79a58 test: remove plugin contract timer flushes 2026-05-11 17:19:44 +01:00
Shakker
d4f3d4edad test: verify schema and timing messages 2026-05-11 17:18:19 +01:00
Shakker
8f79e34cbe test: verify install and runtime messages 2026-05-11 17:16:25 +01:00
Peter Steinberger
b3a9eba793 test: wait for msteams monitor startup 2026-05-11 17:14:23 +01:00
Peter Steinberger
902e4807c4 test: wait for qa suite stagger starts 2026-05-11 17:12:42 +01:00
Peter Steinberger
d104793520 test: wait for microsoft voice capture 2026-05-11 17:11:03 +01:00
Shakker
a63267eb6a test: verify generated core values 2026-05-11 17:07:48 +01:00
Peter Steinberger
6e7943f5bb refactor: share channel route target collection 2026-05-11 17:07:18 +01:00
Peter Steinberger
baba186717 test: wait for session history revocation 2026-05-11 17:07:09 +01:00
Peter Steinberger
d381879dd7 test: route extension ansi helpers through sdk 2026-05-11 17:06:47 +01:00
Peter Steinberger
19b78380f5 test: assert CLI lastCallUsage persists to session store 2026-05-11 17:06:47 +01:00
Neerav Makwana
af2897e29b fix: persist CLI lastCallUsage for session context totals (#78194)
- Session store: derive totalTokens for CLI providers from agentMeta.lastCallUsage
  when present (avoids cumulative usage; matches persistSessionUsageUpdate).
- Claude CLI runner: populate lastCallUsage from the final attempt usage blob.
- Add regression test for claude-cli lastCallUsage snapshot.

Fixes #78194.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 17:06:47 +01:00
Peter Steinberger
1fcb6e6427 test: remove inbound debounce timer flush 2026-05-11 17:05:28 +01:00
Shakker
4fcc3e526b test: verify extension runtime messages 2026-05-11 17:04:33 +01:00
Peter Steinberger
0218afd8e3 test: wait for run-node spawn 2026-05-11 17:04:04 +01:00
Peter Steinberger
80d1df6e68 test: remove slack duplicate timer flush 2026-05-11 17:02:45 +01:00
Peter Steinberger
166f2bcee4 test: wait for openai realtime socket 2026-05-11 17:01:27 +01:00
Peter Steinberger
f3f120cde8 test: wait for openai tts capture events 2026-05-11 16:59:54 +01:00
Peter Steinberger
435e1a74fa test: keep extension tests on sdk terminal helper 2026-05-11 16:59:35 +01:00
Chinar Amrutkar
f2c15f94ae fix(channels): narrow bundled channel loader diagnostics
Narrow bundled channel wrong-loader diagnostics, preserve ordinary missing-register debug details, and add focused loader coverage.

Verification:
- pnpm test src/plugins/loader.test.ts src/plugins/loader.cli-metadata.test.ts -- --reporter=verbose
- env -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN pnpm check:changed

CI notes:
- Real behavior proof passed with maintainer proof: override label.
- check-additional-boundaries-d is red from existing extension test imports outside this PR: extensions/telegram/src/bot.create-telegram-bot.test.ts and extensions/whatsapp/src/login.coverage.test.ts.

Co-authored-by: Chinar Amrutkar <chinar.amrutkar@gmail.com>
2026-05-11 16:58:06 +01:00
Peter Steinberger
820b21ad46 test: remove synology preauth timer flush 2026-05-11 16:57:45 +01:00
Peter Steinberger
c9c9c3f7f1 fix: surface plugin beta fallback outcomes 2026-05-11 16:57:27 +01:00
Shakker
9a1de1c4ca test: verify channel warning values 2026-05-11 16:57:18 +01:00
Peter Steinberger
761b2ae870 test: remove feishu comment timer flushes 2026-05-11 16:55:54 +01:00
Peter Steinberger
a3db718d86 test: remove feishu queue timer flush 2026-05-11 16:54:26 +01:00
Peter Steinberger
63ba3cd63d fix(doctor): match route channel coverage to runtime 2026-05-11 16:53:05 +01:00
stainlu
c9fadc597a docs(changelog): scope message-tool warning reference 2026-05-11 16:53:05 +01:00
stainlu
d9862141c1 fix(doctor): keep message-tool warning deterministic 2026-05-11 16:53:05 +01:00
stainlu
f79b8468ac fix(doctor): respect default-account route coverage 2026-05-11 16:53:05 +01:00
stainlu
4ce4a951a1 fix(doctor): normalize channel route coverage 2026-05-11 16:53:05 +01:00
stainlu
0923e9e9d9 fix(doctor): honor account route coverage 2026-05-11 16:53:05 +01:00
stainlu
7382bdfaf8 fix(doctor): respect route account coverage 2026-05-11 16:53:05 +01:00
stainlu
aecebd3347 fix(doctor): warn for scoped channel fallbacks 2026-05-11 16:53:05 +01:00
stainlu
60acfd9dfe fix(doctor): include fallback channel warnings 2026-05-11 16:53:05 +01:00
stainlu
1831162ac1 fix(doctor): warn routed agents missing message tool 2026-05-11 16:53:05 +01:00
Peter Steinberger
5dc7a05f7f test: remove acp approval retry timer flush 2026-05-11 16:52:02 +01:00
Shakker
98c825c4e3 test: verify qa runtime values 2026-05-11 16:51:31 +01:00
Peter Steinberger
d4b2560d3c test: remove mcp shutdown timer flush 2026-05-11 16:50:20 +01:00
Peter Steinberger
accf0ff335 test: remove keyed queue timer flush 2026-05-11 16:48:31 +01:00
Shakker
28a23ca980 test: verify generated command values 2026-05-11 16:47:42 +01:00
Peter Steinberger
49fa943eca test: remove hook queue timer flush 2026-05-11 16:45:58 +01:00
Shakker
2deeb9f668 test: verify teams generated values 2026-05-11 16:45:49 +01:00
corevibe555
a1fc955aef fix(memory): load sqlite-vec platform variant fallback
Resolve the sqlite-vec platform package exported native extension when the meta package is absent, preserving explicit extensionPath priority and keeping the existing config hint on load failures.

Adds coverage for the real exported vec0 subpath so package.json export-map regressions fail in tests.

Fixes #77838.

Co-authored-by: corevibe555 <leaderbossprog2025@gmail.com>
2026-05-11 16:45:45 +01:00
Peter Steinberger
3bad58e3eb test: remove whatsapp route timer flush 2026-05-11 16:44:31 +01:00
Peter Steinberger
72998128ce test: remove qa agent process sleep 2026-05-11 16:42:38 +01:00
Val Alexander
4eb37254b3 fix(ui): localize chat panel strings
Localize the remaining Control UI chat welcome, composer, run-control, session/model/thinking/agent selector, and zh-CN Skills labels through the existing Control UI i18n pipeline.

Fixes #79937.

Verification:
- pnpm ui:i18n:check
- pnpm exec oxfmt --check --threads=1 ui/src/ui/chat/chat-welcome.ts ui/src/ui/chat/run-controls.ts ui/src/ui/chat/session-controls.ts ui/src/ui/views/chat.ts ui/src/ui/chat/run-controls.test.ts ui/src/ui/views/chat.test.ts ui/src/i18n/locales/en.ts ui/src/i18n/locales/zh-CN.ts
- pnpm test ui/src/ui/chat/run-controls.test.ts ui/src/ui/views/chat.test.ts ui/src/i18n/test/translate.test.ts
- git diff --check origin/main..HEAD
2026-05-11 10:42:34 -05:00
Shakker
3bd1ff4140 test: verify memory plugin artifacts 2026-05-11 16:42:29 +01:00
Peter Steinberger
f707f3a5bb test: fix main check failures 2026-05-11 16:41:46 +01:00
Peter Steinberger
8e1f1b56ae test: remove voice call manager sleeps 2026-05-11 16:41:17 +01:00
Shakker
561c19cb58 test: verify plugin warning messages 2026-05-11 16:40:07 +01:00
Peter Steinberger
b0db82be15 test: remove voice call timing sleeps 2026-05-11 16:38:08 +01:00
Val Alexander
6b3cd9043e fix(control-ui): keep channel statuses responsive
Summary:
- Keep Channels responsive by opening on cached/runtime snapshots, bounding live probes, and preventing stale slow probe results from replacing newer snapshots.
- Reduce Control UI churn by scoping Nodes polling to the active Nodes tab, debouncing sessions.changed reconciliation, and bounding secondary chat/session refreshes.
- Scope config schema analysis before section-limited renders so excluded root sections are not fully analyzed.

Verification:
- pnpm test ui/src/ui/app-channels.test.ts ui/src/ui/controllers/channels.test.ts ui/src/ui/app-settings.refresh-active-tab.node.test.ts ui/src/ui/app-gateway.sessions.node.test.ts ui/src/ui/app-lifecycle-connect.node.test.ts ui/src/ui/controllers/sessions.test.ts ui/src/ui/views/config.browser.test.ts src/gateway/server-methods/channels.status.test.ts src/gateway/control-ui.http.test.ts ui/src/ui/app-polling.node.test.ts ui/src/ui/app-gateway-chat-load.node.test.ts ui/src/ui/app-gateway.node.test.ts ui/src/ui/app-chat.test.ts ui/src/ui/app-render.helpers.node.test.ts ui/src/ui/app-lifecycle.node.test.ts
- pnpm exec oxfmt --check --threads=1 <changed files>
- git diff --check origin/main...HEAD
- node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json <changed TypeScript files>
- pnpm changed:lanes --json

Note: local pnpm check:changed reached core lint and failed on src/gateway/server-methods/nodes.invoke-wake.test.ts, which is unchanged in this PR and already present on current origin/main; changed-file lint passed under the same repo wrapper.
2026-05-11 10:37:35 -05:00
Shakker
678c2c070d test: verify browser policy responses 2026-05-11 16:36:47 +01:00
Peter Steinberger
b29b2558a7 test: remove launcher polling waits 2026-05-11 16:35:29 +01:00
Shakker
80175cfb74 test: verify browser route values 2026-05-11 16:33:31 +01:00
Shakker
c5e481eeb1 test: verify cdp connection options 2026-05-11 16:31:57 +01:00
Shakker
8aa0bea4b6 test: check anthropic beta headers 2026-05-11 16:30:51 +01:00
Peter Steinberger
7e57b69e6e test: finish broad matcher cleanup 2026-05-11 16:30:29 +01:00
Shakker
46a0d3ba85 test: check node wake dynamic values 2026-05-11 16:28:50 +01:00
Shakker
08acf80891 test: check daemon install messages 2026-05-11 16:26:36 +01:00
Shakker
b11bdabfa2 test: check doctor plugin warnings 2026-05-11 16:25:36 +01:00
Shakker
6923cf348a test: check doctor allowlist warnings 2026-05-11 16:24:16 +01:00
Shakker
99ae349ad2 test: check gateway discovery logs 2026-05-11 16:23:09 +01:00
Shakker
6a1f53316f test: check tailscale preserve logs 2026-05-11 16:22:18 +01:00
Peter Steinberger
e8785972d0 test: tighten agent auth assertions 2026-05-11 16:21:43 +01:00
Shakker
07805cc75b test: check session memory filenames 2026-05-11 16:21:22 +01:00
Shakker
4630076381 test: check cron timer handles 2026-05-11 16:19:50 +01:00
Shakker
3ce0b9769e test: check cleanup backup prompts 2026-05-11 16:18:56 +01:00
Shakker
948e87939f test: check sandbox command messages 2026-05-11 16:18:12 +01:00
Peter Steinberger
9340105bb5 fix(agents): preserve media tools for alsoAllow policies 2026-05-11 16:17:39 +01:00
Shakker
70935a110c test: check gateway stage error logs 2026-05-11 16:17:18 +01:00
Neerav Makwana
5171c2654a fix(models/auth): preserve primary when login omits --set-default
Provider applyConfig patches merged during models auth login could replace
agents.defaults.model.primary even without --set-default. Snapshot the prior
defaults.model and restore it after the patch unless the user opts in.

Fixes #78162.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 16:16:49 +01:00
Peter Steinberger
eb34d09232 test: tighten agent assertions 2026-05-11 16:16:36 +01:00
Shakker
1067abc665 test: check device identity pem blocks 2026-05-11 16:16:20 +01:00
Shakker
d23fb1e708 test: check heartbeat ack send options 2026-05-11 16:15:32 +01:00
Shakker
f80db58689 test: check heartbeat telegram send options 2026-05-11 16:14:09 +01:00
Ayaan Zaidi
9c16388177 ci(mantis): serialize telegram account proofs 2026-05-11 20:42:00 +05:30
Shakker
77e3f2b6e2 test: check migration backup filenames 2026-05-11 16:11:36 +01:00
Shakker
723ebb2a2c test: check sync hook warning text 2026-05-11 16:10:45 +01:00
Shakker
a150e35928 test: check plugin service failure logs 2026-05-11 16:10:06 +01:00
Shakker
691440f061 test: check inbound claim hook warnings 2026-05-11 16:09:26 +01:00
Shakker
584c9bdeb2 test: check reply dispatch hook warnings 2026-05-11 16:08:38 +01:00
Peter Steinberger
938b1e0225 test: cover MiniMax Anthropic route guard 2026-05-11 16:08:30 +01:00
Peter Steinberger
4bb7acd88b test: tighten config assertions 2026-05-11 16:06:43 +01:00
Shakker
c0c8f7c2d4 test: check security fix outputs 2026-05-11 16:06:21 +01:00
Shakker
fb4d18bcba test: check skill scanner permission errors 2026-05-11 16:04:57 +01:00
Shakker
788ef05384 test: check release tag errors 2026-05-11 16:04:04 +01:00
Shakker
ef6b157389 test: check i18n warning messages 2026-05-11 16:02:42 +01:00
Neerav Makwana
7bf4458bbe fix: guard empty MiniMax Anthropic messages (#74731)
Fixes #74589. Thanks @neeravmakwana and @DerekEXS.
2026-05-11 16:02:03 +01:00
Shakker
bc33a2049d test: check chat idempotency keys 2026-05-11 16:01:51 +01:00
Shakker
338fbd8bfd test: check control ui nav calls 2026-05-11 16:00:51 +01:00
Shakker
618818d20b test: check usage filter warnings 2026-05-11 15:59:49 +01:00
Peter Steinberger
8aa286476d test: tighten command assertions 2026-05-11 15:59:03 +01:00
Shakker
3e332426fc test: check browser navigation page handles 2026-05-11 15:58:55 +01:00
Shakker
2a42e4743f test: check browser doctor notes 2026-05-11 15:57:53 +01:00
Jayesh Betala
0c9f34eac1 fix(telegram): honor forced document videos
Fixes #80389. Thanks @jbetala7.
2026-05-11 20:27:36 +05:30
Peter Steinberger
ea663dbb56 test: allow old Linux package update baselines 2026-05-11 15:57:12 +01:00
Shakker
b58ee9eee2 test: check matrix verification block logs 2026-05-11 15:56:31 +01:00
Peter Steinberger
2d2f4bb2bd test: align cron heartbeat override expectation 2026-05-11 15:55:21 +01:00
Peter Steinberger
402fa0e935 fix: keep cron heartbeat wakes on session route 2026-05-11 15:55:21 +01:00
Shakker
7b28a52676 test: fix whatsapp ansi helper import 2026-05-11 15:55:06 +01:00
jeffjhunter
850d685d4b Fix Codex app-server OAuth harness auth 2026-05-11 15:54:43 +01:00
Shakker
affaeaf8d3 test: check telegram bot error output 2026-05-11 15:54:08 +01:00
Shakker
af9c09a21f test: check telegram chat action logs 2026-05-11 15:51:54 +01:00
Peter Steinberger
16b33fc91e test: tighten auto reply assertions 2026-05-11 15:51:21 +01:00
Shakker
9bfd1947d5 test: check twitch client log messages 2026-05-11 15:51:05 +01:00
Shakker
ffb814c420 test: check whatsapp login messages 2026-05-11 15:49:59 +01:00
Shakker
aa072aedef test: check acp gateway startup args 2026-05-11 15:45:50 +01:00
Shakker
2a53725161 test: check bonjour warning messages 2026-05-11 15:44:25 +01:00
Shakker
180fa826ba test: check acp resume lifecycle fields 2026-05-11 15:42:42 +01:00
FullerStackDev
b8e9492086 fix(bonjour): back off probing watchdog repairs 2026-05-11 15:42:39 +01:00
Shakker
af4e90f41b test: verify acp spawn wake routing 2026-05-11 15:41:38 +01:00
Peter Steinberger
0693603e5f test: tighten remaining plugin sdk assertions 2026-05-11 15:41:25 +01:00
Statxc
6943b5b4a6 fix: tighten system event dedupe identity
Refs #69478.

Co-authored-by: statxc <181730535+statxc@users.noreply.github.com>
2026-05-11 15:41:08 +01:00
Shakker
de0e5f662a test: check oauth ref ids 2026-05-11 15:40:07 +01:00
Peter Steinberger
ab7e4e79cf docs: mark symbolic header shim temporary 2026-05-11 15:39:38 +01:00
Shakker
c714755af6 test: verify tool hash digest shape 2026-05-11 15:38:56 +01:00
Ayaan Zaidi
adc3ba45ca ci(mantis): render proof media responsively 2026-05-11 20:08:02 +05:30
Shakker
4b6c43af48 test: check media path resolver options 2026-05-11 15:37:51 +01:00
Shakker
cd5018b40e test: check export session arguments 2026-05-11 15:36:41 +01:00
Shakker
99bac079ed test: check models command workspace args 2026-05-11 15:35:50 +01:00
Shakker
8f66462125 test: verify restart sentinel payloads 2026-05-11 15:34:48 +01:00
Peter Steinberger
46e150ea68 test: tighten plugin sdk assertions 2026-05-11 15:33:31 +01:00
Shakker
69f4639aac test: check stop target payloads 2026-05-11 15:33:09 +01:00
Shakker
9139ce0652 test: inspect reply dispatch hook inputs 2026-05-11 15:32:00 +01:00
Shakker
e521f56116 test: check directive alias parsing 2026-05-11 15:30:04 +01:00
Ayaan Zaidi
1ff833d66d ci(mantis): fit telegram proof gifs in comments 2026-05-11 19:59:54 +05:30
YBoy
ff8bc72c81 fix: consolidate gateway doctor service notes (#78688)
Fixes #80287.

Co-authored-by: YB0y <brianandez6@gmail.com>
2026-05-11 15:29:14 +01:00
Shakker
f9c3d683cd test: cover queued followup retargeting 2026-05-11 15:28:54 +01:00
Peter Steinberger
f994094cb4 fix(cron): sanitize target-last heartbeat wakes 2026-05-11 15:28:39 +01:00
Shakker
ec5a97467c test: cover reply routing decisions 2026-05-11 15:28:05 +01:00
Peter Steinberger
8ad588d9e6 test: tighten isolated cron assertions 2026-05-11 15:27:33 +01:00
Shakker
3255d2e09d test: check session fork headers 2026-05-11 15:27:15 +01:00
Shakker
754450cbb9 test: verify transcript replay records 2026-05-11 15:26:14 +01:00
Shakker
c4b551f85e test: check capability cli error text 2026-05-11 15:25:22 +01:00
Shakker
a4b95296ed test: exercise command policy resolvers 2026-05-11 15:22:20 +01:00
Peter Steinberger
0ddf10ff89 test: tighten cron assertions 2026-05-11 15:22:15 +01:00
Shakker
bc6b34a67a test: check mcp config messages 2026-05-11 15:19:34 +01:00
Peter Steinberger
601b70557d test: tighten config validation assertions 2026-05-11 15:17:26 +01:00
Shakker
17c75df670 test: check config guard error output 2026-05-11 15:16:59 +01:00
Peter Steinberger
9074f08fc3 test: tighten channel assertion checks 2026-05-11 15:15:12 +01:00
Shakker
5ad73cb995 test: verify default account warning copy 2026-05-11 15:14:43 +01:00
Shakker
6c19f389a8 test: spell out gateway send responses 2026-05-11 15:13:07 +01:00
Shakker
50a9f9a3ce test: cover exec safe bin warning text 2026-05-11 15:11:20 +01:00
Gabriel
83ffc1f47a fix(gateway): dedupe inflight outbound requests (#68341)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-11 15:10:21 +01:00
Shakker
0343a2e689 test: pin realtime relay requests 2026-05-11 15:09:19 +01:00
Peter Steinberger
281a88d6df test: tighten cli gateway assertions 2026-05-11 15:08:14 +01:00
Shakker
fd7448299f test: pin browser state errors 2026-05-11 15:07:16 +01:00
Peter Steinberger
3dd2266723 test: tighten cli smoke assertions 2026-05-11 15:04:49 +01:00
Shakker
8ee4290e06 test: pin Zalo lifecycle logs 2026-05-11 15:04:34 +01:00
Peter Steinberger
02eff52f16 test(plugin-sdk): align compact progress draft expectation 2026-05-11 15:04:30 +01:00
Peter Steinberger
f3f1509ee9 fix(plugin-sdk): restore compact progress draft cap 2026-05-11 15:04:30 +01:00
Peter Steinberger
b2153e01d8 docs: add memory budget changelog entry (#74088) 2026-05-11 15:04:30 +01:00
YB0y
3b8cfc3657 fix(memory-core): cap MEMORY.md size during dreaming promotions to prevent unbounded growth (#73691)
Dreaming's deep-phase promotion path appends to ~/.openclaw/workspace-<agent>/MEMORY.md
without a durable size budget. After weeks of use, the file grows past the bootstrap
injection cap (~12KB/file), at which point bootstrap silently truncates promoted memory
and (per the issue body) session writes can hit lock timeouts that wedge the gateway.

Adds a bounded compaction step in applyShortTermPromotions: before each write, drop the
OLDEST auto-promoted sections (date-ordered) until existing + new section fits within
memoryFileMaxChars (default 10,000 chars, safely below the 12KB bootstrap cap).
User-authored content is preserved unconditionally; only dreaming-owned sections are
eligible for compaction.

Verified:
- pnpm install --frozen-lockfile
- pnpm test extensions/memory-core/src/memory-budget.test.ts extensions/memory-core/src/short-term-promotion.test.ts
- pnpm exec oxfmt --check --threads=1 extensions/memory-core/src/memory-budget.ts extensions/memory-core/src/memory-budget.test.ts extensions/memory-core/src/short-term-promotion.ts extensions/memory-core/src/short-term-promotion.test.ts CHANGELOG.md
- pnpm check:changed
- pnpm tsgo:core
- pnpm tsgo:extensions
- pnpm tsgo:test:src
- git diff --check
- live driver: real applyShortTermPromotions across 5 sweeps with oversized seeded MEMORY.md — file stayed bounded, oldest sections compacted, user content preserved

Closes #73691
2026-05-11 15:04:30 +01:00
Shakker
1317779a05 test: pin gh config discovery results 2026-05-11 15:02:11 +01:00
Peter Steinberger
6b2b7d12e5 test: tighten media understanding assertions 2026-05-11 15:01:19 +01:00
Shakker
54edf9513b test: pin cron channel delivery calls 2026-05-11 15:00:20 +01:00
Peter Steinberger
2858afd4cf test: tighten config session assertions 2026-05-11 14:59:09 +01:00
Peter Steinberger
4615f08817 fix: harden gh config discovery 2026-05-11 14:57:42 +01:00
tmimmanuel
72b5cddbe1 fix(doctor): surface GH_CONFIG_DIR hint when gh auth lives at a different HOME
When OpenClaw spawns an agent shell with a different HOME than the user
that ran `gh auth login` (per-agent codex homes, systemd User= services,
sudo'd shells), `gh` looks at $XDG_CONFIG_HOME/gh or $HOME/.config/gh and
reports "not logged into any GitHub hosts" even though the operator HOME
has a valid hosts.yml.

Add `detectGhConfigDirMismatch` in src/agents/skills/gh-config-discovery.ts:
a pure helper that takes process env plus a fileExists probe and returns
either "auth-discoverable", "no-known-auth", "explicit-gh-config-dir-set",
or a "mismatch" with the alternate config dir, the host file path, and a
suggested GH_CONFIG_DIR value to set on the gateway service environment.
The helper checks `/root`, `$SUDO_USER`'s home, and `$USER`'s home as
candidate operator homes on Linux/macOS, and uses platform-specific path
joins so the same logic works on Windows test runners.

Wire the helper into the doctor skills health flow: when the github skill
is reported and the gh binary is present, call the discovery helper and,
on a mismatch, print a "GitHub CLI" note with the operator-actionable
fix instructions before any unavailable-skill repair prompt.

Update skills/github/SKILL.md with a troubleshooting subsection that
documents GH_CONFIG_DIR for service/agent environments where HOME differs
from the user that ran `gh auth login`.

Fixes #78063.
2026-05-11 14:57:42 +01:00
Shakker
0abf14777d test: pin cron model switch retry 2026-05-11 14:57:04 +01:00
Peter Steinberger
0c2296015c test: tighten cli assertion checks 2026-05-11 14:56:43 +01:00
Peter Steinberger
511d706cf5 test: tighten crestodian assertions 2026-05-11 14:54:32 +01:00
Peter Steinberger
bfcd816953 test: tighten provider live assertions 2026-05-11 14:52:12 +01:00
Peter Steinberger
ed6d72efcf test: tighten browser mcp assertions 2026-05-11 14:50:16 +01:00
Peter Steinberger
5dbeacabc9 test: tighten browser route assertions 2026-05-11 14:47:22 +01:00
Peter Steinberger
248207dace test: tighten browser server assertions 2026-05-11 14:45:43 +01:00
Peter Steinberger
09fcd19814 test: tighten codex event assertions 2026-05-11 14:42:25 +01:00
Peter Steinberger
c20d45e346 test: tighten codex binding assertions 2026-05-11 14:40:27 +01:00
Feelw00
c1b59a95bf fix(cron): mark manual cron runs active (#78243)
Summary:
- Mark forced/manual cron runs active in the task registry until completion and clear them in finally.
- Add regression coverage for manual run success and failure cleanup.
- Update changelog for #78243 and apply a small lint-only test fix needed after rebasing on latest main.

Fixes #78233

Verification:
- pnpm test src/plugin-sdk/channel-streaming.test.ts src/cron/active-jobs-manual-run.test.ts
- pnpm run lint:extensions:bundled
- pnpm test extensions/codex/src/app-server/side-question.test.ts
- CI: https://github.com/openclaw/openclaw/actions/runs/25673031776

Co-authored-by: Feelw00 <dhrtn1006@naver.com>
2026-05-11 14:40:21 +01:00
Peter Steinberger
ebf0d6bc8e test: tighten qa lab live assertions 2026-05-11 14:38:49 +01:00
Peter Steinberger
1320e0ec80 test: tighten qa lab web assertions 2026-05-11 14:36:53 +01:00
Peter Steinberger
1f1a1412ff test: tighten qa lab config assertions 2026-05-11 14:34:40 +01:00
Shakker
6f3fd2410c test: pin browser fallback calls 2026-05-11 14:32:39 +01:00
Peter Steinberger
c8c1f46da1 test: tighten qa lab runtime assertions 2026-05-11 14:30:10 +01:00
Shakker
563bbd3df4 test: pin Telegram dispatch drafts 2026-05-11 14:28:38 +01:00
Peter Steinberger
ee5b06f9fe docs: clarify contributor changelog ownership 2026-05-11 14:26:56 +01:00
Peter Steinberger
d2f578cbb4 fix: retire timed-out codex app-server clients 2026-05-11 14:26:56 +01:00
Peter Steinberger
fecf18d277 test: tighten qa matrix assertions 2026-05-11 14:26:48 +01:00
Shakker
610b695a12 test: pin Telegram draft stream checks 2026-05-11 14:26:31 +01:00
Peter Steinberger
a3c7fea512 fix(agents): avoid Pi resource discovery stalls
Co-authored-by: dataCenter430 <titan032000@gmail.com>
2026-05-11 14:25:55 +01:00
Peter Steinberger
ac7e1c36eb fix(whatsapp): retry opening-phase 428 closes
Co-authored-by: dataCenter430 <titan032000@gmail.com>
2026-05-11 14:25:55 +01:00
Shakker
1f8d29e532 test: pin command registry checks 2026-05-11 14:25:18 +01:00
Shakker
19c66ad3fe test: pin Codex run attempt assertions 2026-05-11 14:24:01 +01:00
VACInc
6a741102d1 test(codex): keep native tool observability fixture generic 2026-05-11 14:23:46 +01:00
VACInc
88d0c77add docs: note codex tool observability fix 2026-05-11 14:23:46 +01:00
VACInc
a28bf10ce2 fix(codex): observe native tool completions 2026-05-11 14:23:46 +01:00
Peter Steinberger
5b6f4d6bb6 test: tighten acpx memory assertions 2026-05-11 14:23:32 +01:00
Peter Steinberger
ac8a193cbe test: tighten memory wiki assertions 2026-05-11 14:21:08 +01:00
Shakker
ead6179718 test: pin Codex side question calls 2026-05-11 14:20:02 +01:00
Peter Steinberger
97bf9bfd22 docs: credit qqbot binding fix contributor (#73567) 2026-05-11 14:19:34 +01:00
statxc
5eda2a2bc6 fix(qqbot): align #69546 fix with merged main 2026-05-11 14:19:34 +01:00
statxc
278ffbdb53 fix(qqbot): type active config provider 2026-05-11 14:19:34 +01:00
statxc
d69b663021 fix(qqbot): re-evaluate routing bindings per inbound message
QQBot's gateway captured `ctx.cfg` once at startup and reused that
reference for every inbound, so peer-specific bindings added via the
CLI were ignored until the gateway restarted (the routing resolver
caches evaluated bindings keyed by the cfg object reference).

Add a small `ActiveCfgProvider` that reads `getRuntimeConfig()` from
the plugin SDK on every event and falls back to the startup snapshot
when the runtime registry is not populated, mirroring Telegram's
per-event lookup pattern. Wire it into `handleMessage` so both the
inbound pipeline and outbound dispatch run against the live config.

Fixes #69546.
2026-05-11 14:19:34 +01:00
Peter Steinberger
8d2dd8cf2e test: tighten openai extension assertions 2026-05-11 14:19:09 +01:00
Peter Steinberger
03d9bc14b5 test: fix progress draft truncation expectations 2026-05-11 14:18:23 +01:00
Shakker
c214a5f262 test: pin self-hosted provider setup 2026-05-11 14:17:08 +01:00
Peter Steinberger
242e2474a6 test: tighten telegram extension assertions 2026-05-11 14:16:48 +01:00
Shakker
6462472358 test: pin session schema success 2026-05-11 14:14:28 +01:00
Peter Steinberger
6781957a99 test: tighten channel extension assertions 2026-05-11 14:13:46 +01:00
Shakker
31f128e86f test: pin tailscale bind diagnostics 2026-05-11 14:13:27 +01:00
Shakker
1dddb502a8 test: pin config schema fields 2026-05-11 14:12:14 +01:00
Peter Steinberger
493f363857 test: tighten slack monitor assertions 2026-05-11 14:11:39 +01:00
Shakker
98f07a5387 test: pin cron delivery targets 2026-05-11 14:09:54 +01:00
Peter Steinberger
8975ac83f4 test: tighten slack extension assertions 2026-05-11 14:09:30 +01:00
Shakker
19a040ee88 test: pin cron session entries 2026-05-11 14:08:06 +01:00
Peter Steinberger
8218595cd1 docs: add changelog for follow-up queue guard (#68839) 2026-05-11 14:07:58 +01:00
Feelw00
137d566422 fix(auto-reply): guard FOLLOWUP_QUEUES delete against late drain finally
Regression: the drain IIFE finally (`drain.ts:263-271`) performed an
unconditional `FOLLOWUP_QUEUES.delete(key)` + `clearFollowupDrainCallback(key)`
using only the key, without checking whether the captured `queue` still matched
the map entry. Under the `/stop` + immediate followup sequence, a late-returning
D1 finally could delete the map entry for a fresh Q2 and orphan it until the
next enqueue.

Fix: only remove the map entry and drain callback when `FOLLOWUP_QUEUES.get(key)
=== queue`. Mirrors the identity pattern noted in
`subagent-announce-queue.ts:62-64`.

Adds `src/auto-reply/reply/queue/drain.identity-guard.test.ts` which uses real
`enqueueFollowupRun` / `scheduleFollowupDrain` / `clearSessionQueues` (no
module mocks) and a Deferred gate to park D1 inside `runFollowup`. The test
uses `restartIfIdle=false` on the Q2 enqueue so D1's finally is the only
mutator that can touch the map entry, producing deterministic pre/post-fix
differentiation:
  pre-fix  : get(key) === undefined (Q2 orphaned), depth === 0
  post-fix : get(key) === Q2,                     depth === 1

AI-assisted (fully tested). 1082 auto-reply/reply tests pass, pnpm check +
pnpm build clean.
2026-05-11 14:07:58 +01:00
Shakker
535348a1c7 test: pin cron main wake calls 2026-05-11 14:06:50 +01:00
Shakker
36d90ce431 test: pin cron read status 2026-05-11 14:05:33 +01:00
Peter Steinberger
68cec724b1 test: tighten signal extension assertions 2026-05-11 14:04:55 +01:00
Val Alexander
42fc84f4b4 fix(control-ui): add static mount fallback
Summary:
- Add a plain HTML Control UI fallback when the module app never mounts.
- Document blank-page recovery guidance and keep the fallback retry-friendly.
- Cover the timeout path with iframe-isolated regression tests.

Verification:
- pnpm exec oxfmt --check --threads=1 ui/index.html ui/src/ui/mount-fallback.test.ts
- pnpm test ui/src/ui/app.talk.test.ts ui/src/ui/mount-fallback.test.ts
- pnpm ui:build
- pnpm check:changed
- GitHub CI for 8ef18e8bca completed without failures.
2026-05-11 08:03:49 -05:00
Peter Steinberger
58087ef3d6 test: tighten extension auth assertions 2026-05-11 14:02:35 +01:00
Peter Steinberger
0a92d7a8ff fix: widen progress draft preview lines 2026-05-11 14:02:19 +01:00
Feelw00
08cffbb067 fix(gateway): clear node wake state without registration (#68848)
Summary:
- Clear speculative gateway node wake state when APNs registration is missing.
- Add regression coverage for unregistered node IDs.
- Add changelog credit for @Feelw00.

Verification:
- git diff --check
- pnpm test src/gateway/server-methods/nodes.wake-leak.test.ts src/gateway/server-methods/nodes.invoke-wake.test.ts
- GitHub exact-head checks green on 29db03ff4e
2026-05-11 14:02:03 +01:00
Peter Steinberger
2c89dad895 test: tighten remaining UI assertions 2026-05-11 13:59:43 +01:00
Peter Steinberger
36aea9792f docs: update changelog for #80333 2026-05-11 13:58:14 +01:00
samzong
1ecd46f49b fix(channels): cache selected channel registry lookups 2026-05-11 13:58:14 +01:00
Shakker
7c75001492 test: pin cron diagnostics entries 2026-05-11 13:58:01 +01:00
Peter Steinberger
9c5a150336 test: tighten UI view assertions 2026-05-11 13:57:15 +01:00
Shakker
a012bfb296 test: pin cron timer handles 2026-05-11 13:55:45 +01:00
Peter Steinberger
ef9c03c4bb test: tighten UI gateway assertions 2026-05-11 13:54:54 +01:00
Shakker
82cc6f1d25 test: pin cron schedule logs 2026-05-11 13:54:38 +01:00
Shakker
0fcddd3974 test: pin cron reaper store 2026-05-11 13:53:01 +01:00
Shakker
e3cde42b49 test: pin attachment offload warning 2026-05-11 13:52:04 +01:00
Peter Steinberger
552f088af9 test: tighten gateway live assertions 2026-05-11 13:51:37 +01:00
Shakker
f801009008 test: pin runtime recovery logs 2026-05-11 13:50:39 +01:00
Peter Steinberger
318794f808 test: tighten gateway helper assertions 2026-05-11 13:49:35 +01:00
Shakker
c165b9c650 test: pin agent identity writes 2026-05-11 13:49:23 +01:00
Shakker
bcdec7bfb9 test: pin plugin approval ids 2026-05-11 13:47:51 +01:00
Peter Steinberger
cca6c4cfcf test: tighten gateway send assertions 2026-05-11 13:45:24 +01:00
Shakker
17b4ab369e test: pin tools catalog plugin fields 2026-05-11 13:45:00 +01:00
Peter Steinberger
296a0feddc test: tighten gateway rate limit assertions 2026-05-11 13:43:34 +01:00
Peter Steinberger
26b32601f0 test: tighten tools catalog assertions 2026-05-11 13:41:40 +01:00
Shakker
29f85ca246 test: pin gateway client logs 2026-05-11 13:41:18 +01:00
Val Alexander
96b672c54d Stabilize Control UI connection diagnostics (#80510)
Summary:
- Catch browser-side WebSocket constructor security failures and surface wss://, Tailscale, and loopback dashboard guidance.
- Classify the browser WebSocket security code through Control UI login and overview insecure-context hints.
- Keep the changelog attribution under the active Fixes section.


Verification:
- pnpm test ui/src/ui/gateway.node.test.ts ui/src/ui/views/login-gate.test.ts ui/src/ui/views/overview.node.test.ts src/logging/diagnostic.test.ts
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/logging/diagnostic-stability.ts src/logging/diagnostic.test.ts ui/src/ui/gateway.ts ui/src/ui/gateway.node.test.ts ui/src/ui/views/login-gate.test.ts ui/src/ui/views/overview-hints.ts ui/src/ui/views/overview.node.test.ts
- git diff --check origin/main...HEAD
- pnpm check:changed
- GitHub Real behavior proof and CI preflight passed on 1ea05289b1
2026-05-11 07:40:47 -05:00
Peter Steinberger
39348e9a93 test: tighten skill gateway assertions 2026-05-11 13:39:41 +01:00
Shakker
1517c36dbd test: pin reload deferral warnings 2026-05-11 13:38:53 +01:00
Shakker
b41d766394 test: pin skill update config writes 2026-05-11 13:37:28 +01:00
Peter Steinberger
6fb630aec1 test: avoid mutating diagnostics snapshot keys 2026-05-11 13:36:51 +01:00
Peter Steinberger
7c6c2fa994 test: tighten gateway server response assertions 2026-05-11 13:36:51 +01:00
Shakker
6963fd1492 test: pin session reset hook strings 2026-05-11 13:36:00 +01:00
Ayaan Zaidi
6887b12be7 docs(changelog): add Telegram thinking status entry (#80341) (thanks @VACInc) 2026-05-11 18:04:53 +05:30
Ayaan Zaidi
377d7a0b4c fix(telegram): simplify thinking defaults 2026-05-11 18:04:53 +05:30
VACInc
9a47f0fd3d fix: preserve native status thinking precedence 2026-05-11 18:04:53 +05:30
VACInc
d468741c5b test: fix native status alias index mock 2026-05-11 18:04:53 +05:30
VACInc
8192147b90 fix: respect native status thinking overrides 2026-05-11 18:04:53 +05:30
VACInc
6562bac624 fix: show Telegram thinking defaults 2026-05-11 18:04:53 +05:30
Shakker
ee77ce467a test: cover diagnostics snapshots 2026-05-11 13:33:48 +01:00
Peter Steinberger
653483d9c8 test: tighten gateway server method assertions 2026-05-11 13:32:24 +01:00
Shakker
4b51e86914 test: pin chat abort payloads 2026-05-11 13:31:28 +01:00
Shakker
06f39a97f1 test: pin session archive filenames 2026-05-11 13:29:53 +01:00
Peter Steinberger
da7cc2b11c fix(feishu): make manual setup the default 2026-05-11 13:29:13 +01:00
Peter Steinberger
2838eb4d8e test: tighten node pairing authz assertions 2026-05-11 13:28:24 +01:00
Peter Steinberger
4c070299c8 test: tighten telegram session recreation assertions 2026-05-11 13:27:09 +01:00
Shakker
eabb129bcf test: pin subagent hook session keys 2026-05-11 13:26:17 +01:00
Peter Steinberger
951444cb83 test: tighten gateway preauth assertions 2026-05-11 13:25:47 +01:00
Shakker
c2346d1042 test: pin conversation label calls 2026-05-11 13:24:55 +01:00
Peter Steinberger
344f42a52a test: tighten gateway helper call assertions 2026-05-11 13:24:11 +01:00
Shakker
f60a12ccca test: pin fast reply bootstrap checks 2026-05-11 13:23:34 +01:00
Peter Steinberger
fb11851c7f docs: refresh config baseline 2026-05-11 13:21:47 +01:00
Peter Steinberger
0362b75824 feat(discord): add voice channel allowlist 2026-05-11 13:21:47 +01:00
Peter Steinberger
696a98871d test: tighten gateway call assertions 2026-05-11 13:21:32 +01:00
Shakker
0d8d350d16 test: pin gateway doctor notes 2026-05-11 13:20:48 +01:00
Ayaan Zaidi
663206aac4 ci(mantis): derive telegram proof refs from pr 2026-05-11 17:50:23 +05:30
Peter Steinberger
bf5202b056 test: tighten hook mapping assertions 2026-05-11 13:19:44 +01:00
Shakker
b48baece87 test: assert onboard option errors 2026-05-11 13:19:12 +01:00
Peter Steinberger
9c810b552b docs: add gateway streaming envelope changelog (#80299) 2026-05-11 13:19:00 +01:00
samzong
3880b72294 fix(gateway): share streaming event envelopes
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 13:19:00 +01:00
Peter Steinberger
e50f323c1f test(exec): isolate OpenClaw home in security floor tests 2026-05-11 13:18:50 +01:00
Peter Steinberger
1cbe6e271b fix(exec): address security floor review 2026-05-11 13:18:50 +01:00
Bryan Pearson
235ad7ec95 fix(exec): keep configured security authoritative 2026-05-11 13:18:50 +01:00
Peter Steinberger
6fcceed61f test: tighten chat attachment assertions 2026-05-11 13:18:13 +01:00
Shakker
2d5701237b test: assert agents add outputs 2026-05-11 13:17:57 +01:00
Peter Steinberger
323ba824ed test: tighten control ui http assertions 2026-05-11 13:16:58 +01:00
Peter Steinberger
29f36e0072 fix: avoid llama.cpp router autoload during discovery (#74057) 2026-05-11 13:16:06 +01:00
brokemac79
f4be39c4f4 fix(providers): read nested llama cpp props context 2026-05-11 13:16:06 +01:00
brokemac79
7c7d19ec84 fix(providers): use llama.cpp runtime context cap 2026-05-11 13:16:06 +01:00
brokemac79
ccdaf1875a fix(doctor): tolerate malformed crontab output (#78112)
Fixes #77773.

Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
2026-05-11 13:15:57 +01:00
Peter Steinberger
a57691cdcb test: tighten gateway websocket assertions 2026-05-11 13:15:45 +01:00
Shakker
75b745d559 test: assert scheduled task command parsing 2026-05-11 13:14:29 +01:00
Peter Steinberger
db9549c46f test: tighten gateway role assertions 2026-05-11 13:13:30 +01:00
Shakker
9c37951435 test: assert service audit issues 2026-05-11 13:13:14 +01:00
Peter Steinberger
c4ed66c58b test: tighten gateway misc assertions 2026-05-11 13:12:01 +01:00
Shakker
0c50714a03 test: assert approval bootstrap retry warning 2026-05-11 13:11:45 +01:00
Shakker
945fcc10fd test: assert runtime guard diagnostics 2026-05-11 13:10:53 +01:00
Peter Steinberger
d932d89778 test: tighten session store rpc assertions 2026-05-11 13:10:18 +01:00
Shakker
fbaac02823 test: assert windows task restart spawn 2026-05-11 13:09:59 +01:00
Val Alexander
342ae551ae fix(logging): reduce active-only liveness noise
Summary:
- Reduce active-only diagnostic liveness noise by emitting transient event-loop max delay samples as info-level telemetry.
- Keep warnings for queued or waiting work and for sustained high P99 loop delay.
- Cover the active-only path in the diagnostic stability tests and changelog.

Verification:
- pnpm format:check src/logging/diagnostic-stability.ts src/logging/diagnostic.test.ts CHANGELOG.md
- pnpm test src/logging/diagnostic.test.ts
- pnpm check:changed
- GitHub PR checks passed on head 25e674fe41.
2026-05-11 07:09:12 -05:00
Peter Steinberger
35827b7dbb test: tighten gateway discovery assertions 2026-05-11 13:09:06 +01:00
Shakker
f7d68cf435 test: assert channel allowlist warnings 2026-05-11 13:08:43 +01:00
Peter Steinberger
4bfdb6ef30 test: tighten gateway health assertions 2026-05-11 13:07:15 +01:00
Peter Steinberger
2dcc05a9eb docs: add Fly container detection changelog (#80209) 2026-05-11 13:06:49 +01:00
Lior Balmas
b94919ab1b test(gateway): isolate Fly env container checks 2026-05-11 13:06:49 +01:00
Lior Balmas
0f8fc6bb61 fix(runtime): detect Fly Machines as containers 2026-05-11 13:06:49 +01:00
Shakker
9bb7f220c9 test: assert daemon config guard json 2026-05-11 13:06:23 +01:00
Peter Steinberger
1f49d34c5f fix(gateway): preserve batched client tool calls 2026-05-11 13:06:05 +01:00
Lellansin
0e6aca34db fix(gateway): align OpenAI chat completions tool protocol
fix(gateway): remove unnecessary type assertion in buildAgentPrompt

fix(gateway): reject unsupported forced tool_choice modes

tool_choice=required and named function tool_choice are now rejected
with invalid_request_error until hard enforcement is implemented
at the agent runtime layer. Only auto and none remain supported.

docs: update Chat Completions tool_choice contract to match rejection behavior

Only auto and none are currently accepted; required and named
function tool_choice are rejected until hard enforcement exists.
2026-05-11 13:06:05 +01:00
Peter Steinberger
efbc550dc9 test: tighten gateway helper assertions 2026-05-11 13:05:47 +01:00
Peter Steinberger
26ac5a3596 test: tighten assistant identity assertions 2026-05-11 13:04:24 +01:00
Ayaan Zaidi
d4c7519989 ci(mantis): allow fork telegram proof 2026-05-11 17:33:29 +05:30
Peter Steinberger
e6b0b37e3f test: tighten websocket log assertions 2026-05-11 13:02:51 +01:00
Shakker
1d5785ba85 test: assert gateway restart handoffs 2026-05-11 13:02:47 +01:00
Peter Steinberger
e0679d0d0c docs: add changelog for sessions resolve scope (#79474) (thanks @samzong) 2026-05-11 13:02:42 +01:00
samzong
c1b29bf5db fix(gateway): scope session resolve store loads 2026-05-11 13:02:42 +01:00
samzong
3e87e55604 fix(ui): preserve empty plugin allowlists
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 13:02:34 +01:00
samzong
adafd4f5be docs(changelog): note plugin allowlist revert fix
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 13:02:34 +01:00
samzong
8e92b069d2 fix(ui): remove reverted plugin allow entries
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 13:02:34 +01:00
Peter Steinberger
776c39b00c test: tighten gateway readiness assertions 2026-05-11 13:01:23 +01:00
Shakker
8f1e6ab13c test: assert config write warnings 2026-05-11 13:00:44 +01:00
Peter Steinberger
e8dc492cb0 test: tighten gateway runtime assertions 2026-05-11 12:59:51 +01:00
Peter Steinberger
8d6bef0de1 test: tighten session create assertions 2026-05-11 12:58:08 +01:00
Shakker
a62b8c77a4 test: assert followup collect prompts 2026-05-11 12:57:48 +01:00
Peter Steinberger
96c2502bfb test: tighten gateway startup assertions 2026-05-11 12:56:28 +01:00
Shakker
51ad59ea0c test: assert acp ledger replay order 2026-05-11 12:55:19 +01:00
Peter Steinberger
a199ddf995 test: tighten gateway response assertions 2026-05-11 12:54:28 +01:00
Shakker
85d5718236 test: assert cli startup routing 2026-05-11 12:52:39 +01:00
Peter Steinberger
3c1d8bbc09 test: tighten shared auth rotation assertions 2026-05-11 12:51:41 +01:00
Peter Steinberger
ee9522ef8d fix: keep browser status page probe within timeout 2026-05-11 12:51:07 +01:00
ai-hpc
b4a420185c fix(browser): add pageReady to Chrome MCP existing-session status
Closes #80268

For Chrome MCP existing-session profiles, browser status previously
exposed only transport-handshake fields (cdpHttp, cdpReady) sourced
from isTransportAvailable(...). It did not surface whether a
page-level tool round-trip (list_pages, etc.) actually succeeds, so
operators and downstream tooling had no honest signal to distinguish
"transport handshake passed" from "page tools are usable".

This adds a pageReady field to BrowserStatus, derived from
profileCtx.isReachable(...) for chrome-mcp profiles (with a status-
bound 5s timeout) and mirroring cdpReady for managed CDP profiles
where the WS handshake already covers page-level reachability.

The status route opts the page probe into ephemeral mode so a passive
status call does not seed a persistent cached Chrome MCP session as a
side effect. listChromeMcpTabs reuses an existing cached attach
session if one already exists, otherwise opens a temporary session
that is closed immediately after the round-trip. The cached-session
path used by /tabs and other interactive routes is unchanged.

isReachable now threads the new ephemeral option (alongside timeoutMs)
into listChromeMcpTabs; existing callers in tabs.ts pass only
timeoutMs and continue to use the cached path.

The page probe is skipped when transport itself is down so status
latency does not regress on offline profiles.

Test changes:
- basic.existing-session.test.ts: the prior assertion that running:
  true and cdpReady: true with isReachable: false is now flipped to
  assert pageReady: false in that state, matching the new contract.
- New tests cover: probe-throws (treated as page-down), both-succeed
  (pageReady: true), transport-down (probe skipped, pageReady: false),
  and an ephemeral-mode regression that asserts the status probe
  passes { ephemeral: true } so it cannot seed a cached session.
2026-05-11 12:51:07 +01:00
Shakker
1eb42c68d9 test: assert completion cache writes 2026-05-11 12:50:46 +01:00
Peter Steinberger
7a6dbffa05 test: tighten gateway auth path assertions 2026-05-11 12:49:55 +01:00
Peter Steinberger
a85c7936e9 test: tighten node pending work assertions 2026-05-11 12:48:31 +01:00
Shakker
c7016bf988 test: assert update cli errors 2026-05-11 12:47:36 +01:00
Peter Steinberger
5f0449d3f3 test: tighten client bootstrap assertions 2026-05-11 12:47:25 +01:00
Peter Steinberger
913c621adb ci: add plugin inspector prerelease advisory 2026-05-11 12:46:33 +01:00
Shakker
cffe71e2ba test: assert legacy sender warnings 2026-05-11 12:46:02 +01:00
Peter Steinberger
d26bc48ae7 test: tighten models http assertions 2026-05-11 12:45:55 +01:00
Peter Steinberger
5da239473c fix(sessions): stream transcript reverse scans 2026-05-11 12:44:59 +01:00
jack-stormentswe
9654239af9 fix(sessions): stream JSONL transcript scans instead of buffering whole files (#54296)
The remaining whole-file transcript scans flagged by ClawSweeper triage on
splitting on newlines. On long-running sessions where transcripts grow into
the multi-MB / 100s-of-MB range that scales peak RSS with file size and is
the practical OOM risk in the report.

Add a shared streaming helper module `src/config/sessions/transcript-stream.ts`
exposing:

- `streamSessionTranscriptLines(filePath, { signal? })`: forward async-iterator
  over trimmed non-empty lines using `fs.createReadStream` + `readline` with
  `crlfDelay: Infinity`. Bounded to one line of memory at a time and honours
  an abort signal between lines.
- `readSessionTranscriptTailLines(filePath, { maxBytes? })`: tail-only read of
  the last `maxBytes` of a file (default 4 MiB, clamped to [1 KiB, 64 MiB]),
  returning trimmed non-empty lines in reverse order. Drops the leading line
  of the slice when the window does not start at byte zero so callers never
  see a partial-line suffix.

Migrate every flagged whole-file scan to these helpers while preserving the
malformed-line tolerance and idempotency-key return semantics callers depend
on (see `Remaining risk / open question` on the issue):

- `src/config/sessions/transcript.ts`: `readLatestAssistantTextFromSessionTranscript`,
  `readTailAssistantTextFromSessionTranscript`, and the delivery-mirror dedupe
  helper `findLatestEquivalentAssistantMessageId` now use the tail helper;
  `transcriptHasIdempotencyKey` uses the forward stream helper.
- `src/gateway/server-methods/chat.ts`: the inline `transcriptHasIdempotencyKey`
  used by chat-method append idempotency now uses the forward stream helper
  and tolerates malformed lines mid-scan (matching the sibling helper in
  `config/sessions/transcript.ts`).
- `src/gateway/session-compaction-checkpoints.ts`: `readTranscriptEntriesForForkAsync`
  builds the fork entry array from the forward stream helper instead of one
  big `fileHandle.readFile("utf-8")` call.

Fixes #54296.
2026-05-11 12:44:59 +01:00
Shakker
69c2bc58fa test: assert cron model diagnostics 2026-05-11 12:44:21 +01:00
Kaspre
775a24e57c fix(doctor): warn when per-agent model omits fallbacks key and defaults chain is non-empty (#79826)
* fix(doctor): warn when per-agent model omits fallbacks key and defaults chain is non-empty

`resolveAgentModelFallbacksOverride` in `src/agents/agent-scope.ts` returns
`[]` (no fallbacks) when a per-agent model is configured without an explicit
`fallbacks` key. At runtime this silently clobbers
`agents.defaults.model.fallbacks`, leaving the agent with no fallbacks.

Two config patterns hit this:

1. String form: `"model": "openai/gpt-5.5"` — user likely means "use this model,
   inherit fallbacks from defaults".
2. Object without `fallbacks` key: `"model": { "primary": "openai/gpt-5.5" }` —
   user likely means "just set the primary, keep defaults fallbacks".

The only explicit "no fallbacks" signal is `fallbacks: []`. This change adds
`collectImplicitFallbackClobberWarnings` / `noteImplicitFallbackClobberWarnings`
to the doctor config-analysis flow, which warns on either ambiguous shape only
when `agents.defaults.model.fallbacks` is non-empty (so there is something to
clobber).

No semantic change to how fallbacks resolve; this is a doctor-only diagnostic.

Closes #79369. Extends the scope of closed PR #79389 (string-form only) to
also cover the object-without-fallbacks case.

* fix(doctor): mirror runtime model primary normalization

* fix(doctor): strengthen fallback warning proof

* fix(doctor): tolerate malformed agent lists

* fix(doctor): type guarded agent runtime policy

* fix(ui): sync quick settings i18n baseline

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-11 12:43:51 +01:00
Peter Steinberger
9c736af39d test: tighten session cost usage assertions 2026-05-11 12:43:05 +01:00
Shakker
2d73d59905 test: assert cron store loads 2026-05-11 12:41:55 +01:00
pashpashpash
2846d9ea56 test: type acp cli option mock assertions 2026-05-11 12:41:21 +01:00
Peter Steinberger
6ee0c9a696 fix(codex): honor codex fallback blocking 2026-05-11 12:41:21 +01:00
Peter Steinberger
3f05165c47 fix(codex): preserve codex auth order 2026-05-11 12:41:21 +01:00
pashpashpash
30ed0329cb fix(codex): avoid mutating rate limit candidates 2026-05-11 12:41:21 +01:00
Peter Steinberger
10c43aefd8 fix(codex): ignore blocked account fallback state 2026-05-11 12:41:21 +01:00
Peter Steinberger
554d80c060 fix(codex): scope auth state updates 2026-05-11 12:41:21 +01:00
pashpashpash
edd7e3c70c test: fix current extension test assertions 2026-05-11 12:41:21 +01:00
Peter Steinberger
b2b381ac4d fix(codex): prefer live account credential state 2026-05-11 12:41:21 +01:00
pashpashpash
e9f8387a63 docs: align slash command btw contract 2026-05-11 12:41:21 +01:00
Peter Steinberger
dbe568556e fix(codex): avoid app-server request cross-talk 2026-05-11 12:41:21 +01:00
Peter Steinberger
95cee42b5b fix(codex): prefer direct codex auth order 2026-05-11 12:41:21 +01:00
Peter Steinberger
8185eb40e8 fix(codex): complete side thread request parity 2026-05-11 12:41:21 +01:00
pashpashpash
3e5544cc76 test(zalouser): type mock Zalo constructor result 2026-05-11 12:41:21 +01:00
pashpashpash
ddc9581d00 fix(codex): preserve side thread tools 2026-05-11 12:41:21 +01:00
pashpashpash
e15f99e34e fix(codex): show api key profile handles 2026-05-11 12:41:21 +01:00
pashpashpash
ac618c6d9d fix(codex): preserve account ladder indentation 2026-05-11 12:41:21 +01:00
pashpashpash
7f5a10e0e4 fix(codex): clarify account auth ladder 2026-05-11 12:41:21 +01:00
pashpashpash
004854e76e fix(codex): preserve blank account separators 2026-05-11 12:41:21 +01:00
pashpashpash
1877c600ea fix(codex): infer api key account fallback 2026-05-11 12:41:21 +01:00
pashpashpash
e310824828 fix(codex): explain account auth fallback 2026-05-11 12:41:21 +01:00
pashpashpash
3ae2799e28 fix(codex): preserve auth candidates for auto profiles 2026-05-11 12:41:21 +01:00
pashpashpash
cc95d4dd28 fix(codex): rotate auth profiles inside harness 2026-05-11 12:41:21 +01:00
pashpashpash
f447e5b9db fix(btw): keep Codex side questions tool-free 2026-05-11 12:41:21 +01:00
pashpashpash
517566e39a fix(auth): accept friendly OpenAI order for Codex profiles 2026-05-11 12:41:21 +01:00
pashpashpash
a947e8fae0 fix(codex): align btw side thread semantics 2026-05-11 12:41:21 +01:00
pashpashpash
42e259a696 fix(codex): route btw through native side threads 2026-05-11 12:41:21 +01:00
Peter Steinberger
4aa13b5338 test: tighten outbound target assertions 2026-05-11 12:40:55 +01:00
Shakker
1c452ddabf test: assert aux reload failures 2026-05-11 12:40:15 +01:00
Shakker
996a38466f test: assert session usage errors 2026-05-11 12:38:28 +01:00
Peter Steinberger
f57bcb0788 test: tighten outbound route assertions 2026-05-11 12:37:21 +01:00
Shakker
5569973d90 test: assert restart sentinel warnings 2026-05-11 12:36:53 +01:00
Shakker
34186196df test: assert gateway startup logs 2026-05-11 12:35:03 +01:00
Peter Steinberger
691b760df3 test: tighten outbound action runner assertions 2026-05-11 12:34:58 +01:00
Peter Steinberger
1a7efcad4b docs: add memory symlink traversal changelog (#80331) (thanks @samzong) 2026-05-11 12:34:01 +01:00
samzong
5ad3fa0a17 fix(memory): preserve ENOTDIR missing reads
Signed-off-by: samzong <samzong.lu@gmail.com>
2026-05-11 12:34:01 +01:00
samzong
c6748a8eeb fix(memory): block extra path symlink traversal
## Considered and deferred

- packages/memory-host-sdk/src/host/read-file.ts:77 [BOT-SCOPE]: Fully race-proof parent traversal would need a lower-level pinned/openat-style primitive; this diff fixes static symlink traversal and rejects symlink components before read.
2026-05-11 12:34:01 +01:00
Shakker
d21c47d711 test: assert plugin route runtime scopes 2026-05-11 12:33:04 +01:00
Peter Steinberger
2f1a9faae8 test: tighten outbound storage assertions 2026-05-11 12:31:18 +01:00
Peter Steinberger
3756e5dc10 test: tighten infra edge-case assertions 2026-05-11 12:29:37 +01:00
Shakker
7d966238b3 test: assert whatsapp inbox payloads 2026-05-11 12:27:44 +01:00
Peter Steinberger
7aa8f69808 test: tighten approval runtime assertions 2026-05-11 12:27:02 +01:00
Peter Steinberger
e520d9b8f6 test: tighten proxy dispatcher assertions 2026-05-11 12:25:27 +01:00
Shakker
06292d83a5 test: assert get-reply fixture config 2026-05-11 12:24:05 +01:00
Peter Steinberger
b9c5290a45 test: tighten infra warning and restart assertions 2026-05-11 12:21:46 +01:00
Shakker
a29b2b4026 test: assert session compaction payloads 2026-05-11 12:21:39 +01:00
Peter Steinberger
9c9b719cc9 test: tighten ssrf dispatcher assertions 2026-05-11 12:18:55 +01:00
Peter Steinberger
8e7ee67f67 test: tighten ssrf pinning assertions 2026-05-11 12:17:53 +01:00
Shakker
40457455e1 test: assert tts contract attempts 2026-05-11 12:17:30 +01:00
Peter Steinberger
26a0de82df test: tighten runtime fetch formdata assertions 2026-05-11 12:16:32 +01:00
Peter Steinberger
c2a13e292f test: tighten heartbeat runner assertions 2026-05-11 12:15:17 +01:00
Peter Steinberger
0f03af8643 test: tighten infra fetch summary assertions 2026-05-11 12:13:28 +01:00
Kaspre
7eefb26bc8 fix(heartbeat): remap cron-run exec events to session keys (#80214)
Summary:
- Remap cron-run async exec, ACP, node-event, and watchdog completion events to the queue heartbeat drains.
- Route per-sender cron-run events to the agent main queue and global-scope events to `global` while preserving the originating `agentId`.
- Tighten exec-completion classification and treat cron-run descendants as ephemeral for retention pruning.

Verification:
- CI: https://github.com/openclaw/openclaw/actions/runs/25625964382 passed.
- Real behavior proof: https://github.com/openclaw/openclaw/actions/runs/25666664248/job/75340798016 passed.
- PR targeted validation: `node scripts/run-vitest.mjs run --config test/vitest/vitest.unit.config.ts src/routing/session-key.test.ts src/infra/heartbeat-events-filter.test.ts src/agents/bash-tools.exec-runtime.test.ts src/agents/acp-spawn-parent-stream.test.ts src/cron/session-reaper.test.ts`.
- PR targeted typecheck: `pnpm tsgo:core`.

Refs #52305.
Related: #18237, #14191.

Co-authored-by: Kaspre <kaspre@gmail.com>
2026-05-11 12:13:17 +01:00
Shakker
ccc6109853 test: assert plugin update warnings 2026-05-11 12:13:14 +01:00
Peter Steinberger
2cd08508ea test: tighten infra helper assertions 2026-05-11 12:11:36 +01:00
Peter Steinberger
c1e4b4d2a9 test: tighten device auth token assertions 2026-05-11 12:10:27 +01:00
Peter Steinberger
c53d7aee0f test: tighten agent event context assertions 2026-05-11 12:08:25 +01:00
Shakker
a6f80874b3 test: assert acp cli option payloads 2026-05-11 12:07:57 +01:00
Peter Steinberger
1e9ddc33a3 test: tighten device identity storage assertions 2026-05-11 12:07:06 +01:00
Peter Steinberger
605fb9731d test: tighten channel runtime context assertions 2026-05-11 12:06:05 +01:00
Peter Steinberger
01d9d1be83 test: tighten apns auth assertions 2026-05-11 12:03:43 +01:00
Peter Steinberger
58ca32a79a test: tighten safe npm install env assertions 2026-05-11 12:02:39 +01:00
Shakker
499d789f97 test: assert config compat warnings 2026-05-11 12:02:01 +01:00
Peter Steinberger
950be50c0d test: tighten session maintenance warning assertions 2026-05-11 12:00:57 +01:00
Peter Steinberger
ffba41fe6b fix(codex): ignore echoed abort marker prompts 2026-05-11 11:59:56 +01:00
Peter Steinberger
be0e85a72d fix(codex): accept abort markers without request responses 2026-05-11 11:59:56 +01:00
Peter Steinberger
b273b81e5b fix(codex): narrow app-server abort marker fallback 2026-05-11 11:59:56 +01:00
Peter Steinberger
4ff28a7735 fix(codex): release interrupted app-server turns 2026-05-11 11:59:56 +01:00
Shakker
6207ba7010 test: assert session maintenance warnings 2026-05-11 11:59:11 +01:00
Peter Steinberger
42f277dc60 test: tighten gateway tls runtime assertions 2026-05-11 11:58:36 +01:00
Peter Steinberger
1b6143b7f9 fix: hide sandbox marker in command previews 2026-05-11 11:58:29 +01:00
Shakker
fd21722cdf test: assert port conflict hints 2026-05-11 11:57:19 +01:00
Shakker
51be8f4647 test: assert temp dir repair warnings 2026-05-11 11:56:15 +01:00
Peter Steinberger
cb0f983544 test: tighten windows task restart assertions 2026-05-11 11:55:43 +01:00
Peter Steinberger
1a61e28117 test: tighten inbound reply dispatch assertions 2026-05-11 11:54:11 +01:00
Shakker
f2d9d76996 test: assert channel ingress access fields 2026-05-11 11:52:06 +01:00
Peter Steinberger
4e67506f71 test: tighten qa runner runtime assertions 2026-05-11 11:51:19 +01:00
Shakker
5e318ce3cd test: assert channel config DM policies 2026-05-11 11:50:40 +01:00
Shakker
3f30ec4602 test: assert acp dispatch payloads 2026-05-11 11:48:11 +01:00
Peter Steinberger
1ff126c682 test: tighten plugin tool payload assertions 2026-05-11 11:46:51 +01:00
Shakker
ca73c8da43 test: assert tool payload parse blocks 2026-05-11 11:44:55 +01:00
Shakker
5b66d7f865 test: assert anthropic vertex stream options 2026-05-11 11:43:11 +01:00
Shakker
af322da872 test: assert anthropic vertex catalog 2026-05-11 11:42:25 +01:00
Peter Steinberger
3f5f038cc9 test: tighten active tab refresh assertions 2026-05-11 11:42:19 +01:00
Shakker
6c4ffec1be test: assert browser plugin registration 2026-05-11 11:41:18 +01:00
Peter Steinberger
526d5390c6 test: tighten exec approval parser assertions 2026-05-11 11:41:01 +01:00
Peter Steinberger
c71bc216cf test: tighten sessions controller assertions 2026-05-11 11:39:55 +01:00
Shakker
63649bbbff test: assert matrix monitor payloads 2026-05-11 11:39:46 +01:00
Peter Steinberger
71192383e7 test: tighten webrtc realtime talk assertions 2026-05-11 11:38:27 +01:00
Shakker
21e0f60890 test: assert matrix startup directory calls 2026-05-11 11:38:04 +01:00
Peter Steinberger
3021d36f84 test: tighten acpx runtime lease assertions 2026-05-11 11:36:55 +01:00
Shakker
0f83118dfd test: assert matrix registration calls 2026-05-11 11:36:31 +01:00
Peter Steinberger
accba2c4e2 test: tighten anthropic vertex stream assertions 2026-05-11 11:35:32 +01:00
Shakker
bc338a4019 test: assert matrix config storage calls 2026-05-11 11:35:27 +01:00
Peter Steinberger
8ac299ee49 test: tighten browser cdp screenshot assertions 2026-05-11 11:34:16 +01:00
Harris Ali
39cbe94f07 fix(msteams): normalize pre-suffixed thread session keys (#78850)
Normalize pre-thread-qualified Teams route session keys before deriving channel-thread lanes so cached route reuse cannot create malformed mixed thread sessions.

Co-authored-by: Harris Ali <harrisali@getfieldforce.com>
2026-05-11 05:34:14 -05:00
Shakker
5a4201fd86 test: assert matrix client error shapes 2026-05-11 11:33:23 +01:00
Peter Steinberger
5b293150c3 test: tighten browser doctor assertions 2026-05-11 11:32:59 +01:00
Andy
6d26609f7b fix(windows): prevent restart race from duplicate schtasks /Run (#52487)
Prevent duplicate scheduled-task /Run attempts during Windows gateway restart by checking the task state before retrying.

Co-authored-by: Andy K <andyk-ms@users.noreply.github.com>
2026-05-11 05:32:48 -05:00
Peter Steinberger
37fa027772 test: tighten codex protocol validator assertions 2026-05-11 11:31:04 +01:00
Shakker
8de5a3e2b8 test: assert matrix profile action calls 2026-05-11 11:30:41 +01:00
Shakker
8a13d09b3a test: assert matrix recovery key result 2026-05-11 11:29:41 +01:00
Peter Steinberger
c60950856d test: tighten codex conversation binding assertions 2026-05-11 11:29:16 +01:00
Shakker
432e19527e test: assert matrix raw event serialization 2026-05-11 11:28:35 +01:00
Shakker
b00e84e6be test: assert matrix poll parsing 2026-05-11 11:27:50 +01:00
Peter Steinberger
3ed9b23834 test: tighten memory import insight assertions 2026-05-11 11:27:02 +01:00
Shakker
83748bc8bb test: assert matrix client options 2026-05-11 11:26:41 +01:00
Shakker
4c63dd9f95 test: assert matrix room config results 2026-05-11 11:26:02 +01:00
Peter Steinberger
c59cb73584 test: tighten memory palace assertions 2026-05-11 11:25:14 +01:00
Shakker
5a77d791dd test: assert matrix event summaries 2026-05-11 11:24:25 +01:00
Shakker
deaed7a2bd test: assert matrix device health summary 2026-05-11 11:23:50 +01:00
Peter Steinberger
75daa12562 test: tighten openai device code assertions 2026-05-11 11:23:25 +01:00
Shakker
81281609b8 test: assert matrix direct room mappings 2026-05-11 11:22:23 +01:00
Shakker
d17a347f8c test: assert matrix tool action details 2026-05-11 11:20:51 +01:00
Peter Steinberger
3a5155bfff test: tighten qa live gateway assertions 2026-05-11 11:19:54 +01:00
Shakker
ab12985d71 test: assert matrix action schema fields 2026-05-11 11:19:03 +01:00
Shakker
225cbb7b21 test: assert matrix sync store payloads 2026-05-11 11:18:10 +01:00
Peter Steinberger
75f6bd212c test: tighten whatsapp live runtime assertions 2026-05-11 11:17:52 +01:00
Peter Steinberger
22e2ee3103 docs: clarify fixed issue closeout 2026-05-11 11:17:23 +01:00
Shakker
d29865f4b6 test: assert matrix resolver runtime forwarding 2026-05-11 11:16:41 +01:00
Peter Steinberger
c7fd9fcbb7 test: tighten mantis telegram builder assertions 2026-05-11 11:16:22 +01:00
Shakker
68fdb8007d test: assert matrix message adapter calls 2026-05-11 11:14:49 +01:00
Peter Steinberger
36e457aa72 test: tighten extension test call typing 2026-05-11 11:14:16 +01:00
Shakker
3e31b0946f test: assert matrix runtime exports 2026-05-11 11:14:02 +01:00
Peter Steinberger
cb088c8160 fix(ui): preserve draft on chat stop 2026-05-11 11:13:23 +01:00
Shakker
3e2cd6676a test: assert matrix device action results 2026-05-11 11:13:16 +01:00
Peter Steinberger
cd52ea1108 test: tighten slack draft stream assertions 2026-05-11 11:11:51 +01:00
Shakker
324289eebf test: assert msteams attachment warning 2026-05-11 11:11:42 +01:00
Shakker
3a040d3562 test: assert msteams consent upload request 2026-05-11 11:11:00 +01:00
Shakker
432ffec88d test: assert msteams inbound media diagnostics 2026-05-11 11:10:25 +01:00
Peter Steinberger
e376aa4ee1 docs: clarify model override fallback routes 2026-05-11 11:09:47 +01:00
Shakker
202f65c40b test: assert msteams message adapter calls 2026-05-11 11:09:30 +01:00
Peter Steinberger
37f1f5d4ab test: tighten slack progress block assertions 2026-05-11 11:09:03 +01:00
Peter Steinberger
f9016145c8 test: tighten slack security audit assertions 2026-05-11 11:07:46 +01:00
Shakker
fcb631e1d3 test: assert msteams owner role graph request 2026-05-11 11:07:23 +01:00
Peter Steinberger
4d4512c144 test: tighten telegram media download assertions 2026-05-11 11:06:33 +01:00
Shakker
ae3be984a5 test: assert msteams adaptive card dispatch payload 2026-05-11 11:06:17 +01:00
Jeff J Hunter
3247b091d6 Add browser and tool profile quick settings (#80609)
Summary:
- The PR adds Browser enabled and Tool profile controls to Control UI Quick Settings, stacks the tool profile row for narrow cards, and adds focused UI tests plus a screenshot asset.
- Reproducibility: not applicable. This PR adds a Control UI quick-settings capability rather than fixing a reported reproducible bug. Source inspection and the supplied screenshot/log proof cover the changed behavior.

Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.

Validation:
- ClawSweeper review passed for head 06adff19fd.
- Required merge gates passed before the squash merge.

Prepared head SHA: 06adff19fd
Review: https://github.com/openclaw/openclaw/pull/80609#issuecomment-4419255136

Co-authored-by: Jeff J Hunter <support@aipersonamethod.com>
2026-05-11 10:06:00 +00:00
Shakker
e2d51cacfe test: assert msteams delivery failure event 2026-05-11 11:04:50 +01:00
Peter Steinberger
3b1ad58241 test: tighten telegram gateway assertions 2026-05-11 11:03:44 +01:00
Shakker
b73c1dc58f test: assert google meet bridge session fields 2026-05-11 11:03:29 +01:00
Peter Steinberger
1327f6742f ci: keep ClawSweeper comment dispatch best effort 2026-05-11 11:02:00 +01:00
Shakker
e31af364ab test: assert browser existing-session profile shape 2026-05-11 11:01:09 +01:00
Shakker
9bccba3544 test: assert browser dispatcher error responses 2026-05-11 10:59:51 +01:00
Shakker
62ace89c23 test: tighten browser permission assertions 2026-05-11 10:58:37 +01:00
Shakker
9b72e7cfa6 test: tighten browser control state assertion 2026-05-11 10:57:40 +01:00
Peter Steinberger
94035bc200 test: tighten telegram monitor assertions 2026-05-11 10:57:02 +01:00
Shakker
ec2bef8154 test: tighten memory citation assertions 2026-05-11 10:56:32 +01:00
Shakker
ae98568b00 test: tighten qqbot stt request assertions 2026-05-11 10:55:07 +01:00
Peter Steinberger
89b894d630 fix: allow voice approval followups 2026-05-11 10:54:42 +01:00
Peter Steinberger
b3e2f3b261 fix: repair broken plugin package entries 2026-05-11 10:53:55 +01:00
Shakker
92ff210941 test: tighten qqbot reminder assertions 2026-05-11 10:53:41 +01:00
Peter Steinberger
c0602499ef docs: refresh crabbox skill for run helpers 2026-05-11 10:53:38 +01:00
Peter Steinberger
7a6f73a8aa fix(whatsapp): apply hot-reloaded DM policy 2026-05-11 10:53:10 +01:00
Shakker
ff3bf53938 test: tighten qqbot setup config assertions 2026-05-11 10:52:39 +01:00
Peter Steinberger
95948ce504 test: tighten telegram session route assertions 2026-05-11 10:51:51 +01:00
Shakker
5a9e8a29e5 test: tighten qqbot outbound assertions 2026-05-11 10:50:55 +01:00
Shakker
a4e6d00770 test: tighten qqbot quote assertion 2026-05-11 10:49:59 +01:00
Peter Steinberger
3eedeab04d test: tighten codex oauth refresh assertions 2026-05-11 10:49:32 +01:00
Shakker
5e43abe378 test: tighten qqbot attachment assertions 2026-05-11 10:49:05 +01:00
Shakker
c4cd22af0b test: tighten qqbot group config assertion 2026-05-11 10:48:08 +01:00
Shakker
946393a926 test: tighten qqbot policy assertions 2026-05-11 10:47:08 +01:00
Peter Steinberger
3e8ea999ba test: tighten directive parser assertions 2026-05-11 10:46:07 +01:00
Shakker
10575ea84a test: tighten telegram binding rejection assertions 2026-05-11 10:44:35 +01:00
Peter Steinberger
bbd3e7da75 test: tighten agent runner utility assertions 2026-05-11 10:44:10 +01:00
Shakker
59e1a00f5c test: tighten telegram threading context assertions 2026-05-11 10:42:48 +01:00
Peter Steinberger
3939750648 test: tighten tts command assertions 2026-05-11 10:41:46 +01:00
Peter Steinberger
9de498bfb0 test: fix current test type assertions 2026-05-11 10:41:37 +01:00
Shakker
3aa43c1dbd test: tighten msteams token store assertion 2026-05-11 10:41:23 +01:00
Shakker
90c97346f0 test: tighten googlechat target assertions 2026-05-11 10:40:01 +01:00
Peter Steinberger
c880d917cd test: tighten session lifecycle assertions 2026-05-11 10:39:24 +01:00
Shakker
b69f4cfdee test: tighten googlechat access assertions 2026-05-11 10:38:38 +01:00
Peter Steinberger
e21e83db97 fix(config): normalize Gemini provider catalog writes 2026-05-11 10:37:52 +01:00
Shakker
e88956d235 test: tighten googlechat auth assertions 2026-05-11 10:37:32 +01:00
Shakker
3112fbcb4d test: tighten diffs store cleanup assertion 2026-05-11 10:36:35 +01:00
Shakker
11aacaaf1d test: tighten google shared payload assertions 2026-05-11 10:33:58 +01:00
Shakker
7c18a5f575 test: tighten feishu account assertion 2026-05-11 10:32:45 +01:00
Ayaan Zaidi
becb6e8bbb fix(mantis): route telegram proof through trusted harness 2026-05-11 15:02:36 +05:30
Shakker
7e1afc0fea test: tighten zalouser channel assertion 2026-05-11 10:31:33 +01:00
Peter Steinberger
02f3b531a6 test: tighten channel catalog assertions 2026-05-11 10:31:14 +01:00
Shakker
0a39738257 test: tighten memory event assertions 2026-05-11 10:30:15 +01:00
Shakker
e588eadb5b test: tighten memory tool debug assertions 2026-05-11 10:29:26 +01:00
Shakker
efa6da6e02 test: tighten memory dreaming command assertions 2026-05-11 10:28:20 +01:00
Peter Steinberger
d1140d0f6f test: fix discord threading lint 2026-05-11 10:28:12 +01:00
Shakker
eae975d42d test: tighten google manifest alias assertions 2026-05-11 10:27:17 +01:00
Shakker
3fe1c1504d test: tighten memory dreaming markdown assertion 2026-05-11 10:25:54 +01:00
Shakker
9365da211a test: tighten browser cli timeout assertion 2026-05-11 10:24:58 +01:00
Shakker
81c48622ca test: tighten browser cli lazy assertions 2026-05-11 10:24:17 +01:00
Peter Steinberger
76b6ad1484 test: tighten daemon probe assertions 2026-05-11 10:24:02 +01:00
Shakker
79da106d25 test: tighten google provider hook assertions 2026-05-11 10:23:05 +01:00
Shakker
e4ea45495c test: tighten google web search assertion 2026-05-11 10:20:42 +01:00
Peter Steinberger
4cfba8b45d chore: fix transport lint regressions 2026-05-11 10:19:46 +01:00
Shakker
b29bcbcf75 test: tighten mattermost setup assertion 2026-05-11 10:19:38 +01:00
Shakker
497fed0e50 test: tighten discord webhook error assertions 2026-05-11 10:17:59 +01:00
Shakker
33910876a7 test: tighten imessage gating assertion 2026-05-11 10:16:33 +01:00
Peter Steinberger
1307cf4d5c test: tighten port probe assertions 2026-05-11 10:15:48 +01:00
Shakker
1ba3a2c882 test: tighten imessage inbound assertion 2026-05-11 10:15:38 +01:00
Shakker
1c484d4303 test: tighten openshell backend assertion 2026-05-11 10:14:38 +01:00
Peter Steinberger
313ce2c18c docs: add pnpm follow-up changelog (#80588) 2026-05-11 10:13:49 +01:00
Altay
7084c7d43f test(pnpm): check workflow pnpm major 2026-05-11 10:13:49 +01:00
Altay
a3cbc67a37 test(pnpm): derive workflow pin from package manager 2026-05-11 10:13:49 +01:00
Altay
7d35f28b6c chore(pnpm): align follow-up pnpm 11 surfaces 2026-05-11 10:13:49 +01:00
Peter Steinberger
dcb37a39b3 test: tighten setup command assertions 2026-05-11 10:12:44 +01:00
Shakker
c95bbca8f1 test: tighten zai onboard assertions 2026-05-11 10:12:37 +01:00
Shakker
4452df5b17 test: tighten slack probe timeout assertion 2026-05-11 10:11:29 +01:00
Peter Steinberger
b9185703bc chore: add model transport debugging 2026-05-11 10:11:03 +01:00
Shakker
640d1994c0 test: tighten brave search error assertions 2026-05-11 10:10:42 +01:00
Peter Steinberger
e2e63b82ac test: tighten security cli assertions 2026-05-11 10:10:33 +01:00
Shakker
b60de25021 test: tighten minimax provider assertions 2026-05-11 10:09:10 +01:00
Peter Steinberger
804edb10f3 test: tighten cron model preflight assertions 2026-05-11 10:08:30 +01:00
Shakker
fcfff66e98 test: tighten discord component fallback assertions 2026-05-11 10:07:45 +01:00
Shakker
000e39310d test: tighten discord preflight binding assertions 2026-05-11 10:06:35 +01:00
Shakker
6efb4e13db test: tighten discord acp preflight assertions 2026-05-11 10:05:18 +01:00
Peter Steinberger
6e6decf5d2 test: tighten cron sandbox config assertions 2026-05-11 10:04:37 +01:00
Shakker
9885680469 test: tighten discord acp bind assertions 2026-05-11 10:04:30 +01:00
Peter Steinberger
37fac48f97 test: tighten cron session key assertions 2026-05-11 10:02:29 +01:00
Shakker
8a9f99d3e5 test: tighten discord native command assertions 2026-05-11 10:02:02 +01:00
Shakker
4766ad6b06 test: tighten discord gateway metadata assertions 2026-05-11 10:00:56 +01:00
Peter Steinberger
8cdaf771db test: tighten embeddings http assertions 2026-05-11 10:00:23 +01:00
Shakker
3911058708 test: tighten discord threading utility assertions 2026-05-11 09:59:58 +01:00
oliviareid-svg
337f1b2a42 fix(microsoft-foundry): replace unsafe non-null assertion in subscription lookup (#62742)
subs.find() can return undefined if the selected subscription ID does not match any enabled subscription. Replace the unsafe non-null assertion with an explicit guard and descriptive error.

Co-authored-by: oliviareid-svg <oliviareid@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-11 03:59:34 -05:00
Shakker
1bf6bd33b5 test: tighten discord component context assertions 2026-05-11 09:58:51 +01:00
Shakker
493995467e test: tighten discord binding api assertions 2026-05-11 09:58:07 +01:00
Shakker
c5d816b873 test: tighten discord thread starter assertions 2026-05-11 09:56:58 +01:00
Peter Steinberger
2e1e914572 test: tighten approval bootstrap assertions 2026-05-11 09:56:35 +01:00
Shakker
48d320b931 test: tighten discord route assertions 2026-05-11 09:54:48 +01:00
Shakker
37bce8ad4d test: tighten discord channel access assertions 2026-05-11 09:53:54 +01:00
Shakker
13458025bc test: tighten discord dm auth assertions 2026-05-11 09:53:18 +01:00
Shakker
893632fc67 test: tighten slack reaction assertions 2026-05-11 09:52:35 +01:00
Peter Steinberger
76903f4dbf test: tighten gateway close assertions 2026-05-11 09:51:47 +01:00
Shakker
733545c90d test: tighten discord voice assertions 2026-05-11 09:51:04 +01:00
Peter Steinberger
e432c32701 test: tighten gateway method list assertions 2026-05-11 09:49:42 +01:00
Ayaan Zaidi
96d4dd68da fix(mantis): validate telegram driver before lease 2026-05-11 14:19:36 +05:30
Shakker
4ddccbd28d test: tighten comfy provider assertions 2026-05-11 09:48:48 +01:00
Shakker
0f4a37c828 test: tighten tlon security assertions 2026-05-11 09:47:46 +01:00
Peter Steinberger
7e8f74ded4 test: tighten chat abort auth assertions 2026-05-11 09:46:00 +01:00
Shakker
0f574902d8 test: tighten discord action assertions 2026-05-11 09:45:50 +01:00
Peter Steinberger
0ed0f93620 test: tighten skill upload store assertions 2026-05-11 09:42:26 +01:00
Shakker
50efe3f55e test: tighten qa matrix tee assertions 2026-05-11 09:42:08 +01:00
Shakker
928bd2de01 test: tighten mattermost slash monitor assertions 2026-05-11 09:41:24 +01:00
Shakker
9da1ac1bb1 test: tighten mattermost websocket assertions 2026-05-11 09:40:24 +01:00
Peter Steinberger
84190e3de3 test: tighten tasks handler assertions 2026-05-11 09:39:59 +01:00
Shakker
192d161f7f test: tighten mattermost draft assertions 2026-05-11 09:39:12 +01:00
Shakker
8b8f653b50 test: tighten mattermost client assertions 2026-05-11 09:38:25 +01:00
Peter Steinberger
037ebe76f3 test: tighten tools effective assertions 2026-05-11 09:37:49 +01:00
Shakker
efbffd808f test: tighten mattermost gating assertions 2026-05-11 09:37:30 +01:00
Peter Steinberger
32906ea64c test: use stable array ordering helpers 2026-05-11 09:37:13 +01:00
Peter Steinberger
f2031ee8c1 test: remove redundant slack test cast 2026-05-11 09:37:13 +01:00
Peter Steinberger
de630ce4f0 docs: update changelog for retry-after fix (#68543) 2026-05-11 09:37:13 +01:00
Feelw00
b7fc2451e7 fix(infra): positive jitter 는 Math.ceil 로 non-integer retryAfterMs 하방도 보장 (cross-review) 2026-05-11 09:37:13 +01:00
Feelw00
a77bd213ce fix(infra): Retry-After 경계(===)에서 contract 우선, symmetric 은 >만 (codex override) 2026-05-11 09:37:13 +01:00
Feelw00
317e474b84 fix(infra): retryAfterMs === maxDelayMs 경계에서도 symmetric fallback (greptile review) 2026-05-11 09:37:13 +01:00
Feelw00
62dff64700 fix(infra): retryAfterMs > maxDelayMs 때 symmetric jitter 유지 (codex review) 2026-05-11 09:37:13 +01:00
Feelw00
d49480527e fix(infra): retryAsync retry-after 를 jitter 가 침범하지 않도록 positive-only mode 적용 2026-05-11 09:37:13 +01:00
Shakker
d4dbcea0cf test: tighten mattermost slash assertions 2026-05-11 09:36:52 +01:00
Shakker
394011ab16 test: tighten irc send assertions 2026-05-11 09:36:13 +01:00
Shakker
d67ad56658 test: tighten qa matrix cli assertions 2026-05-11 09:34:53 +01:00
Peter Steinberger
fdb4b8940c test: tighten gateway reload assertions 2026-05-11 09:34:38 +01:00
Peter Steinberger
21fb799168 fix(agents): label sandbox tool workdirs 2026-05-11 09:33:34 +01:00
Peter Steinberger
eb38d2d277 fix(deps): update fs-safe Windows stat fallback 2026-05-11 09:33:15 +01:00
Peter Steinberger
e8ab20c0e4 test: tighten session search assertions 2026-05-11 09:31:44 +01:00
Shakker
d9314f7f45 test: tighten mattermost authz assertions 2026-05-11 09:31:30 +01:00
Shakker
3b89a8b961 test: tighten mattermost auth assertions 2026-05-11 09:30:36 +01:00
Peter Steinberger
12624457d0 test: tighten message hook mapper assertions 2026-05-11 09:29:37 +01:00
Shakker
86a84015a9 test: tighten channel send assertions 2026-05-11 09:29:18 +01:00
Peter Steinberger
50700ccca1 test: tighten backup create assertions 2026-05-11 09:27:39 +01:00
Shakker
337d58404f test: tighten dreaming repair assertions 2026-05-11 09:27:29 +01:00
Shakker
2b5c18012c test: tighten memory cli assertions 2026-05-11 09:26:40 +01:00
Peter Steinberger
0dbdbc1372 test: tighten device bootstrap assertions 2026-05-11 09:25:59 +01:00
Shakker
413197238b test: tighten msteams feedback assertions 2026-05-11 09:24:46 +01:00
Peter Steinberger
00cf49d607 test: fix assertion type checks 2026-05-11 09:23:54 +01:00
Peter Steinberger
fb02e25798 test: tighten package update step assertions 2026-05-11 09:23:26 +01:00
Ayaan Zaidi
1564e70b3b fix(browser): reuse chrome mcp screenshot format 2026-05-11 13:52:38 +05:30
Baris Albayrak
86794d638e docs(changelog): link #77222 for chrome-mcp screenshot fix 2026-05-11 13:52:38 +05:30
Baris Albayrak
694e05be0e docs(changelog): credit @barbarhan for #74685 2026-05-11 13:52:38 +05:30
Baris Albayrak
6e4c17ca35 fix(browser): read chrome MCP screenshot extension 2026-05-11 13:52:38 +05:30
Shakker
cdc8247dd8 test: tighten browser and memory path assertions 2026-05-11 09:22:22 +01:00
Peter Steinberger
6a58d84b2d test: tighten restart handoff assertions 2026-05-11 09:21:21 +01:00
Shakker
95d711977b test: tighten acpx auth bridge assertions 2026-05-11 09:21:17 +01:00
Shakker
38295d3c04 test: tighten slack and openshell assertions 2026-05-11 09:20:24 +01:00
Shakker
27ec47d433 test: tighten device pair assertions 2026-05-11 09:18:03 +01:00
Peter Steinberger
43653f5d23 test: tighten shell env assertions 2026-05-11 09:17:24 +01:00
Shakker
1772716fc1 test: tighten qa aimock server assertions 2026-05-11 09:16:28 +01:00
Shakker
fb451028d5 test: tighten fal image assertions 2026-05-11 09:14:43 +01:00
Peter Steinberger
dd5ce8712f test: tighten tsdown config assertions 2026-05-11 09:13:42 +01:00
Shakker
d544414eef test: tighten copilot model assertions 2026-05-11 09:13:17 +01:00
Shakker
44b13ef25e test: tighten copilot stream assertions 2026-05-11 09:12:02 +01:00
Peter Steinberger
da9e77f6e9 test: tighten diagnostic support export assertions 2026-05-11 09:11:15 +01:00
Shakker
7e6c407c03 test: tighten minimax provider assertions 2026-05-11 09:09:52 +01:00
Peter Steinberger
b282745b4c test: tighten app render helper assertions 2026-05-11 09:08:49 +01:00
Shakker
32f3af8bbc test: tighten feishu assertion coverage 2026-05-11 09:08:33 +01:00
Peter Steinberger
e9174fc984 test: tighten tool card assertions 2026-05-11 09:06:29 +01:00
Shakker
6066e878f6 test: tighten slack setup manifest assertion 2026-05-11 09:05:16 +01:00
Peter Steinberger
2d64ee0aec test: tighten google live talk assertions 2026-05-11 09:05:10 +01:00
Shakker
69b6f1f676 test: tighten speech provider assertions 2026-05-11 09:04:29 +01:00
Shakker
baa72f4c45 test: tighten hermes secret assertions 2026-05-11 09:03:18 +01:00
Peter Steinberger
85e9dd0720 test: tighten command palette item assertions 2026-05-11 09:02:44 +01:00
Shakker
4bef5422cd test: tighten openrouter provider assertions 2026-05-11 09:02:24 +01:00
Peter Steinberger
71d814ee35 test: tighten browser chrome diagnostics 2026-05-11 09:00:57 +01:00
Peter Steinberger
f12f123f43 fix: keep workspace file status on Windows 2026-05-11 08:58:52 +01:00
Shakker
c249163537 test: tighten zalouser setup assertions 2026-05-11 08:58:41 +01:00
Peter Steinberger
f4aa97f660 test: tighten browser cli inspect assertions 2026-05-11 08:57:56 +01:00
Shakker
f7938c82db test: tighten comfy video assertions 2026-05-11 08:57:09 +01:00
Peter Steinberger
043d27b0ea test: tighten codex media request assertions 2026-05-11 08:56:04 +01:00
Shakker
63236764b5 test: tighten comfy music assertions 2026-05-11 08:55:54 +01:00
Shakker
02ddac4f76 test: tighten qa inbound assertions 2026-05-11 08:54:44 +01:00
Peter Steinberger
3870850d91 test: tighten codex auth bridge assertions 2026-05-11 08:54:12 +01:00
Shakker
e3b5e28cff test: tighten mattermost slash state assertions 2026-05-11 08:52:53 +01:00
Shakker
ee0563cb52 test: tighten qa bus client assertions 2026-05-11 08:50:44 +01:00
Shakker
54807c3af8 test: tighten synology tls assertions 2026-05-11 08:49:52 +01:00
Peter Steinberger
89641f37ae test: tighten codex plugin inventory assertions 2026-05-11 08:49:39 +01:00
Shakker
004bb2013e test: tighten device pair notify assertions 2026-05-11 08:48:57 +01:00
Ayaan Zaidi
799bd8a23b ci(mantis): fetch ffmpeg proof tools directly 2026-05-11 13:18:34 +05:30
Peter Steinberger
cb3d5c0c61 test: tighten codex plugin thread config assertions 2026-05-11 08:48:28 +01:00
Shakker
9062313486 test: tighten msteams conversation store assertions 2026-05-11 08:48:01 +01:00
Peter Steinberger
672ef67fa7 test: tighten discord component assertions 2026-05-11 08:47:10 +01:00
Shakker
42e1d68a74 test: tighten msteams credential assertions 2026-05-11 08:46:54 +01:00
Shakker
f1190f2ad5 test: tighten ollama provider policy assertions 2026-05-11 08:46:09 +01:00
Peter Steinberger
bd26b13d1e test: tighten discord subagent hook assertions 2026-05-11 08:45:58 +01:00
Shakker
ce1fe33ca0 test: tighten ollama stream content assertions 2026-05-11 08:45:26 +01:00
Peter Steinberger
baba16518e test: tighten matrix reaction assertions 2026-05-11 08:44:39 +01:00
Shakker
6187b425d5 test: tighten discord voice command assertions 2026-05-11 08:44:21 +01:00
Shakker
d8a9860df7 test: tighten google meet oauth assertions 2026-05-11 08:43:29 +01:00
Peter Steinberger
852d267767 test: tighten matrix credential assertions 2026-05-11 08:43:26 +01:00
Shakker
829375f634 test: tighten msteams pending upload fs assertions 2026-05-11 08:42:47 +01:00
Peter Steinberger
086bb3514f test: tighten matrix route assertions 2026-05-11 08:41:50 +01:00
Shakker
923c993e5a test: tighten tlon sse subscription assertions 2026-05-11 08:41:43 +01:00
Ayaan Zaidi
1caf3ae674 ci(mantis): install static proof media tools 2026-05-11 13:11:16 +05:30
Shakker
1941142391 test: tighten qqbot websocket option assertions 2026-05-11 08:40:26 +01:00
Shakker
6a8fd8b7f3 test: tighten google api config assertions 2026-05-11 08:39:45 +01:00
Peter Steinberger
cb593f3b08 test: tighten mattermost route assertions 2026-05-11 08:39:40 +01:00
Shakker
3fe229182f test: tighten discord voice access assertions 2026-05-11 08:38:43 +01:00
Peter Steinberger
baaf42cd22 test: tighten memory atomic reindex assertions 2026-05-11 08:38:22 +01:00
Shakker
a4f606e2cf test: tighten mistral realtime config assertion 2026-05-11 08:37:28 +01:00
Peter Steinberger
fe9e3bde6a test: tighten memory wiki query assertions 2026-05-11 08:36:44 +01:00
Shakker
a371976787 test: tighten msteams allowlist assertion 2026-05-11 08:35:41 +01:00
Peter Steinberger
44dfb10e6a test: tighten msteams graph assertions 2026-05-11 08:35:20 +01:00
Peter Steinberger
3e9efe3b11 test: tighten auth profile assertions 2026-05-11 08:34:06 +01:00
Shakker
dda4ac92db test: tighten msteams pending upload assertions 2026-05-11 08:33:33 +01:00
Shakker
62962a7257 test: tighten oc-path jsonl resolver assertions 2026-05-11 08:32:32 +01:00
Ayaan Zaidi
64cfb2be70 ci(mantis): avoid host apt in telegram proof 2026-05-11 13:02:04 +05:30
Shakker
29b41f49c4 test: tighten oc-path jsonc resolver assertions 2026-05-11 08:31:34 +01:00
Shakker
5d15f47887 test: tighten fireworks stream assertions 2026-05-11 08:30:37 +01:00
Peter Steinberger
4fc1ff7dfd test: tighten ollama web search assertions 2026-05-11 08:29:38 +01:00
Shakker
3014351dfb test: tighten elevenlabs realtime config assertion 2026-05-11 08:29:33 +01:00
Shakker
efc9106408 test: tighten file-transfer tar budget assertions 2026-05-11 08:27:45 +01:00
Peter Steinberger
2251e9f489 fix: normalize onboarded gemini catalog ids 2026-05-11 08:26:54 +01:00
Shakker
6a72bb9782 test: tighten msteams poll store assertions 2026-05-11 08:26:38 +01:00
Shakker
4ad9286e19 test: tighten zca client assertion 2026-05-11 08:25:29 +01:00
Ayaan Zaidi
449eb09a15 docs(changelog): note telegram edit cache 2026-05-11 12:54:41 +05:30
Ayaan Zaidi
4c2b63975c test(telegram): prove edited message context 2026-05-11 12:54:41 +05:30
Ayaan Zaidi
f79117e479 fix(telegram): cache edited messages 2026-05-11 12:54:41 +05:30
Shakker
ce5df3380b test: tighten perplexity transport assertions 2026-05-11 08:24:32 +01:00
Shakker
dfbd9b6023 test: tighten zalo group policy assertions 2026-05-11 08:23:32 +01:00
Leo Ge
66b4306a2a fix(fal): route GPT Image 2/NB2 edits through Fal edit endpoints
Fix Fal image-edit routing for GPT Image 2 and Nano Banana 2, including multi-image edit payloads and provider-specific reference limits.

- Routes GPT Image 2/Nano Banana 2 edits through Fal `/edit` endpoints with `image_urls`.
- Keeps Flux/custom image-to-image edits on singular `image_url` and preserves exact custom `/edit` paths.
- Documents and tests provider caps: Flux/custom 1, GPT Image 2 10, Nano Banana 2 14.

Verified with focused Fal provider tests, oxlint, oxfmt, `git diff --check`, docs listing, green PR CI, and live Fal calls for GPT Image 2, Nano Banana 2, Flux, plus the GPT Image 2 10-ref cap edge.

Co-authored-by: Leo Ge <116452300+leoge007@users.noreply.github.com>
2026-05-11 08:22:34 +01:00
Pavan Kumar Gondhi
17ceca86d6 Redact persisted secret-shaped payloads [AI] (#79006)
* fix: redact persisted secret-shaped payloads

* docs: add changelog entry for PR merge
2026-05-11 12:52:32 +05:30
Shakker
be8bf3585e test: tighten searxng empty result assertion 2026-05-11 08:22:05 +01:00
Shakker
c7f7cd6e5e test: tighten qa cron wait assertion 2026-05-11 08:21:08 +01:00
Shakker
93cac4c7dc test: tighten slack target assertions 2026-05-11 08:20:22 +01:00
Peter Steinberger
4866f7960c test: tighten openai plugin manifest assertions 2026-05-11 08:19:33 +01:00
Shakker
748788177b test: tighten exa provider assertions 2026-05-11 08:18:30 +01:00
Ayaan Zaidi
6729044966 ci(mantis): prepare telegram proof tooling 2026-05-11 12:47:46 +05:30
Ayaan Zaidi
4facdded3e fix(telegram): use repo-owned user driver 2026-05-11 12:47:46 +05:30
Shakker
ad08232753 test: tighten volcengine tts assertions 2026-05-11 08:16:12 +01:00
Shakker
4c05c39d39 test: tighten venice compat assertions 2026-05-11 08:14:45 +01:00
Shakker
a0c087594e test: tighten google embedding request assertions 2026-05-11 08:13:32 +01:00
Shakker
5ca5fc5746 test: tighten diff language hint assertions 2026-05-11 08:12:34 +01:00
Peter Steinberger
ae720e5892 test: tighten openai transport assertions 2026-05-11 08:12:06 +01:00
Shakker
86a67b4b15 test: tighten feishu streaming card assertions 2026-05-11 08:11:24 +01:00
Shakker
138aa763ce test: tighten msteams probe assertions 2026-05-11 08:10:17 +01:00
Shakker
a74bf2bfcc test: tighten discord channel resolver assertions 2026-05-11 08:09:12 +01:00
Shakker
628885ebfc test: tighten xiaomi speech provider assertions 2026-05-11 08:08:06 +01:00
Peter Steinberger
e092d50e77 test: tighten qa credentials admin assertions 2026-05-11 08:07:01 +01:00
Shakker
f528a70a8f test: tighten nextcloud preflight assertions 2026-05-11 08:06:51 +01:00
Shakker
f4ad760c6a test: tighten tavily tool result assertions 2026-05-11 08:05:51 +01:00
Shakker
11fdf60d05 test: tighten llm task schema assertions 2026-05-11 08:04:32 +01:00
Peter Steinberger
122c0104cd test: tighten slack message adapter assertions 2026-05-11 08:04:00 +01:00
Shakker
247c1f58e7 test: tighten mistral provider assertions 2026-05-11 08:03:25 +01:00
Shakker
a2f1b01ad8 test: tighten feishu probe error assertions 2026-05-11 08:02:13 +01:00
Peter Steinberger
e9947d9316 test: tighten telegram account config assertions 2026-05-11 08:01:59 +01:00
Shakker
abbb598986 test: tighten nextcloud replay status assertions 2026-05-11 08:01:20 +01:00
Shakker
e003849454 test: tighten slack user resolution assertion 2026-05-11 07:59:20 +01:00
Peter Steinberger
533099a3e5 test: tighten telegram thread binding assertions 2026-05-11 07:59:09 +01:00
Shakker
5e01b16976 test: tighten teams feedback reflection assertion 2026-05-11 07:57:10 +01:00
Peter Steinberger
f28a987442 refactor: centralize reply prompt envelope 2026-05-11 07:56:45 +01:00
Peter Steinberger
c6041616e1 build(canvas): refresh A2UI bundle hash 2026-05-11 07:56:36 +01:00
Peter Steinberger
a1811b33ce test: tighten telegram lane delivery assertions 2026-05-11 07:56:22 +01:00
Peter Steinberger
c743c61c69 fix(gateway): clarify token source conflict warning 2026-05-11 07:56:12 +01:00
Shakker
eb81dd899c test: tighten twitch client send assertion 2026-05-11 07:56:00 +01:00
Shakker
fd2ebf4458 test: tighten discord dns assertion 2026-05-11 07:54:37 +01:00
Peter Steinberger
5dba5db7af test: tighten acp lifecycle assertions 2026-05-11 07:54:26 +01:00
Shakker
3c1fd7030e test: tighten line send receipt assertions 2026-05-11 07:53:29 +01:00
Peter Steinberger
6715ee6a2b test: tighten reset hook assertions 2026-05-11 07:52:41 +01:00
Shakker
e149a23a3b test: tighten clickclack account assertions 2026-05-11 07:51:25 +01:00
Peter Steinberger
94c7882713 test: tighten usage command assertions 2026-05-11 07:50:46 +01:00
Peter Steinberger
f4ba9553c0 fix(models): preserve fallback chain for override models 2026-05-11 07:50:19 +01:00
Shakker
8d695fc5be test: tighten anthropic stream assertion 2026-05-11 07:49:58 +01:00
Peter Steinberger
d9fe18c574 test: tighten backup command assertions 2026-05-11 07:48:50 +01:00
4479 changed files with 222893 additions and 46751 deletions

View File

@@ -0,0 +1,159 @@
---
name: clawdtributor
description: "Use for OpenClaw clawtributors PR/issue triage: Discrawl discovery, live-open rechecks, deep review, topic grouping, and compact @handle/LOC/type/blast/verification summaries."
---
# Clawdtributor
Use for the `#clawtributors` queue: Discord-discovered OpenClaw PRs/issues that need live GitHub status plus maintainer-quality review.
## Compose with other skills
- `$discrawl`: local Discord archive sync/search.
- `$openclaw-pr-maintainer`: live GitHub PR/issue review, duplicate search, close/land rules.
- `$gitcrawl`: related issue/PR and current-main/stale-proof search.
- `$openclaw-testing` / `$crabbox`: proof choice when a candidate needs real validation.
## Archive flow
Local archive first; verify freshness for current questions.
```bash
discrawl status --json
discrawl sync
```
Resolve channel if needed:
```bash
sqlite3 "$HOME/.discrawl/discrawl.db" \
"select id,name from channels where name like '%clawtributor%' order by name;"
```
Current known channel id from prior work: `1458141495701012561`. Re-resolve if it stops matching.
Extract recent refs:
```bash
sqlite3 "$HOME/.discrawl/discrawl.db" "
select m.created_at, coalesce(nullif(mm.username,''), m.author_id), m.content
from messages m
left join members mm on mm.guild_id=m.guild_id and mm.user_id=m.author_id
where m.channel_id='1458141495701012561'
and m.created_at >= '<ISO cutoff>'
order by m.created_at desc;" |
perl -nE 'while(m{github\.com/openclaw/openclaw/(pull|issues)/(\d+)}g){say "$1\t$2\t$_"}'
```
Map a PR/issue back to the Discord handle:
```bash
sqlite3 -separator $'\t' "$HOME/.discrawl/discrawl.db" "
select m.created_at,
coalesce(nullif(mm.username,''), nullif(mm.global_name,''), m.author_id)
from messages m
left join members mm on mm.guild_id=m.guild_id and mm.user_id=m.author_id
where m.channel_id='1458141495701012561'
and m.content like '%github.com/openclaw/openclaw/<pull-or-issues>/<number>%'
order by m.created_at desc
limit 1;"
```
Show only `@handle` in the final list. Do not write the word Discord unless the user asks for source details.
## Live GitHub recheck
Always recheck live state before listing, closing, or saying "open".
```bash
GITHUB_TOKEN= GITHUB_TOKEN_NODIFF= GH_TOKEN= \
gh api repos/openclaw/openclaw/pulls/<number> \
--jq '. | {number,title,state,merged,mergeable,draft,author:.user.login,url:.html_url,updatedAt:.updated_at,additions,deletions,changedFiles:.changed_files}'
```
For issues:
```bash
GITHUB_TOKEN= GITHUB_TOKEN_NODIFF= GH_TOKEN= \
gh api repos/openclaw/openclaw/issues/<number> \
--jq '. | {number,title,state,author:.user.login,url:.html_url,updatedAt:.updated_at,pull_request}'
```
If `gh` says bad credentials, clear env vars with empty assignments as above. Use `--jq '. | {...}'` for object projections.
## Review depth
For each open item, inspect enough to classify risk:
- PR body, linked issue, comments, files, additions/deletions, checks.
- Current `origin/main` code path and adjacent tests.
- Related threads with `gitcrawl neighbors/search`.
- Whether main already fixed it, the PR is obsolete, or the idea is invalid.
- Blast radius: touched runtime surfaces, config/schema, plugin/core boundary, user-visible behavior, release/package surface.
- Verification: say if local unit/docs proof is enough, live/provider proof is needed, or it is not directly verifiable.
Do not close from title alone. If closing as done on main or nonsensical, prove it against current main and comment first when mutation is requested. Bulk close/reopen above 5 requires explicit scope.
## Candidate selection
When asked for `5 new`, exclude refs already surfaced in the session and refill from the archive until there are 5 live-open candidates. If fewer than 5 remain open, list all open ones and say how many short.
When asked to `update`, `refresh`, `recheck`, `check again`, or similar, return an updated live-open candidate list. Do not fill the main list with items that merely merged/closed since the last pass; put those numbers in a short bottom line.
Prefer:
- Fresh, open, external contributor work.
- Small, high-confidence bugfixes.
- Clear repro, tests, or obvious code-path proof.
Demote:
- Broad product/features without owner decision.
- Large rewrites with unclear contract.
- PRs already in progress, merged, closed, duplicate, or fixed on main.
## Topic grouping
Group only when useful or requested:
- Agents/tooling
- Providers/auth/models
- Channels/messaging
- UI/web
- Gateway/protocol/runtime
- Config/memory/cache
- Docker/install/release
- Docs/tests/chore
- Closed/obsolete
Infer topic from labels, touched files, title/body, and actual code path.
## Output format
No Markdown tables. Compact bullets. Use color/risk markers:
- 🟢 low/narrow
- 🟡 medium or needs targeted proof
- 🔴 broad/high runtime risk
- 🟣 security/policy/owner-boundary slow review
- ✅ merged
- ⚪ closed unmerged
Required line shape:
```markdown
- **PR #81244** `@whatsskill.` `+118/-1` `bug` 🟢 verifiable: yes. This prevents chat action buttons from overlapping short assistant replies. Blast: web chat rendering, low.
- **Issue #81245** `@alice` `LOC n/a` `bug` 🟡 verifiable: partial. This reports duplicate Telegram replies when reconnecting after gateway restart. Blast: Telegram channel runtime, medium.
```
Rules:
- Bold the `PR #n` or `Issue #n` marker.
- Use `@handle`, not author bio text.
- PR LOC is `+additions/-deletions`; issue LOC is `LOC n/a`.
- Type: `bug`, `feature`, `perf`, `security`, `docs`, `test`, `chore`, or `refactor`.
- Write a full sentence for what it does.
- Always include blast radius in one phrase.
- Always include `verifiable: yes|partial|no` plus the shortest proof hint when helpful.
- If status is not open, still show it only when the user asked for all surfaced refs; use ✅ or ⚪ and state merged/closed.
- For refresh-style asks, bottom line: `Merged/closed since last pass: #81016 merged, #81026 closed.` Omit if none.

View File

@@ -0,0 +1,103 @@
---
name: codex-review
description: "Codex code review closeout: local dirty changes, PR branch vs main, parallel tests."
---
# Codex Review
Run Codex's built-in code review as a closeout check. This is code review (`codex review`), not Guardian `auto_review` approval routing.
Use when:
- user asks for Codex review / autoreview / second-model review
- after non-trivial code edits, before final/commit/ship
- reviewing a local branch or PR branch after fixes
## Contract
- Treat review output as advisory. Never blindly apply it.
- Verify every finding by reading the real code path and adjacent files.
- Read dependency docs/source/types when the finding depends on external behavior.
- Reject unrealistic edge cases, speculative risks, broad rewrites, and fixes that over-complicate the codebase.
- Prefer small fixes at the right ownership boundary; no refactor unless it clearly improves the bug class.
- Keep going until Codex review returns no accepted/actionable findings.
- If a review-triggered fix changes code, rerun focused tests and rerun Codex review.
- If rejecting a finding as intentional/not worth fixing, add a brief inline code comment only when it explains a real invariant or ownership decision that future reviewers should know.
- Do not push just to review. Push only when the user requested push/ship/PR update.
## Pick Target
Dirty local work:
```bash
codex review --uncommitted
```
Branch/PR work:
```bash
git fetch origin
codex review --base origin/main
```
Do not pass an inline prompt with `--base`; current CLI rejects `--base` + `[PROMPT]` even though help text is ambiguous. If custom instructions are needed, run the plain base review first, then do a local/manual follow-up pass.
If an open PR exists, use its actual base:
```bash
base=$(gh pr view --json baseRefName --jq .baseRefName)
codex review --base "origin/$base"
```
Committed single change:
```bash
codex review --commit HEAD
```
## Parallel Closeout
Format first if formatting can change line locations. Then it is OK to run tests and review in parallel:
```bash
scripts/codex-review --parallel-tests "<focused test command>"
```
Tradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain.
## Context Efficiency
Codex review is usually noisy. Default to a subagent filter when subagents are available. Ask it to run the review and return only:
- actionable findings it accepts
- findings it rejects, with one-line reason
- exact files/tests to rerun
Run inline only for tiny changes or when subagents are unavailable.
## Helper
Bundled helper:
```bash
~/.codex/skills/codex-review/scripts/codex-review --help
```
If installed from `agent-scripts`, path is:
```bash
/Users/steipete/Projects/agent-scripts/skills/codex-review/scripts/codex-review --help
```
The helper:
- chooses dirty `--uncommitted` first
- otherwise uses current PR base if `gh pr view` works
- otherwise uses `origin/main` for non-main branches
- writes only to stdout unless `--output` or `CODEX_REVIEW_OUTPUT` is set
- supports `--dry-run` and `--parallel-tests`
## Final Report
Include:
- review command used
- tests/proof run
- findings accepted/rejected, briefly why
- final clean review command, or why a remaining finding was consciously rejected

View File

@@ -0,0 +1,188 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: codex-review [options]
Options:
--mode auto|local|branch Target selection. Default: auto.
--base REF Base ref for branch review. Default: PR base or origin/main.
--codex-bin PATH Codex binary. Default: codex.
--output FILE Also save output to file.
--parallel-tests CMD Run review and test command concurrently.
--dry-run Print selected commands, do not run.
-h, --help Show help.
Modes:
local codex review --uncommitted
branch codex review --base <base>
auto dirty tree -> local, else PR/current branch -> branch
EOF
}
mode=auto
base_ref=
codex_bin=${CODEX_BIN:-codex}
output=${CODEX_REVIEW_OUTPUT:-}
parallel_tests=
dry_run=false
while [[ $# -gt 0 ]]; do
case "$1" in
--mode)
mode=${2:-}
shift 2
;;
--base)
base_ref=${2:-}
shift 2
;;
--codex-bin)
codex_bin=${2:-}
shift 2
;;
--output)
output=${2:-}
shift 2
;;
--parallel-tests)
parallel_tests=${2:-}
shift 2
;;
--dry-run)
dry_run=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
done
case "$mode" in
auto|local|branch) ;;
*)
echo "invalid --mode: $mode" >&2
exit 2
;;
esac
git rev-parse --show-toplevel >/dev/null
current_branch=$(git branch --show-current 2>/dev/null || true)
dirty=false
if [[ -n "$(git status --porcelain)" ]]; then
dirty=true
fi
pr_url=
if [[ -z "$base_ref" && "$mode" != local ]] && command -v gh >/dev/null 2>&1; then
if pr_lines=$(gh pr view --json baseRefName,url --jq '[.baseRefName, .url] | @tsv' 2>/dev/null); then
base_name=${pr_lines%%$'\t'*}
pr_url=${pr_lines#*$'\t'}
if [[ -n "$base_name" ]]; then
base_ref="origin/$base_name"
fi
fi
fi
if [[ -z "$base_ref" ]]; then
base_ref=origin/main
fi
review_kind=
if [[ "$mode" == local || ( "$mode" == auto && "$dirty" == true ) ]]; then
review_kind=local
elif [[ "$mode" == branch || ( "$mode" == auto && -n "$current_branch" && "$current_branch" != "main" ) ]]; then
review_kind=branch
else
echo "no review target: clean main checkout and no forced mode" >&2
exit 1
fi
if [[ "$review_kind" == local ]]; then
review_cmd=("$codex_bin" review --uncommitted)
else
review_cmd=("$codex_bin" review --base "$base_ref")
fi
printf 'codex-review target: %s\n' "$review_kind"
printf 'branch: %s\n' "${current_branch:-detached}"
if [[ -n "$pr_url" ]]; then
printf 'pr: %s\n' "$pr_url"
fi
printf 'review:'
printf ' %q' "${review_cmd[@]}"
printf '\n'
if [[ -n "$parallel_tests" ]]; then
printf 'tests: %s\n' "$parallel_tests"
fi
if [[ "$review_kind" == branch ]]; then
printf 'fetch: git fetch origin --quiet\n'
fi
if [[ -n "$output" ]]; then
printf 'output: %s\n' "$output"
fi
if [[ "$dry_run" == true ]]; then
exit 0
fi
if [[ "$review_kind" == branch ]]; then
git fetch origin --quiet || {
echo "warning: git fetch origin failed; reviewing with existing refs" >&2
}
fi
run_review() {
if [[ -n "$output" ]]; then
mkdir -p "$(dirname "$output")"
"${review_cmd[@]}" 2>&1 | tee "$output"
else
"${review_cmd[@]}"
fi
}
if [[ -z "$parallel_tests" ]]; then
run_review
exit $?
fi
review_status_file=$(mktemp)
tests_status_file=$(mktemp)
(
set +e
run_review
status=$?
printf '%s\n' "$status" > "$review_status_file"
) &
review_pid=$!
(
set +e
bash -lc "$parallel_tests"
status=$?
printf '%s\n' "$status" > "$tests_status_file"
) &
tests_pid=$!
wait "$review_pid" || true
wait "$tests_pid" || true
review_status=$(cat "$review_status_file")
tests_status=$(cat "$tests_status_file")
rm -f "$review_status_file" "$tests_status_file"
printf 'codex-review exit: %s\n' "$review_status"
printf 'tests exit: %s\n' "$tests_status"
if [[ "$review_status" != 0 || "$tests_status" != 0 ]]; then
exit 1
fi

View File

@@ -1,6 +1,6 @@
---
name: crabbox
description: Use Crabbox for OpenClaw remote Linux validation. Default to Blacksmith Testbox; includes direct Blacksmith and owned AWS/Hetzner fallback notes when Crabbox fails.
description: Use Crabbox for OpenClaw remote validation across Linux, macOS, Windows, and WSL2. Default to the repo Crabbox config, use brokered AWS for normal broad proof, and keep Blacksmith Testbox as an explicit opt-in or outage diagnostic path.
---
# Crabbox
@@ -9,9 +9,15 @@ Use Crabbox when OpenClaw needs remote Linux proof for broad tests, CI-parity
checks, secrets, hosted services, Docker/E2E/package lanes, warmed reusable
boxes, sync timing, logs/results, cache inspection, or lease cleanup.
Default backend: `blacksmith-testbox`. The separate `blacksmith-testbox` skill
has been removed; this skill owns both the normal Crabbox path and the direct
Blacksmith fallback playbook.
Default backend: the repo `.crabbox.yaml`, currently brokered AWS. Do not
override it to Blacksmith unless the user explicitly asks for Blacksmith proof,
the task is specifically about Testbox behavior, or AWS/brokered Crabbox is the
broken layer.
Blacksmith Testbox is a delegated fallback, not the default router. If a
Blacksmith run queues, fails capacity, fails auth, or cannot allocate, stop
after one real attempt and switch to the repo default or report the blocker.
Do not retry Blacksmith in a loop.
## First Checks
@@ -28,16 +34,20 @@ pnpm crabbox:run -- --help | sed -n '1,120p'
- OpenClaw scripts prefer `../crabbox/bin/crabbox` when present. The user PATH
shim can be stale.
- Check `.crabbox.yaml` for repo defaults, but override provider explicitly.
Even if config still says AWS, maintainer validation should normally pass
`--provider blacksmith-testbox`.
- For live/provider bugs, check keys on the local Mac before downgrading to
mocks: source local `~/.profile` and test only presence/length. If Crabbox
does not already have the key, copy only the exact needed key into the remote
process environment for that one command. Do not print it, do not sync it as a
repo file, and do not leave it in remote shell history or logs. If no
secret-safe injection path is available, say true live provider auth is
blocked instead of silently using a fake key.
- Check `.crabbox.yaml` for repo defaults and honor them. For normal Linux
validation, omit `--provider` so the wrapper uses brokered AWS.
- Pass `--provider blacksmith-testbox` only for explicit Blacksmith/Testbox
work or a deliberate comparison.
- If a warm direct-provider lease smells stale, retry with `--full-resync`
(alias `--fresh-sync`) before replacing the lease. This resets the remote
workdir, skips the fingerprint fast path, reseeds Git when possible, and
uploads the checkout from scratch.
- For live/provider bugs, use the configured secret workflow before downgrading
to mocks. Copy only the exact needed key into the remote process environment
for that one command. Do not print it, do not sync it as a repo file, and do
not leave it in remote shell history or logs. If no secret-safe injection path
is available, say true live provider auth is blocked instead of silently using
a fake key.
- Prefer local targeted tests for tight edit loops. Broad gates belong remote.
- Do not treat inherited shell env as operator intent. In particular,
`OPENCLAW_LOCAL_CHECK_MODE=throttled` from the local shell is not permission
@@ -51,7 +61,8 @@ pnpm crabbox:run -- --help | sed -n '1,120p'
## macOS And Windows Targets
Use these only when the task needs an existing non-Linux host. OpenClaw broad
validation still defaults to `blacksmith-testbox`.
Linux validation uses the repo Crabbox config unless a provider is explicitly
requested.
Crabbox supports static SSH targets:
@@ -64,14 +75,15 @@ Crabbox supports static SSH targets:
- `target=macos` and `target=windows --windows-mode wsl2` use the POSIX SSH,
bash, Git, rsync, and tar contract.
- Native Windows uses OpenSSH, PowerShell, Git, and tar; sync is manifest tar
archive transfer into `static.workRoot`.
archive transfer into `static.workRoot`. Direct native Windows runs support
`--script*`, `--env-from-profile`, `--preflight`, and PowerShell `--shell`.
- `crabbox actions hydrate/register` are Linux-only today; use plain
`crabbox run` loops for static macOS and Windows hosts.
- Live proof needs a reachable, operator-managed SSH host. Without one, verify
with `../crabbox/bin/crabbox run --help`, config/flag tests, and the Crabbox
Go test suite.
## Default Blacksmith Backend
## Default Brokered AWS Backend
Use this for `pnpm check`, `pnpm check:changed`, `pnpm test`,
`pnpm test:changed`, Docker/E2E/live/package gates, or anything likely to fan
@@ -80,11 +92,7 @@ out across many Vitest projects.
Changed gate:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox \
--blacksmith-org openclaw \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job check \
--blacksmith-ref main \
pnpm crabbox:run -- \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
@@ -95,11 +103,7 @@ pnpm crabbox:run -- --provider blacksmith-testbox \
Full suite:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox \
--blacksmith-org openclaw \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job check \
--blacksmith-ref main \
pnpm crabbox:run -- \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
@@ -110,11 +114,7 @@ pnpm crabbox:run -- --provider blacksmith-testbox \
Focused rerun:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox \
--blacksmith-org openclaw \
--blacksmith-workflow .github/workflows/ci-check-testbox.yml \
--blacksmith-job check \
--blacksmith-ref main \
pnpm crabbox:run -- \
--idle-timeout 90m \
--ttl 240m \
--timing-json \
@@ -124,20 +124,99 @@ pnpm crabbox:run -- --provider blacksmith-testbox \
Read the JSON summary. Useful fields:
- `provider`: should be `blacksmith-testbox`
- `leaseId`: `tbx_...`
- `syncDelegated`: should be `true`
- `provider`: should normally be `aws`
- `leaseId`: `cbx_...`
- `syncDelegated`: should normally be `false`
- `commandPhases`: populated when the command prints `CRABBOX_PHASE:<name>`
- `commandMs` / `totalMs`
- `exitCode`
Crabbox should stop one-shot Blacksmith Testboxes automatically after the run.
Verify cleanup when a run fails, is interrupted, or the command output is
unclear:
Crabbox should stop one-shot AWS leases automatically after the run. Verify
cleanup when a run fails, is interrupted, or the command output is unclear:
```sh
blacksmith testbox list
../crabbox/bin/crabbox list --provider aws
```
## Observability Flags
Use these on debugging runs before inventing ad hoc logging:
- `--preflight`: prints run context, workspace mode, SSH target, remote user/cwd,
and target-specific tool probes. Defaults cover `git`, `tar`, `node`, `npm`,
`corepack`, `pnpm`, `yarn`, `bun`, `docker`, plus POSIX
`sudo`/`apt`/`bubblewrap` and native Windows
`powershell`/`execution_policy`/`longpaths`/`temp`/`pwsh`. Add
`--preflight-tools node,bun,docker`, `CRABBOX_PREFLIGHT_TOOLS`, or repo
`run.preflightTools` to replace the list. `default` expands built-ins; `none`
prints only the workspace summary. Preflight is diagnostic only; install
toolchains through Actions hydration, images, devcontainer/Nix/mise/asdf, or
the run script. On `blacksmith-testbox`, this prints a delegated-unsupported
note because the workflow owns setup.
- `CRABBOX_ENV_ALLOW=NAME,...`: forwards only listed local env vars for direct
providers and prints `set len=N secret=true` style summaries. On
`blacksmith-testbox`, env forwarding is unsupported; put secrets in the
Testbox workflow instead.
- `--env-from-profile <file>` plus `--allow-env NAME`: loads simple
`export NAME=value` / `NAME=value` lines from a local profile without
executing it, then forwards only allowlisted names. `--allow-env` is
repeatable and comma-separated. Profile values override ambient allowlisted
env values for that run. Direct POSIX, WSL2, and native Windows runs are
supported; delegated providers are not. Crabbox probes the uploaded profile
remotely and prints redacted presence/length metadata before the command.
- `--env-helper <name>`: with `--env-from-profile` on POSIX SSH targets,
persists `.crabbox/env/<name>` and `.crabbox/env/<name>.env` so follow-up
commands on the same lease can run through `./.crabbox/env/<name> <command>`.
Use only on leases you control; the profile stays until cleanup, lease reset,
or `--full-resync`.
- `--script <file>` / `--script-stdin`: upload a local script into
`.crabbox/scripts/` and execute it on the remote box. Shebang scripts execute
directly on POSIX; scripts without a shebang run through `bash`. Native
Windows uploads run through Windows PowerShell, and Crabbox appends `.ps1`
when needed. Arguments after `--` become script args.
- `--fresh-pr owner/repo#123|URL|number`: skip dirty local sync and create a
fresh remote checkout of the GitHub PR. Bare numbers use the current repo's
GitHub origin. Add `--apply-local-patch` only when the current local
`git diff --binary HEAD` should be applied on top of that PR checkout.
- `--full-resync` / `--fresh-sync`: reset a stale direct-provider workdir
before syncing. Use after sync fingerprints look wrong, SSH times out before
sync, or rsync watchdog output suggests it. It is redundant with
`--fresh-pr`, incompatible with `--no-sync`, and unsupported by delegated
providers.
- `--capture-stdout <path>` / `--capture-stderr <path>`: write remote streams to
local files and keep binary/noisy output out of retained logs. Parent
directories must already exist. These are direct-provider only.
- `--capture-on-fail`: on non-zero direct-provider exits, downloads
`.crabbox/captures/*.tar.gz` with `test-results`, `playwright-report`,
`coverage`, JUnit XML, and nearby logs. Treat as secret-bearing until reviewed.
- `--keep-on-failure`: leave a failed one-shot lease alive for live debugging
until idle/TTL expiry. Useful on direct providers and delegated one-shots.
- `--timing-json`: final machine-readable timing. Add
`echo CRABBOX_PHASE:install`, `CRABBOX_PHASE:test`, etc. in long shell
commands; direct providers and Blacksmith Testbox both report them as
`commandPhases`.
Live-provider debug template for direct AWS/Hetzner leases:
```sh
mkdir -p .crabbox/logs
pnpm crabbox:run -- --provider aws \
--preflight \
--allow-env OPENAI_API_KEY,OPENAI_BASE_URL \
--timing-json \
--capture-stdout .crabbox/logs/live-provider.stdout.log \
--capture-stderr .crabbox/logs/live-provider.stderr.log \
--capture-on-fail \
--shell -- \
"echo CRABBOX_PHASE:install; pnpm install --frozen-lockfile; echo CRABBOX_PHASE:test; pnpm test:live"
```
Do not pass `--capture-*`, `--download`, `--checksum`, `--force-sync-large`, or
`--sync-only` to delegated providers. Also do not pass `--script*`,
`--fresh-pr`, `--full-resync`, or `--env-helper` there. Crabbox rejects these
because the provider owns sync or command transport. `--keep-on-failure` is OK
for delegated one-shots when you need to inspect a failed lease.
## Efficient Bug E2E Verification
Use the smallest Crabbox lane that proves the reported user path, not just the
@@ -149,8 +228,8 @@ Pick the lane by symptom:
- Docker/setup/install bug: build a package tarball and run the matching
`scripts/e2e/*-docker.sh` or package script. This proves npm packaging,
install paths, runtime deps, config writes, and container behavior.
- Provider/model/auth bug: prefer true live E2E. First source local Mac
`~/.profile`, then inject the single needed key into Crabbox if needed. Scrub
- Provider/model/auth bug: prefer true live E2E. Use the configured secret
workflow, then inject the single needed key into Crabbox if needed. Scrub
unrelated provider env vars in the child command so interactive defaults do
not drift to another provider. If only a dummy key is used, label the proof
narrowly, e.g. "UI/install path only; live provider auth not exercised."
@@ -179,6 +258,13 @@ Efficient flow:
Keep it efficient:
- Reuse existing E2E scripts and helper assertions before writing ad hoc shell.
- Use `--script <file>` or `--script-stdin` for multi-line E2E commands instead
of quote-heavy `--shell` strings on direct SSH providers.
- Use `--fresh-pr <pr>` when validating an upstream PR in isolation from the
local dirty tree. Add `--apply-local-patch` only when testing a local fixup on
top of that PR.
- Use `--full-resync` before replacing a warmed direct-provider lease when the
remote workdir or sync fingerprint appears stale.
- Use one-shot Crabbox for a single proof; use a reusable Testbox only when
several commands must share built images, installed packages, or live state.
- Prefer `OPENCLAW_CURRENT_PACKAGE_TGZ` with Docker/package lanes when testing a
@@ -189,6 +275,31 @@ Keep it efficient:
- Include `--timing-json` on broad or flaky runs when command duration or sync
behavior matters.
Before/after PR proof on delegated Testbox:
- For PRs that should prove "broken before, fixed after", compare base and PR
on the same Testbox when practical. Fetch both refs, create detached temp
worktrees under `/tmp`, install in each, then run the same harness twice.
- Do not checkout base/PR refs in the synced repo root. Delegated Testbox sync
may leave the root dirty with local files; `git checkout` can abort or mix
proof state.
- Temp harness files under `/tmp` do not resolve repo packages by default. Put
the harness inside the worktree, or in ESM use
`createRequire(path.join(process.cwd(), "package.json"))` before requiring
workspace deps such as `@lydell/node-pty`.
- For full-screen TUI/CLI bugs, a PTY harness is stronger than helper-only
assertions. Use a real PTY, wait for visible lifecycle markers, send input,
then send control keys and assert process exit/stuck behavior.
- When validating a rebased local branch before push, remember delegated sync
usually validates synced file content on a detached dirty checkout, not a
remote commit object. Record the local head SHA, changed files, Testbox id,
and final success markers; after pushing, ensure the pushed SHA has the same
file content.
- If GitHub CI is still queued but the exact changed content passed Testbox
`pnpm check:changed`, `pnpm check:test-types`, and the real E2E proof, it is
reasonable to merge once required checks allow it. Note any still-running
unrelated shards in the proof comment instead of waiting forever.
Interactive CLI/onboarding:
- For full-screen or prompt-heavy CLI flows, run the target command inside tmux
@@ -215,13 +326,13 @@ Interactive CLI/onboarding:
## Reuse And Keepalive
For most Blacksmith-backed Crabbox calls, one-shot is enough. Use reuse only
when you need multiple manual commands on the same hydrated box.
For most Crabbox calls, one-shot is enough. Use reuse only when you need
multiple manual commands on the same hydrated box.
If Crabbox returns a reusable id or you intentionally keep a lease:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox --id <tbx_id> --no-sync --timing-json --shell -- "pnpm test <path>"
pnpm crabbox:run -- --id <cbx_id-or-slug> --no-sync --timing-json --shell -- "pnpm test <path>"
```
Stop boxes you created before handoff:
@@ -249,10 +360,17 @@ Useful WebVNC commands:
```sh
../crabbox/bin/crabbox webvnc --provider hetzner --id <cbx_id-or-slug> --open
../crabbox/bin/crabbox webvnc --provider hetzner --id <cbx_id-or-slug> --daemon --open
../crabbox/bin/crabbox webvnc --provider hetzner --id <cbx_id-or-slug> --status
../crabbox/bin/crabbox webvnc --provider hetzner --id <cbx_id-or-slug> --stop
../crabbox/bin/crabbox screenshot --provider hetzner --id <cbx_id-or-slug> --output desktop.png
../crabbox/bin/crabbox webvnc daemon start --provider hetzner --id <cbx_id-or-slug> --open
../crabbox/bin/crabbox webvnc daemon status --provider hetzner --id <cbx_id-or-slug>
../crabbox/bin/crabbox webvnc daemon stop --provider hetzner --id <cbx_id-or-slug>
../crabbox/bin/crabbox webvnc status --provider hetzner --id <cbx_id-or-slug>
../crabbox/bin/crabbox webvnc reset --provider hetzner --id <cbx_id-or-slug> --open
../crabbox/bin/crabbox desktop doctor --provider hetzner --id <cbx_id-or-slug>
../crabbox/bin/crabbox desktop click --provider hetzner --id <cbx_id-or-slug> --x 640 --y 420
../crabbox/bin/crabbox desktop paste --provider hetzner --id <cbx_id-or-slug> --text "user@example.com"
../crabbox/bin/crabbox desktop key --provider hetzner --id <cbx_id-or-slug> ctrl+l
../crabbox/bin/crabbox artifacts collect --id <cbx_id-or-slug> --all --output artifacts/<slug>
../crabbox/bin/crabbox artifacts publish --dir artifacts/<slug> --pr <number>
```
`desktop launch --webvnc --open` is usually the nicest one-shot: it starts the
@@ -263,14 +381,16 @@ WebVNC portal, and opens the portal. Keep browsers windowed for human QA; use
## If Crabbox Fails
Keep the fallback narrow. First decide whether the failure is Crabbox itself,
Blacksmith/Testbox, repo hydration, sync, or the test command.
the brokered AWS lease, Blacksmith/Testbox, repo hydration, sync, or the test
command.
Fast checks:
```sh
command -v crabbox
../crabbox/bin/crabbox --version
crabbox run --provider blacksmith-testbox --help | sed -n '1,140p'
pnpm crabbox:run -- --help | sed -n '1,140p'
../crabbox/bin/crabbox doctor
command -v blacksmith
blacksmith --version
blacksmith testbox list
@@ -280,32 +400,36 @@ Common Crabbox-only failures:
- Provider missing or old CLI: use `../crabbox/bin/crabbox` from the sibling
repo, or update/install Crabbox before retrying.
- Bad local config: pass `--provider blacksmith-testbox` plus explicit
`--blacksmith-*` flags instead of relying on `.crabbox.yaml`.
- Slug/claim confusion: use the raw `tbx_...` id, or run one-shot without
`--id`.
- Bad local config: inspect `.crabbox.yaml`, `crabbox config show`, and
`crabbox whoami`; normal OpenClaw proof should use brokered AWS without
asking for cloud keys.
- Slug/claim confusion: use the raw `cbx_...` / `tbx_...` id, or run one-shot
without `--id`.
- Sync/timing bug: add `--debug --timing-json`; capture the final JSON and the
printed Actions URL.
- Cleanup uncertainty: run `blacksmith testbox list` and stop only boxes you
printed Actions URL. Large sync warnings now include top source directories
by file count and a hint to update `.crabboxignore` / `sync.exclude`; inspect
those before reaching for `--force-sync-large`. Quiet rsync watchdogs and SSH
timeouts now print `next_action=` hints; follow them, usually `--full-resync`
first and a fresh lease second.
- Cleanup uncertainty: run `crabbox list --provider aws`; for explicit
Blacksmith runs, use `blacksmith testbox list` and stop only boxes you
created.
- Testbox queued/capacity pressure: do not convert a broad changed gate or full
suite into local `OPENCLAW_LOCAL_CHECK_MODE=throttled pnpm ...`. Leave the
remote lane queued, switch to a narrower targeted local check, or stop and
report the capacity blocker.
- Testbox queued/capacity pressure: do not retry Blacksmith repeatedly. Rerun
once without `--provider` so `.crabbox.yaml` routes to brokered AWS, or report
the Blacksmith blocker if Testbox itself is the requested proof.
If Crabbox cannot dispatch, sync, attach, or stop but Blacksmith itself works,
first try the same command through the repo wrapper with `--debug` and
`--timing-json`:
If brokered AWS cannot dispatch, sync, attach, or stop, retry once with
`--debug` and `--timing-json`:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox --debug --timing-json -- \
pnpm crabbox:run -- --debug --timing-json -- \
CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test:changed
```
Full suite:
```sh
pnpm crabbox:run -- --provider blacksmith-testbox --debug --timing-json -- \
pnpm crabbox:run -- --debug --timing-json -- \
CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test
```
@@ -324,9 +448,10 @@ Raw Blacksmith footguns:
- Treat `blacksmith testbox list` as cleanup diagnostics, not a shared reusable
queue.
Escalate to owned AWS/Hetzner only when Blacksmith is down, quota-limited,
missing the needed environment, or owned capacity is the explicit goal. Use the
Owned Cloud Fallback section below.
Use Blacksmith only when the task is specifically about Testbox, brokered AWS
is unavailable, or an explicit comparison is needed. If Blacksmith is down or
quota-limited, do not keep probing it; stay on brokered AWS and note the
delegated-provider outage.
## Blacksmith Backend Notes
@@ -362,13 +487,14 @@ Important Blacksmith footguns:
blacksmith auth login --non-interactive --organization openclaw
```
## Owned Cloud Fallback
## Brokered AWS
Use AWS/Hetzner only when Blacksmith is down, quota-limited, missing the needed
environment, or owned capacity is explicitly the goal.
Use AWS for normal OpenClaw remote proof. The repo `.crabbox.yaml` already
selects brokered AWS, so omit `--provider` unless you are testing a different
provider deliberately.
```sh
pnpm crabbox:warmup -- --provider aws --class beast --market on-demand --idle-timeout 90m
pnpm crabbox:warmup -- --class beast --market on-demand --idle-timeout 90m
pnpm crabbox:hydrate -- --id <cbx_id-or-slug>
pnpm crabbox:run -- --id <cbx_id-or-slug> --timing-json --shell -- "env NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test:changed"
pnpm crabbox:stop -- <cbx_id-or-slug>
@@ -392,8 +518,8 @@ crabbox whoami
- If broker auth is missing, run `crabbox login --url https://crabbox.openclaw.ai --provider aws`.
- If the CLI asks for `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, or AWS
profile setup during normal OpenClaw validation, assume the agent selected
the wrong path. Use brokered `crabbox login`, `--provider blacksmith-testbox`,
or an existing brokered lease before asking the user for cloud credentials.
the wrong path. Use brokered `crabbox login` or an existing brokered lease
before asking the user for cloud credentials.
- Ask for AWS keys only for explicit direct-provider/account administration,
not for normal brokered OpenClaw proof.
- Trusted automation may still use
@@ -406,8 +532,7 @@ macOS config lives at:
```
It should include `broker.url`, `broker.token`, and usually `provider: aws`
for owned-cloud lanes. Do not let that config override the OpenClaw default
when Blacksmith proof is requested; pass `--provider blacksmith-testbox`.
for OpenClaw lanes. Let that config drive normal validation.
### Interactive Desktop / WebVNC
@@ -427,7 +552,10 @@ crabbox run --id <lease> --shell -- 'DISPLAY=:99 xdotool search --onlyvisible --
crabbox status --id <id-or-slug> --wait
crabbox inspect --id <id-or-slug> --json
crabbox sync-plan
crabbox history --limit 20
crabbox history --lease <id-or-slug>
crabbox attach <run_id>
crabbox events <run_id> --json
crabbox logs <run_id>
crabbox results <run_id>
crabbox cache stats --id <id-or-slug>
@@ -442,14 +570,15 @@ Use `--market spot|on-demand` only on AWS warmup/one-shot runs.
## Failure Triage
- Crabbox cannot find provider: verify `../crabbox/bin/crabbox --help` lists
`blacksmith-testbox`; update Crabbox before falling back.
the provider selected by `.crabbox.yaml`; update Crabbox before falling back.
- Hydration stuck or failed: open the printed GitHub Actions run URL and inspect
the hydration step.
- Sync failed: rerun with `--debug`; check changed-file count and whether the
checkout is dirty.
- Command failed: rerun only the failing shard/file first. Do not rerun a full
suite until the focused failure is understood.
- Cleanup uncertain: `blacksmith testbox list`; stop owned `tbx_...` leases you
- Cleanup uncertain: `crabbox list --provider aws`; for explicit Blacksmith
runs, use `blacksmith testbox list` and stop owned `tbx_...` leases you
created.
- Crabbox broken but Blacksmith works: use the direct Blacksmith fallback above,
then file/fix the Crabbox issue.

View File

@@ -0,0 +1,114 @@
---
name: openclaw-debugging
description: Debug OpenClaw model, provider, tool-surface, code-mode, streaming, and live/Crabbox behavior by choosing the right logs, probes, and proof path before changing code.
---
# OpenClaw Debugging
Use this skill when OpenClaw behavior differs between local tests, live models,
providers, code mode, Tool Search, Crabbox, or CI, and the next move should be a
debug signal rather than a guess.
## Read First
- `docs/logging.md` for log files, `openclaw logs`, and targeted debug flags.
- `docs/reference/test.md` for local test commands.
- `docs/reference/code-mode.md` for code-mode exec/wait and tool catalog rules.
- Use `$openclaw-testing` for choosing test lanes.
- Use `$crabbox` for broad, Docker, package, Linux, live-key, or CI-parity proof.
## Default Loop
1. State the suspected boundary: config, tool construction, provider payload,
fetch, stream/SSE, transcript replay, worker/runtime, package/dist, or CI.
2. Add or enable the narrowest signal that proves that boundary.
3. Reproduce with the same provider/model/config. Do not randomly switch models
unless the model itself is the variable being tested.
4. Compare configured state with actual run activation.
5. Patch the root cause.
6. Rerun the exact failing probe, then broaden only if the contract requires it.
## Model Transport Logs
Use targeted env flags instead of global debug when the model request shape or
stream timing matters:
```bash
OPENCLAW_DEBUG_MODEL_TRANSPORT=1 openclaw gateway
OPENCLAW_DEBUG_MODEL_PAYLOAD=tools OPENCLAW_DEBUG_SSE=events openclaw gateway
OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted OPENCLAW_DEBUG_SSE=peek openclaw gateway
```
Useful flags:
- `OPENCLAW_DEBUG_MODEL_TRANSPORT=1`: request start, fetch response, SDK
headers, first SSE event, stream done, and transport errors at `info`.
- `OPENCLAW_DEBUG_MODEL_PAYLOAD=summary`: bounded payload summary.
- `OPENCLAW_DEBUG_MODEL_PAYLOAD=tools`: all model-facing tool names.
- `OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted`: capped, redacted JSON payload.
Use only while debugging; prompts/message text may still appear.
- `OPENCLAW_DEBUG_SSE=events`: first-event and stream-completion timing.
- `OPENCLAW_DEBUG_SSE=peek`: first five redacted SSE events.
- `OPENCLAW_DEBUG_CODE_MODE=1`: code-mode tool-surface diagnostics.
Watch logs with:
```bash
openclaw logs --follow
```
## Common Boundaries
- **Config vs activation:** config can be enabled while the run disables tools,
is raw, has an empty allowlist, or lacks model tool support. Check the actual
visible tools before enforcing provider payload invariants.
- **Tool surface:** inspect final model-visible tool names, not only the tool
registry or config. Code mode means exactly `exec` and `wait` only after it
actually activates.
- **Provider payload:** log fields, model id, service tier, reasoning, input
size, metadata keys, prompt-cache key presence, and tool names before SDK
call.
- **Fetch vs SSE:** fetch response proves HTTP headers arrived; first SSE event
proves provider body progress. A gap here is a stream/body/provider issue, not
tool execution.
- **Worker/dist:** run `pnpm build` when touching workers, dynamic imports,
package exports, lazy runtime boundaries, or published paths.
- **Live keys:** use the configured secret workflow for missing provider keys
before saying live proof is blocked. Env checks are presence-only; never print
secrets.
## Code Pointers
- Model payload + Responses stream:
`src/agents/openai-transport-stream.ts`
- Guarded fetch/timing:
`src/agents/provider-transport-fetch.ts`
- OpenAI/Codex provider wrappers:
`src/agents/pi-embedded-runner/openai-stream-wrappers.ts`
- Tool construction, Tool Search, code-mode activation:
`src/agents/pi-embedded-runner/run/attempt.ts`
- Code-mode runtime and worker:
`src/agents/code-mode.ts`
`src/agents/code-mode.worker.ts`
- Tool Search catalog:
`src/agents/tool-search.ts`
## Proof Choice
- Single helper/payload bug: local targeted Vitest.
- Docs/logging-only: `pnpm check:docs` and `git diff --check`.
- Worker/dist/lazy import/package surface: targeted tests plus `pnpm build`.
- Live provider/model behavior: same provider/model with debug flags and a real
key if available.
- Docker/package/Linux/CI-parity: `$crabbox`.
- CI failure: exact SHA, relevant job only, logs only after failure/completion.
## Output Habit
Report:
- boundary tested
- exact command/env shape, redacted
- observed signal, such as tool names or first SSE event timing
- fix location
- narrow proof and any remaining risk

View File

@@ -0,0 +1,4 @@
interface:
display_name: "OpenClaw Debugging"
short_description: "Debug model, tool, stream, and live behavior"
default_prompt: "Use $openclaw-debugging to identify the right OpenClaw debug boundary, turn on targeted logs, and choose the narrowest local or Crabbox proof."

View File

@@ -42,16 +42,20 @@ Choose the page type before writing:
Use this default topic page structure:
1. Title: name the major entity or surface.
2. Overview: explain what it is, what it owns, and what it does not own.
2. Opening overview: start with a few unheaded sentences that explain what it
is, what it owns, and what it does not own. Do not add a `## Overview`
heading unless the page is itself an overview index.
3. Requirements: include only when setup needs specific accounts, versions,
permissions, plugins, operating systems, or credentials.
4. Quickstart: show the recommended setup path and smallest reliable verification.
5. Configuration: show the minimum configuration needed to use the surface,
common variants users must choose between, and where each option is set:
CLI, config file, environment variable, plugin manifest, dashboard, or API.
6. Subtopics: organize the entity's major concepts, workflows, and decisions by
reader intent.
7. Troubleshooting: diagnose common observable failures.
6. Major subtopics: organize the entity's major concepts, workflows, and
decisions by reader intent. Put each major subtopic under its own heading;
do not wrap them in a generic `## Subtopics` section.
7. Troubleshooting: diagnose common observable failures under an explicit
`## Troubleshooting` heading.
8. Related: link to guides, references, commands, concepts, and adjacent topics.
Topic pages may be longer than quickstarts, but they should not become exhaustive

View File

@@ -56,7 +56,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- For unpublished targets, pack the candidate on the host, serve the `.tgz` over the harness HTTP server, and point the guest updater at that served package. Prefer `openclaw update --tag http://<host-ip>:<port>/openclaw-<version>.tgz --yes --json`; when channel persistence also matters, pass `--channel <stable|beta>` and set `OPENCLAW_UPDATE_PACKAGE_SPEC` to the same served URL in the guest update environment. The command under test must still be `openclaw update`, not direct npm.
- For unpublished local-fix validation, remember the old baseline updater code still controls the first hop. A fix that lives only in the new updater code cannot change that already-running old process; the served candidate must either keep package/plugin metadata compatible with the baseline host or the baseline itself must include the updater fix.
- For beta/stable verification, resolve the tag immediately before the run (`npm view openclaw@beta version dist.tarball` or `npm view openclaw@latest ...`). Tags can move while a long VM matrix is already running; restart the matrix when the intended prerelease appears after an earlier registry 404/tag-lag check.
- Source Peter's profile in the host shell (`set -a; source "$HOME/.profile"; set +a`) before OpenAI/Anthropic lanes. Do not print profile contents or env dumps; pass provider secrets through the guest exec environment.
- Use the configured secret workflow to inject only the provider keys needed by OpenAI/Anthropic lanes. Do not print secrets or env dumps; pass provider secrets through the guest exec environment.
- Same-guest update verification should set the default model explicitly to `openai/gpt-5.4` before the agent turn and use a fresh explicit `--session-id` so old session model state does not leak into the check.
- The aggregate npm-update wrapper must resolve the Linux VM with the same Ubuntu fallback policy as `parallels-linux-smoke.sh` before both fresh and update lanes. Treat any Ubuntu guest with major version `>= 24` as acceptable when the exact default VM is missing, preferring the closest version match. On Peter's current host today, missing `Ubuntu 24.04.3 ARM64` should fall back to `Ubuntu 25.10`.
- On macOS same-guest update checks, restart the gateway after the npm upgrade before `gateway status` / `agent`; launchd can otherwise report a loaded service while the old process has exited and the fresh process is not RPC-ready yet.

View File

@@ -138,7 +138,9 @@ Output only qualifying candidates, with: ref, surface, proof, cause, fix sketch,
- Start every PR review with 1-3 plain sentences explaining what the change does and why it matters. Put this before `Findings`.
- Then list findings first. If none, say `No blocking findings` or `No findings`.
- Always answer: bug/behavior being fixed, PR/issue URL and affected surface, and best-fix verdict.
- Always answer: bug/behavior being fixed, PR/issue URL and affected surface, provenance for regressions when traceable, and best-fix verdict.
- For bug/regression fixes, include a compact `Provenance:` line after cause/root-cause when a bounded history pass can identify it. Use `git log -S/-G`, `git blame`, linked PRs/issues, and tests; separate author, committer/merger, and current PR author when they differ.
- Phrase provenance as `introduced by`, `made visible by`, or `carried forward by`, with confidence (`clear`, `likely`, `unknown`). If unclear, say what evidence is missing instead of guessing. For features, docs, and refactors, use `Provenance: N/A` or omit it when no broken behavior is being fixed.
- Keep summaries compact, but include enough proof that the verdict is auditable without rereading the PR.
## Read beyond the diff
@@ -160,8 +162,9 @@ Output only qualifying candidates, with: ref, surface, proof, cause, fix sketch,
- Before landing, require:
1. symptom evidence such as a repro, logs, or a failing test
2. a verified root cause in code with file/line
3. a fix that touches the implicated code path
4. a regression test when feasible, or explicit manual verification plus a reason no test was added
3. provenance for regressions when traceable by bounded git/PR history
4. a fix that touches the implicated code path
5. a regression test when feasible, or explicit manual verification plus a reason no test was added
- If the claim is unsubstantiated or likely wrong, request evidence or changes instead of merging.
- If the linked issue appears outdated or incorrect, correct triage first. Do not merge a speculative fix.
- If Crabbox/E2E proof is blocked, say exactly why and use the closest available

View File

@@ -227,7 +227,9 @@ pnpm openclaw qa manual \
- Treat the concrete Codex model name as user/config input; do not hardcode it in source, docs examples, or scenarios.
- Live QA preserves `CODEX_HOME` so Codex CLI auth/config works while keeping `HOME` and `OPENCLAW_HOME` sandboxed.
- Mock QA should scrub `CODEX_HOME`.
- If Codex returns fallback/auth text every turn, first check `CODEX_HOME`, `~/.profile`, and gateway child logs before changing scenario assertions.
- If Codex returns fallback/auth text every turn, first check `CODEX_HOME`,
relevant secret-backed auth, and gateway child logs before changing
scenario assertions.
- For model comparison, include `codex-cli/<codex-model>` as another candidate in `qa character-eval`; the report should label it as an opaque model name.
## Repo facts

View File

@@ -0,0 +1,196 @@
---
name: openclaw-refactor-docs
description: Refactor an existing OpenClaw docs page with source-audited preservation, restructuring, and verification.
---
# OpenClaw Refactor Docs
## Overview
Use this skill when the user gives a target OpenClaw docs page and asks to
rewrite, refactor, reorganize, split, shorten, or improve it.
This skill builds on `openclaw-docs`: use that skill for style, page types,
structure, examples, discoverability, and verification. This skill adds the
rewrite workflow needed to avoid losing accurate behavior during a major docs
refactor.
## Inputs
Required:
- A target docs page path, such as `docs/plugins/codex-harness.md`.
Optional:
- Desired page type, such as topic page, guide, reference, or troubleshooting.
- Specific goals, such as shorter main page, move details to reference pages, or
align with current CLI behavior.
- Related source files, schemas, commands, tests, specs, or PRs.
If the target page is missing or ambiguous, ask one concise question before
editing. Otherwise, proceed.
## Working Contract
Refactor the target page to be more useful, concise, and comprehensive within
its stated scope.
Do not treat a rewrite as permission to discard behavior facts. Preserve,
verify, move, or explicitly retire existing material. Incorrect docs are worse
than verbose docs.
Prefer this split:
- Topic or guide pages cover the 80/20 path, decisions readers must make, safe
setup, smallest reliable verification, common failures, and links onward.
- Reference pages cover exhaustive fields, defaults, enums, limits, precedence
rules, API contracts, narrow internals, and rare debugging details.
- Troubleshooting pages start from observable symptoms and map to checks,
causes, and fixes.
## Workflow
### 1. Load the doc standard
Read `../openclaw-docs/SKILL.md` first. Apply its page-type, style,
examples, navigation, and verification guidance throughout the refactor.
Run `pnpm docs:list` when available, then read only the target page and the
likely entry points, references, or related pages needed for the refactor.
### 2. Classify the page
Before editing, decide the intended page type from `openclaw-docs`.
If the current page mixes page types, choose the main page type and plan where
the other material belongs:
- Move exhaustive contracts to an existing or new reference page.
- Move symptom-driven material to an existing or new troubleshooting page.
- Move narrow setup workflows to a guide when they interrupt the main path.
- Keep concise routing, decision, and safety details in the main page when
readers need them to complete the workflow.
### 3. Preserve and audit existing facts
Create a working inventory from the old page before rewriting. Include:
- Config fields, flags, commands, slash commands, env vars, defaults, enums,
nullable values, and constraints.
- Precedence rules, fallback behavior, caps, limits, rate limits, timeouts,
lifecycle states, queueing behavior, and compatibility rules.
- Auth, permission, approval, sandbox, safety, privacy, and destructive-action
behavior.
- Setup requirements, supported versions, dependencies, operating systems,
credentials, and account requirements.
- Error messages, troubleshooting symptoms, diagnostics, and recovery steps.
- Examples, expected output, command routing tables, and cross-links.
For each fact, choose one outcome:
- Keep it in the refactored target page.
- Move it to a specific existing page.
- Move it to a specific new page.
- Delete it because current source proves it is obsolete or out of scope.
Do not infer defaults, permissions, policy, timeout behavior, or safety posture
from names or intent. Verify them.
### 4. Find source of truth
Use the nearest authoritative source for each behavior-sensitive claim:
- Public schema, plugin manifest, generated config docs, or exported types for
config fields.
- CLI implementation, slash-command handlers, help text, and command tests for
commands and flags.
- Runtime source and tests for lifecycle, queueing, permission, fallback,
timeout, and provider behavior.
- Protocol docs, SDK facades, and contract tests for APIs and plugin surfaces.
- Existing docs only as secondary evidence unless the target is purely
conceptual.
If a page promises a reference, compare its tables against the schema,
manifest, CLI help, generated docs, or exported types. Missing public fields,
defaults, precedence rules, caps, or side effects are correctness bugs.
### 5. Plan moved material
When moving detail out of the target page, record the destination before
editing:
- Existing page: name the page and section.
- New page: choose the page type, slug, title, frontmatter summary,
`doc-schema-version: 1`, and `read_when` hints.
- Target page: keep a short summary and link from the point where readers need
the deeper detail.
Avoid duplicate truth. If the same contract appears in multiple places, choose
one canonical page and link to it.
### 6. Rewrite
Rewrite in this order:
1. Make the first screen answer what the reader can do and why this page exists.
2. Put the recommended path before alternatives.
3. Keep only decision-making and common operational detail in the main flow.
4. Move exhaustive tables and rare details to the planned reference pages.
5. Preserve concise routing tables when they help readers choose commands,
config paths, harnesses, plugins, providers, or references.
6. Add troubleshooting from observable symptoms, not internal guesses.
7. Link related concepts, guides, references, diagnostics, and adjacent tools.
Add `doc-schema-version: 1` to the YAML frontmatter of every docs page that the
refactor migrates, creates, or materially rewrites. Apply it only to docs page
files, not `docs.json`, glossary JSON, or other non-page metadata. If a
migrated page is generated, update the generator so regeneration preserves the
marker instead of hand-editing generated output.
Do not leave placeholders such as "TODO", "TBD", or "see docs" unless the user
explicitly asks for a draft.
### 7. Compare old and new
After editing, compare the old and new page:
- Confirm all behavior-sensitive facts were kept, moved, or intentionally
deleted with source-backed reason.
- Check that the main page still covers the 80/20 scenario end to end.
- Check that reference pages remain exhaustive for the scope they claim.
- Check that links from the target page reach moved details.
- Check that headings are stable, searchable, and action-oriented.
If the refactor deliberately removes relevant material, say where it went or why
it was removed in the final report.
### 8. Verify
Run the smallest reliable docs checks for the touched surface:
- `pnpm docs:list`
- `git diff --check -- <touched-files>`
- Targeted `pnpm exec oxfmt --check --threads=1 <touched-files>`
- `pnpm docs:check-mdx`
- `pnpm docs:check-links`
- `pnpm docs:check-i18n-glossary` when link text, navigation, labels, or glossary
surfaces changed
- Generated-doc checks when schemas, generated config docs, API docs, or
generated baselines are touched
Run commands and examples from the page whenever feasible. If you cannot verify
a behavior-sensitive claim, either remove the claim, mark the uncertainty in the
work-in-progress report, or ask for the missing source.
## Final Report
Report:
- What changed in the target page.
- What details moved and their destination pages.
- What source-of-truth checks backed behavior-sensitive claims.
- What validation ran and what failed for unrelated reasons.
Do not include a long rewrite diary. Lead with remaining risks only if there are
any.

View File

@@ -0,0 +1,90 @@
---
name: openclaw-release-ci
description: "Run, watch, debug, and summarize OpenClaw full release CI, release checks, live provider gates, install/update proofs, and release-secret preflights."
---
# OpenClaw Release CI
Use this with `$openclaw-release-maintainer` and `$openclaw-testing` when a release candidate needs full validation, install/update proof, live provider checks, or CI recovery.
## Guardrails
- No version bump, tag, npm publish, GitHub release, or release promotion without explicit operator approval.
- Validate provider secrets before dispatching expensive full release matrices.
- Do not set GitHub secrets from unvalidated 1Password candidates. If a candidate returns 401/403, leave the existing secret alone and report the exact missing provider.
- Use `$one-password` for secret reads/writes: one persistent tmux session, targeted items only, no secret output.
- Watch one parent run plus compact child summaries. Avoid broad `gh run view` polling loops; REST quota is easy to burn.
- Fetch logs only for failed or currently-blocking jobs. If quota is low, stop polling and wait for reset.
- Treat live-provider flakes separately from code failures: prove key validity, provider HTTP status, retry evidence, and exact failing lane before editing code.
## Preflight
Before full release validation:
```bash
node .agents/skills/openclaw-release-ci/scripts/verify-provider-secrets.mjs --required openai,anthropic,fireworks
gh api rate_limit --jq '.resources.core'
git status --short --branch
git rev-parse HEAD
```
If env lacks keys, use `$one-password` to inject or set them, then rerun the script. The script prints only provider status and HTTP class, never tokens.
## Dispatch
Prefer the trusted workflow on `main`, target the exact release SHA:
```bash
gh workflow run full-release-validation.yml \
--repo openclaw/openclaw \
--ref main \
-f ref=<release-sha> \
-f provider=openai \
-f mode=both \
-f release_profile=full \
-f rerun_group=all
```
Use `release_profile=stable` unless the operator explicitly asks for the broad advisory provider/media matrix. Use narrow `rerun_group` after focused fixes.
## Watch
Use the summary helper instead of repeated raw polling:
```bash
node .agents/skills/openclaw-release-ci/scripts/release-ci-summary.mjs <full-release-run-id>
```
Then watch only when useful:
```bash
gh run watch <full-release-run-id> --repo openclaw/openclaw --exit-status
```
Stop watchers before ending the turn or switching strategy.
## Failure Triage
1. Confirm parent SHA and child run IDs.
2. List failed jobs only:
```bash
gh run view <child-run-id> --repo openclaw/openclaw --json jobs \
--jq '.jobs[] | select(.conclusion=="failure" or .conclusion=="timed_out" or .conclusion=="cancelled") | [.databaseId,.name,.conclusion,.url] | @tsv'
```
3. Fetch one failed job log. If rate-limited, note reset time and avoid more REST calls.
4. For secret-looking failures, validate the provider endpoint from the same secret source before editing code.
5. For live-cache failures, inspect whether it is missing/invalid key, empty text, provider refusal, timeout, or baseline miss. Do not weaken release gates without clear provider evidence.
6. Fix narrowly, run local/changed proof, commit, push, rerun the smallest matching group.
## Evidence
Record:
- release SHA
- full parent run URL
- child run IDs and conclusions: CI, Release Checks, Plugin Prerelease, NPM Telegram
- targeted local proof commands
- provider-secret preflight result
- known gaps or unrelated failures
For lessons and recovery patterns, read `references/release-ci-notes.md`.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "OpenClaw Release CI"
short_description: "Verify and debug OpenClaw release validation runs"
default_prompt: "Use $openclaw-release-ci to preflight provider secrets, watch full release validation, summarize child runs, and triage only failing release lanes."

View File

@@ -0,0 +1,41 @@
# Release CI Notes
## What Went Wrong
- Full validation was started before all provider keys were proven valid.
- GitHub secret presence was confused with key validity.
- Repeated `gh run view` and log fetches exhausted REST quota.
- Parent run state was less useful than child run evidence.
- Live-cache failures needed structured classification: invalid key, empty provider output, timeout, or real cache regression.
- Background watchers accumulated and made interruption recovery harder.
## Better Defaults
- Run provider-secret preflight first. Require real `/models` or equivalent endpoint checks for release-blocking providers.
- Keep one watcher open. Use child summaries every few minutes, not every few seconds.
- Fetch failed-job logs only after a job reaches a terminal failing state.
- Prefer narrow `rerun_group` recovery after a focused fix.
- Leave bad secrets unset. A 401 candidate from 1Password should not overwrite GitHub.
- Make the final release evidence note durable: parent URL, child run URLs, SHA, command proof, and gaps.
## Secret Handling Pattern
- Use `$one-password`; never run broad env dumps.
- Search exact item titles or known ids.
- Validate candidates without printing values.
- Set GitHub secrets only after endpoint validation succeeds.
- After setting, verify metadata with `gh secret list`, not value output.
## Live Cache Pattern
- Empty text with token usage is a provider/output issue until proven otherwise.
- Retry lane-level mismatches once with a fresh session id.
- Keep cache baselines strict, but log enough structured usage to distinguish cache miss from response mismatch.
- If a provider key validates locally but fails in Actions, inspect whether the workflow reads the expected secret name.
## Quota-Safe GitHub Pattern
- Check `gh api rate_limit --jq '.resources.core'` before log-heavy work.
- Use one child-run listing call, then inspect failed jobs only.
- If remaining quota is low, pause until reset; do not keep polling.
- Prefer GraphQL only for metadata when REST is exhausted; logs still need REST.

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env node
import { execFileSync } from "node:child_process";
import process from "node:process";
const runId = process.argv[2];
const repo = process.env.OPENCLAW_RELEASE_REPO || "openclaw/openclaw";
if (!runId) {
console.error("usage: release-ci-summary.mjs <full-release-run-id>");
process.exit(2);
}
function gh(args) {
return execFileSync("gh", args, {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
}
function jsonGh(args) {
return JSON.parse(gh(args));
}
function rate() {
try {
return jsonGh(["api", "rate_limit"]).resources.core;
} catch {
return undefined;
}
}
const core = rate();
if (core) {
const reset = new Date(core.reset * 1000).toISOString();
console.log(`rate: remaining=${core.remaining}/${core.limit} reset=${reset}`);
if (core.remaining < 20) {
console.error("rate too low for CI summary; wait for reset before polling");
process.exit(3);
}
}
const parent = jsonGh([
"run",
"view",
runId,
"--repo",
repo,
"--json",
"status,conclusion,createdAt,headSha,url,jobs",
]);
console.log(`parent: ${runId} ${parent.status}/${parent.conclusion || "none"}`);
console.log(`sha: ${parent.headSha}`);
console.log(`url: ${parent.url}`);
for (const job of parent.jobs ?? []) {
const marker = job.conclusion || job.status;
console.log(`parent-job: ${marker} ${job.name}`);
}
const since = parent.createdAt;
const runList = gh([
"api",
`repos/${repo}/actions/runs?per_page=100`,
"--jq",
`.workflow_runs[] | select(.created_at >= "${since}") | select(.name=="CI" or .name=="OpenClaw Release Checks" or .name=="Plugin Prerelease" or .name=="NPM Telegram Beta E2E" or .name=="Full Release Validation") | [.id,.name,.status,.conclusion,.head_sha,.html_url] | @tsv`,
]).trim();
if (!runList) {
console.log("children: none found yet");
process.exit(0);
}
console.log("children:");
for (const line of runList.split("\n")) {
const [id, name, status, conclusion, sha, url] = line.split("\t");
console.log(`child: ${id} ${name} ${status}/${conclusion || "none"} sha=${sha}`);
console.log(`child-url: ${url}`);
}

View File

@@ -0,0 +1,113 @@
#!/usr/bin/env node
import process from "node:process";
const args = new Map();
for (let index = 2; index < process.argv.length; index += 1) {
const arg = process.argv[index];
if (!arg.startsWith("--")) continue;
const [key, inlineValue] = arg.slice(2).split("=", 2);
const value = inlineValue ?? process.argv[index + 1];
if (inlineValue === undefined) index += 1;
args.set(key, value);
}
const requiredInput = String(args.get("required") ?? "openai,anthropic").trim();
const required = new Set(
(requiredInput.toLowerCase() === "none" ? "" : requiredInput)
.split(",")
.map((entry) => entry.trim().toLowerCase())
.filter(Boolean),
);
const timeoutMs = Number(args.get("timeout-ms") ?? 10_000);
function envFirst(names) {
for (const name of names) {
const value = process.env[name]?.trim();
if (value) return { name, value };
}
return undefined;
}
async function checkProvider(id, config) {
const secret = envFirst(config.env);
if (!secret) {
return { id, ok: false, status: "missing", env: config.env.join("|") };
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const headers = config.headers(secret.value);
const response = await fetch(config.url, {
headers,
signal: controller.signal,
});
return {
id,
ok: response.ok,
status: response.ok ? "ok" : `http_${response.status}`,
env: secret.name,
};
} catch (error) {
return {
id,
ok: false,
status: error?.name === "AbortError" ? "timeout" : "error",
env: secret.name,
};
} finally {
clearTimeout(timer);
}
}
const providers = {
openai: {
env: ["OPENAI_API_KEY"],
url: "https://api.openai.com/v1/models",
headers: (token) => ({ authorization: `Bearer ${token}` }),
},
anthropic: {
env: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_TOKEN"],
url: "https://api.anthropic.com/v1/models",
headers: (token) => ({
"anthropic-version": "2023-06-01",
"x-api-key": token,
}),
},
fireworks: {
env: ["FIREWORKS_API_KEY"],
url: "https://api.fireworks.ai/inference/v1/models",
headers: (token) => ({ authorization: `Bearer ${token}` }),
},
openrouter: {
env: ["OPENROUTER_API_KEY"],
url: "https://openrouter.ai/api/v1/models",
headers: (token) => ({ authorization: `Bearer ${token}` }),
},
};
const unknown = [...required].filter((id) => !providers[id]);
if (unknown.length > 0) {
console.error(`unknown providers: ${unknown.join(",")}`);
process.exit(2);
}
const results = [];
for (const id of Object.keys(providers)) {
if (required.has(id) || envFirst(providers[id].env)) {
results.push(await checkProvider(id, providers[id]));
}
}
let failed = false;
for (const result of results) {
const requiredLabel = required.has(result.id) ? "required" : "optional";
console.log(`${result.id}: ${result.status} env=${result.env} ${requiredLabel}`);
if (required.has(result.id) && !result.ok) failed = true;
}
if (failed) {
console.error("release provider secret preflight failed");
process.exit(1);
}

View File

@@ -65,8 +65,8 @@ Use this skill for release and publish-time workflow. Keep ordinary development
stable base version section, for example `v2026.4.20-beta.1` uses
`## 2026.4.20` release notes.
- When any beta or stable release is live, make a best-effort Discord
announcement using Peter's bot token from `.profile`; do not block or roll
back the release if the announcement fails.
announcement using the configured secret workflow; do not block or roll back
the release if the announcement fails.
- When asked to announce on X, use `~/Projects/bird/bird` and follow the
release tweet style below.
@@ -288,13 +288,11 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
## Check all relevant release builds
- Always validate the OpenClaw npm release path before creating the tag.
- Source Peter's profile before live release validation so OpenAI and Anthropic
credentials are available without printing secrets:
`set -a; source "$HOME/.profile"; set +a`.
- Use the configured secret workflow before live release validation so OpenAI
and Anthropic credentials are available without printing secrets.
- Parallels validation and any local live model QA for this train must use both
`OPENAI_API_KEY` and `ANTHROPIC_API_KEY`. If either is missing after sourcing
`.profile`, stop before starting those local long lanes and report the
missing key.
`OPENAI_API_KEY` and `ANTHROPIC_API_KEY`. If either cannot be injected, stop
before starting those local long lanes and report the missing key.
- Live credentialed channel QA is the GitHub Actions workflow
`QA-Lab - All Lanes` (`.github/workflows/qa-live-telegram-convex.yml`), not a
local substitute. Dispatch it from Actions against the release tag and wait
@@ -592,8 +590,7 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
If a pre-npm lane fails before any tag/package leaves the machine, fix and
rerun the same intended beta attempt. Repeat up to the operator's
authorized beta-attempt limit, normally 4.
24. Announce the beta/stable release on Discord best-effort using Peter's bot
token from `.profile`.
24. Announce the beta/stable release on Discord best-effort using the configured secret workflow.
25. If the operator requested beta only, stop after beta verification and the
announcement.
26. If the stable release was published to `beta`, use the light stable

View File

@@ -581,6 +581,8 @@ function cmdNotify(target, author, locationType, secretTypes, replyToNodeId) {
}
const body = [
`> **Note:** This is an automated message sent by the OpenClaw maintainer team. **NO_REPLY.**`,
"",
`@${author} :warning: **Security Notice: Secret Leakage Detected**`,
"",
`GitHub Secret Scanning detected the following exposed secret types in ${locationDesc}:`,

View File

@@ -19,9 +19,13 @@ or validating a change without wasting hours.
Prove the touched surface first. Do not reflexively run the whole suite.
1. Inspect the diff and classify the touched surface:
- source: `pnpm changed:lanes --json`, then `pnpm check:changed`
- tests only: `pnpm test:changed`
- one failing file: `pnpm test <path-or-filter> -- --reporter=verbose`
- normal source checkout, source change: `pnpm changed:lanes --json`, then `pnpm check:changed`
- normal source checkout, tests only: `pnpm test:changed`
- normal source checkout, one failing file: `pnpm test <path-or-filter> -- --reporter=verbose`
- Codex worktree or linked/sparse checkout, one/few explicit files: `node scripts/run-vitest.mjs <path-or-filter>`
- Codex worktree or linked/sparse checkout, changed gates or anything broad:
`node scripts/crabbox-wrapper.mjs run ... --shell -- "pnpm check:changed"`
and let `.crabbox.yaml` choose the provider
- workflow-only: `git diff --check`, workflow syntax/lint (`actionlint` when available)
- docs-only: `pnpm docs:list`, docs formatter/lint only if docs tooling changed or requested
2. Reproduce narrowly before fixing.
@@ -36,11 +40,19 @@ Prove the touched surface first. Do not reflexively run the whole suite.
- Prefer GitHub Actions for release/Docker proof when the workflow already has the prepared image and secrets.
- Use `scripts/committer "<msg>" <paths...>` when committing; stage only your files.
- If deps are missing, run `pnpm install`, retry once, then report the first actionable error.
- For Blacksmith Testbox proof, use Crabbox first. `pnpm crabbox:run -- --provider
blacksmith-testbox --timing-json -- <command...>` warms, claims, syncs, runs,
reports, and cleans up one-shot boxes. Reuse only an id/slug created in this
operator session; `blacksmith testbox list` is diagnostics only, not a shared
work queue.
- In a Codex worktree or linked/sparse checkout, do not run direct local
`pnpm test*`, `pnpm check*`, `pnpm crabbox:run`, or `scripts/committer` until
you have verified pnpm will not reconcile or reinstall dependencies. Use
`node scripts/run-vitest.mjs` for tiny local proof, `node
scripts/crabbox-wrapper.mjs` for Testbox, and `git commit --no-verify` only
after the relevant remote or node-wrapper proof is already clean.
- For remote proof, use Crabbox first and omit `--provider` unless a specific
provider is being tested. The repo Crabbox config routes normal broad proof to
brokered AWS. Blacksmith Testbox is explicit opt-in; if it queues, fails
capacity, or cannot allocate, retry once through the default Crabbox route or
report the Testbox blocker. Reuse only an id/slug created in this operator
session; `blacksmith testbox list` is diagnostics only, not a shared work
queue.
## Local Test Shortcuts
@@ -55,6 +67,14 @@ OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test <path-or-filter>
Use targeted file paths whenever possible. Avoid raw `vitest`; use the repo
`pnpm test` wrapper so project routing, workers, and setup stay correct.
When the checkout is a Codex worktree, prefer the direct node harness instead:
```bash
node scripts/run-vitest.mjs <path-or-filter>
```
That keeps the test scoped without giving pnpm a chance to run dependency
status checks or install reconciliation in a linked worktree.
## Command Semantics

View File

@@ -28,6 +28,9 @@ OPENCLAW_GATEWAY_TOKEN=
# OPENCLAW_STATE_DIR=~/.openclaw
# OPENCLAW_CONFIG_PATH=~/.openclaw/openclaw.json
# OPENCLAW_HOME=~
# Docker setup stores auth profile encryption key material outside the mounted
# OpenClaw state dir and mounts this host directory into the container.
# OPENCLAW_AUTH_PROFILE_SECRET_DIR=/absolute/path/to/.openclaw-auth-profile-secrets
# Allowlist of extra directories that `$include` directives in openclaw.json may
# resolve files from. Path-list separated (':' on POSIX, ';' on Windows). Each

2
.github/CODEOWNERS vendored
View File

@@ -11,6 +11,8 @@
/.github/workflows/codeql.yml @openclaw/openclaw-secops
/.github/workflows/codeql-android-critical-security.yml @openclaw/openclaw-secops
/.github/workflows/codeql-critical-quality.yml @openclaw/openclaw-secops
/.github/workflows/dependency-change-awareness.yml @openclaw/openclaw-secops
/test/scripts/dependency-change-awareness-workflow.test.ts @openclaw/openclaw-secops
/src/security/ @openclaw/openclaw-secops
/src/secrets/ @openclaw/openclaw-secops
/src/config/*secret*.ts @openclaw/openclaw-secops

View File

@@ -2,10 +2,9 @@
You are Mantis running native Telegram Desktop visual proof for an OpenClaw PR.
Goal: inspect the pull request, decide the best Telegram-visible behavior to
prove, run before/after native Telegram Desktop sessions, iterate until the GIFs
are visually good, and leave a Mantis evidence manifest for the workflow to
publish.
Goal: inspect the pull request, decide whether it has an honest
Telegram-visible before/after behavior, then either run native Telegram Desktop
proof or leave a no-visual-proof manifest for the workflow to publish.
Hard limits:
@@ -16,6 +15,9 @@ Hard limits:
- Do not use fixed `/status` proof unless it genuinely proves the PR.
- Do not finish with tiny, cropped-wrong, off-bottom, or sidebar-heavy GIFs.
- Do not invent a generic proof. The proof must match the PR behavior.
- Do not force GIFs for internal-only, workflow-only, test-only, docs-only, or
otherwise non-visual PRs. A no-visual-proof manifest is a successful outcome
when GIFs would be misleading.
Inputs are provided as environment variables:
@@ -24,33 +26,81 @@ Inputs are provided as environment variables:
- `BASELINE_SHA`
- `CANDIDATE_REF`
- `CANDIDATE_SHA`
- `MANTIS_CANDIDATE_TRUST`
- `MANTIS_OUTPUT_DIR`
- `MANTIS_INSTRUCTIONS`
- `CRABBOX_PROVIDER`
- `OPENCLAW_TELEGRAM_USER_PROOF_CMD`
- optional `CRABBOX_LEASE_ID`
Required workflow:
1. Read `.agents/skills/telegram-crabbox-e2e-proof/SKILL.md`.
2. Inspect the PR with `gh pr view "$MANTIS_PR_NUMBER"` and
`gh pr diff "$MANTIS_PR_NUMBER"` when `MANTIS_PR_NUMBER` is set. If the run
came from workflow dispatch without a PR number, inspect
`BASELINE_SHA..CANDIDATE_SHA`.
3. Decide what Telegram message, mock model response, command, callback, button,
`gh pr diff "$MANTIS_PR_NUMBER"`.
3. Decide whether the PR has a visibly reproducible Telegram Desktop
before/after. If it does not, write
`${MANTIS_OUTPUT_DIR}/mantis-evidence.json` with `comparison.pass: true`, no
artifacts, and a summary that starts with
`Mantis did not generate before/after GIFs because`. Include the concrete
reason in the summary. Use this manifest shape and do not create worktrees
or start Crabbox for this case:
```json
{
"schemaVersion": 1,
"id": "telegram-desktop-proof",
"title": "Mantis Telegram Desktop Proof",
"summary": "Mantis did not generate before/after GIFs because <reason>.",
"scenario": "telegram-desktop-proof",
"comparison": {
"baseline": {
"ref": "<BASELINE_REF>",
"sha": "<BASELINE_SHA>",
"expected": "no visible Telegram Desktop delta",
"status": "skipped"
},
"candidate": {
"ref": "<CANDIDATE_REF>",
"sha": "<CANDIDATE_SHA>",
"expected": "no visible Telegram Desktop delta",
"status": "skipped",
"fixed": true
},
"pass": true
},
"artifacts": []
}
```
4. Decide what Telegram message, mock model response, command, callback, button,
media, or sequence best proves the PR. Use `MANTIS_INSTRUCTIONS` as extra
maintainer guidance, not as a replacement for reading the PR.
4. Create detached worktrees under
5. Create detached worktrees under
`.artifacts/qa-e2e/mantis/telegram-desktop-proof-worktrees/baseline` and
`.artifacts/qa-e2e/mantis/telegram-desktop-proof-worktrees/candidate`, then
install and build each worktree with the repo's normal `pnpm` commands.
5. In each worktree, run the real-user Telegram Crabbox proof flow from the
skill. Use the same proof idea for baseline and candidate. You may iterate
and rerun if the visual result is not convincing.
6. Open Telegram Desktop directly to the newest relevant message with the
If `MANTIS_CANDIDATE_TRUST` is `fork-pr-head`, treat the
candidate worktree as untrusted fork code: do not pass GitHub, OpenAI,
Crabbox, Convex, or other workflow secrets into candidate install, build, or
runtime commands. The candidate SUT may receive only the proof runner's
short-lived Telegram bot token, generated local config/state paths, and mock
model key needed for this isolated proof.
6. In each worktree, run the real-user Telegram Crabbox proof flow from the
skill with `$OPENCLAW_TELEGRAM_USER_PROOF_CMD`; do not run
`pnpm qa:telegram-user:crabbox` directly. The proof command comes from the
trusted workflow checkout while the current directory controls which
baseline or candidate OpenClaw build is tested. Use
`$OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT`, the workflow-provided `crabbox`
binary, and the workflow-provided local `ffmpeg`/`ffprobe`; do not generate,
install, or patch replacement proof tooling during the run. Use the same
proof idea for baseline and candidate. You may iterate and rerun if the
visual result is not convincing.
7. Open Telegram Desktop directly to the newest relevant message with the
runner `view` command before finishing each recording. Keep the chat scrolled
to the bottom so new proof messages appear in-frame.
7. Finish each session with `--preview-crop telegram-window`.
8. Build `${MANTIS_OUTPUT_DIR}/mantis-evidence.json` with:
8. Finish each session with `--preview-crop telegram-window`.
9. Build `${MANTIS_OUTPUT_DIR}/mantis-evidence.json` with:
```bash
node scripts/mantis/build-telegram-desktop-proof-evidence.mjs \
@@ -80,6 +130,8 @@ Visual acceptance:
Expected final state:
- `${MANTIS_OUTPUT_DIR}/mantis-evidence.json` exists.
- The manifest contains paired `motionPreview` artifacts labeled `Main` and
`This PR`.
- Visual proof manifests contain paired `motionPreview` artifacts labeled
`Main` and `This PR`.
- No-visual-proof manifests contain no artifacts and have `comparison.pass:
true`.
- The worktree can be dirty only under `.artifacts/`.

92
.github/labeler.yml vendored
View File

@@ -244,6 +244,10 @@
- "docs/gateway/security.md"
- "security/**"
"extensions: admin-http-rpc":
- changed-files:
- any-glob-to-any-file:
- "extensions/admin-http-rpc/**"
"extensions: copilot-proxy":
- changed-files:
- any-glob-to-any-file:
@@ -454,3 +458,91 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/gradium/**"
"extensions: amazon-bedrock":
- changed-files:
- any-glob-to-any-file:
- "extensions/amazon-bedrock/**"
"extensions: anthropic-vertex":
- changed-files:
- any-glob-to-any-file:
- "extensions/anthropic-vertex/**"
"extensions: brave":
- changed-files:
- any-glob-to-any-file:
- "extensions/brave/**"
"extensions: chutes":
- changed-files:
- any-glob-to-any-file:
- "extensions/chutes/**"
"extensions: diffs":
- changed-files:
- any-glob-to-any-file:
- "extensions/diffs/**"
"extensions: elevenlabs":
- changed-files:
- any-glob-to-any-file:
- "extensions/elevenlabs/**"
"extensions: firecrawl":
- changed-files:
- any-glob-to-any-file:
- "extensions/firecrawl/**"
"extensions: github-copilot":
- changed-files:
- any-glob-to-any-file:
- "extensions/github-copilot/**"
"extensions: google":
- changed-files:
- any-glob-to-any-file:
- "extensions/google/**"
"extensions: microsoft":
- changed-files:
- any-glob-to-any-file:
- "extensions/microsoft/**"
"extensions: mistral":
- changed-files:
- any-glob-to-any-file:
- "extensions/mistral/**"
"extensions: ollama":
- changed-files:
- any-glob-to-any-file:
- "extensions/ollama/**"
"extensions: opencode":
- changed-files:
- any-glob-to-any-file:
- "extensions/opencode/**"
"extensions: opencode-go":
- changed-files:
- any-glob-to-any-file:
- "extensions/opencode-go/**"
"extensions: openrouter":
- changed-files:
- any-glob-to-any-file:
- "extensions/openrouter/**"
"extensions: openshell":
- changed-files:
- any-glob-to-any-file:
- "extensions/openshell/**"
"extensions: perplexity":
- changed-files:
- any-glob-to-any-file:
- "extensions/perplexity/**"
"extensions: sglang":
- changed-files:
- any-glob-to-any-file:
- "extensions/sglang/**"
"extensions: thread-ownership":
- changed-files:
- any-glob-to-any-file:
- "extensions/thread-ownership/**"
"extensions: vllm":
- changed-files:
- any-glob-to-any-file:
- "extensions/vllm/**"
"extensions: xai":
- changed-files:
- any-glob-to-any-file:
- "extensions/xai/**"
"extensions: zai":
- changed-files:
- any-glob-to-any-file:
- "extensions/zai/**"

View File

@@ -124,5 +124,6 @@ jobs:
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
if: always()
continue-on-error: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -26,7 +26,7 @@ permissions:
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-manual-v1-{1}', github.workflow, github.run_id) || (github.event_name == 'pull_request' && format('{0}-v7-{1}', github.workflow, github.event.pull_request.number) || (github.repository == 'openclaw/openclaw' && format('{0}-v7-{1}', github.workflow, github.ref) || format('{0}-v7-{1}-{2}', github.workflow, github.ref, github.sha))) }}
cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -452,7 +452,7 @@ jobs:
contents: read
needs: [preflight]
if: needs.preflight.outputs.run_build_artifacts == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
outputs:
channels-result: ${{ steps.built_artifact_checks.outputs['channels-result'] }}
@@ -655,7 +655,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_fast_core == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -750,7 +750,7 @@ jobs:
name: ${{ matrix.checkName }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_contracts_shards == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -856,7 +856,7 @@ jobs:
name: ${{ matrix.checkName }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_fast == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -1059,7 +1059,7 @@ jobs:
name: checks-node-compat-node22
needs: [preflight]
if: needs.preflight.outputs.run_build_artifacts == 'true' && github.event_name == 'workflow_dispatch'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
steps:
- name: Checkout
@@ -1136,7 +1136,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_node_core_nondist == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && (matrix.runner || 'ubuntu-24.04') || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'ubuntu-24.04') || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -1304,7 +1304,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' }}
runs-on: ${{ github.repository == 'openclaw/openclaw' && matrix.runner || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && matrix.runner || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
fail-fast: false
@@ -1398,6 +1398,7 @@ jobs:
pnpm tool-display:check
pnpm check:host-env-policy:swift
pnpm dup:check:coverage
pnpm deps:patches:check
;;
prod-types)
pnpm tsgo:prod
@@ -1465,7 +1466,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' }}
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
fail-fast: false
@@ -1794,7 +1795,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_checks_windows == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-windows-2025' || 'windows-2025' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'windows-2025' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-windows-2025' || 'windows-2025') }}
timeout-minutes: 60
env:
NODE_OPTIONS: --max-old-space-size=8192
@@ -1907,7 +1908,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_macos_node == 'true' }}
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-6vcpu-macos-latest' || 'macos-latest' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-latest' || (github.repository == 'openclaw/openclaw' && 'blacksmith-6vcpu-macos-latest' || 'macos-latest') }}
timeout-minutes: 20
strategy:
fail-fast: false
@@ -1951,7 +1952,7 @@ jobs:
name: "macos-swift"
needs: [preflight]
if: needs.preflight.outputs.run_macos_swift == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-12vcpu-macos-latest' || 'macos-latest' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'macos-26' || (github.repository == 'openclaw/openclaw' && 'blacksmith-12vcpu-macos-latest' || 'macos-26') }}
timeout-minutes: 20
steps:
- name: Checkout
@@ -2048,7 +2049,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_android_job == 'true'
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
fail-fast: false

View File

@@ -225,11 +225,17 @@ jobs:
"" \
"Command router queued. I will update this comment with the next step.")"
status_payload="$(jq -nc --arg body "$status_body" '{body:$body}')"
status_response="$(GH_TOKEN="$TARGET_TOKEN" gh api \
status_err="$(mktemp)"
if status_response="$(GH_TOKEN="$TARGET_TOKEN" gh api \
"repos/$TARGET_REPO/issues/$ITEM_NUMBER/comments" \
--method POST \
--input - <<< "$status_payload")"
status_comment_id="$(jq -r '.id // empty' <<< "$status_response")"
--input - <<< "$status_payload" 2>"$status_err")"; then
status_comment_id="$(jq -r '.id // empty' <<< "$status_response")"
else
cat "$status_err" >&2
echo "::warning::Could not create ClawSweeper queued status comment; dispatching command router without one."
fi
rm -f "$status_err"
;;
esac
fi

View File

@@ -137,8 +137,10 @@ jobs:
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_PROVIDER: ${{ secrets.ANTHROPIC_API_KEY != '' && 'anthropic' || 'openai' }}
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ secrets.ANTHROPIC_API_KEY != '' && 'claude-opus-4-6' || vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_THINKING: low
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "1"
LOCALE: ${{ matrix.locale }}
run: node --import tsx scripts/control-ui-i18n.ts sync --locale "${LOCALE}" --write

View File

@@ -0,0 +1,171 @@
name: Dependency Change Awareness
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] metadata-only workflow; no checkout or untrusted code execution
types: [opened, reopened, synchronize, ready_for_review]
permissions:
pull-requests: write
issues: write
concurrency:
group: dependency-change-awareness-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
dependency-change-awareness:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Label and comment on dependency changes
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const marker = "<!-- openclaw:dependency-change-awareness -->";
const labelName = "dependencies-changed";
const maxListedFiles = 25;
const pullRequest = context.payload.pull_request;
if (!pullRequest) {
core.info("No pull_request payload found; skipping.");
return;
}
const isDependencyFile = (filename) =>
filename === "package.json" ||
filename === "pnpm-lock.yaml" ||
filename === "pnpm-workspace.yaml" ||
filename === "ui/package.json" ||
filename.startsWith("patches/") ||
/^packages\/[^/]+\/package\.json$/u.test(filename) ||
/^extensions\/[^/]+\/package\.json$/u.test(filename);
const sanitizeDisplayValue = (value) =>
String(value)
.replace(/[\u0000-\u001f\u007f]/gu, "?")
.slice(0, 240);
const markdownCode = (value) =>
`\`${sanitizeDisplayValue(value).replaceAll("`", "\\`")}\``;
const ignoreUnavailableWritePermission = (action) => (error) => {
if (error?.status === 403) {
core.warning(
`Skipping dependency change ${action}; token does not have issue write permission.`,
);
return;
}
if (error?.status === 404 || error?.status === 422) {
core.warning(`Dependency change ${action} is unavailable.`);
return;
}
throw error;
};
const files = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pullRequest.number,
per_page: 100,
});
const dependencyFiles = files
.map((file) => file.filename)
.filter((filename) => typeof filename === "string" && isDependencyFile(filename))
.sort((left, right) => left.localeCompare(right));
const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
per_page: 100,
});
const existingComment = comments.find(
(comment) =>
comment.user?.login === "github-actions[bot]" && comment.body?.includes(marker),
);
const labels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
per_page: 100,
});
const hasLabel = labels.some((label) => label.name === labelName);
if (dependencyFiles.length === 0) {
if (hasLabel) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
name: labelName,
}).catch(ignoreUnavailableWritePermission("label removal"));
}
if (existingComment) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
}).catch(ignoreUnavailableWritePermission("comment deletion"));
}
await core.summary
.addHeading("Dependency Change Awareness")
.addRaw("No dependency-related file changes detected.")
.write();
core.info("No dependency-related file changes detected.");
return;
}
if (!hasLabel) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
labels: [labelName],
}).catch(ignoreUnavailableWritePermission(`label "${labelName}" update`));
}
const listedFiles = dependencyFiles.slice(0, maxListedFiles);
const omittedCount = dependencyFiles.length - listedFiles.length;
const fileLines = listedFiles.map((filename) => `- ${markdownCode(filename)}`);
if (omittedCount > 0) {
fileLines.push(`- ${omittedCount} additional dependency-related files not shown`);
}
const body = [
marker,
"",
"### Dependency Changes Detected",
"",
"This PR changes dependency-related files. Maintainers should confirm these changes are intentional.",
"",
"Changed files:",
...fileLines,
"",
"Maintainer follow-up:",
"- Review whether the dependency changes are intentional.",
"- Inspect resolved package deltas when lockfile or workspace dependency policy changes are present.",
"- Run `pnpm deps:changes:report -- --base-ref origin/main --markdown /tmp/dependency-changes.md --json /tmp/dependency-changes.json` locally for detailed release-style evidence.",
].join("\n");
if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body,
}).catch(ignoreUnavailableWritePermission("comment update"));
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pullRequest.number,
body,
}).catch(ignoreUnavailableWritePermission("comment creation"));
}
await core.summary
.addHeading("Dependency Change Awareness")
.addRaw(`Detected ${dependencyFiles.length} dependency-related file change(s).`)
.addList(dependencyFiles.map((filename) => markdownCode(filename)))
.write();
core.notice(`Detected ${dependencyFiles.length} dependency-related file change(s).`);

View File

@@ -16,29 +16,37 @@ permissions:
jobs:
sync-publish-repo:
runs-on: ubuntu-latest
env:
OPENCLAW_DOCS_SYNC_TOKEN: ${{ secrets.OPENCLAW_DOCS_SYNC_TOKEN }}
steps:
- name: Skip publish sync without token
if: env.OPENCLAW_DOCS_SYNC_TOKEN == ''
run: echo "OPENCLAW_DOCS_SYNC_TOKEN is not configured; skipping docs publish repo sync."
- name: Checkout source repo
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Checkout ClawHub docs source
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
uses: actions/checkout@v6
with:
repository: openclaw/clawhub
path: clawhub-source
fetch-depth: 1
persist-credentials: false
token: ${{ secrets.OPENCLAW_DOCS_SYNC_TOKEN || github.token }}
token: ${{ env.OPENCLAW_DOCS_SYNC_TOKEN || github.token }}
- name: Setup Node
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
uses: actions/setup-node@v6
with:
node-version: "22.18.0"
- name: Clone publish repo
env:
OPENCLAW_DOCS_SYNC_TOKEN: ${{ secrets.OPENCLAW_DOCS_SYNC_TOKEN }}
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
run: |
set -euo pipefail
for attempt in 1 2 3 4 5; do
@@ -56,6 +64,7 @@ jobs:
exit 1
- name: Sync docs into publish repo
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
run: |
clawhub_sha="$(git -C "$GITHUB_WORKSPACE/clawhub-source" rev-parse HEAD)"
node scripts/docs-sync-publish.mjs \
@@ -67,13 +76,16 @@ jobs:
--clawhub-source-sha "$clawhub_sha"
- name: Install docs MDX checker dependency
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
working-directory: publish
run: npm install --no-save --package-lock=false @mdx-js/mdx@3.1.1
- name: Check publish docs MDX
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
run: node "$GITHUB_WORKSPACE/publish/.openclaw-sync/check-docs-mdx.mjs" "$GITHUB_WORKSPACE/publish/docs"
- name: Commit publish repo sync
if: env.OPENCLAW_DOCS_SYNC_TOKEN != ''
working-directory: publish
run: |
set -euo pipefail

View File

@@ -297,6 +297,7 @@ jobs:
echo "conclusion=${conclusion}" >> "$GITHUB_OUTPUT"
if [[ "$conclusion" != "success" ]]; then
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
exit 1
fi
}
@@ -396,6 +397,7 @@ jobs:
echo "conclusion=${conclusion}" >> "$GITHUB_OUTPUT"
if [[ "$conclusion" != "success" ]]; then
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
exit 1
fi
}
@@ -504,6 +506,7 @@ jobs:
echo "conclusion=${conclusion}" >> "$GITHUB_OUTPUT"
if [[ "$conclusion" != "success" ]]; then
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
exit 1
fi
}
@@ -726,6 +729,7 @@ jobs:
echo "conclusion=${conclusion}" >> "$GITHUB_OUTPUT"
if [[ "$conclusion" != "success" ]]; then
gh run view "$run_id" --json jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, url}' || true
exit 1
fi
summary:
@@ -735,62 +739,6 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Request private evidence update
env:
RELEASE_PRIVATE_DISPATCH_TOKEN: ${{ secrets.OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN }}
TARGET_REF: ${{ inputs.ref }}
PACKAGE_SPEC: ${{ inputs.evidence_package_spec || inputs.npm_telegram_package_spec }}
GITHUB_RUN_ID_VALUE: ${{ github.run_id }}
RELEASE_CHECKS_RESULT: ${{ needs.release_checks.result }}
run: |
set -euo pipefail
if [[ "$RELEASE_CHECKS_RESULT" == "skipped" ]]; then
echo "Release checks were skipped by rerun group; skipping automatic private evidence update."
exit 0
fi
if [[ -z "${RELEASE_PRIVATE_DISPATCH_TOKEN// }" ]]; then
echo "OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN is not configured; skipping automatic private evidence update."
exit 0
fi
release_id="${TARGET_REF#refs/tags/}"
release_id="${release_id#v}"
if [[ "$PACKAGE_SPEC" =~ ^openclaw@(.+)$ ]]; then
release_id="${BASH_REMATCH[1]}"
fi
release_id="$(printf '%s' "$release_id" | tr '/:@ ' '----' | tr -cd 'A-Za-z0-9._-')"
if [[ -z "$release_id" ]]; then
echo "::error::Could not derive release evidence id from target ref '${TARGET_REF}'."
exit 1
fi
payload="$(
jq -cn \
--arg full_validation_run_id "$GITHUB_RUN_ID_VALUE" \
--arg release_id "$release_id" \
--arg release_ref "$TARGET_REF" \
--arg package_spec "$PACKAGE_SPEC" \
--arg notes "Automatically requested by Full Release Validation ${GITHUB_RUN_ID_VALUE} after child workflows completed; the parent summary re-checks current child run conclusions." \
'{
event_type: "openclaw_full_release_validation_completed",
client_payload: {
full_validation_run_id: $full_validation_run_id,
release_id: $release_id,
release_ref: $release_ref,
package_spec: $package_spec,
notes: $notes
}
}'
)"
curl --fail-with-body \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${RELEASE_PRIVATE_DISPATCH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openclaw/releases-private/dispatches \
-d "$payload"
- name: Verify child workflow results
env:
GH_TOKEN: ${{ github.token }}
@@ -935,6 +883,54 @@ jobs:
} >> "$GITHUB_STEP_SUMMARY"
}
summarize_failed_child() {
local label="$1"
local run_id="$2"
if [[ -z "${run_id// }" ]]; then
return 0
fi
local run_json status conclusion artifacts_json
run_json="$(gh run view "$run_id" --json status,conclusion,url,jobs)"
status="$(jq -r '.status' <<< "$run_json")"
conclusion="$(jq -r '.conclusion' <<< "$run_json")"
if [[ "$status" == "completed" && "$conclusion" == "success" ]]; then
return 0
fi
{
echo
echo "### Failed child detail: ${label}"
echo
jq -r '
"- Run: " + (.url // ""),
"- Result: `" + (.status // "") + "/" + (.conclusion // "") + "`",
"",
"Failed jobs:",
(.jobs[]
| select(.conclusion != "success" and .conclusion != "skipped")
| "- `" + (.name | gsub("`"; "\\`")) + "`: `" + ((.conclusion // .status // "") | tostring) + "` " + (.url // ""))
' <<< "$run_json" || true
echo
echo "Artifacts:"
artifacts_json="$(
gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${run_id}/artifacts?per_page=100" 2>/dev/null || true
)"
if [[ -n "${artifacts_json// }" ]]; then
jq -r '
if ((.artifacts // []) | length) == 0 then
"- none"
else
(.artifacts[]
| "- `" + (.name | gsub("`"; "\\`")) + "` (" + ((.size_in_bytes // 0) | tostring) + " bytes)")
end
' <<< "$artifacts_json" || echo "- unable to list artifacts"
else
echo "- unable to list artifacts"
fi
} >> "$GITHUB_STEP_SUMMARY"
}
failed=0
append_child_overview
@@ -968,4 +964,126 @@ jobs:
summarize_child_timing "release_checks" "$RELEASE_CHECKS_RUN_ID"
summarize_child_timing "npm_telegram" "$NPM_TELEGRAM_RUN_ID"
if [[ "$failed" != "0" ]]; then
summarize_failed_child "normal_ci" "$NORMAL_CI_RUN_ID"
summarize_failed_child "plugin_prerelease" "$PLUGIN_PRERELEASE_RUN_ID"
summarize_failed_child "release_checks" "$RELEASE_CHECKS_RUN_ID"
summarize_failed_child "npm_telegram" "$NPM_TELEGRAM_RUN_ID"
fi
exit "$failed"
- name: Request private evidence update
env:
RELEASE_PRIVATE_DISPATCH_TOKEN: ${{ secrets.OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN }}
TARGET_REF: ${{ inputs.ref }}
PACKAGE_SPEC: ${{ inputs.evidence_package_spec || inputs.npm_telegram_package_spec }}
GITHUB_RUN_ID_VALUE: ${{ github.run_id }}
RELEASE_CHECKS_RESULT: ${{ needs.release_checks.result }}
run: |
set -euo pipefail
if [[ "$RELEASE_CHECKS_RESULT" == "skipped" ]]; then
echo "Release checks were skipped by rerun group; skipping automatic private evidence update."
exit 0
fi
if [[ -z "${RELEASE_PRIVATE_DISPATCH_TOKEN// }" ]]; then
echo "OPENCLAW_RELEASES_PRIVATE_DISPATCH_TOKEN is not configured; skipping automatic private evidence update."
exit 0
fi
release_id="${TARGET_REF#refs/tags/}"
release_id="${release_id#v}"
if [[ "$PACKAGE_SPEC" =~ ^openclaw@(.+)$ ]]; then
release_id="${BASH_REMATCH[1]}"
fi
release_id="$(printf '%s' "$release_id" | tr '/:@ ' '----' | tr -cd 'A-Za-z0-9._-')"
if [[ -z "$release_id" ]]; then
echo "::warning::Could not derive release evidence id from target ref '${TARGET_REF}'; skipping automatic private evidence update."
exit 0
fi
payload="$(
jq -cn \
--arg full_validation_run_id "$GITHUB_RUN_ID_VALUE" \
--arg release_id "$release_id" \
--arg release_ref "$TARGET_REF" \
--arg package_spec "$PACKAGE_SPEC" \
--arg notes "Automatically requested by Full Release Validation ${GITHUB_RUN_ID_VALUE} after child workflows completed; the parent summary re-checks current child run conclusions." \
'{
event_type: "openclaw_full_release_validation_completed",
client_payload: {
full_validation_run_id: $full_validation_run_id,
release_id: $release_id,
release_ref: $release_ref,
package_spec: $package_spec,
notes: $notes
}
}'
)"
if ! curl --fail-with-body \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${RELEASE_PRIVATE_DISPATCH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openclaw/releases-private/dispatches \
-d "$payload"; then
echo "::warning::Automatic private release evidence dispatch failed; child workflow validation remains authoritative."
fi
- name: Write release validation manifest
if: ${{ success() }}
env:
TARGET_REF: ${{ inputs.ref }}
TARGET_SHA: ${{ needs.resolve_target.outputs.sha }}
RELEASE_PROFILE: ${{ inputs.release_profile }}
RERUN_GROUP: ${{ inputs.rerun_group }}
RUN_RELEASE_SOAK: ${{ inputs.run_release_soak || inputs.release_profile == 'full' }}
NORMAL_CI_RUN_ID: ${{ needs.normal_ci.outputs.run_id }}
PLUGIN_PRERELEASE_RUN_ID: ${{ needs.plugin_prerelease.outputs.run_id }}
RELEASE_CHECKS_RUN_ID: ${{ needs.release_checks.outputs.run_id }}
NPM_TELEGRAM_RUN_ID: ${{ needs.npm_telegram.outputs.run_id }}
run: |
set -euo pipefail
manifest_dir="${RUNNER_TEMP}/full-release-validation"
mkdir -p "$manifest_dir"
jq -n \
--arg workflowName "Full Release Validation" \
--arg runId "$GITHUB_RUN_ID" \
--arg runAttempt "$GITHUB_RUN_ATTEMPT" \
--arg workflowRef "$GITHUB_REF_NAME" \
--arg targetRef "$TARGET_REF" \
--arg targetSha "$TARGET_SHA" \
--arg releaseProfile "$RELEASE_PROFILE" \
--arg rerunGroup "$RERUN_GROUP" \
--arg runReleaseSoak "$RUN_RELEASE_SOAK" \
--arg normalCiRunId "$NORMAL_CI_RUN_ID" \
--arg pluginPrereleaseRunId "$PLUGIN_PRERELEASE_RUN_ID" \
--arg releaseChecksRunId "$RELEASE_CHECKS_RUN_ID" \
--arg npmTelegramRunId "$NPM_TELEGRAM_RUN_ID" \
'{
version: 1,
workflowName: $workflowName,
runId: $runId,
runAttempt: $runAttempt,
workflowRef: $workflowRef,
targetRef: $targetRef,
targetSha: $targetSha,
releaseProfile: $releaseProfile,
rerunGroup: $rerunGroup,
runReleaseSoak: $runReleaseSoak,
childRuns: {
normalCi: $normalCiRunId,
pluginPrerelease: $pluginPrereleaseRunId,
releaseChecks: $releaseChecksRunId,
npmTelegram: $npmTelegramRunId
}
}' > "${manifest_dir}/full-release-validation-manifest.json"
- name: Upload release validation manifest
if: ${{ success() }}
uses: actions/upload-artifact@v7
with:
name: full-release-validation-${{ github.run_id }}
path: ${{ runner.temp }}/full-release-validation
if-no-files-found: error

View File

@@ -100,7 +100,7 @@ jobs:
install-smoke-fast:
needs: [preflight]
if: needs.preflight.outputs.run_fast_install_smoke == 'true' && needs.preflight.outputs.run_full_install_smoke != 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
@@ -208,7 +208,7 @@ jobs:
root_dockerfile_image:
needs: [preflight]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
outputs:
image_ref: ${{ steps.image.outputs.image_ref }}
env:
@@ -284,7 +284,7 @@ jobs:
qr_package_install_smoke:
needs: [preflight]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
steps:
- name: Checkout CLI
uses: actions/checkout@v6
@@ -299,7 +299,7 @@ jobs:
root_dockerfile_smokes:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
steps:
- name: Checkout CLI
uses: actions/checkout@v6
@@ -401,7 +401,7 @@ jobs:
installer_smoke:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
@@ -471,7 +471,7 @@ jobs:
bun_global_install_smoke:
needs: [preflight, root_dockerfile_image]
if: needs.preflight.outputs.run_full_install_smoke == 'true' && needs.preflight.outputs.run_bun_global_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
steps:
- name: Checkout CLI
uses: actions/checkout@v6
@@ -505,7 +505,7 @@ jobs:
docker-e2e-fast:
needs: [preflight]
if: needs.preflight.outputs.run_fast_install_smoke == 'true' || needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 12
env:
DOCKER_BUILD_SUMMARY: "false"

View File

@@ -21,7 +21,7 @@ on:
type: string
permissions:
contents: write
contents: read
issues: write
pull-requests: write
@@ -538,7 +538,6 @@ jobs:
private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
@@ -546,9 +545,15 @@ jobs:
if: ${{ always() && needs.resolve_request.outputs.pr_number != '' && steps.run_mantis.outputs.output_dir != '' }}
env:
GH_TOKEN: ${{ steps.mantis_app_token.outputs.token }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
ARTIFACT_URL: ${{ steps.upload_artifact.outputs.artifact-url }}
MANTIS_ARTIFACT_R2_ACCESS_KEY_ID: ${{ secrets.MANTIS_ARTIFACT_R2_ACCESS_KEY_ID }}
MANTIS_ARTIFACT_R2_BUCKET: openclaw-crabbox-artifacts
MANTIS_ARTIFACT_R2_ENDPOINT: ${{ vars.MANTIS_ARTIFACT_R2_ENDPOINT }}
MANTIS_ARTIFACT_R2_PUBLIC_BASE_URL: https://artifacts.openclaw.ai
MANTIS_ARTIFACT_R2_REGION: auto
MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY: ${{ secrets.MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY }}
REQUEST_SOURCE: ${{ needs.resolve_request.outputs.request_source }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
shell: bash
run: |
set -euo pipefail

View File

@@ -21,7 +21,7 @@ on:
type: string
permissions:
contents: write
contents: read
issues: write
pull-requests: write
@@ -546,7 +546,6 @@ jobs:
private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
@@ -554,9 +553,15 @@ jobs:
if: ${{ always() && needs.resolve_request.outputs.pr_number != '' && steps.run_mantis.outputs.output_dir != '' }}
env:
GH_TOKEN: ${{ steps.mantis_app_token.outputs.token }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
ARTIFACT_URL: ${{ steps.upload_artifact.outputs.artifact-url }}
MANTIS_ARTIFACT_R2_ACCESS_KEY_ID: ${{ secrets.MANTIS_ARTIFACT_R2_ACCESS_KEY_ID }}
MANTIS_ARTIFACT_R2_BUCKET: openclaw-crabbox-artifacts
MANTIS_ARTIFACT_R2_ENDPOINT: ${{ vars.MANTIS_ARTIFACT_R2_ENDPOINT }}
MANTIS_ARTIFACT_R2_PUBLIC_BASE_URL: https://artifacts.openclaw.ai
MANTIS_ARTIFACT_R2_REGION: auto
MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY: ${{ secrets.MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY }}
REQUEST_SOURCE: ${{ needs.resolve_request.outputs.request_source }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
shell: bash
run: |
set -euo pipefail

View File

@@ -44,7 +44,7 @@ on:
- prehydrated
permissions:
contents: write
contents: read
issues: write
pull-requests: write
@@ -368,7 +368,6 @@ jobs:
private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
@@ -376,9 +375,15 @@ jobs:
if: ${{ always() && inputs.pr_number != '' && steps.run_mantis.outputs.output_dir != '' && steps.upload_artifact.outputs.artifact-url != '' }}
env:
GH_TOKEN: ${{ steps.mantis_app_token.outputs.token }}
TARGET_PR: ${{ inputs.pr_number }}
ARTIFACT_URL: ${{ steps.upload_artifact.outputs.artifact-url }}
MANTIS_ARTIFACT_R2_ACCESS_KEY_ID: ${{ secrets.MANTIS_ARTIFACT_R2_ACCESS_KEY_ID }}
MANTIS_ARTIFACT_R2_BUCKET: openclaw-crabbox-artifacts
MANTIS_ARTIFACT_R2_ENDPOINT: ${{ vars.MANTIS_ARTIFACT_R2_ENDPOINT }}
MANTIS_ARTIFACT_R2_PUBLIC_BASE_URL: https://artifacts.openclaw.ai
MANTIS_ARTIFACT_R2_REGION: auto
MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY: ${{ secrets.MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY }}
REQUEST_SOURCE: workflow_dispatch
TARGET_PR: ${{ inputs.pr_number }}
shell: bash
run: |
set -euo pipefail

View File

@@ -5,19 +5,9 @@ on:
types: [created]
workflow_dispatch:
inputs:
baseline_ref:
description: Ref, tag, or SHA to capture as the before GIF
required: true
default: main
type: string
candidate_ref:
description: Ref, tag, or SHA to capture as the after GIF
required: true
default: main
type: string
pr_number:
description: Optional PR number to receive the QA evidence comment
required: false
description: PR number to capture
required: true
type: string
instructions:
description: Optional freeform proof instructions for the agent
@@ -37,18 +27,15 @@ on:
type: string
permissions:
contents: write
actions: read
contents: read
issues: write
pull-requests: write
concurrency:
group: mantis-telegram-desktop-proof-${{ github.event.issue.number || inputs.pr_number || inputs.candidate_ref || github.run_id }}-${{ github.run_attempt }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
PNPM_VERSION: "11.0.8"
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
CRABBOX_REF: main
@@ -63,10 +50,10 @@ jobs:
(
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.issue.labels.*.name, 'mantis: telegram-visible-proof') &&
(
contains(github.event.comment.body, '@Mantis') ||
contains(github.event.comment.body, '@mantis') ||
contains(github.event.comment.body, '/mantis')
contains(github.event.comment.body, '@openclaw-mantis') ||
contains(github.event.comment.body, '/openclaw-mantis')
)
)
}}
@@ -103,7 +90,6 @@ jobs:
lease_id: ${{ steps.resolve.outputs.lease_id }}
pr_number: ${{ steps.resolve.outputs.pr_number }}
request_source: ${{ steps.resolve.outputs.request_source }}
should_run: ${{ steps.resolve.outputs.should_run }}
steps:
- name: Resolve refs and target PR
id: resolve
@@ -117,47 +103,11 @@ jobs:
core.info(`${name}=${value ?? ""}`);
}
if (eventName === "workflow_dispatch") {
const inputs = context.payload.inputs ?? {};
setOutput("should_run", "true");
setOutput("baseline_ref", inputs.baseline_ref || "main");
setOutput("candidate_ref", inputs.candidate_ref || "main");
setOutput("pr_number", inputs.pr_number || "");
setOutput("instructions", inputs.instructions || "");
setOutput("crabbox_provider", inputs.crabbox_provider || "aws");
setOutput("lease_id", inputs.crabbox_lease_id || "");
setOutput("request_source", "workflow_dispatch");
return;
}
if (eventName !== "issue_comment") {
core.setFailed(`Unsupported event: ${eventName}`);
return;
}
const issue = context.payload.issue;
const body = context.payload.comment?.body ?? "";
if (!issue?.pull_request) {
core.setFailed("Mantis issue_comment trigger requires a pull request comment.");
return;
}
const normalized = body.toLowerCase();
const requested =
(normalized.includes("@mantis") || normalized.includes("/mantis")) &&
normalized.includes("telegram") &&
(normalized.includes("desktop") || normalized.includes("native")) &&
normalized.includes("proof");
if (!requested) {
core.notice("Comment mentioned Mantis but did not request Telegram desktop proof.");
setOutput("should_run", "false");
setOutput("baseline_ref", "");
setOutput("candidate_ref", "");
setOutput("pr_number", "");
setOutput("instructions", "");
setOutput("crabbox_provider", "");
setOutput("lease_id", "");
setOutput("request_source", "unsupported_issue_comment");
const inputs = context.payload.inputs ?? {};
const prNumber =
eventName === "workflow_dispatch" ? inputs.pr_number : String(context.payload.issue?.number ?? "");
if (!prNumber) {
core.setFailed("Mantis Telegram desktop proof requires a pull request.");
return;
}
@@ -165,59 +115,40 @@ jobs:
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: issue.number,
pull_number: Number(prNumber),
});
let mergedBaseline = "";
let mergedCandidate = "";
if (pr.merged) {
const { data: commits } = await github.rest.pulls.listCommits({
owner,
repo,
pull_number: issue.number,
per_page: 100,
});
mergedCandidate = pr.merge_commit_sha || commits.at(-1)?.sha || "";
mergedBaseline = mergedCandidate && commits.length > 0 ? `${mergedCandidate}~${commits.length}` : "";
}
const baselineMatch = body.match(/(?:baseline|base)[\s:=]+([^\s`]+)/i);
const candidateMatch = body.match(/(?:candidate|head)[\s:=]+([^\s`]+)/i);
const providerMatch = body.match(/(?:provider|crabbox_provider)[\s:=]+([^\s`]+)/i);
const leaseMatch = body.match(/(?:lease|lease_id|crabbox_lease_id)[\s:=]+([^\s`]+)/i);
const provider = providerMatch?.[1] || "aws";
const body = eventName === "workflow_dispatch" ? inputs.instructions || "" : context.payload.comment?.body || "";
const provider = inputs.crabbox_provider || "aws";
if (!["aws", "hetzner"].includes(provider)) {
core.setFailed(`Unsupported Crabbox provider for Mantis Telegram desktop proof: ${provider}`);
return;
}
const rawCandidate = candidateMatch?.[1];
const candidate =
rawCandidate && !["head", "pr", "pr-head"].includes(rawCandidate.toLowerCase())
? rawCandidate
: mergedCandidate || pr.head.sha;
setOutput("should_run", "true");
setOutput("baseline_ref", baselineMatch?.[1] || mergedBaseline || "main");
setOutput("candidate_ref", candidate);
setOutput("pr_number", String(issue.number));
setOutput("baseline_ref", pr.base.sha);
setOutput("candidate_ref", pr.head.sha);
setOutput("pr_number", String(pr.number));
setOutput("instructions", body);
setOutput("crabbox_provider", provider);
setOutput("lease_id", leaseMatch?.[1] || "");
setOutput("request_source", "issue_comment");
setOutput("lease_id", inputs.crabbox_lease_id || "");
setOutput("request_source", eventName);
await github.rest.reactions.createForIssueComment({
owner,
repo,
comment_id: context.payload.comment.id,
content: "eyes",
}).catch((error) => core.warning(`Could not add eyes reaction: ${error.message}`));
if (eventName === "issue_comment") {
await github.rest.reactions.createForIssueComment({
owner,
repo,
comment_id: context.payload.comment.id,
content: "eyes",
}).catch((error) => core.warning(`Could not add eyes reaction: ${error.message}`));
}
validate_refs:
name: Validate selected refs
needs: resolve_request
if: ${{ needs.resolve_request.outputs.should_run == 'true' }}
runs-on: ubuntu-24.04
outputs:
baseline_revision: ${{ steps.validate.outputs.baseline_revision }}
candidate_revision: ${{ steps.validate.outputs.candidate_revision }}
candidate_trust: ${{ steps.validate.outputs.candidate_trust }}
steps:
- name: Checkout harness ref
uses: actions/checkout@v6
@@ -241,55 +172,56 @@ jobs:
git fetch --no-tags origin "+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr/${PR_NUMBER}" || true
fi
validate_ref() {
local label="$1"
resolve_commit() {
local input_ref="$2"
local revision=""
local reason=""
if ! revision="$(git rev-parse --verify "${input_ref}^{commit}" 2>/dev/null)"; then
echo "${label} ref '${input_ref}' is not available in the workflow checkout." >&2
exit 1
fi
if git merge-base --is-ancestor "$revision" refs/remotes/origin/main; then
reason="main-ancestor"
elif git tag --points-at "$revision" | grep -Eq '^v'; then
reason="release-tag"
else
local pr_head_count
pr_head_count="$(
gh api \
-H "Accept: application/vnd.github+json" \
"repos/${GITHUB_REPOSITORY}/commits/${revision}/pulls" \
--jq '[.[] | select(.state == "open" and .head.repo.full_name == "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${revision}"'")] | length'
)"
if [[ "$pr_head_count" != "0" ]]; then
reason="open-pr-head"
fi
fi
if [[ -z "$reason" ]]; then
echo "${label} ref '${input_ref}' resolved to ${revision}, which is not trusted for this secret-bearing Mantis run." >&2
echo "$1 ref '${input_ref}' is not available in the workflow checkout." >&2
exit 1
fi
printf '%s\n' "$revision"
}
baseline_revision="$(validate_ref baseline "$BASELINE_REF")"
candidate_revision="$(validate_ref candidate "$CANDIDATE_REF")"
baseline_revision="$(resolve_commit baseline "$BASELINE_REF")"
candidate_revision="$(resolve_commit candidate "$CANDIDATE_REF")"
if ! git merge-base --is-ancestor "$baseline_revision" refs/remotes/origin/main; then
echo "baseline ref '${BASELINE_REF}' resolved to ${baseline_revision}, which is not on main." >&2
exit 1
fi
pr_head="$(
gh api \
-H "Accept: application/vnd.github+json" \
"repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" \
--jq '{state, head_sha: .head.sha, head_repo: .head.repo.full_name}'
)"
pr_state="$(jq -r '.state' <<<"$pr_head")"
pr_head_sha="$(jq -r '.head_sha' <<<"$pr_head")"
pr_head_repo="$(jq -r '.head_repo' <<<"$pr_head")"
if [[ "$pr_state" != "open" || "$candidate_revision" != "$pr_head_sha" ]]; then
echo "candidate ref '${CANDIDATE_REF}' resolved to ${candidate_revision}, which is not the open PR head." >&2
exit 1
fi
candidate_trust="open-pr-head"
if [[ "$pr_head_repo" != "$GITHUB_REPOSITORY" ]]; then
candidate_trust="fork-pr-head"
fi
echo "baseline_revision=${baseline_revision}" >> "$GITHUB_OUTPUT"
echo "candidate_revision=${candidate_revision}" >> "$GITHUB_OUTPUT"
echo "candidate_trust=${candidate_trust}" >> "$GITHUB_OUTPUT"
{
echo "baseline: \`${BASELINE_REF}\`"
echo "baseline SHA: \`${baseline_revision}\`"
echo "baseline trust: \`main-ancestor\`"
echo "candidate: \`${CANDIDATE_REF}\`"
echo "candidate SHA: \`${candidate_revision}\`"
echo "candidate trust: \`${candidate_trust}\`"
} >> "$GITHUB_STEP_SUMMARY"
run_telegram_desktop_proof:
name: Run agentic native Telegram proof
needs: [resolve_request, validate_refs]
if: ${{ needs.resolve_request.outputs.should_run == 'true' }}
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 360
environment: qa-live-shared
@@ -297,6 +229,31 @@ jobs:
comparison_status: ${{ steps.inspect.outputs.comparison_status }}
output_dir: ${{ steps.inspect.outputs.output_dir }}
steps:
- name: Wait for older Mantis Telegram account run
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
current_created="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" --jq .created_at)"
while true; do
blockers="$(
for workflow in mantis-telegram-desktop-proof.yml mantis-telegram-live.yml; do
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 100 --json databaseId,status,createdAt,url \
| jq -r \
--argjson current_id "$GITHUB_RUN_ID" \
--arg current_created "$current_created" \
'.[] | select(.databaseId != $current_id) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested") | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
done | sort -u
)"
if [[ -z "$blockers" ]]; then
break
fi
echo "Waiting for older Mantis Telegram account run:"
printf '%s\n' "$blockers" | head -n 10
sleep 60
done
- name: Checkout harness ref
uses: actions/checkout@v6
with:
@@ -331,6 +288,32 @@ jobs:
crabbox --version
crabbox media preview --help >/dev/null
- name: Install local proof tools
shell: bash
run: |
set -euo pipefail
test -f scripts/e2e/telegram-user-driver.py
cat >"${RUNNER_TEMP}/openclaw-telegram-user-crabbox-proof" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
exec node --import tsx "${GITHUB_WORKSPACE}/scripts/e2e/telegram-user-crabbox-proof.ts" "$@"
EOF
chmod 0755 "${RUNNER_TEMP}/openclaw-telegram-user-crabbox-proof"
sudo install -m 0755 "${RUNNER_TEMP}/openclaw-telegram-user-crabbox-proof" /usr/local/bin/openclaw-telegram-user-crabbox-proof
/usr/local/bin/openclaw-telegram-user-crabbox-proof --help >/dev/null
media_tools="${RUNNER_TEMP}/mantis-media-tools"
install -d "$media_tools"
curl --fail --location --retry 3 --retry-delay 2 \
--connect-timeout 15 --max-time 180 \
https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz \
--output "$media_tools/ffmpeg.tar.xz"
tar -xJf "$media_tools/ffmpeg.tar.xz" -C "$media_tools"
bin_dir="$(find "$media_tools" -type d -path '*/bin' | head -n 1)"
sudo install -m 0755 "$bin_dir/ffmpeg" /usr/local/bin/ffmpeg
sudo install -m 0755 "$bin_dir/ffprobe" /usr/local/bin/ffprobe
ffmpeg -version >/dev/null
ffprobe -version >/dev/null
- name: Ensure agent key exists
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_MANTIS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
@@ -350,8 +333,9 @@ jobs:
printf '%s\n' 'Defaults env_keep += "CODEX_HOME CODEX_INTERNAL_ORIGINATOR_OVERRIDE"'
printf '%s\n' 'Defaults env_keep += "BASELINE_REF BASELINE_SHA CANDIDATE_REF CANDIDATE_SHA"'
printf '%s\n' 'Defaults env_keep += "CRABBOX_ACCESS_CLIENT_ID CRABBOX_ACCESS_CLIENT_SECRET CRABBOX_COORDINATOR CRABBOX_COORDINATOR_TOKEN CRABBOX_LEASE_ID CRABBOX_PROVIDER"'
printf '%s\n' 'Defaults env_keep += "GH_TOKEN MANTIS_INSTRUCTIONS MANTIS_OUTPUT_DIR MANTIS_PR_NUMBER"'
printf '%s\n' 'Defaults env_keep += "GH_TOKEN MANTIS_CANDIDATE_TRUST MANTIS_INSTRUCTIONS MANTIS_OUTPUT_DIR MANTIS_PR_NUMBER"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_BUILD_PRIVATE_QA OPENCLAW_ENABLE_PRIVATE_QA_CLI OPENCLAW_QA_CONVEX_SECRET_CI OPENCLAW_QA_CONVEX_SITE_URL OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN"'
printf '%s\n' 'Defaults env_keep += "OPENCLAW_TELEGRAM_USER_CRABBOX_BIN OPENCLAW_TELEGRAM_USER_CRABBOX_PROVIDER OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT OPENCLAW_TELEGRAM_USER_PROOF_CMD"'
} | sudo tee /etc/sudoers.d/mantis-codex-env >/dev/null
sudo chmod 0440 /etc/sudoers.d/mantis-codex-env
codex_home="/tmp/mantis-codex-home-${GITHUB_RUN_ID}"
@@ -375,11 +359,12 @@ jobs:
CANDIDATE_SHA: ${{ needs.validate_refs.outputs.candidate_revision }}
CRABBOX_ACCESS_CLIENT_ID: ${{ secrets.CRABBOX_ACCESS_CLIENT_ID }}
CRABBOX_ACCESS_CLIENT_SECRET: ${{ secrets.CRABBOX_ACCESS_CLIENT_SECRET }}
CRABBOX_COORDINATOR: ${{ secrets.CRABBOX_COORDINATOR }}
CRABBOX_COORDINATOR_TOKEN: ${{ secrets.CRABBOX_COORDINATOR_TOKEN }}
CRABBOX_COORDINATOR: ${{ secrets.CRABBOX_COORDINATOR || secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR }}
CRABBOX_COORDINATOR_TOKEN: ${{ secrets.CRABBOX_COORDINATOR_TOKEN || secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN }}
CRABBOX_LEASE_ID: ${{ needs.resolve_request.outputs.lease_id }}
CRABBOX_PROVIDER: ${{ needs.resolve_request.outputs.crabbox_provider }}
GH_TOKEN: ${{ github.token }}
MANTIS_CANDIDATE_TRUST: ${{ needs.validate_refs.outputs.candidate_trust }}
MANTIS_INSTRUCTIONS: ${{ needs.resolve_request.outputs.instructions }}
MANTIS_OUTPUT_DIR: ${{ env.MANTIS_OUTPUT_DIR }}
MANTIS_PR_NUMBER: ${{ needs.resolve_request.outputs.pr_number }}
@@ -387,12 +372,17 @@ jobs:
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR: ${{ secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR }}
OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN: ${{ secrets.OPENCLAW_QA_MANTIS_CRABBOX_COORDINATOR_TOKEN }}
OPENCLAW_TELEGRAM_USER_CRABBOX_BIN: /usr/local/bin/crabbox
OPENCLAW_TELEGRAM_USER_CRABBOX_PROVIDER: ${{ needs.resolve_request.outputs.crabbox_provider }}
OPENCLAW_TELEGRAM_USER_DRIVER_SCRIPT: ${{ github.workspace }}/scripts/e2e/telegram-user-driver.py
OPENCLAW_TELEGRAM_USER_PROOF_CMD: /usr/local/bin/openclaw-telegram-user-crabbox-proof
with:
openai-api-key: ${{ secrets.OPENCLAW_MANTIS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
prompt-file: .github/codex/prompts/mantis-telegram-desktop-proof.md
model: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
effort: high
effort: medium
sandbox: danger-full-access
codex-args: '["-c","service_tier=\"fast\""]'
codex-home: /tmp/mantis-codex-home-${{ github.run_id }}
safety-strategy: unprivileged-user
codex-user: codex
@@ -432,7 +422,6 @@ jobs:
private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
@@ -441,6 +430,12 @@ jobs:
env:
ARTIFACT_URL: ${{ steps.upload_artifact.outputs.artifact-url }}
GH_TOKEN: ${{ steps.mantis_app_token.outputs.token }}
MANTIS_ARTIFACT_R2_ACCESS_KEY_ID: ${{ secrets.MANTIS_ARTIFACT_R2_ACCESS_KEY_ID }}
MANTIS_ARTIFACT_R2_BUCKET: openclaw-crabbox-artifacts
MANTIS_ARTIFACT_R2_ENDPOINT: ${{ vars.MANTIS_ARTIFACT_R2_ENDPOINT }}
MANTIS_ARTIFACT_R2_PUBLIC_BASE_URL: https://artifacts.openclaw.ai
MANTIS_ARTIFACT_R2_REGION: auto
MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY: ${{ secrets.MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY }}
REQUEST_SOURCE: ${{ needs.resolve_request.outputs.request_source }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
shell: bash

View File

@@ -33,18 +33,15 @@ on:
type: string
permissions:
contents: write
actions: read
contents: read
issues: write
pull-requests: write
concurrency:
group: mantis-telegram-live-${{ github.event.issue.number || inputs.pr_number || inputs.candidate_ref || github.run_id }}-${{ github.run_attempt }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
PNPM_VERSION: "11.0.8"
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
CRABBOX_REF: main
@@ -253,6 +250,31 @@ jobs:
comparison_status: ${{ steps.run_mantis.outputs.comparison_status }}
output_dir: ${{ steps.run_mantis.outputs.output_dir }}
steps:
- name: Wait for older Mantis Telegram account run
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
current_created="$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" --jq .created_at)"
while true; do
blockers="$(
for workflow in mantis-telegram-desktop-proof.yml mantis-telegram-live.yml; do
gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" --limit 100 --json databaseId,status,createdAt,url \
| jq -r \
--argjson current_id "$GITHUB_RUN_ID" \
--arg current_created "$current_created" \
'.[] | select(.databaseId != $current_id) | select(.createdAt < $current_created or (.createdAt == $current_created and .databaseId < $current_id)) | select(.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending" or .status == "requested") | "\(.createdAt)\t#\(.databaseId)\t\(.status)\t\(.url)"'
done | sort -u
)"
if [[ -z "$blockers" ]]; then
break
fi
echo "Waiting for older Mantis Telegram account run:"
printf '%s\n' "$blockers" | head -n 10
sleep 60
done
- name: Checkout harness ref
uses: actions/checkout@v6
with:
@@ -458,7 +480,6 @@ jobs:
private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
permission-contents: write
permission-issues: write
permission-pull-requests: write
@@ -466,9 +487,15 @@ jobs:
if: ${{ always() && needs.resolve_request.outputs.pr_number != '' && steps.run_mantis.outputs.output_dir != '' }}
env:
GH_TOKEN: ${{ steps.mantis_app_token.outputs.token }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
ARTIFACT_URL: ${{ steps.upload_artifact.outputs.artifact-url }}
MANTIS_ARTIFACT_R2_ACCESS_KEY_ID: ${{ secrets.MANTIS_ARTIFACT_R2_ACCESS_KEY_ID }}
MANTIS_ARTIFACT_R2_BUCKET: openclaw-crabbox-artifacts
MANTIS_ARTIFACT_R2_ENDPOINT: ${{ vars.MANTIS_ARTIFACT_R2_ENDPOINT }}
MANTIS_ARTIFACT_R2_PUBLIC_BASE_URL: https://artifacts.openclaw.ai
MANTIS_ARTIFACT_R2_REGION: auto
MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY: ${{ secrets.MANTIS_ARTIFACT_R2_SECRET_ACCESS_KEY }}
REQUEST_SOURCE: ${{ needs.resolve_request.outputs.request_source }}
TARGET_PR: ${{ needs.resolve_request.outputs.pr_number }}
shell: bash
run: |
set -euo pipefail

View File

@@ -427,6 +427,7 @@ jobs:
add_profile_suite live-cli-backend-docker "stable full"
add_profile_suite live-acp-bind-docker "stable full"
add_profile_suite live-codex-harness-docker "stable full"
add_profile_suite live-subagent-announce-docker "stable full"
add_profile_suite native-live-extensions-a-k "full"
add_profile_suite native-live-extensions-media-audio "full"
@@ -454,7 +455,7 @@ jobs:
validate_release_live_cache:
needs: validate_selected_ref
if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'live-cache')
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 20
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@@ -504,7 +505,7 @@ jobs:
validate_repo_e2e:
needs: validate_selected_ref
if: inputs.include_repo_e2e && inputs.live_suite_filter == ''
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: ${{ inputs.release_test_profile == 'full' && 90 || 60 }}
env:
OPENCLAW_VITEST_MAX_WORKERS: "2"
@@ -533,7 +534,7 @@ jobs:
validate_special_e2e:
needs: validate_selected_ref
if: inputs.include_repo_e2e && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'openshell-e2e')
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
@@ -607,7 +608,7 @@ jobs:
needs: [validate_selected_ref, prepare_docker_e2e_image]
if: inputs.include_release_path_suites && inputs.docker_lanes == ''
name: Docker E2E (${{ matrix.label }})
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
@@ -875,7 +876,7 @@ jobs:
plan_docker_lane_groups:
needs: validate_selected_ref
if: inputs.docker_lanes != ''
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-4vcpu-ubuntu-2404' }}
timeout-minutes: 5
outputs:
groups_json: ${{ steps.groups.outputs.groups_json }}
@@ -902,7 +903,7 @@ jobs:
needs: [validate_selected_ref, prepare_docker_e2e_image, plan_docker_lane_groups]
if: inputs.docker_lanes != ''
name: Docker E2E targeted lanes (${{ matrix.group.label }})
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -1111,7 +1112,7 @@ jobs:
needs: [validate_selected_ref, prepare_docker_e2e_image]
if: inputs.include_openwebui && !inputs.include_release_path_suites && inputs.docker_lanes == ''
name: Docker E2E (openwebui)
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 60
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@@ -1238,7 +1239,7 @@ jobs:
prepare_docker_e2e_image:
needs: validate_selected_ref
if: inputs.include_release_path_suites || inputs.include_openwebui || inputs.docker_lanes != ''
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ inputs.release_test_profile == 'full' && 90 || 60 }}
permissions:
actions: read
@@ -1482,7 +1483,7 @@ jobs:
prepare_live_test_image:
needs: validate_selected_ref
if: inputs.include_live_suites && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'live-') || startsWith(inputs.live_suite_filter, 'docker-live-models'))
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 60
permissions:
contents: read
@@ -1555,7 +1556,7 @@ jobs:
name: Docker live models (${{ matrix.provider_label }})
needs: [validate_selected_ref, prepare_live_test_image]
if: inputs.include_live_suites && inputs.live_model_providers == '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models')
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 45
strategy:
fail-fast: false
@@ -1707,7 +1708,7 @@ jobs:
name: Docker live models (selected providers)
needs: [validate_selected_ref, prepare_live_test_image]
if: inputs.include_live_suites && inputs.live_model_providers != '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models')
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: 45
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@@ -1882,7 +1883,7 @@ jobs:
validate_live_provider_suites:
needs: validate_selected_ref
if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || (startsWith(inputs.live_suite_filter, 'native-live-') && !startsWith(inputs.live_suite_filter, 'native-live-extensions-media') && inputs.live_suite_filter != 'native-live-extensions-a-k'))
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
@@ -2153,27 +2154,11 @@ jobs:
fi
case "${{ matrix.suite_id }}" in
live-cli-backend-docker)
echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=codex-cli/gpt-5.4" >> "$GITHUB_ENV"
# Keep the release-blocking CI lane on Codex API-key auth. The
# staged auth-file path remains supported for local maintainer
# reruns, but it can hang on stale subscription/session state in
# an otherwise healthy release run.
echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=claude-cli/claude-sonnet-4-6" >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key" >> "$GITHUB_ENV"
# Replace the staged config.toml with a minimal CI-safe config so
# the repo stays trusted for MCP/tool use without inheriting
# maintainer-local provider/profile overrides that do not exist
# inside CI.
# Codex's workspace-write sandbox relies on user namespaces that
# this Docker lane does not provide, so run Codex unsandboxed
# inside the already-isolated container to keep MCP cron/tool
# execution representative instead of failing on nested sandbox
# setup.
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_USE_CI_SAFE_CODEX_CONFIG=1" >> "$GITHUB_ENV"
;;
live-codex-harness-docker)
# Keep CI on the API-key path for now. The staged Codex auth secret
@@ -2219,7 +2204,7 @@ jobs:
name: Docker live suites (${{ matrix.label }})
needs: [validate_selected_ref, prepare_live_test_image]
if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'live-'))
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
@@ -2291,6 +2276,12 @@ jobs:
timeout_minutes: 40
profile_env_only: false
profiles: stable full
- suite_id: live-subagent-announce-docker
label: Docker live subagent announce
command: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 20m bash .release-harness/scripts/test-live-subagent-announce-docker.sh
timeout_minutes: 25
profile_env_only: false
profiles: stable full
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
@@ -2388,14 +2379,11 @@ jobs:
fi
case "${{ matrix.suite_id }}" in
live-cli-backend-docker)
echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=codex-cli/gpt-5.4" >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=claude-cli/claude-sonnet-4-6" >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key" >> "$GITHUB_ENV"
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
echo "OPENCLAW_LIVE_CLI_BACKEND_USE_CI_SAFE_CODEX_CONFIG=1" >> "$GITHUB_ENV"
;;
live-codex-harness-docker)
echo "OPENCLAW_LIVE_CODEX_HARNESS_AUTH=api-key" >> "$GITHUB_ENV"
@@ -2435,7 +2423,7 @@ jobs:
name: Live media suites (${{ matrix.label }})
needs: validate_selected_ref
if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'native-live-extensions-media') || inputs.live_suite_filter == 'native-live-extensions-a-k')
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_call' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
container:
image: ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04
credentials:

View File

@@ -16,6 +16,10 @@ on:
description: Existing successful preflight workflow run id to promote without rebuilding
required: false
type: string
full_release_validation_run_id:
description: Successful Full Release Validation run id for this tag/SHA, required for real publish
required: false
type: string
npm_dist_tag:
description: npm dist-tag to publish to
required: true
@@ -169,12 +173,27 @@ jobs:
- name: Verify release contents
run: pnpm release:check
- name: Generate dependency release evidence
id: dependency_evidence
env:
RELEASE_REF: ${{ inputs.tag }}
RELEASE_NPM_DIST_TAG: ${{ inputs.npm_dist_tag }}
run: |
set -euo pipefail
node scripts/generate-dependency-release-evidence.mjs \
--release-ref "$RELEASE_REF" \
--npm-dist-tag "$RELEASE_NPM_DIST_TAG" \
--output-dir "$RUNNER_TEMP/openclaw-release-dependency-evidence" \
--github-output "$GITHUB_OUTPUT" \
--github-step-summary "$GITHUB_STEP_SUMMARY"
- name: Pack prepared npm tarball
id: packed_tarball
env:
OPENCLAW_PREPACK_PREPARED: "1"
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_NPM_DIST_TAG: ${{ inputs.npm_dist_tag }}
DEPENDENCY_EVIDENCE_DIR: ${{ steps.dependency_evidence.outputs.dir }}
run: |
set -euo pipefail
PACK_OUTPUT="$RUNNER_TEMP/npm-pack-output.txt"
@@ -246,6 +265,7 @@ jobs:
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
cp "$PACK_PATH" "$ARTIFACT_DIR/"
cp -R "$DEPENDENCY_EVIDENCE_DIR" "$ARTIFACT_DIR/dependency-evidence"
printf '%s\n' "$RELEASE_TAG" > "$ARTIFACT_DIR/release-tag.txt"
printf '%s\n' "$RELEASE_SHA" > "$ARTIFACT_DIR/release-sha.txt"
printf '%s\n' "$RELEASE_NPM_DIST_TAG" > "$ARTIFACT_DIR/release-npm-dist-tag.txt"
@@ -261,6 +281,8 @@ jobs:
packageVersion: process.env.PACKAGE_VERSION,
tarballName: process.env.TARBALL_NAME,
tarballSha256: process.env.TARBALL_SHA256,
dependencyEvidenceDir: "dependency-evidence",
dependencyEvidenceManifest: "dependency-evidence/dependency-evidence-manifest.json",
};
fs.writeFileSync(
path.join(process.env.ARTIFACT_DIR, "preflight-manifest.json"),
@@ -269,6 +291,27 @@ jobs:
NODE
echo "dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT"
- name: Verify prepared npm tarball install
env:
PREFLIGHT_ARTIFACT_DIR: ${{ steps.packed_tarball.outputs.dir }}
run: |
set -euo pipefail
TARBALL_PATH="$(find "$PREFLIGHT_ARTIFACT_DIR" -maxdepth 1 -type f -name '*.tgz' -print | sort | tail -n 1)"
if [[ -z "$TARBALL_PATH" ]]; then
echo "Prepared preflight tarball not found." >&2
ls -la "$PREFLIGHT_ARTIFACT_DIR" >&2 || true
exit 1
fi
PACKAGE_VERSION="$(node -p "require('./package.json').version")"
node --import tsx scripts/openclaw-npm-prepublish-verify.ts "$TARBALL_PATH" "$PACKAGE_VERSION"
- name: Upload dependency release evidence
uses: actions/upload-artifact@v7
with:
name: openclaw-release-dependency-evidence-${{ inputs.tag }}
path: ${{ steps.dependency_evidence.outputs.dir }}
if-no-files-found: error
- name: Upload prepared npm publish bundle
uses: actions/upload-artifact@v7
with:
@@ -295,12 +338,17 @@ jobs:
- name: Require preflight artifact promotion on real publish
env:
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
run: |
set -euo pipefail
if [[ -z "${PREFLIGHT_RUN_ID}" ]]; then
echo "Real publish requires preflight_run_id from a successful npm preflight run." >&2
exit 1
fi
if [[ -z "${FULL_RELEASE_VALIDATION_RUN_ID}" ]]; then
echo "Real publish requires full_release_validation_run_id from a successful Full Release Validation run." >&2
exit 1
fi
publish_openclaw_npm:
# KEEP THE REAL RELEASE/PUBLISH PATH ON A GITHUB-HOSTED RUNNER.
@@ -368,6 +416,16 @@ jobs:
RUN_JSON="$(gh run view "$PREFLIGHT_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw NPM Release"], ["headBranch", process.env.EXPECTED_PREFLIGHT_BRANCH], ["event", "workflow_dispatch"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced npm preflight run ${process.env.PREFLIGHT_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using npm preflight run ${process.env.PREFLIGHT_RUN_ID}: ${run.url}`);'
- name: Verify full release validation run metadata
env:
GH_TOKEN: ${{ github.token }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
EXPECTED_WORKFLOW_BRANCH: ${{ github.ref_name }}
run: |
set -euo pipefail
RUN_JSON="$(gh run view "$FULL_RELEASE_VALIDATION_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "Full Release Validation"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"], ["status", "completed"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID}: ${run.url}`);'
- name: Download prepared npm tarball
uses: actions/download-artifact@v8
with:
@@ -377,6 +435,15 @@ jobs:
run-id: ${{ inputs.preflight_run_id }}
github-token: ${{ github.token }}
- name: Download full release validation manifest
uses: actions/download-artifact@v8
with:
name: full-release-validation-${{ inputs.full_release_validation_run_id }}
path: full-release-validation
repository: ${{ github.repository }}
run-id: ${{ inputs.full_release_validation_run_id }}
github-token: ${{ github.token }}
- name: Validate release tag and package metadata
if: ${{ inputs.preflight_run_id == '' }}
env:
@@ -433,6 +500,32 @@ jobs:
exit 1
fi
- name: Verify full release validation target
run: |
set -euo pipefail
EXPECTED_RELEASE_SHA="$(git rev-parse HEAD)"
MANIFEST_FILE="full-release-validation/full-release-validation-manifest.json"
if [[ ! -f "$MANIFEST_FILE" ]]; then
echo "Full release validation manifest is missing." >&2
ls -la full-release-validation >&2 || true
exit 1
fi
WORKFLOW_NAME="$(jq -r '.workflowName // ""' "$MANIFEST_FILE")"
TARGET_SHA="$(jq -r '.targetSha // ""' "$MANIFEST_FILE")"
RERUN_GROUP="$(jq -r '.rerunGroup // ""' "$MANIFEST_FILE")"
if [[ "$WORKFLOW_NAME" != "Full Release Validation" ]]; then
echo "Full release validation manifest workflow mismatch: $WORKFLOW_NAME" >&2
exit 1
fi
if [[ "$TARGET_SHA" != "$EXPECTED_RELEASE_SHA" ]]; then
echo "Full release validation target SHA mismatch: expected $EXPECTED_RELEASE_SHA, got $TARGET_SHA" >&2
exit 1
fi
if [[ "$RERUN_GROUP" != "all" ]]; then
echo "Full release validation must run rerun_group=all before npm publish; got $RERUN_GROUP" >&2
exit 1
fi
- name: Resolve publish tarball
id: publish_tarball
run: |

View File

@@ -489,9 +489,7 @@ jobs:
reports_root=".artifacts/clawgrit-reports"
mkdir -p "$reports_root"
git -C "$reports_root" init -b main
git -C "$reports_root" remote add origin https://github.com/openclaw/clawgrit-reports.git
auth_header="$(printf 'x-access-token:%s' "$CLAWGRIT_REPORTS_TOKEN" | base64 -w0)"
git -C "$reports_root" config http.https://github.com/.extraheader "AUTHORIZATION: basic ${auth_header}"
git -C "$reports_root" remote add origin "https://x-access-token:${CLAWGRIT_REPORTS_TOKEN}@github.com/openclaw/clawgrit-reports.git"
if git -C "$reports_root" ls-remote --exit-code --heads origin main >/dev/null 2>&1; then
git -C "$reports_root" fetch --depth=1 origin main
git -C "$reports_root" checkout -B main FETCH_HEAD
@@ -501,10 +499,13 @@ jobs:
- name: Publish to clawgrit reports
if: ${{ steps.kova.outputs.report_json != '' && steps.clawgrit.outputs.present == 'true' }}
env:
CLAWGRIT_REPORTS_TOKEN: ${{ secrets.CLAWGRIT_REPORTS_TOKEN }}
shell: bash
run: |
set -euo pipefail
reports_root=".artifacts/clawgrit-reports"
git -C "$reports_root" remote set-url origin "https://x-access-token:${CLAWGRIT_REPORTS_TOKEN}@github.com/openclaw/clawgrit-reports.git"
ref_slug="$(printf '%s' "${TESTED_REF}" | tr -c 'A-Za-z0-9._-' '-')"
run_slug="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
dest="${reports_root}/openclaw-performance/${ref_slug}/${run_slug}/${LANE_ID}"

View File

@@ -516,6 +516,9 @@ jobs:
candidate_version: ${{ needs.prepare_release_package.outputs.package_version }}
candidate_source_sha: ${{ needs.prepare_release_package.outputs.source_sha }}
openai_model: openai/gpt-5.4
ubuntu_runner: ubuntu-24.04
windows_runner: windows-2025
macos_runner: macos-26
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -626,7 +629,7 @@ jobs:
artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
package_sha256: ${{ (needs.resolve_target.outputs.package_acceptance_package_spec == '' && needs.resolve_target.outputs.release_package_spec == '') && needs.prepare_release_package.outputs.package_sha256 || '' }}
suite_profile: custom
docker_lanes: doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor update-restart-auth plugins-offline plugin-update
docker_lanes: doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update
published_upgrade_survivor_baselines: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'last-stable-4 2026.4.23 2026.5.2 2026.4.15' || '' }}
published_upgrade_survivor_scenarios: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'reported-issues' || '' }}
telegram_mode: mock-openai
@@ -685,7 +688,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
@@ -772,7 +775,7 @@ jobs:
needs: [resolve_target, qa_lab_parity_lane_release_checks]
if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
@@ -831,7 +834,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_matrix_enabled == 'true'
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
@@ -911,7 +914,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_telegram_enabled == 'true'
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
@@ -1007,7 +1010,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_discord_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_DISCORD_LIVE_CI_ENABLED == 'true'
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
@@ -1103,7 +1106,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_whatsapp_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_WHATSAPP_LIVE_CI_ENABLED == 'true'
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
@@ -1199,7 +1202,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_slack_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_SLACK_LIVE_CI_ENABLED == 'true'
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read

View File

@@ -11,6 +11,10 @@ on:
description: Successful OpenClaw NPM Release preflight run id, required when publish_openclaw_npm=true
required: false
type: string
full_release_validation_run_id:
description: Successful Full Release Validation run id for this tag/SHA, required when publish_openclaw_npm=true
required: false
type: string
npm_dist_tag:
description: npm dist-tag for the OpenClaw package
required: true
@@ -77,6 +81,7 @@ jobs:
env:
RELEASE_TAG: ${{ inputs.tag }}
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
PUBLISH_OPENCLAW_NPM: ${{ inputs.publish_openclaw_npm && 'true' || 'false' }}
PLUGIN_PUBLISH_SCOPE: ${{ inputs.plugin_publish_scope }}
PLUGINS: ${{ inputs.plugins }}
@@ -101,6 +106,10 @@ jobs:
echo "publish_openclaw_npm=true requires preflight_run_id." >&2
exit 1
fi
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" && -z "${FULL_RELEASE_VALIDATION_RUN_ID}" ]]; then
echo "publish_openclaw_npm=true requires full_release_validation_run_id." >&2
exit 1
fi
if [[ "${PUBLISH_OPENCLAW_NPM}" == "true" && "${WORKFLOW_REF}" != "refs/heads/main" && ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]]; then
echo "publish_openclaw_npm=true requires dispatching this workflow from main or release/YYYY.M.D." >&2
exit 1
@@ -131,6 +140,16 @@ jobs:
run-id: ${{ inputs.preflight_run_id }}
github-token: ${{ github.token }}
- name: Download full release validation manifest
if: ${{ inputs.publish_openclaw_npm }}
uses: actions/download-artifact@v8
with:
name: full-release-validation-${{ inputs.full_release_validation_run_id }}
path: ${{ runner.temp }}/full-release-validation-manifest
repository: ${{ github.repository }}
run-id: ${{ inputs.full_release_validation_run_id }}
github-token: ${{ github.token }}
- name: Checkout release tag
uses: actions/checkout@v6
with:
@@ -186,6 +205,46 @@ jobs:
fi
echo "sha=$release_sha" >> "$GITHUB_OUTPUT"
- name: Validate full release validation manifest
if: ${{ inputs.publish_openclaw_npm }}
env:
GH_TOKEN: ${{ github.token }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
EXPECTED_SHA: ${{ steps.ref.outputs.sha }}
EXPECTED_RELEASE_PROFILE: ${{ inputs.release_profile }}
EXPECTED_WORKFLOW_BRANCH: ${{ github.ref_name }}
run: |
set -euo pipefail
RUN_JSON="$(gh run view "$FULL_RELEASE_VALIDATION_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "Full Release Validation"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"], ["status", "completed"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using full release validation run ${process.env.FULL_RELEASE_VALIDATION_RUN_ID}: ${run.url}`);'
manifest="${RUNNER_TEMP}/full-release-validation-manifest/full-release-validation-manifest.json"
if [[ ! -f "$manifest" ]]; then
echo "Full release validation manifest is missing." >&2
ls -la "${RUNNER_TEMP}/full-release-validation-manifest" >&2 || true
exit 1
fi
workflow_name="$(jq -r '.workflowName // ""' "$manifest")"
target_sha="$(jq -r '.targetSha // ""' "$manifest")"
release_profile="$(jq -r '.releaseProfile // ""' "$manifest")"
rerun_group="$(jq -r '.rerunGroup // ""' "$manifest")"
if [[ "$workflow_name" != "Full Release Validation" ]]; then
echo "Full release validation manifest workflow mismatch: $workflow_name" >&2
exit 1
fi
if [[ "$target_sha" != "$EXPECTED_SHA" ]]; then
echo "Full release validation target SHA mismatch: expected $EXPECTED_SHA, got $target_sha" >&2
exit 1
fi
if [[ "$release_profile" != "$EXPECTED_RELEASE_PROFILE" ]]; then
echo "Full release validation profile mismatch: expected $EXPECTED_RELEASE_PROFILE, got $release_profile" >&2
exit 1
fi
if [[ "$rerun_group" != "all" ]]; then
echo "Full release validation must run rerun_group=all before npm publish; got $rerun_group" >&2
exit 1
fi
- name: Validate release tag is reachable from main or release branch
run: |
set -euo pipefail
@@ -208,6 +267,7 @@ jobs:
RELEASE_TAG: ${{ inputs.tag }}
TARGET_SHA: ${{ steps.manifest.outputs.sha || steps.ref.outputs.sha }}
RELEASE_PROFILE: ${{ inputs.release_profile }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
run: |
{
echo "### Release target"
@@ -215,6 +275,9 @@ jobs:
echo "- Tag: \`${RELEASE_TAG}\`"
echo "- SHA: \`${TARGET_SHA}\`"
echo "- Release profile: \`${RELEASE_PROFILE}\`"
if [[ -n "${FULL_RELEASE_VALIDATION_RUN_ID// }" ]]; then
echo "- Full release validation: \`${FULL_RELEASE_VALIDATION_RUN_ID}\`"
fi
} >> "$GITHUB_STEP_SUMMARY"
publish:
@@ -237,6 +300,7 @@ jobs:
CHILD_WORKFLOW_REF: ${{ github.ref_name }}
RELEASE_TAG: ${{ inputs.tag }}
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
FULL_RELEASE_VALIDATION_RUN_ID: ${{ inputs.full_release_validation_run_id }}
RELEASE_NPM_DIST_TAG: ${{ inputs.npm_dist_tag }}
PLUGIN_PUBLISH_SCOPE: ${{ inputs.plugin_publish_scope }}
PLUGINS: ${{ inputs.plugins }}
@@ -288,7 +352,7 @@ jobs:
wait_for_run() {
local workflow="$1"
local run_id="$2"
local status conclusion url updated_at last_state
local status conclusion url updated_at created_at duration_seconds duration_label last_state
last_state=""
while true; do
@@ -307,11 +371,26 @@ jobs:
sleep 30
done
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')"
echo "${workflow} finished with ${conclusion}: ${url}"
run_json="$(gh run view --repo "$GITHUB_REPOSITORY" "$run_id" --json conclusion,url,createdAt,updatedAt)"
conclusion="$(printf '%s' "$run_json" | jq -r '.conclusion')"
url="$(printf '%s' "$run_json" | jq -r '.url')"
created_at="$(printf '%s' "$run_json" | jq -r '.createdAt')"
updated_at="$(printf '%s' "$run_json" | jq -r '.updatedAt')"
duration_seconds="$(
CREATED_AT="${created_at}" UPDATED_AT="${updated_at}" node --input-type=module -e '
const created = Date.parse(process.env.CREATED_AT ?? "");
const updated = Date.parse(process.env.UPDATED_AT ?? "");
console.log(Number.isFinite(created) && Number.isFinite(updated) ? Math.max(0, Math.round((updated - created) / 1000)) : "");
'
)"
if [[ -n "${duration_seconds}" ]]; then
duration_label="$((duration_seconds / 60))m$(printf '%02d' $((duration_seconds % 60)))s"
else
duration_label="unknown duration"
fi
echo "${workflow} finished with ${conclusion} in ${duration_label}: ${url}"
{
echo "- ${workflow}: ${conclusion} (${url})"
echo "- ${workflow}: ${conclusion} in ${duration_label} (${url})"
} >> "$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
@@ -386,6 +465,33 @@ jobs:
echo "- GitHub release: https://github.com/${GITHUB_REPOSITORY}/releases/tag/${RELEASE_TAG}" >> "$GITHUB_STEP_SUMMARY"
}
upload_dependency_evidence_release_asset() {
local release_version download_dir asset_path asset_name
release_version="${RELEASE_TAG#v}"
download_dir="${RUNNER_TEMP}/openclaw-release-dependency-evidence-asset"
asset_name="openclaw-${release_version}-dependency-evidence.zip"
asset_path="${RUNNER_TEMP}/${asset_name}"
rm -rf "${download_dir}" "${asset_path}"
mkdir -p "${download_dir}"
gh run download "${PREFLIGHT_RUN_ID}" \
--repo "${GITHUB_REPOSITORY}" \
--name "openclaw-npm-preflight-${RELEASE_TAG}" \
--dir "${download_dir}"
if [[ ! -d "${download_dir}/dependency-evidence" ]]; then
echo "Dependency evidence is missing from OpenClaw npm preflight artifact." >&2
find "${download_dir}" -maxdepth 2 -type f -print >&2 || true
exit 1
fi
(cd "${download_dir}" && zip -qr "${asset_path}" dependency-evidence)
gh release upload "${RELEASE_TAG}" "${asset_path}#${asset_name}" \
--repo "${GITHUB_REPOSITORY}" \
--clobber
echo "- Dependency evidence asset: \`${asset_name}\`" >> "$GITHUB_STEP_SUMMARY"
}
{
echo "### Publish sequence"
echo
@@ -414,6 +520,10 @@ jobs:
plugin_npm_run_id="$(dispatch_workflow plugin-npm-release.yml "${npm_args[@]}")"
plugin_clawhub_run_id="$(dispatch_workflow plugin-clawhub-release.yml "${clawhub_args[@]}")"
{
echo "- Plugin npm run ID: \`${plugin_npm_run_id}\`"
echo "- Plugin ClawHub run ID: \`${plugin_clawhub_run_id}\`"
} >> "$GITHUB_STEP_SUMMARY"
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
@@ -427,7 +537,9 @@ jobs:
-f tag="${RELEASE_TAG}" \
-f preflight_only=false \
-f preflight_run_id="${PREFLIGHT_RUN_ID}" \
-f full_release_validation_run_id="${FULL_RELEASE_VALIDATION_RUN_ID}" \
-f npm_dist_tag="${RELEASE_NPM_DIST_TAG}")"
echo "- OpenClaw npm run ID: \`${openclaw_npm_run_id}\`" >> "$GITHUB_STEP_SUMMARY"
else
echo "- OpenClaw npm publish: skipped by input" >> "$GITHUB_STEP_SUMMARY"
fi
@@ -471,4 +583,5 @@ jobs:
if [[ -n "${openclaw_npm_run_id}" ]]; then
create_or_update_github_release
upload_dependency_evidence_release_asset
fi

View File

@@ -6,6 +6,7 @@ on:
workflow_dispatch:
permissions:
actions: read
contents: read
packages: write
pull-requests: read
@@ -20,6 +21,7 @@ env:
jobs:
live_and_openwebui_checks:
permissions:
actions: read
contents: read
packages: write
pull-requests: read

View File

@@ -284,7 +284,7 @@ env:
jobs:
resolve_package:
name: Resolve package candidate
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
outputs:
docker_lanes: ${{ steps.profile.outputs.docker_lanes }}
@@ -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 skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor update-restart-auth plugins-offline plugin-update"
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update"
;;
product)
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor update-restart-auth plugins plugin-update mcp-channels cron-mcp-cleanup openai-web-search-minimal openwebui"
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins plugin-update mcp-channels cron-mcp-cleanup openai-web-search-minimal openwebui"
include_openwebui=true
;;
full)
@@ -588,7 +588,7 @@ jobs:
name: Verify package acceptance
needs: [resolve_package, docker_acceptance, package_telegram]
if: always()
runs-on: blacksmith-4vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Verify package acceptance results

View File

@@ -228,7 +228,20 @@ jobs:
- name: Install ClawHub CLI dependencies
working-directory: clawhub-source
run: bun install --frozen-lockfile
run: |
set -euo pipefail
for attempt in 1 2 3; do
if bun install --frozen-lockfile; then
exit 0
fi
status="$?"
if [[ "${attempt}" == "3" ]]; then
exit "${status}"
fi
echo "bun install failed while preparing ClawHub CLI; retrying (${attempt}/3)."
rm -rf node_modules "${RUNNER_TEMP}/bun-install-cache" || true
sleep $((attempt * 15))
done
- name: Bootstrap ClawHub CLI
run: |
@@ -263,7 +276,7 @@ jobs:
id-token: write
strategy:
fail-fast: false
max-parallel: 12
max-parallel: 32
matrix:
plugin: ${{ fromJson(needs.preview_plugins_clawhub.outputs.matrix) }}
steps:
@@ -309,7 +322,20 @@ jobs:
- name: Install ClawHub CLI dependencies
working-directory: clawhub-source
run: bun install --frozen-lockfile
run: |
set -euo pipefail
for attempt in 1 2 3; do
if bun install --frozen-lockfile; then
exit 0
fi
status="$?"
if [[ "${attempt}" == "3" ]]; then
exit "${status}"
fi
echo "bun install failed while preparing ClawHub CLI; retrying (${attempt}/3)."
rm -rf node_modules "${RUNNER_TEMP}/bun-install-cache" || true
sleep $((attempt * 15))
done
- name: Bootstrap ClawHub CLI
run: |
@@ -392,3 +418,66 @@ jobs:
PACKAGE_TAG: ${{ matrix.plugin.publishTag }}
PACKAGE_DIR: ${{ matrix.plugin.packageDir }}
run: bash scripts/plugin-clawhub-publish.sh --publish "${PACKAGE_DIR}"
- name: Verify published ClawHub package
env:
CLAWHUB_REGISTRY: ${{ env.CLAWHUB_REGISTRY }}
PACKAGE_NAME: ${{ matrix.plugin.packageName }}
PACKAGE_VERSION: ${{ matrix.plugin.version }}
PACKAGE_TAG: ${{ matrix.plugin.publishTag }}
run: |
set -euo pipefail
node --input-type=module <<'EOF'
const registry = (process.env.CLAWHUB_REGISTRY ?? "https://clawhub.ai").replace(/\/+$/, "");
const packageName = process.env.PACKAGE_NAME;
const packageVersion = process.env.PACKAGE_VERSION;
const packageTag = process.env.PACKAGE_TAG;
if (!packageName || !packageVersion || !packageTag) {
throw new Error("Missing ClawHub package verification env.");
}
const encodedName = encodeURIComponent(packageName);
const encodedVersion = encodeURIComponent(packageVersion);
const detailUrl = `${registry}/api/v1/packages/${encodedName}`;
const versionUrl = `${detailUrl}/versions/${encodedVersion}`;
const artifactUrl = `${versionUrl}/artifact/download`;
async function fetchWithRetry(url, options = {}) {
let lastStatus = "unknown";
for (let attempt = 1; attempt <= 12; attempt += 1) {
try {
const response = await fetch(url, { redirect: "manual", ...options });
lastStatus = response.status;
if (response.status !== 429 && response.status < 500) {
return response;
}
} catch (error) {
lastStatus = error instanceof Error ? error.message : String(error);
}
await new Promise((resolve) => setTimeout(resolve, attempt * 5000));
}
throw new Error(`${url} did not stabilize; last status ${lastStatus}.`);
}
const detailResponse = await fetchWithRetry(detailUrl, {
headers: { accept: "application/json" },
});
if (!detailResponse.ok) {
throw new Error(`${detailUrl} returned HTTP ${detailResponse.status}.`);
}
const detail = await detailResponse.json();
const tags = detail?.package?.tags ?? {};
if (tags[packageTag] !== packageVersion) {
throw new Error(
`${packageName}: ClawHub tag ${packageTag} points to ${tags[packageTag] ?? "<missing>"}, expected ${packageVersion}.`,
);
}
const versionResponse = await fetchWithRetry(versionUrl);
if (!versionResponse.ok) {
throw new Error(`${versionUrl} returned HTTP ${versionResponse.status}.`);
}
const artifactResponse = await fetchWithRetry(artifactUrl, { method: "HEAD" });
if (artifactResponse.status < 200 || artifactResponse.status >= 400) {
throw new Error(`${artifactUrl} returned HTTP ${artifactResponse.status}.`);
}
console.log(`${packageName}@${packageVersion} verified on ClawHub.`);
EOF

View File

@@ -209,7 +209,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_static == 'true'
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 45
strategy:
fail-fast: false
@@ -245,7 +245,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_node == 'true'
runs-on: ${{ matrix.runner || 'ubuntu-24.04' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (matrix.runner || 'ubuntu-24.04') }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -318,7 +318,7 @@ jobs:
name: ${{ matrix.check_name }}
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_extensions == 'true'
runs-on: ${{ matrix.runner }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || matrix.runner }}
timeout-minutes: 60
strategy:
fail-fast: false
@@ -346,6 +346,185 @@ jobs:
OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }}
run: pnpm test:extensions:batch -- "$OPENCLAW_EXTENSION_BATCH"
plugin-prerelease-inspector:
permissions:
contents: read
name: plugin-prerelease-inspector
needs: [preflight]
if: needs.preflight.outputs.run_plugin_prerelease_suite == 'true'
continue-on-error: true
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ needs.preflight.outputs.checkout_revision }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Run plugin inspector advisory sweep
env:
OPENCLAW_PLUGIN_INSPECTOR_VERSION: "0.3.10"
OPENCLAW_PLUGIN_INSPECTOR_ROOT: .artifacts/plugin-inspector
shell: bash
run: |
set -euo pipefail
mkdir -p "$OPENCLAW_PLUGIN_INSPECTOR_ROOT"
set +e
node --input-type=module <<'EOF'
import { existsSync } from "node:fs";
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
const artifactRoot = process.env.OPENCLAW_PLUGIN_INSPECTOR_ROOT;
if (!artifactRoot) {
throw new Error("OPENCLAW_PLUGIN_INSPECTOR_ROOT is required");
}
const readJson = async (filePath) => JSON.parse(await readFile(filePath, "utf8"));
const inferSeams = (pluginManifest, packageJson) => {
const contracts = Object.keys(pluginManifest?.contracts ?? {});
if (contracts.includes("tools")) {
return ["dynamic-tool"];
}
const openclawPackage = packageJson?.openclaw ?? {};
if (openclawPackage.extensions || openclawPackage.runtimeExtensions) {
return ["plugin-runtime"];
}
return ["plugin-metadata"];
};
const extensionRoot = path.resolve("extensions");
const fixtures = [];
for (const entry of await readdir(extensionRoot, { withFileTypes: true })) {
if (!entry.isDirectory()) {
continue;
}
const relativePath = `extensions/${entry.name}`;
const packagePath = path.join(extensionRoot, entry.name, "package.json");
const manifestPath = path.join(extensionRoot, entry.name, "openclaw.plugin.json");
if (!existsSync(packagePath) || !existsSync(manifestPath)) {
continue;
}
const packageJson = await readJson(packagePath);
const pluginManifest = await readJson(manifestPath);
fixtures.push({
id: entry.name,
name: pluginManifest.name ?? packageJson.name ?? entry.name,
path: relativePath,
priority: "high",
repo: "local",
seams: inferSeams(pluginManifest, packageJson),
why: "bundled OpenClaw plugin prerelease advisory fixture",
});
}
fixtures.sort((left, right) => left.id.localeCompare(right.id));
if (fixtures.length === 0) {
throw new Error("No bundled plugin fixtures found under extensions/");
}
await mkdir(artifactRoot, { recursive: true });
const config = `${JSON.stringify(
{
version: 1,
submoduleRoot: ".",
openclaw: {
defaultCheckoutPath: ".",
},
fixtures,
},
null,
2,
)}\n`;
await writeFile("plugin-inspector.config.json", config, "utf8");
await writeFile(path.join(artifactRoot, "plugin-inspector.config.json"), config, "utf8");
EOF
config_status=$?
set -e
echo "$config_status" > "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/config-exit-code.txt"
if [ "$config_status" -eq 0 ]; then
set +e
npm exec --yes "@openclaw/plugin-inspector@${OPENCLAW_PLUGIN_INSPECTOR_VERSION}" -- ci \
--config plugin-inspector.config.json \
--openclaw "$PWD" \
--out "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/reports" \
--json \
> "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/plugin-inspector-stdout.json" \
2> "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/plugin-inspector-stderr.log"
inspector_status=$?
set -e
else
inspector_status=127
echo "Skipped plugin-inspector because config generation failed." \
> "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/plugin-inspector-stderr.log"
fi
echo "$inspector_status" > "$OPENCLAW_PLUGIN_INSPECTOR_ROOT/exit-code.txt"
node --input-type=module <<'EOF'
import { existsSync } from "node:fs";
import { appendFile, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
const artifactRoot = process.env.OPENCLAW_PLUGIN_INSPECTOR_ROOT;
const summaryPath = path.join(artifactRoot, "reports/plugin-inspector-ci-summary.json");
const markdownPath = path.join(artifactRoot, "reports/plugin-inspector-ci-summary.md");
const configExitCode = (await readFile(path.join(artifactRoot, "config-exit-code.txt"), "utf8")).trim();
const exitCode = (await readFile(path.join(artifactRoot, "exit-code.txt"), "utf8")).trim();
const lines = [
"## Plugin Inspector Advisory",
"",
`Inspector: @openclaw/plugin-inspector@${process.env.OPENCLAW_PLUGIN_INSPECTOR_VERSION}`,
`Config exit code: ${configExitCode}`,
`Exit code: ${exitCode}`,
];
if (existsSync(summaryPath)) {
const summary = JSON.parse(await readFile(summaryPath, "utf8"));
lines.push(
`Status: ${String(summary.status ?? "unknown").toUpperCase()}`,
"",
"| Metric | Count |",
"| --- | ---: |",
`| Hard breakages | ${summary.summary?.breakages ?? 0} |`,
`| Issues | ${summary.summary?.issues ?? 0} |`,
`| P0 issues | ${summary.summary?.p0Issues ?? 0} |`,
`| P1 issues | ${summary.summary?.p1Issues ?? 0} |`,
`| Compat gaps | ${summary.summary?.compatGaps ?? 0} |`,
`| Inspector gaps | ${summary.summary?.inspectorGaps ?? 0} |`,
"",
"This job is informational; Plugin Prerelease blocking status is unchanged.",
);
await writeFile(path.join(artifactRoot, "advisory-summary.md"), `${lines.join("\n")}\n`, "utf8");
if (existsSync(markdownPath)) {
lines.push("", "### Full inspector summary", "");
lines.push(await readFile(markdownPath, "utf8"));
}
} else {
lines.push("", "No plugin-inspector CI summary was produced.", "");
lines.push("This job is informational; inspect the uploaded stdout/stderr artifacts.");
await writeFile(path.join(artifactRoot, "advisory-summary.md"), `${lines.join("\n")}\n`, "utf8");
}
await appendFile(process.env.GITHUB_STEP_SUMMARY, `${lines.join("\n")}\n`, "utf8");
EOF
- name: Upload plugin inspector advisory artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: plugin-inspector-advisory
path: .artifacts/plugin-inspector/**
if-no-files-found: warn
plugin-prerelease-docker-suite:
name: plugin-prerelease-docker-suite
needs: [preflight]
@@ -375,6 +554,7 @@ jobs:
- plugin-prerelease-static-shard
- plugin-prerelease-node-shard
- plugin-prerelease-extension-shard
- plugin-prerelease-inspector
- plugin-prerelease-docker-suite
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_plugin_prerelease_suite == 'true' }}
runs-on: ubuntu-24.04
@@ -389,6 +569,7 @@ jobs:
STATIC_RESULT: ${{ needs.plugin-prerelease-static-shard.result }}
NODE_RESULT: ${{ needs.plugin-prerelease-node-shard.result }}
EXTENSIONS_RESULT: ${{ needs.plugin-prerelease-extension-shard.result }}
INSPECTOR_RESULT: ${{ needs.plugin-prerelease-inspector.result }}
DOCKER_RESULT: ${{ needs.plugin-prerelease-docker-suite.result }}
shell: bash
run: |
@@ -411,4 +592,5 @@ jobs:
check_required "plugin-prerelease-node" "$RUN_NODE" "$NODE_RESULT"
check_required "plugin-prerelease-extensions" "$RUN_EXTENSIONS" "$EXTENSIONS_RESULT"
check_required "plugin-prerelease-docker" "$RUN_DOCKER" "$DOCKER_RESULT"
echo "plugin-prerelease-inspector advisory result: ${INSPECTOR_RESULT}"
exit "$failed"

View File

@@ -134,20 +134,29 @@ jobs:
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_dispatch' && inputs.sync_website)
runs-on: ubuntu-24.04
env:
OPENCLAW_GH_TOKEN: ${{ secrets.OPENCLAW_GH_TOKEN }}
steps:
- name: Skip website sync without token
if: env.OPENCLAW_GH_TOKEN == ''
run: echo "OPENCLAW_GH_TOKEN is not configured; installer verification passed, skipping website sync."
- name: Checkout OpenClaw
if: env.OPENCLAW_GH_TOKEN != ''
uses: actions/checkout@v6
with:
path: openclaw
- name: Checkout openclaw.ai
if: env.OPENCLAW_GH_TOKEN != ''
uses: actions/checkout@v6
with:
repository: openclaw/openclaw.ai
token: ${{ secrets.OPENCLAW_GH_TOKEN }}
token: ${{ env.OPENCLAW_GH_TOKEN }}
path: openclaw.ai
- name: Sync installer scripts
if: env.OPENCLAW_GH_TOKEN != ''
run: |
cp openclaw/scripts/install.sh openclaw.ai/public/install.sh
cp openclaw/scripts/install-cli.sh openclaw.ai/public/install-cli.sh
@@ -156,6 +165,7 @@ jobs:
chmod +x openclaw.ai/public/install.sh openclaw.ai/public/install-cli.sh
- name: Check for changes
if: env.OPENCLAW_GH_TOKEN != ''
id: changes
working-directory: openclaw.ai
run: |
@@ -196,7 +206,10 @@ jobs:
run: |
git config user.name "openclaw-installer-sync[bot]"
git config user.email "openclaw-installer-sync[bot]@users.noreply.github.com"
git add public/install.sh public/install-cli.sh public/install.ps1 public/install.cmd
git add public/install.sh public/install-cli.sh public/install.ps1
if git ls-files --error-unmatch public/install.cmd >/dev/null 2>&1; then
git add -u -- public/install.cmd
fi
git commit -m "chore: sync installers from openclaw ${GITHUB_SHA::12}"
git pull --rebase origin main
git push origin HEAD:main

15
.gitignore vendored
View File

@@ -41,6 +41,7 @@ apps/macos/.build/
apps/macos-mlx-tts/.build/
apps/shared/MoltbotKit/.build/
apps/shared/OpenClawKit/.build/
apps/shared/*/.build/
apps/shared/OpenClawKit/Package.resolved
**/ModuleCache/
bin/
@@ -50,6 +51,7 @@ apps/macos/.build-local/
apps/macos/.swiftpm/
apps/shared/MoltbotKit/.swiftpm/
apps/shared/OpenClawKit/.swiftpm/
apps/shared/*/.swiftpm/
Core/
apps/ios/*.xcodeproj/
apps/ios/*.xcworkspace/
@@ -108,6 +110,9 @@ USER.md
# local tooling
.serena/
# local QA evidence mirrors; CI publishes canonical Mantis files as Actions artifacts
mantis/
# Local project-agent skill installs. Only repo-owned skills are visible by
# default; promoting a new repo skill should require an intentional `git add -f`.
.agents/skills/*
@@ -115,17 +120,27 @@ USER.md
!.agents/skills/blacksmith-testbox/**
!.agents/skills/crabbox/
!.agents/skills/crabbox/**
!.agents/skills/clawdtributor/
!.agents/skills/clawdtributor/**
!.agents/skills/gitcrawl/
!.agents/skills/gitcrawl/**
!.agents/skills/openclaw-docs/**
!.agents/skills/openclaw-refactor-docs/
!.agents/skills/openclaw-refactor-docs/**
!.agents/skills/openclaw-debugging/
!.agents/skills/openclaw-debugging/**
!.agents/skills/openclaw-ghsa-maintainer/
!.agents/skills/openclaw-ghsa-maintainer/**
!.agents/skills/openclaw-parallels-smoke/
!.agents/skills/openclaw-parallels-smoke/**
!.agents/skills/openclaw-pr-maintainer/
!.agents/skills/openclaw-pr-maintainer/**
!.agents/skills/openclaw-refactor-docs/
!.agents/skills/openclaw-refactor-docs/**
!.agents/skills/openclaw-qa-testing/
!.agents/skills/openclaw-qa-testing/**
!.agents/skills/openclaw-release-ci/
!.agents/skills/openclaw-release-ci/**
!.agents/skills/openclaw-release-maintainer/
!.agents/skills/openclaw-release-maintainer/**
!.agents/skills/openclaw-secret-scanning-maintainer/

View File

@@ -10,12 +10,12 @@ Skills own workflows; root owns hard policy and routing.
- Docs/user-visible work: `pnpm docs:list`, then read relevant docs only.
- Fix/triage answers need source, tests, current/shipped behavior, and dependency contract proof.
- Dependency-backed behavior: read upstream docs/source/types first. No API/default/error/timing guesses.
- Live-verify when feasible. Check env/`~/.profile` for keys before saying blocked; never print secrets.
- Live-verify when feasible. Never print secrets.
- Missing deps: `pnpm install`, retry once, then report first actionable error.
- CODEOWNERS: maint/refactor/tests ok. Larger behavior/product/security/ownership: owner ask/review.
- Product/docs/UI/changelog wording: "plugin/plugins"; `extensions/` is internal.
- New channel/plugin/app/doc surface: update `.github/labeler.yml` + GH labels.
- New `AGENTS.md`: add sibling `CLAUDE.md` symlink.
- New `AGENTS.md`: add sibling `CLAUDE.md` symlink; edit `AGENTS.md` only.
## Map
@@ -31,11 +31,15 @@ Skills own workflows; root owns hard policy and routing.
- Core/tests: no deep plugin internals (`extensions/*/src/**`, `onboard.js`). Use public barrels, SDK facade, generic contracts.
- Owner boundary: owner-specific repair/detection/onboarding/auth/defaults/provider behavior lives in owner plugin. Shared/core gets generic seams only.
- Dependency ownership follows runtime ownership: plugin-only deps stay plugin-local; root deps only for core imports or intentionally internalized bundled plugin runtime.
- Internal bundled plugins ship in core dist; bundled-only facade loader ok only for them.
- External official plugins own package/deps and are excluded from core dist; core uses registry-aware `facade-runtime` or generic contracts.
- Externalizing a bundled plugin: update package excludes, official catalogs, docs, tests, and prove core runtime paths resolve installed plugin roots before root-dep removal.
- Legacy config repair belongs in `openclaw doctor --fix`, not startup/load-time core migrations. Runtime paths use canonical contracts.
- New seams: backward-compatible, documented, versioned. Third-party plugins exist.
- Channels are implementation under `src/channels/**`; plugin authors get SDK seams. Providers own auth/catalog/runtime hooks; core owns generic loop.
- Hot paths should carry prepared facts forward: provider id, model ref, channel id, target, capability family, attachment class. Do not rediscover with broad plugin/provider/channel/capability loaders.
- Do not fix repeated request-time discovery with scattered caches. Move the canonical fact earlier; reuse prepared runtime objects; delete duplicate lookup branches.
- Inline code comments: brief notes for tricky, bug-prone, or previously buggy logic.
- Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
- Config contract: exported types, schema/help, metadata, baselines, docs aligned. Retired public keys stay retired; compat in raw migration/doctor only.
- Prompt cache: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
@@ -45,9 +49,12 @@ Skills own workflows; root owns hard policy and routing.
- Runtime: Node 22+. Keep Node + Bun paths working.
- Package manager/runtime: repo defaults only. No swaps without approval.
- Install: `pnpm install` (keep Bun lock/patches aligned if touched).
- Sharp/Homebrew libvips source-build fail: `SHARP_IGNORE_GLOBAL_LIBVIPS=1 pnpm install`.
- CLI: `pnpm openclaw ...` or `pnpm dev`; build: `pnpm build`.
- Tests: `pnpm test <path-or-filter> [vitest args...]`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`; never raw `vitest`.
- Checks: `pnpm check:changed`; lanes: `pnpm changed:lanes --json`; staged: `pnpm check:changed --staged`; full: `pnpm check`.
- Tests in a normal source checkout: `pnpm test <path-or-filter> [vitest args...]`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`; never raw `vitest`.
- Tests in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm test*`; use `node scripts/run-vitest.mjs <path-or-filter>` for tiny explicit-file proof, or Crabbox/Testbox for anything broader.
- Checks in a normal source checkout: `pnpm check:changed`; lanes: `pnpm changed:lanes --json`; staged: `pnpm check:changed --staged`; full: `pnpm check`.
- Checks in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm check*`; use `node scripts/crabbox-wrapper.mjs run ... --shell -- "pnpm check:changed"` so pnpm runs inside Testbox, not locally.
- Extension tests: `pnpm test:extensions`, `pnpm test extensions`, `pnpm test extensions/<id>`.
- Typecheck: `tsgo` lanes only (`pnpm tsgo*`, `pnpm check:test-types`); never add `tsc --noEmit`, `typecheck`, `check:types`.
- Formatting: `oxfmt`, not Prettier. Use repo wrappers (`pnpm format:*`, `pnpm lint:*`, `scripts/run-oxlint.mjs`).
@@ -56,31 +63,38 @@ Skills own workflows; root owns hard policy and routing.
## Validation
- Use `$openclaw-testing` for test/CI choice and `$crabbox` for remote/full/E2E proof.
- Small/narrow tests, lints, format checks, and type probes are fine locally.
- Small/narrow tests, lints, format checks, and type probes are fine locally only in a healthy normal checkout.
- In Codex worktrees, direct local `pnpm test*`, `pnpm check*`, `pnpm crabbox:run`, and `scripts/committer` can trigger pnpm dependency reconciliation or install prompts. Prefer `node` wrappers locally and Crabbox/Testbox for pnpm-gated proof.
- Full suites, broad changed gates, Docker/package/E2E/live/cross-OS proof, or anything that bogs down the Mac: Crabbox/Testbox.
- One/few files local. If a local command fans out, stop and move broad proof to Crabbox/Testbox.
- Before handoff/push: prove touched surface. Before landing to `main`: issue proof plus appropriate full/broad proof unless scope is clearly narrow.
- Pre-land/pre-commit code changes: use `$codex-review` until no accepted/actionable findings remain, unless equivalent manual review already done, trivial/docs-only, or user opts out.
- If proof is blocked, say exactly what is missing and why.
- Do not land related failing format/lint/type/build/tests. If unrelated on latest `origin/main`, say so with scoped proof.
- Docs/changelog-only and CI/workflow metadata-only: `git diff --check` plus relevant docs/workflow sanity; escalate only if scripts/config/generated/package/runtime behavior changed.
## GitHub / PRs
- Use `$openclaw-pr-maintainer` immediately for OpenClaw issue/PR URLs/numbers, review, triage, duplicate search, close, labels, landing, comments, or maintainer evidence.
- PR refs: `gh pr view/diff`, not web search. Prefer `gitcrawl` for local candidate discovery; verify live with `gh` before mutation.
- Use `$openclaw-pr-maintainer` immediately for maintainer-side OpenClaw issue/PR review, triage, duplicates, labels, comments, close, land, or evidence. Contributor PR creation/refresh follows the requested contributor workflow; linked refs alone do not require maintainer archive tooling.
- PR refs: `gh pr view/diff` or `gh api`, not web search. Prefer `gitcrawl` for maintainer discovery; missing/stale `gitcrawl` falls through to live `gh`, not contributor setup. Verify live with `gh` before mutation.
- Bare issue/PR URL/number means review/report in chat. Suggest comment/close/merge when appropriate; mutate only when asked.
- No unsolicited PR comments/reviews/labels/retitles/rebases/fixups/landing. Exception: close/duplicate action that needs a reason comment after explicit close/sweep/landing request.
- PR review answer: bug/behavior, URL(s), affected surface, best-fix judgment, evidence from code/tests/CI/current or shipped behavior.
- Maintainer decision closes the cluster: if deciding reported behavior/proposed fix is not planned, comment+close all directly associated open issues/PRs unless explicitly told to keep one open. Associated means linked PRs/issues, duplicates, companion workaround PRs, and the canonical issue for the rejected behavior.
- Do not leave associated issues open for hypothetical future repros. Close with rationale; ask for a new issue or reopen only if concrete new evidence appears. Close comment states: decision, why, supported alternative, and what evidence would change the decision.
- PR review answer: bug/behavior, URL(s), affected surface, provenance for regressions when traceable, best-fix judgment, evidence from code/tests/CI/current or shipped behavior.
- Issue/PR final answer: last line is the full GitHub URL.
- Changelog: PR landings/fixes need one unless pure test/internal. Do not mention missing changelog as a review finding; Codex handles it during fix/landing.
- PR verification: before merge, post exact local commands, CI/Testbox run IDs, before/after proof when used, and known proof gaps.
- Issue fixed on `main` with proof: comment proof + commit/PR, then close.
- After landing or requested close/sweep: search duplicates; comment proof + canonical commit/PR/release before closing.
- After landing/ship final: include 2-5 sentence recap of what landed: behavior change, key files/surface, proof run, issue/PR state. Do not answer with only status/links.
- `ship` that fixes an issue: after push, comment proof + commit link, then close the issue.
- GH comments with backticks, `$`, or shell snippets: use heredoc/body file, not inline double-quoted `--body`.
- PR create: real body required. Include Summary + Verification; mention refs, behavior, and proof.
- Real behavior proof section is parsed. Use exact `field: value` labels: `Behavior addressed`, `Real environment tested`, `Exact steps or command run after this patch`, `Evidence after fix`, `Observed result after fix`, `What was not tested`.
- PR artifacts/screenshots: attach to PR/comment/external artifact store. Do not commit `.github/pr-assets`.
- CI polling: exact SHA, relevant checks only, minimal fields. Skip routine noise (`Auto response`, `Labeler`, docs agents, performance/stale). Logs only after failure/completion or concrete need.
- Maintainers: ignore `Real behavior proof` failures that only say PR body lacks real after-fix evidence.
- Maintainers: may skip/ignore `Real behavior proof` when local tests or Crabbox verified behavior; record proof in PR verification.
- `/landpr`: use `~/.codex/prompts/landpr.md`; do not idle on `auto-response` or `check-docs`.
## Code
@@ -115,6 +129,7 @@ Skills own workflows; root owns hard policy and routing.
- Codex harness upgrade (`extensions/codex/package.json` `@openai/codex`): refresh `docs/plugins/codex-harness.md` model snapshot from the new harness `model/list`.
- Docs final answers: include relevant full `https://docs.openclaw.ai/...` URL(s). If issue/PR work too, GitHub URL last.
- Changelog entries: active version `### Changes`/`### Fixes`; single-line bullets only.
- Contributor PR authors should not edit `CHANGELOG.md`; maintainer/AI adds entries during landing/merge.
- Contributor-facing changelog entries thank credited human `@author`. Never thank bots, `@openclaw`, `@clawsweeper`, or `@steipete`; if unknown, omit thanks.
## Git
@@ -132,8 +147,7 @@ Skills own workflows; root owns hard policy and routing.
- Never commit real phone numbers, videos, credentials, live config.
- Secrets: channel/provider creds in `~/.openclaw/credentials/`; model auth profiles in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
- Env keys: check `~/.profile`; redact output.
- Dependency patches/overrides/vendor changes need explicit approval. `pnpm.patchedDependencies` exact versions only.
- Dependency patches/overrides/vendor changes need explicit approval. `pnpm-workspace.yaml` patched dependencies use exact versions only.
- Carbon pins owner-only: do not change `@buape/carbon` unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
- Releases/publish/version bumps need explicit approval. Use `$openclaw-release-maintainer`.
- GHSA/advisories: `$openclaw-ghsa-maintainer` / `$security-triage`. Secret scanning: `$openclaw-secret-scanning-maintainer`.

File diff suppressed because it is too large Load Diff

View File

@@ -107,6 +107,7 @@ For coordinated change sets that genuinely need more than 20 PRs, join the **#cl
- Test locally with your OpenClaw instance
- External PRs must include a filled **Real behavior proof** section in the PR body. Show the real setup you tested, the exact command or steps you ran after the patch, after-fix evidence, the observed result, and anything you did not test. Screenshots, recordings, terminal screenshots, console output, copied live output, linked artifacts, and redacted runtime logs all count. Unit tests, mocks, snapshots, lint, typechecks, and CI are useful but do not satisfy this requirement by themselves. Maintainers may apply `proof: override` only when the proof gate should not apply.
- Do not edit `CHANGELOG.md` in contributor PRs. Maintainers or ClawSweeper add the changelog entry when landing user-facing changes.
- Run tests: `pnpm build && pnpm check && pnpm test`
- For iterative local commits, `scripts/committer --fast "message" <files...>` passes `FAST_COMMIT=1` through to the pre-commit hook so it skips the repo-wide `pnpm check`. Only use it when you've already run equivalent targeted validation for the touched surface.
- For extension/plugin changes, run the fast local lane first:

View File

@@ -1,5 +1,3 @@
# syntax=docker/dockerfile:1.7
# Opt-in plugin dependencies at build time (space- or comma-separated directory names).
# Example: docker build --build-arg OPENCLAW_EXTENSIONS="diagnostics-otel,matrix" .
#

View File

@@ -2,6 +2,480 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.5.12</title>
<pubDate>Fri, 15 May 2026 13:25:16 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026051290</sparkle:version>
<sparkle:shortVersionString>2026.5.12</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.12</h2>
<h3>Changes</h3>
<ul>
<li>Amazon Bedrock: externalize the Bedrock and Bedrock Mantle provider packages so core installs no longer pull AWS SDK dependencies unless those providers are installed.</li>
<li>Plugins: externalize Slack, OpenShell sandbox, and Anthropic Vertex so their runtime dependency cones install only when those plugins are installed.</li>
<li>Control UI/WebChat: add a persisted auto-scroll mode selector so users can keep the current near-bottom behavior, always follow streaming output, or turn automatic streaming scroll off and use the New messages button manually. Fixes #7648 and #81287. Thanks @BunsDev.</li>
<li>ACP: add <code>acp.fallbacks</code> so ACP turns can try configured backup runtime backends when the primary backend is unavailable before any output is emitted. (#69542) Thanks @kaseonedge.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Doctor/Codex: stop warning that the message tool is unavailable for source-reply paths where OpenClaw grants <code>message</code> at runtime, keeping update and doctor output aligned with the OpenAI happy path. Thanks @pashpashpash.</li>
<li>Channels/Weixin: bump the external Weixin catalog entry to <code>@tencent-weixin/openclaw-weixin@2.4.3</code> with the matching package integrity. (#81730) Thanks @scotthuang.</li>
<li>Agents/subagents: apply <code>agents.defaults.subagents.model</code> before target agent primary models during <code>sessions_spawn</code>, so model-scoped runtimes such as <code>claude-cli</code> stay attached to default child runs. Fixes #81395. (#81783) Thanks @joshavant.</li>
<li>Telegram: keep Bot API polling alive during main event-loop stalls by moving ingress to an isolated worker with a durable local spool. Fixes #81132. (#81746) Thanks @joshavant.</li>
<li>Telegram: preserve rendered HTML formatting through lazy cron announce delivery so Markdown links stay clickable instead of falling back to literal anchor tags. Fixes #81742. (#81758)</li>
<li>Telegram: skip unmentioned group media before download when <code>requireMention</code> is active, avoiding failed media-download replies for messages that should be ignored. Fixes #81181. (#81785) Thanks @joshavant.</li>
<li>CLI/plugins: keep bare plugin and parent-command help on the lightweight path, avoiding plugin registry discovery before rendering help.</li>
<li>Gateway/session history: carry monotonic transcript message sequence through live updates and refresh SSE history when stale sequence input would otherwise append bad incremental state. (#81474) Thanks @samzong.</li>
<li>Security/sandbox: include Windows <code>USERPROFILE</code> in the sandbox blocked home roots so credential-bearing binds (such as <code>.codex</code>, <code>.openclaw</code>, or <code>.ssh</code> under the Windows user profile) are denied even when <code>HOME</code> points at a different shell home. (#63074) Thanks @luoyanglang.</li>
<li>Models config/auth: stop inferring provider env-var markers from broad <code>^[A-Z_][A-Z0-9_]*$</code> strings, and resolve config-backed provider <code>apiKey</code> values only through structured env SecretRefs (<code>secrets.providers[id]</code> / <code>secrets.defaults</code>), so unrelated env vars cannot accidentally become provider credentials. Thanks @sallyom.</li>
<li>Media fetch: skip allocating and buffering the response body for bodyless media responses (HEAD probes and 204-style empty bodies), avoiding wasted heap on streams that carry no payload. Thanks @shakkernerd.</li>
<li>CLI/onboarding: forward provider-specific auth flags (e.g. <code>--openai-api-key</code>) through the onboarding wizard so they reach provider auth methods via <code>ctx.opts</code>, letting <code>--openai-api-key "$OPENAI_API_KEY"</code> skip the redundant "use existing env var?" prompt in non-interactive harnesses. (#81669) Thanks @sjf.</li>
<li>CLI/migrate: drop trailing periods from Codex migrate item messages and <code>REASON_CODE_MESSAGES</code> strings so plan/result rows read as labels instead of sentence fragments. (#81705) Thanks @sjf.</li>
<li>Slack: treat malformed private-file redirect <code>Location</code> headers as unfollowable redirects instead of failing Slack media downloads.</li>
<li>Plugins: discover provider plugins from <code>setup.providers[].envVars</code> credentials during provider discovery while keeping the deprecated <code>providerAuthEnvVars</code> fallback. (#81542) Thanks @JARVIS-Glasses.</li>
<li>Docs/Codex harness: clarify that per-agent <code>CODEX_HOME</code> isolates <code>~/.codex</code> while inherited <code>HOME</code> intentionally keeps <code>.agents</code> discovery and subprocess user-home state available.</li>
<li>Auth: reclaim dead-owner stale file locks before retrying locked writes, so crashed OAuth refreshes no longer wedge <code>auth-profiles.json</code> until manual cleanup.</li>
<li>CLI tables: preserve muted/color styling on wrapped continuation lines after multiline cells, keeping <code>openclaw plugins list</code> descriptions readable.</li>
<li>Process execution: collapse case-insensitive duplicate child environment keys on Windows so caller-provided overrides such as <code>PATH</code> cannot be shadowed by host <code>Path</code>.</li>
<li>Gateway/diagnostics: suppress cold-start liveness warnings during the startup grace window while still sampling liveness metrics. Fixes #79915. (#81699) Thanks @joshavant.</li>
<li>Codex harness: keep <code>oauthRef</code>-backed Codex OAuth profiles usable and stop high-confidence app-server OAuth refresh invalidation from retry-spamming raw token-refresh errors without turning entitlement or usage-limit payloads into re-auth prompts.</li>
<li>Browser CLI: request the existing <code>operator.admin</code> gateway scope explicitly for browser control commands, avoiding unnecessary scope-upgrade approval loops. Fixes #81555. (#81716) Thanks @joshavant.</li>
<li>Gateway/diagnostics: suppress cold-start liveness warnings during the startup grace window while still sampling liveness metrics. Fixes #79915. (#81699) Thanks @joshavant.</li>
<li>Plugin SDK: restore the deprecated <code>openclaw/plugin-sdk/memory-core</code> package subpath as an alias of <code>memory-host-core</code>, so published memory companion plugins that still import it resolve on current hosts.</li>
<li>Control UI/i18n: use the installed workspace pi runtime for locale refreshes, update the fallback package pin, prefer the Anthropic CI provider when available, and skip invalid provider credentials instead of failing main.</li>
<li>Codex harness: classify native app-server token-refresh logout and relogin failures as authentication refresh errors, so users get re-authentication guidance instead of a raw runtime failure.</li>
<li>Codex startup: treat selectable configured OpenAI agent models as Codex runtime requirements during plugin auto-enable, startup planning, and doctor install repair, so Anthropic-primary configs can still switch to OpenAI/Codex cleanly.</li>
<li>Agents: preserve source-reply delivery metadata when merging tool-returned media into the final reply, keeping message-tool-only replies deliverable and mirrored. Thanks @pashpashpash and @vincentkoc.</li>
<li>Replies: treat rich presentation, interactive controls, and channel-native payload data as outbound content across follow-up, heartbeat, cron, ACP, and block-streaming delivery paths, preventing card/button-only replies from being dropped as empty.</li>
<li>WebChat/TUI: route Codex <code>tools.message</code> source replies to the active internal UI turn and mirror them to session history, so message-tool-only harness replies, including rich presentation and button-only replies, no longer disappear while WebChat and TUI remain non-targetable outbound channels. (#81586) Thanks @pashpashpash.</li>
<li>Replies: deliver rich-only block replies even when block-streaming coalescing is enabled, keeping card and button payloads from being dropped by the text coalescer. Thanks @pashpashpash.</li>
<li>macOS/companion: require system TLS trust before pinning a first-use direct <code>wss://</code> gateway certificate and honor <code>gateway.remote.tlsFingerprint</code> as the explicit pin for remote node-mode sessions, so fresh endpoints fail closed when macOS cannot trust the certificate unless configured out of band. Fixes #50642. Thanks @BunsDev.</li>
<li>Update: snapshot config before update-time repair and restart writes, preserve plugin install records through doctor cleanup, and keep update-time config size drops from blocking the update while pointing users to the pre-update backup. Fixes #80077. (#80257) Thanks @Jerry-Xin and @vincentkoc.</li>
<li>Sessions/status: classify ACP spawn-child sessions as <code>kind: "spawn-child"</code> instead of <code>"direct"</code> in <code>openclaw sessions</code> and status output; extract the duplicated session-kind classifier into a shared helper (<code>src/sessions/classify-session-kind.ts</code>) so both surfaces stay in sync. Fixes catalog #19. (#79544)</li>
<li>Sessions/Gateway: report <code>agentRuntime.id: "acpx"</code> (or stored backend id) with <code>source: "session-key"</code> for ACP control-plane session rows in <code>openclaw sessions --json</code>, <code>openclaw status</code>, and Gateway session RPC responses instead of the incorrect <code>"auto"</code> / <code>"pi"</code> implicit fallback. Fixes catalog #18. (#79550)</li>
<li>Telegram: delete tool-progress-only draft bubbles before rotating to the real answer, preventing orphaned progress messages in streamed replies.</li>
<li>Codex app-server: keep per-agent <code>CODEX_HOME</code> isolation without rewriting <code>HOME</code> by default, so Codex-run subprocesses can still find normal user-home config, tokens, and CLI state unless the launch explicitly overrides <code>HOME</code>. Thanks @pashpashpash.</li>
<li>iMessage: stop sending visible <code><media:image></code> placeholder text for media-only native image sends while preserving the internal echo key that prevents self-echo duplicate replies. (#81209) Thanks @homer-byte.</li>
<li>Agents/sessions: create configured agent main sessions before first <code>sessions_send</code> or gateway send, so agent-to-agent messages no longer fail when the target agent has not started yet.</li>
<li>gateway: pass Talk session scope to resolver [AI]. (#81379) Thanks @pgondhi987.</li>
<li>Gateway protocol: require v4 clients and stream explicit chat <code>deltaText</code>/<code>replace</code> frames so SDK clients can consume assistant updates without local diffing. (#80725) Thanks @samzong.</li>
<li>GitHub Copilot: exchange OAuth tokens for Copilot API tokens on image understanding requests and route Gemini image payloads through Chat Completions, fixing Copilot Gemini image descriptions. (#80393, #80442) Thanks @afunnyhy.</li>
<li>Gateway: hide pending Node pairing commands, capabilities, and permissions until approval, and refresh the live approved surface when pairings change. (#80741) Thanks @samzong.</li>
<li>Plugins/Feishu/WhatsApp/Line: enforce inbound media size caps while reading download streams, avoiding full buffering of oversized attachments. (#81044, #81050) Thanks @samzong.</li>
<li>Plugins/install: limit install-time code safety scans to plugin-owned runtime entrypoints while keeping dependency manifest denylist checks, so trusted packages with large dependency trees no longer get blocked or warned on third-party runtime internals.</li>
<li>Config: serialize and retry semantic config mutations centrally, so concurrent commands can rebase safe changes instead of clobbering or hand-rolling command-local retry loops. (#76601)</li>
<li>Installer: honor <code>--no-git-update</code> for existing git checkouts before resolving release refs, preventing pinned source installs from moving during reinstall.</li>
<li>Plugins/install: refresh OpenClaw-managed peer dependency pins when installed plugin peer ranges change, while preserving user-owned dependency pins.</li>
<li>Require approval for setup-code device pairing [AI]. (#81292) Thanks @pgondhi987.</li>
<li>Plugins/install: preserve third-party peer dependencies in the managed npm root when later plugin installs or updates recalculate the shared dependency tree. Thanks @shakkernerd.</li>
<li>Plugins/memory: prefer the npm-installed memory-lancedb plugin over the bundled fallback during duplicate resolution, keeping Active Memory's <code>memory_recall</code> tool visible after managed installs. Fixes #81193. Thanks @julio-arcila.</li>
<li>Plugins/uninstall: prune managed third-party peer dependencies after their owning npm plugin is removed, without blocking plugin cleanup on peer-prune failures.</li>
<li>Docker: pin setup-time container paths so stale host <code>.env</code> OpenClaw paths cannot leak into Linux containers. Fixes #80381. (#81105) Thanks @brokemac79.</li>
<li>Channels/WeCom: refresh the official onboarding install to <code>@wecom/wecom-openclaw-plugin@2026.5.7</code> and update existing managed npm installs instead of failing on the package directory. Fixes #79884. (#80390) Thanks @brokemac79.</li>
<li>Anthropic: reseed Claude CLI fresh-session retries from bounded OpenClaw transcript history after session rotation, preventing conversation amnesia. Fixes #80905. (#80934) Thanks @bitloi.</li>
<li>Require explicit browser device pairing [AI]. (#81289) Thanks @pgondhi987.</li>
<li>Require Control UI pairing before proxy-scoped access [AI]. (#81288) Thanks @pgondhi987.</li>
<li>Installer: honor <code>--version</code> for git installs and install from the checked-in lockfile, preventing recent dependency pins from tripping pnpm's minimum-release-age gate during tag installs.</li>
<li>Agents: deliver same-process subagent completion handoffs through the in-process agent dispatcher instead of opening a Gateway RPC loopback.</li>
<li>Harden trusted-proxy source validation [AI]. (#81290) Thanks @pgondhi987.</li>
<li>Agents: add permissive item schemas to array tool parameters before provider submission, preventing OpenAI-compatible schema validation from rejecting plugin tools that omit <code>items</code>. Fixes #81175. (#81217) Thanks @JARVIS-Glasses.</li>
<li>Agents: escalate LLM idle watchdog timeouts through profile rotation and configured model fallback instead of leaving agent turns stuck after a silent model stream. Fixes #76877. (#80449) Thanks @jimdawdy-hub.</li>
<li>Discord voice: treat OpenAI Realtime startup auth failures as fatal, suppress duplicate realtime error logs, and stop autoJoin from retrying the same broken voice channel until credentials are fixed.</li>
<li>ACPX: stop forwarding unsupported timeout config options to Claude ACP while preserving OpenClaw's own turn timeout. (#80812) Thanks @sxxtony.</li>
<li>Session transcripts: redact sensitive message content in the centralized JSONL append path so CLI turns, gateway transcript injection, transcript mirrors, and guarded tool results use the same configured redaction behavior. Fixes #73565. Refs #73563. (#79645) Thanks @Ziy1-Tan.</li>
<li>Channels/iMessage: ignore Apple link-preview plugin payload attachments when users paste URLs, keeping the URL text while avoiding phantom media context. (#79374) Thanks @homer-byte.</li>
<li>Telegram: detect polling stalls from <code>getUpdates</code> liveness only, so outbound API calls no longer mask dead inbound polling; log polling-cycle starts after transport rebuilds. Fixes #78473.</li>
<li>fix: scan plugin runtime entries during install [AI]. (#80998) Thanks @pgondhi987.</li>
<li>fix(plugins): scan installed dependency runtime code [AI]. (#81066) Thanks @pgondhi987.</li>
<li>Inherit tool restrictions for delegated sessions [AI]. (#80979) Thanks @pgondhi987.</li>
<li>Telegram: discard legacy long-poll update offsets that cannot be tied to the current bot token, so token rotation no longer leaves bots silently skipping new messages. (#80671) Thanks @sxxtony.</li>
<li>browser: enforce navigation checks for act interactions [AI]. (#81070) Thanks @pgondhi987.</li>
<li>Validate node exec event provenance [AI]. (#81071) Thanks @pgondhi987.</li>
<li>Gateway: keep active reply runs visible to stuck-session diagnostics and clear no-active-work recovery state, preventing stale queued lanes after compaction or tool failures. Fixes #80677. (#81302)</li>
<li>Codex app-server: rotate incompatible context-engine-managed native threads so Lossless-managed sessions do not resume stale hidden Codex history. (#81223) Thanks @jalehman.</li>
<li>Codex cron: execute scheduled command-style automation payloads before workspace bootstrap or memory review, preserving existing isolated cron jobs after Codex harness migration. (#81510) Thanks @jalehman.</li>
<li>Plugin LLM completions: honor Codex agent-runtime policy for canonical OpenAI model refs, so context-engine summarizers can use Codex OAuth instead of requiring direct <code>OPENAI_API_KEY</code> auth. (#81511) Thanks @jalehman.</li>
<li>Gateway/OpenAI HTTP: return OpenAI-compatible 400 errors for invalid sampling params and provider validation failures instead of collapsing them to 500s. (#81275) Thanks @Lellansin.</li>
<li>Telegram: publish plugin and skill command description localizations to native command menus while filtering unsupported locale codes and preserving Telegram command limits. (#81351) Thanks @jzakirov.</li>
<li>Limit hook CLI tool authority [AI]. (#81065) Thanks @pgondhi987.</li>
<li>Require admin scope for node device token management [AI]. (#81067) Thanks @pgondhi987.</li>
<li>Restrict chat sender allowlist matching [AI]. (#80898) Thanks @pgondhi987.</li>
<li>Update: suppress the false newer-config warning during restart health probing after an update handoff, while keeping future-version mutation guards intact. (#78652)</li>
<li>Sessions: redact persisted tool result detail metadata before writing transcripts so diagnostic secrets do not survive tool output redaction. (#80444) Thanks @nimbleenigma.</li>
<li>Codex runtime: allow the official installed <code>@openclaw/codex</code> package to use its private task-runtime and MCP projection SDK helpers, fixing <code>MODULE_NOT_FOUND</code> during migrated OpenAI/Codex beta runs.</li>
<li>Codex migration: make Enter activate the highlighted checkbox row before continuing, so <code>Skip for now</code> and bulk-selection rows work even when planned items start preselected.</li>
<li>Codex harness: keep auth-profile-backed media tools such as <code>image_generate</code> available when OpenAI auth lives in the agent's auth-profile store instead of environment variables.</li>
<li>WhatsApp/install: allow Baileys' pinned libsignal git subdependency under pnpm 11 so source installs and local checks can complete.</li>
<li>Require auth for sandbox browser CDP relay [AI]. (#81002) Thanks @pgondhi987.</li>
<li>fix: detect carried exec command forms [AI]. (#81000) Thanks @pgondhi987.</li>
<li>Reject truncated exec approval commands [AI]. (#81001) Thanks @pgondhi987.</li>
<li>Enforce inline shell wrapper payload matching [AI]. (#80978) Thanks @pgondhi987.</li>
<li>fix(node-pairing): replace changed pending requests [AI]. (#80894) Thanks @pgondhi987.</li>
<li>Rate limit Google Chat webhook requests [AI]. (#80974) Thanks @pgondhi987.</li>
<li>Docker: mount the auth-profile secret key directory so OAuth-backed auth profiles survive container rebuilds. (#80991)</li>
<li>Onboarding: accept Codex auth profiles for canonical OpenAI model checks, avoiding false missing-auth warnings. (#80913) Thanks @rubencu.</li>
<li>fix(feishu): normalize webhook rate-limit client keys [AI]. (#80975) Thanks @pgondhi987.</li>
<li>fix(auth): prevent bootstrap pairing scope changes [AI]. (#80976) Thanks @pgondhi987.</li>
<li>Validate Control UI loopback retry endpoints [AI]. (#80900) Thanks @pgondhi987.</li>
<li>Harden exported markdown link rendering [AI]. (#80902) Thanks @pgondhi987.</li>
<li>fix(gateway): honor minimal discovery mode for wide-area DNS-SD [AI]. (#80903) Thanks @pgondhi987.</li>
<li>slack: enforce reaction notification policy [AI]. (#80907) Thanks @pgondhi987.</li>
<li>Enforce gateway command scopes by caller context [AI]. (#80891) Thanks @pgondhi987.</li>
<li>Telegram/groups: in single-account setups, treat an explicit empty <code>accounts.<id>.groups: {}</code> map the same as undefined so the root <code>channels.telegram.groups</code> allowlist still applies, instead of silently dropping every group update under the default <code>groupPolicy: "allowlist"</code>. Multi-account semantics are unchanged so per-account explicit-empty groups still scope-disable a single account without affecting siblings; the explicit way to block all groups for any account remains <code>groupPolicy: "disabled"</code>. Fixes #79427. (#81030) Thanks @kinjitakabe.</li>
<li>Codex (app-server): project user-configured <code>mcp.servers</code> into new Codex thread configs, matching the codex-cli runtime's existing <code>-c mcp_servers=...</code> behavior so app-server-runtime agents see the same user MCP servers the CLI runtime already exposes. Plugin-curated apps remain attached via the separate <code>apps</code> config patch. Fixes #80814. Thanks @kinjitakabe.</li>
<li>Enforce Slack plugin approval button authorization [AI]. (#80899) Thanks @pgondhi987.</li>
<li>Recognize PowerShell -ec inline commands [AI]. (#80893) Thanks @pgondhi987.</li>
<li>fix(qqbot): authorize approval button callbacks [AI]. (#80892) Thanks @pgondhi987.</li>
<li>Telegram: render supported HTML tags in streamed and durable replies instead of showing literal markup. (#80977)</li>
<li>Scrub streamable MCP redirect headers [AI]. (#80906) Thanks @pgondhi987.</li>
<li>fix(memory-wiki): require admin scope for ingest [AI]. (#80897) Thanks @pgondhi987.</li>
<li>memory-wiki: require write scope for Obsidian search [AI]. (#80904) Thanks @pgondhi987.</li>
<li>WhatsApp/install: allow Baileys' pinned libsignal git subdependency under pnpm 11 so source installs and local checks can complete.</li>
<li>WhatsApp: externalize the channel as a ClawHub/npm plugin outside the core npm runtime bundle, and bump Baileys to <code>7.0.0-rc11</code> so libsignal resolves from the registry instead of a GitHub tarball.</li>
<li>WhatsApp: keep optional audio decoding dependencies local to the external plugin so the core npm install no longer pulls WhatsApp-only media helpers.</li>
<li>Build: skip copied metadata for bundled plugins that are excluded from build entries, preventing update/status rebuilds from advertising missing QQ Bot runtime files. (#80925)</li>
<li>Control UI/sessions: nest subagent sessions under their parent session in the session picker dropdown using a visual <code>└─ </code> prefix, making the parent-child relationship clear. Fixes #77628. (#78623) Thanks @chinar-amrutkar.</li>
<li>Auto-reply: surface a visible error when the configured model backend fails and fallback produces no visible reply, while preserving intentional silent turns and side-effect-only deliveries. (#80917) Thanks @dutifulbob.</li>
<li>Agents/exec: skip redundant heartbeat wake-ups for subagent session exec completions, preventing spurious LLM invocations on parent sessions. Fixes #66748. (#66749) Thanks @ggzeng.</li>
<li>Provider streams: keep OpenAI-compatible SSE and JSON fallback streams draining across split chunks and fail Azure Responses streams with a bounded first-event diagnostic instead of stalling. Refs #80926. (#80927) Thanks @galiniliev and @CaptainTimon.</li>
<li>Agents: rewrite generic provider internal errors with support request IDs into user-friendly transient error copy. (#49401) Thanks @y471823206.</li>
<li>WhatsApp: finish handling pending debounced inbound messages before closing the socket. (#81246) Thanks @mcaxtr.</li>
<li>CLI/commitments: write <code>--json</code> output to stdout instead of diagnostic logs so automation can parse commitment list and dismiss results. (#81215) Thanks @giodl73-repo.</li>
<li>Update: allow pnpm GitHub-source OpenClaw updates to approve the OpenClaw package build, so source installs complete their prepare/prepack lifecycle. (#81294) Thanks @fuller-stack-dev.</li>
<li>Telegram: preserve supported HTML tags in visible replies and durable mirrors so formatted messages render correctly instead of degrading to escaped text. (#80977) Thanks @obviyus.</li>
<li>Plugins/runtime: attribute deprecated runtime config load/write warnings to the plugin id and source that triggered them so logs and plugin doctor runs are actionable. Refs #81394. (#81425) Thanks @BKF-Gitty.</li>
<li>Agents/cron: honor a cron payload's explicit <code>timeoutSeconds</code> for the LLM idle watchdog even when it numerically equals <code>agents.defaults.timeoutSeconds</code>, preserving explicit per-run timeout intent and preventing stalled streaming replies from being cut to the implicit 120s cap. (#79426) Thanks @legolaz8451.</li>
<li>Codex app-server: keep the short post-tool completion watchdog armed across dynamic tool completion bookkeeping so embedded Codex runs fail fast and release their session lane when Codex goes quiet after a tool result. (#81697) Thanks @mbelinky.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Gateway/OpenAI HTTP: honor <code>max_completion_tokens</code> and <code>max_tokens</code> on inbound <code>/v1/chat/completions</code> requests so client-provided token caps reach the upstream provider via <code>streamParams.maxTokens</code>, with <code>max_completion_tokens</code> taking precedence when both are sent. Thanks @Lellansin.</li>
<li>Models/OpenAI CLI auth: make <code>openclaw models auth login --provider openai</code> start the ChatGPT/Codex account login by default, while <code>--method api-key</code> remains the explicit OpenAI API-key setup path.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside explicit SDK OAuth auth-result config patches, so provider helpers emit <code>google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside SDK OAuth auth-result default config patches, so helper-built provider auth flows emit <code>google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids returned by direct <code>openclaw models auth login --set-default</code> provider auth flows before writing config, so Gemini testing targets <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids in per-agent config defaults and auth patches, so agent-specific emitted config keeps targeting <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids in provider catalog rows when API-key onboarding only reapplies the agent default, so emitted config keeps testing <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids in <code>config set</code> mutation output for agent overrides and provider catalog rows, so current config emits <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: canonicalize provider-qualified retired Gemini 3 Pro Preview refs during Google forward-compatible model resolution, so emitted config uses <code>google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>Google/Gemini: normalize proxy-prefixed retired Gemini 3 Pro Preview catalog rows, so emitted configs use <code>google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside per-agent model overrides before writing config, so agent-specific config emits <code>google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids in subagent, heartbeat, compaction, and subagent-tool model config during writes, so current config keeps emitting <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Docs/subagents: document <code>agents.defaults.subagents.announceTimeoutMs</code> in the sub-agent and configuration references. (#75509) Thanks @akrimm702.</li>
<li>Cron: add direct <code>cron.get</code>, <code>openclaw cron get <id></code>, and agent-tool <code>get</code> support for inspecting one stored cron job by id. (#75117) Thanks @samzong.</li>
<li>Agents/tools: add per-sender tool policies with canonical channel-scoped sender keys, so operators can restrict dangerous tools by requester identity across global, agent, group, core, bundled, and plugin tool surfaces. (#66933) Thanks @JerranC.</li>
<li>ACP: expose Gateway session lineage metadata through ACP session listings and session info snapshots so clients can render subagent graphs without private Gateway side channels. (#73458) Thanks @samzong.</li>
<li>Channels/iMessage: add <code>openclaw channels status --channel <name></code> filtering and document the BlueBubbles-to-imsg cutover path so operators can probe iMessage without starting both channel monitors. (#80706) Thanks @omarshahine.</li>
<li>CI: add a non-blocking <code>plugin-inspector-advisory</code> artifact to Plugin Prerelease so release runs capture bundled plugin compatibility triage without changing the blocking gate.</li>
<li>Runtime/Fly: detect Fly Machines as container environments from their runtime env vars, so gateway bind and Bonjour defaults match remote container launches. (#80209) Thanks @liorb-mountapps.</li>
<li>Providers/fal: route GPT Image 2 and Nano Banana 2 reference-image edit requests to <code>/edit</code> with <code>image_urls</code> array, enforce NB2 edit geometry using <code>aspect_ratio</code> and <code>resolution</code> params, lift Fal edit mode input-image caps to 10 for GPT Image 2 and 14 for Nano Banana 2, and allow aspect-ratio hints in edit mode. (#77295) Thanks @leoge007.</li>
<li>Control UI: show a plain HTML recovery panel when the app module never registers, giving blank dashboard pages a retry path and browser-extension troubleshooting link. Fixes #44107. Thanks @BunsDev.</li>
<li>Docs: rename the broad tools nav to Capabilities, keep automation and agent coordination as sections, and keep the tools overview focused on tools, skills, and plugins. https://docs.openclaw.ai/tools</li>
</ul>
<ul>
<li>Build: enable additional low-churn oxlint rules for promise, TypeScript, and runtime footgun checks.</li>
<li>Build: enable stricter Vitest lint rules for focused, disabled, conditional, hook, matcher, and expectation hazards.</li>
<li>Build: pin explicit oxfmt defaults in the shared formatter config to keep formatting behavior stable across upgrades.</li>
<li>TypeScript: enable stricter compiler checks for implicit returns, side-effect imports, overrides, and unused production code.</li>
<li>Logging: add targeted model transport, payload, SSE, and code-mode diagnostics with redacted URL handling.</li>
<li>Agents: allow <code>session.agentToAgent.maxPingPongTurns</code> up to 20 while keeping the default at 5 for longer agent-to-agent reply chains. Fixes #52382. (#52400) Thanks @thirumaleshp.</li>
<li>Agents: add per-agent <code>tools.message.crossContext</code> overrides so sandboxed/public agents can restrict message sends to the current conversation without changing the global bot policy.</li>
<li>Agents: add per-agent <code>tools.message.actions.allow</code> overrides so sandboxed/public agents can expose and enforce send-only message tools.</li>
<li>Agents: omit the sandbox workspace marker from compact command progress previews while keeping internal sandbox diagnostics unchanged.</li>
<li>Agents: widen progress draft command preview lines by 50% so Discord inline tool updates preserve more useful command context.</li>
<li>Codex app-server: retire timed-out app-server clients after bounded turn interrupts so Discord agents do not reuse a CPU-spinning Codex process after an attempt timeout.</li>
<li>Codex app-server: default migrated native plugin destructive-action policy to enabled while preserving explicit global and per-plugin false overrides.</li>
<li>Build: upgrade workspace package management to pnpm 11 and keep Docker, install, update, and release workflows on the pnpm 11 config surface. (#79414) Thanks @altaywtf.</li>
<li>Build: align Telegram QA workflows and git source installs with the pnpm 11 workspace build allowlist surface. (#80588) Thanks @altaywtf.</li>
<li>Models: add provider-level <code>localService</code> startup for on-demand local model servers before OpenAI-compatible requests, including one-shot model probes.</li>
<li>Agents: trim default system prompt guidance and send-only message tool schemas to reduce prompt tokens while preserving GPT-5 personality guidance.</li>
<li>Context: add <code>/context map</code> to send a treemap image of the current session context contributors. (#79867)</li>
<li>Slack: add <code>unfurlLinks</code> and <code>unfurlMedia</code> config for bot <code>chat.postMessage</code> replies, including per-account overrides, so Slack link and media previews can be suppressed without workspace-wide settings. Fixes #48435. (#80145) Thanks @esegev1 and @HemantSudarshan.</li>
<li>Slack: add explicit <code>replyBroadcast</code> support for text and Block Kit thread replies so agents can opt into Slack's parent-channel <code>reply_broadcast</code> behavior. (#64365) Thanks @tony88331.</li>
<li>Slack: preserve mention target/source metadata in inbound prompt context so agents can distinguish direct bot mentions from implicit thread wakes that mention someone else. Fixes #79025. (#75356) Thanks @tmimmanuel.</li>
<li>Slack: canonicalize outbound delivery-mirror routes for native DM channel IDs to the peer user session so <code>message.send</code> calls to <code>D...</code> targets do not split the same Slack DM thread into a channel session. Fixes #80091. (#80111) Thanks @bek91.</li>
<li>Plugin SDK: deprecate public subpaths that existed for at least one month and have no bundled extension production imports, keep legacy barrel/test/zod subpath package exports for backwards compatibility, and track both sets in the SDK surface report.</li>
<li>Plugin SDK: deprecate public subpaths currently used by only one or two bundled plugin owners, keeping them importable while steering new plugin code to focused shared SDK seams or plugin-owned APIs.</li>
<li>Plugin SDK: remove the owner-specific <code>provider-auth-login</code> public subpath after moving Chutes, GitHub Copilot, and OpenAI Codex auth flows back to provider-owned modules.</li>
<li>Plugin SDK: remove provider-specific model, stream, and xAI compatibility helpers from public exports after moving bundled callers to provider-owned modules.</li>
<li>Plugin SDK: expose runtime-supplied active model metadata to native plugin tool factories for diagnostics and plugin-owned policy decisions. Fixes #77857. Thanks @jamiezigelbaum.</li>
<li>QA/Mantis: add Telegram live PR evidence automation with Convex-leased credentials, Crabbox transcript capture, motion GIF previews, and inline PR comments.</li>
<li>QA/Mantis: add a Telegram desktop scenario builder that leases Crabbox, installs native Telegram Desktop, configures an OpenClaw Telegram gateway with leased bot credentials, and records VNC screenshot/video artifacts.</li>
<li>Discord/voice: add realtime voice diagnostics for speaker turns, playback resets, barge-in detection, and audio cutoff analysis.</li>
<li>Talk: add <code>talk.realtime.instructions</code> so operators can append realtime voice style instructions while preserving OpenClaw's built-in agent-consult guidance. (#79081) Thanks @VACInc.</li>
<li>Discord/voice: default test and source installs to the pure-JS <code>opusscript</code> decoder by ignoring optional native <code>@discordjs/opus</code> builds, avoiding slow native addon compiles outside dedicated voice-performance lanes.</li>
<li>Discord/voice: add an opt-in native <code>@discordjs/opus</code> install script and decoder preference for live voice-performance lanes without charging unrelated Docker/tests for native addon builds.</li>
<li>Discord/voice: add <code>voice.allowedChannels</code> to restrict voice joins and bot voice-state moves to configured channels while preserving open voice behavior when unset.</li>
<li>Gateway/skills: add an opt-in private skill archive upload install path gated by <code>skills.install.allowUploadedArchives</code>, so trusted Gateway clients can stage and install zip-backed skills only when operators explicitly enable the code-install surface. (#74430) Thanks @samzong.</li>
<li>Codex app-server: enable Codex native code-mode-only for harness threads so deferred OpenClaw dynamic tools run through Codex's own searchable code execution surface instead of a PI-style wrapper.</li>
<li>Dependencies: refresh workspace pins and patch targets, including ACPX <code>@agentclientprotocol/claude-agent-acp</code> <code>0.33.1</code>, Codex ACP <code>0.14.0</code>, Baileys <code>7.0.0-rc10</code>, Google GenAI <code>2.0.1</code>, OpenAI <code>6.37.0</code>, AWS SDK <code>3.1045.0</code>, Kysely <code>0.29.0</code>, Tlon skill <code>0.3.6</code>, Aimock <code>1.19.5</code>, and tsdown <code>0.22.0</code>.</li>
<li>Dependencies: refresh workspace pins for Anthropic SDK, Smithy shared ini loading, Playwright, YAML, Aimock, TypeScript native preview, Vitest, Oxlint/Oxfmt, Vite, and pnpm 11.1.0.</li>
<li>Dependencies: hard-pin non-peer direct dependency specs across bundled packages and add a changed-check guard so runtime installs resolve the exact versions tested by maintainers.</li>
<li>Dependencies: move embedded Pi packages to the <code>@earendil-works</code> namespace, refresh Twitch Twurple packages, and move <code>@openclaw/fs-safe</code> from the GitHub release pin to the published npm package.</li>
<li>Build: route Testbox changed-check delegation through Crabbox and remove the OpenClaw-specific Blacksmith Testbox helper scripts.</li>
<li>Agents/compaction: preserve scoped background exec/process session references across embedded compaction and after-turn runtime contexts without exposing sessions from unrelated scopes. Fixes #79284. (#79307) Thanks @TurboTheTurtle.</li>
<li>Agents/process: tell agents to inspect background sessions with <code>process log</code> before sending interactive input and to use <code>waitingForInput</code>/<code>stdinWritable</code> hints from <code>log</code>/<code>poll</code>.</li>
<li>CLI/onboarding: improve setup, onboarding, configure, and channel command wayfinding so terminal flows explain the next useful command instead of relying on terse setup labels.</li>
<li>Agents/Codex: remove the configurable Codex dynamic-tools profile so Codex app-server always owns workspace, edit, patch, exec, process, and plan tools while OpenClaw integration tools remain available.</li>
<li>macOS app: update the Peekaboo bridge dependency to Peekaboo 3.0.0.</li>
<li>Dependencies: refresh workspace pins and move the WhatsApp plugin from <code>@whiskeysockets/baileys</code> to <code>baileys</code> while keeping the <code>7.0.0-rc10</code> runtime.</li>
<li>Plugin SDK: add bundled-plugin session actions, <code>sendSessionAttachment</code>, and Cron-backed <code>scheduleSessionTurn</code>/tag cleanup under the grouped session namespace. Replaces #75578/#75581/#75588 and part of #73384/#74483. Thanks @100yenadmin.</li>
<li>Plugin SDK/media-understanding: add <code>extractStructuredWithModel(...)</code> plus the optional provider-side <code>extractStructured(...)</code> seam so trusted plugins can run bounded image-first structured extraction with optional supplemental text context through provider-owned runtimes such as Codex.</li>
<li>Exec approvals: add <code>tools.exec.commandHighlighting</code> so parser-derived command highlighting in approval prompts can be enabled globally or per agent. (#79348) Thanks @jesse-merhi.</li>
<li>Codex app-server: mirror native Codex subagent spawn lifecycle events into Task Registry so app-server child agents appear in task/status surfaces without relying on transcript text. (#79512) Thanks @mbelinky.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>CLI/media: render terminal QR codes with full-block characters by default so the bundled <code>qrcode</code> terminal renderer does not emit a pathologically dense ANSI final row in compact half-block mode that breaks scanning in some terminals. Fixes #77820. Thanks @KrasimirKralev.</li>
<li>Agents/compaction: read post-compaction AGENTS.md refresh context from the queued run workspace instead of the runner process cwd, so CLI-backed follow-up turns re-inject the correct workspace startup rules after compaction. Fixes #70541. (#75532) Thanks @vyctorbrzezowski.</li>
<li>Agents/read tool: treat positive offsets beyond EOF as empty ranges instead of surfacing the upstream read error, so stale pagination cursors no longer crash tool calls while unrelated read failures still fail loud. Fixes #62466. (#75536) Thanks @vyctorbrzezowski.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview refs left in Google API-key onboarding model allowlists and fallbacks, so setup-emitted config keeps testing <code>google/gemini-3.1-pro-preview</code> instead of <code>google/gemini-3-pro-preview</code>.</li>
<li>Telegram/context: bound selected topic context to the active session so messages from before <code>/new</code> or <code>/reset</code> are not replayed into later turns. (#80848) Thanks @VACInc.</li>
<li>Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids when resolving exact configured proxy-provider refs, so <code>kilocode/google/gemini-3-pro-preview</code> resolves to <code>kilocode/google/gemini-3.1-pro-preview</code> for Gemini 3.1 testing.</li>
<li>CLI: strip generic OSC terminal escape payloads from sanitized output fields, preventing clipboard/title escape bodies from leaking into commitment tables and other terminal-safe text. Thanks @shakkernerd.</li>
<li>Codex app-server: match connector-backed plugin approval elicitations by stable connector id so enabled destructive actions no longer fall through to display-name-only rejection.</li>
<li>Build: replace selected build utility <code>tsx</code> preloads with Node native type stripping so Node 26 build paths no longer emit <code>DEP0205</code> module loader deprecation warnings. (#78584) Thanks @keshavbotagent.</li>
<li>Media generation: honor configured music and video generation timeouts when tool calls omit <code>timeoutMs</code>, matching image generation behavior. (#80687)</li>
<li>CLI/update/status: label beta-channel plugin fallback and model-pricing refresh failures as warnings, keeping mixed beta/latest plugin cohorts visible without making core update or Gateway reachability look failed. Fixes #80689. Thanks @BKF-Gitty.</li>
<li>Doctor/plugins: relink managed npm plugin <code>openclaw</code> peer dependencies during <code>doctor --fix</code>, while refusing to follow package-local <code>node_modules</code> symlinks outside the plugin package. (#77412) Thanks @TheCrazyLex.</li>
<li>iMessage: route inbound tapbacks as reaction system events instead of normal messages, defaulting to bot-authored-message notifications while allowing <code>reactionNotifications: "off" | "own" | "all"</code> overrides. Fixes #60274; refs #39031 and #39322. Thanks @hyperclaw.</li>
<li>Control UI/performance: scope Nodes polling to the active Nodes tab, debounce stale session-list reconciliation, and bound chat-side session refreshes so long-running dashboards avoid background reload churn. Thanks @BunsDev.</li>
<li>Plugins/channels: explain bundled channel entry files that reach the legacy plugin loader as setup-runtime loader mismatches instead of generic missing-register failures. Thanks @chinar-amrutkar.</li>
<li>Plugins/session-end: fire a typed <code>session_end</code> plugin hook with reason <code>shutdown</code> (or <code>restart</code> when a restart is expected) for every session that was still active when the gateway process stops. Previously SIGTERM/SIGINT/restart paths closed the gateway without enumerating active sessions, leaving downstream <code>session_end</code> plugins (e.g. claude-mem) with ghost rows accumulating across restarts. The new shutdown finalizer drains an in-memory tracker that is populated by <code>session_start</code> and forgotten by replace / reset / delete / compaction emitters, so previously-finalized sessions are never double-fired. The drain is bounded to a 2 s total budget so a slow plugin cannot block process exit. Adds <code>"shutdown"</code> and <code>"restart"</code> to <code>PluginHookSessionEndReason</code>. Fixes #57790. Thanks @pandadev66.</li>
<li>Codex app-server: clamp Codex code-mode sandboxing to workspace-write when an OpenClaw sandbox is active, preventing Docker gateway socket access from becoming a danger-full-access Codex turn.</li>
<li>TUI: exit immediately on Ctrl+C/SIGINT after gateway disconnect and bound shutdown drain so terminal teardown cannot strand sessions. Fixes #75379. (#75381) Thanks @udaymanish6.</li>
<li>Matrix: default outbound markdown tables to bullet lists instead of fenced code blocks. Fixes #78990. (#80890) Thanks @kinjitakabe.</li>
<li>Bonjour/Gateway: treat active ciao probing and fresh name-conflict renames as in-progress so the mDNS watchdog waits for probe settlement before retrying, preventing rapid re-advertise loops on Windows, WSL, and other multicast-hostile hosts. (#74778) Refs #74242. Thanks @fuller-stack-dev.</li>
<li>Providers/MiniMax: send a minimal Anthropic-compatible user fallback when message conversion filters a turn to an empty payload, so MiniMax M2.7 no longer returns <code>chat content is empty</code> after tool-heavy sessions. Fixes #74589. Thanks @neeravmakwana and @DerekEXS.</li>
<li>Tools/media: preserve implicit allow-all semantics from <code>tools.alsoAllow</code>-only policies when preconstructing built-in media generation and PDF tools, so configured media tools become live without forcing <code>tools.allow: ["*", ...]</code>. Fixes #77841. Thanks @trialanderrorstudios.</li>
<li>Codex/Telegram: separate code-mode tool progress from final replies, render bridged tool calls with native tool labels, and repair persisted missing tool results for safer follow-up turns. (#80663) Thanks @jalehman.</li>
<li>Memory/search: load the platform-specific <code>sqlite-vec-<platform>-<arch></code> variant directly when the meta <code>sqlite-vec</code> package is missing from a global install, so vector recall keeps working on <code>npm install -g openclaw@latest</code> upgrades where optionalDependencies left only the platform variant on disk. Fixes #77838. Thanks @corevibe555 and @Simon2256928.</li>
<li>Cron: keep long manual cron runs active in the task registry until completion, preventing transient <code>lost</code> markers before durable recovery reconciles. Fixes #78233. (#78243) Thanks @Feelw00.</li>
<li>Doctor/GitHub CLI: surface a <code>GH_CONFIG_DIR</code> hint when the GitHub skill is usable but <code>gh</code> auth lives under a different operator HOME than the agent process, without warning for disabled or filtered skills. Fixes #78063. (#78095) Thanks @tmimmanuel.</li>
<li>Gateway: dedupe concurrent <code>send</code>, <code>poll</code>, and <code>message.action</code> requests while delivery is still in flight, preventing duplicate outbound work for the same idempotency key. (#68341) Thanks @thesomewhatyou.</li>
<li>Cron: keep main-session <code>systemEvent</code> heartbeat wakes on their bound session route for both direct and queued wake paths by dropping inherited explicit heartbeat destinations when forcing <code>target: "last"</code>. Fixes #73900. Thanks @richardmqq.</li>
<li>Telegram: honor forced document delivery for video media so <code>--force-document</code> sends MP4s as documents instead of typed videos. Fixes #80389. (#80405) Thanks @jbetala7.</li>
<li>Gateway: clear speculative node wake state when APNs registration is missing, preventing unregistered or mistyped node IDs from retaining wake throttle entries. Fixes #68847. (#68848) Thanks @Feelw00.</li>
<li>Auto-reply: keep late follow-up queue drain finalizers from deleting a replacement queue registered after <code>/stop</code>, preventing immediate follow-up messages from being orphaned. Fixes #68838. (#68839) Thanks @Feelw00.</li>
<li>Feishu: make manual App ID/App Secret setup the default channel-binding path while keeping QR scan-to-create as an optional best-effort flow, and document the manual fallback for domestic Feishu mobile clients that do not react to the QR code. Fixes #80591. Thanks @wei-wei-zhao.</li>
<li>Memory: cap dreaming promotion writes to <code>MEMORY.md</code> by compacting oldest auto-promoted sections while preserving user-authored notes, keeping active memory below the bootstrap budget. Fixes #73691. (#74088) Thanks @YB0y.</li>
<li>Telegram: show resolved thinking defaults in native <code>/status</code> and <code>/think</code> menus while preserving explicit session overrides. (#80341) Thanks @VACInc.</li>
<li>Channels: cache selected channel registry lookups against the active fallback snapshot so pinned-empty registries refresh native command and alias routing after active registry swaps. (#80333) Thanks @samzong.</li>
<li>Codex app-server: reuse native Codex CLI OAuth for isolated app-server harness login, refresh, and app inventory cache keys so ChatGPT-authenticated Codex runs no longer fall back to unauthenticated OpenAI API calls. (#79877) Thanks @jeffjhunter.</li>
<li>Gateway: scope <code>sessions.resolve</code> sessionId and label store loads to the requested agent so large unrelated agent stores are not parsed for scoped lookups. Fixes #51264. (#79474) Thanks @samzong.</li>
<li>Gateway: share serialized streaming event envelopes across eligible WebSocket and node subscribers while preserving per-client sequence numbers. (#80299) Thanks @samzong.</li>
<li>Gateway: consolidate duplicate <code>openclaw doctor</code> service config panels while preserving the declined-repair <code>--force</code> hint. Fixes #80287. (#78688) Thanks @YB0y.</li>
<li>Browser: report Chrome MCP existing-session page readiness in browser status without letting status probes exceed the client timeout. Fixes #80268. (#80280) Thanks @ai-hpc.</li>
<li>WhatsApp: route opening-phase Baileys 428 connectionClosed through the WhatsApp reconnect policy and keep post-open 428 closes retryable, so transient setup socket closes retry with WhatsApp diagnostics instead of escaping as a bare <code>channel exited</code> error. Fixes #75736; mitigates #77443. Thanks @dataCenter430.</li>
<li>Agents: disable Pi's default filesystem resource discovery for embedded runs while keeping OpenClaw inline extension factories active, avoiding Windows event-loop stalls during first WhatsApp-triggered agent startup. Fixes #77443. Thanks @dataCenter430.</li>
<li>Providers/self-hosted: read model-scoped llama.cpp runtime context from <code>/props.default_generation_settings.n_ctx</code> while keeping top-level <code>n_ctx</code> as a fallback, so session budgeting reflects the loaded context window. Fixes #73664. (#74057) Thanks @brokemac79.</li>
<li>Memory: reject symlinked directory components in configured extra memory paths before reading Markdown files. (#80331) Thanks @samzong.</li>
<li>Sessions/transcripts: replace whole-file <code>readFile</code> scans with shared streaming helpers (<code>streamSessionTranscriptLines</code> and <code>streamSessionTranscriptLinesReverse</code>) for idempotency lookup, latest/tail assistant text reads, delivery-mirror dedupe, and compaction fork loading, so long-running sessions no longer materialize the full transcript in memory. Forward scans use <code>readline</code> over a bounded <code>createReadStream</code>; reverse scans read bounded chunks from the file end and decode complete JSONL lines newest-first without a fixed tail cap. Synthetic 200 MiB transcript: peak RSS delta drops from +252 MiB to +27 MiB while preserving malformed-line tolerance and idempotency-key return semantics. Fixes #54296. Thanks @jack-stormentswe.</li>
<li>Browser/CDP: filter browser-internal targets from raw CDP and persistent Playwright tab selection so navigation opens real page tabs. Fixes #55734. Thanks @Demine4.</li>
<li>WhatsApp: apply hot-reloaded <code>dmPolicy</code> and <code>allowFrom</code> settings to the active Web listener before processing new inbound DMs. Fixes #80538. Thanks @Ampaskopi129.</li>
<li>Plugins: let <code>openclaw doctor --fix</code> repair managed plugin installs whose package entrypoints fail package-directory boundary validation after local state moves. Fixes #80592. Thanks @wei-wei-zhao.</li>
<li>Voice-call: resume voice-originated exec approval follow-ups as internal non-delivery turns instead of rejecting them as <code>unknown channel: voice</code>. Fixes #80540. Thanks @patrickmch.</li>
<li>Control UI: preserve the composer draft when Stop is tapped during an active chat run, preventing accidental prompt loss on mobile. Fixes #80586. Thanks @KCALLC.</li>
<li>Infra/retry: keep jittered retry delays at or above server-supplied Retry-After lower bounds when the hint can be honored. Fixes #68541. (#68543) Thanks @Feelw00.</li>
<li>Docs: clarify that <code>/model provider/model</code> is an exact session route, while duplicate bare model ids only use configured fallback order on non-session override paths. Refs #80562. Thanks @gaodaabao.</li>
<li>Redact persisted secret-shaped payloads [AI]. (#79006) Thanks @pgondhi987.</li>
<li>Agents: label <code>.openclaw/sandboxes</code> exec workdirs as sandbox runs in compact tool summaries instead of showing the full path.</li>
<li>OpenAI Codex: surface browser OAuth and device-code login failures instead of treating failed logins as empty successful auth results. Refs #80363.</li>
<li>CLI agents: carry runtime-only current-turn sender/reply context into CLI model prompts while keeping prompt-build hook input and transcript text clean.</li>
<li>Control UI: keep workspace file presence checks from treating <code>fs-safe</code> stat helper failures as missing files, restoring Agents file status for existing Windows workspace files. Fixes #79953. Thanks @lovelefeng-glitch.</li>
<li>Microsoft Foundry: report an explicit error when the Azure subscription prompt returns an id that is not present in the enabled subscription list, instead of continuing from an unsafe subscription assertion. (#62742) Thanks @oliviareid-svg.</li>
<li>fix(matrix): gate name-based allowlist resolution [AI]. (#79007) Thanks @pgondhi987.</li>
<li>Slack: include the bot's own root/parent message in new thread sessions so in-thread replies reach the agent with the parent text the user is responding to, instead of only <code>reply_to_id</code> metadata. Fixes #79338. Thanks @sxxtony.</li>
<li>Docker: keep image builds on the source pnpm workspace policy so pnpm 11 can prune production dependencies without a Docker-only workspace rewrite.</li>
<li>Agents/compaction: restore info-level gateway logs for embedded compaction start, completion, and incomplete outcomes. (#71961) Thanks @rubencu.</li>
<li>Telegram: build reply-aware inbound turns through the shared channel context path so agents see the current reply target inline with the current message.</li>
<li>Telegram: recover legacy message cache files that mixed JSON-array and line-delimited entries so restarted gateways preserve reply-window context. (#80567)</li>
<li>Telegram: update the reply-context cache when messages are edited, so streamed bot replies appear in later agent context with their final text instead of the first draft.</li>
<li>Skills/Windows: normalize compacted skill prompt locations to forward slashes after home-prefix compaction so Windows skill paths remain readable by model file tools. (#52200) Thanks @chienchandler.</li>
<li>Control UI/Windows: update <code>@openclaw/fs-safe</code> so agent workspace file presence checks fall back correctly on Windows, preventing existing AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, and MEMORY.md files from showing as missing. Fixes #79953. Thanks @lovelefeng-glitch.</li>
<li>Memory: skip managed dreaming cron reconciliation warnings for ordinary cron and heartbeat hook contexts that cannot manage Gateway cron. (#77027) Thanks @rubencu.</li>
<li>Cron: treat Codex app-server turn acceptance, CLI process spawn, and tool starts as execution milestones, preventing isolated runs from tripping the early startup watchdog after work has begun.</li>
<li>Codex app-server: treat current-turn <code><turn_aborted></code> raw markers as terminal so interrupted native-tool turns release Discord agent sessions instead of waiting for the outer timeout.</li>
<li>Yuanbao: bump <code>openclaw-plugin-yuanbao</code> to 2.13.1 to support <code>sourceReplyDeliveryMode: "automatic"</code> for group chat. (#79814) Thanks @loongfay.</li>
<li>Memory: keep <code>memory_search</code> result <code>corpus</code> labels aligned with the hit source, so session transcript hits surface as <code>sessions</code> and memory-file hits stay <code>memory</code>. Fixes #72885. (#71898, #72886) Thanks @rubencu.</li>
<li>Codex app-server: default native plugin app tool approvals to automatic so non-destructive read tools run when destructive actions are disabled.</li>
<li>Plugins: allow untracked local source plugins in the global extensions directory to load TypeScript package entries while keeping managed installs strict about compiled runtime output. Fixes #80503. Thanks @Kaspre.</li>
<li>Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids while converting manifest catalog rows into emitted provider config, so <code>google/gemini-3.1-pro-preview</code> is used for testing instead of <code>google/gemini-3-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids inside saved model allowlists and fallback chains, so proxy routes like <code>openrouter/google/gemini-3-pro-preview</code> are persisted as Gemini 3.1 Pro Preview.</li>
<li>Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids in configured proxy/provider-auth model catalogs, so regenerated config keeps testing <code>google/gemini-3.1-pro-preview</code> instead of <code>google/gemini-3-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired nested Gemini 3 Pro Preview ids while onboarding provider catalog presets, so setup-emitted proxy configs test <code>google/gemini-3.1-pro-preview</code> instead of <code>google/gemini-3-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids in provider catalog rows during generic config writes, so unrelated config changes keep testing <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Models: keep configured fallback chains ahead of configured primary models for override selections with duplicate model ids, preventing fallback jumps to the wrong provider. Fixes #80562.</li>
<li>Native apps: advertise the Gateway protocol compatibility range so chat and node sessions can connect to v3 gateways after additive v4 client updates.</li>
<li>Gateway/agents: keep stale <code>sessions_send</code> ACP manager and <code>web_fetch</code> runtime chunks importable after package updates, preventing live gateways from breaking before restart. Fixes #78804. Thanks @Gomesy72.</li>
<li>Gateway/install: preserve service environment value-source metadata in <code>openclaw gateway install</code>, so systemd reinstall paths keep env-file-backed secrets out of inline unit metadata. Refs #77406, #77427. Thanks @stainlu and @brokemac79.</li>
<li>Auto-reply/reset: include inbound sender context in bare <code>/new</code> and <code>/reset</code> model prompts while keeping startup instructions out of transcript prompts, so agents see sender identity on the first reset turn. Fixes #77360. Thanks @srb11e.</li>
<li>Gateway: avoid synchronous restart-sentinel state probes during post-attach startup, preventing slow Windows or redirected state directories from blocking channel turns. Fixes #79264. Thanks @liyi58.</li>
<li>Agents/auth: update successful model auth profile status with one locked store write, reducing post-model reply latency from duplicate <code>auth-profiles.json</code> saves. Thanks @mcaxtr.</li>
<li>Agents/image: honor explicit <code>image</code> tool model overrides even when <code>agents.defaults.imageModel</code> is unset, restoring one-off vision calls for configured multimodal providers. Fixes #79341. Thanks @haumanto.</li>
<li>Doctor/update: leave live systemd gateway units unchanged during noninteractive update-mode service repair, so update-time doctor does not silently overwrite operator-owned unit directives. Refs #80462.</li>
<li>Update: accept optional leading <code>v</code> prefixes when verifying exact npm package install targets, so <code>openclaw update --tag v2026...</code> does not roll back after installing the matching bare package version. Refs #74069; #80480. Thanks @Kaspre.</li>
<li>Doctor: treat missing plugin ids in <code>plugins.deny</code> as stale config warnings instead of fatal validation errors, and remove them during stale plugin cleanup so update repair does not restore last-known-good config for deny-only stale plugin refs. Refs #77802. Thanks @Kaspre.</li>
<li>Codex app-server: preserve prompt-local current-turn context through context-engine prompt projection, so replied-to Telegram messages stay visible to the Codex model input.</li>
<li>Telegram: pass agent-scoped media roots through gateway message actions so workspace-local media from the active agent is not rejected as cross-agent access. Thanks @frankekn.</li>
<li>CLI/gateway: keep <code>gateway status --deep</code> plugin-aware so configured plugin manifest warnings, including missing channel config metadata, stay visible during install and update smoke checks.</li>
<li>Doctor/status: clarify gateway token source conflict warnings and suppress them inside the managed Gateway service credential context.</li>
<li>Feishu: accept Schema 2 card callbacks whose operator identity is nested under <code>operator.user_id</code>, so card buttons dispatch instead of being dropped as malformed. Fixes #71670. (#71787) Thanks @rubencu.</li>
<li>Feishu: fall back to a top-level group send when normal group quoted replies target a withdrawn or missing message, preventing replies from disappearing silently while preserving native topic safety. Fixes #79349. Thanks @arlen8411.</li>
<li>Doctor: stop flagging the live compatibility agent directory as orphaned when the configured default agent is not <code>main</code>. Fixes #74313. (#74438) Thanks @carlos4s.</li>
<li>Auth/Claude CLI: persist fresher managed external CLI OAuth credentials back to <code>auth-profiles.json</code>, preventing stale <code>anthropic:claude-cli</code> profiles from repeatedly bootstrapping and flooding debug logs. Fixes #80129. Thanks @Caulderein.</li>
<li>Context: render <code>/context map</code> only from actual run context and persist Codex app-server run reports without counting deferred tool-search schemas as prompt-loaded tool schemas.</li>
<li>Codex app-server: report Codex-native tool execution to diagnostics so long-running native <code>bash</code>, web, file, and MCP tools no longer look like stale embedded runs to the watchdog. (#80217)</li>
<li>Codex app-server: refresh Codex account rate limits after subscription usage-limit failures so Discord and other channel replies can show the next reset time instead of saying Codex returned none. Thanks @pashpashpash.</li>
<li>Agents/auth: let Codex-backed OpenAI agent turns use <code>auth.order.openai</code> entries for Codex-compatible OAuth and API-key profiles while keeping existing <code>openai-codex</code> profile ordering valid.</li>
<li>Codex app-server: emit async <code>after_tool_call</code> observations for native tool completions not covered by the native hook relay so observability plugins can record Codex-native tools. (#80372) Thanks @VACInc.</li>
<li>Tasks: route group and channel task completions through the requester session so the parent agent can send the visible summary instead of stopping at a generic task-status line. Fixes #77251. (#77365) Thanks @funmerlin.</li>
<li>Telegram: preserve blank lines between manually indented bullet blocks and following numbered sections in rendered replies. Fixes #76998. Thanks @evgyur.</li>
<li>Agents/sandbox: allow read-only sandbox sessions to read the <code>/agent</code> workspace mount while keeping write/edit/apply_patch workspace-only guarded, restoring <code>read /agent/...</code> for <code>workspaceAccess: "ro"</code>. Fixes #39497. Thanks @stainlu and @teosborne.</li>
<li>Slack: pass configured agent identity through draft preview sends so partial streaming replies keep custom username/avatar on the initial Slack message. Fixes #38235. (#38237) Thanks @lacymorrow.</li>
<li>Slack: support <code>allowBots: "mentions"</code> for bot-authored messages that mention the receiving bot, matching the documented Discord-style mode without accepting every bot message. Fixes #43587. (#43588) Thanks @raw34.</li>
<li>Slack: refresh private file URLs with <code>files.info</code> when inbound DM file events omit or stale attachment URLs, preventing file attachments from being dropped before media hydration. Fixes #50129. (#50200) Thanks @smartchainark.</li>
<li>Slack: add scoped message-tool formatting hints so agents use Markdown for plain sends and direct mrkdwn for Block Kit fields. Fixes #34609. (#50979) Thanks @carrotRakko.</li>
<li>Slack: describe <code>download-file</code> file ids separately from message timestamps and return a targeted recovery error when agents pass <code>messageId</code> instead of <code>fileId</code>. (#74155) Thanks @jarvis-ai-gregmoser.</li>
<li>Slack: retain processed room messages for <code>requireMention=false</code> channels so always-on Slack rooms keep recent conversation context between turns. (#38658) Thanks @syedamaann.</li>
<li>Slack: compile interactive reply directives for direct outbound sends without bypassing the <code>interactiveReplies</code> capability gate, preserving Block Kit for Slack CLI and cron deliveries. (#78220) Thanks @kazamak.</li>
<li>Slack: keep DM last-route updates scoped to the active non-main DM session, including threaded DM turns, so isolated Slack DM sessions do not overwrite the shared main route. (#73085) Thanks @clawSean.</li>
<li>Slack/ACP: route Slack channel and DM messages through configured ACP bindings when no runtime binding exists, keeping bound thread replies pinned to the persistent ACP session and dropping unavailable configured targets instead of falling back to <code>main</code>. (#73101) Thanks @Raasl.</li>
<li>Slack: mark unresolved thread replies as ambiguous and skip them instead of treating them as root channel messages, keeping thread continuation on the SDK-backed participation store. (#75630) Thanks @soichiyo.</li>
<li>Slack: let same-channel message tool sends opt out of inherited thread context with <code>topLevel: true</code> or <code>threadId: null</code>, allowing agents to post a new parent-channel message from inside a Slack thread. Fixes #79807. Thanks @vexclawx31.</li>
<li>Slack: prefer full rich-text block content over truncated socket-mode message previews so long inbound Slack messages reach agents intact. Fixes #79027. Thanks @BobAccentWebDev.</li>
<li>Slack: include structured Slack API error details in setup, probe, streaming, and reply logs while preserving token redaction. (#53966) Thanks @deucemask.</li>
<li>Gateway/agents: keep structured reasons when active-run queueing fails and deprecate the legacy boolean queue helper, so steering and subagent wake diagnostics distinguish completed, non-streaming, and compacting runs. Fixes #80156. Thanks @markus-lassfolk.</li>
<li>System events: dedupe keyed events across the queue while preserving unkeyed, delivery-route, and trust-boundary event identity. (#73040) Thanks @statxc.</li>
<li>Agents/UI: compact exec and tool progress rows by hiding redundant shell tool names, replacing known workspace paths with short context markers, and preserving Discord trace scrubbing for compact command lines.</li>
<li>ACPX: run and await the embedded ACP backend startup probe by default so the gateway <code>ready</code> signal no longer fires before the acpx runtime has either become usable or reported a probe failure; set <code>OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE=0</code> to restore lazy startup. Fixes #79596. Thanks @bzelones.</li>
<li>Gateway/status: surface model-pricing bootstrap and refresh failures as degraded health/status warnings while keeping Gateway liveness healthy. Fixes #79599. Thanks @bzelones.</li>
<li>OpenAI-compatible models: strip prior assistant reasoning fields from replayed Chat Completions history by default, preventing oMLX/vLLM Qwen follow-up turns from rejecting or stalling on stale <code>reasoning</code> payloads. Fixes #46637. Thanks @zipzagster and @lexhoefsloot.</li>
<li>CLI/onboarding: give non-Azure custom providers a safe generated context window and heal legacy 4k wizard entries without overwriting explicit valid small model limits, preventing first-turn compaction loops. Fixes #79428. (#79911) Thanks @Jefsky.</li>
<li>OpenAI-compatible models: add <code>compat.strictMessageKeys</code> to strip Chat Completions replay messages to <code>role</code> and <code>content</code> for strict providers that reject OpenAI-style tool and metadata keys. Fixes #50374. Thanks @choutos.</li>
<li>Bedrock Mantle: add <code>plugins.entries.amazon-bedrock-mantle.config.discovery.enabled=false</code> to suppress automatic Mantle discovery and IAM bearer-token generation while keeping the plugin enabled. Fixes #67288. Thanks @kanekoh.</li>
<li>Ollama: stop native <code>/api/chat</code> requests from copying catalog <code>contextWindow</code> or <code>maxTokens</code> into <code>options.num_ctx</code> unless <code>params.num_ctx</code> is explicitly configured, avoiding pathological prompt-ingestion latency on local large-context models. Fixes #62267. Thanks @BenSHPD.</li>
<li>Ollama: keep the model idle watchdog enabled for <code>*:cloud</code> models routed through a local Ollama host, so cloud-backed tool-loop stalls fail over visibly instead of inheriting local-model no-idle behavior. Fixes #79350. Thanks @geek111.</li>
<li>Voice/Ollama: honor routed voice agent <code>tools.allow</code> for classic embedded voice responses, including empty allowlists, so no-tool Ollama agents do not receive tool schemas. Fixes #79506. Thanks @donkeykong91.</li>
<li>Agents/doctor: warn when channel-routed agents cannot call the <code>message</code> tool, so operators can fix tool policy mismatches before explicit channel actions such as attachments or thread replies fail. Refs #80128. Thanks @jeffjhunterai.</li>
<li>Gateway: reread config from disk after the first in-process restart loop startup, preventing SIGUSR1 restarts from reusing a stale startup snapshot and dropping config written after boot. Fixes #79947. Thanks @TheLevti.</li>
<li>Codex app-server: deliver native image-generation outputs from Codex <code>savedPath</code> events as reply media, so blank-text image generation turns still attach the generated file. Thanks @keshavbotagent.</li>
<li>Network/SSRF: keep pinned automatic DNS lookups on IPv4 when dual-stack hosts also publish AAAA records, and treat <code>EADDRNOTAVAIL</code> as a transient gateway network failure instead of a fatal crash. Fixes #80078. Thanks @takamasa-aiso.</li>
<li>Control UI: show compact one-line live/idle/terminal run status badges in the Sessions table and rename the active-minute filter to its updated-within meaning. Fixes #78307. Thanks @BunsDev.</li>
<li>Control UI: scope chat session-list refreshes by agent and skip disk-only agent store discovery for configured-only lists, preventing post-first-message session switching stalls on large Windows stores. Fixes #79675. Thanks @lovelefeng-glitch, @BunsDev.</li>
<li>Control UI: allow Appearance tweakcn theme imports through the served CSP so browser-local custom theme links no longer fail with a <code>connect-src</code> violation. Fixes #78504. Thanks @BunsDev.</li>
<li>Control UI/config: remove plugin allowlist entries that the form auto-added when a plugin enable toggle is reverted before saving, so reverting the visible toggle clears dirty state without persisting unintended allowlist changes. (#78329) Thanks @samzong.</li>
<li>Gateway/mobile: reuse bootstrap-issued device-token scopes on handoff reconnects and surface device-token scope mismatches separately from token mismatches while preserving full shared-token dashboard/native sessions. Fixes #79292. Thanks @BunsDev.</li>
<li>Media/host-read: allow buffer-verified gzip, tar, and 7z archives in the shared host-local media validator alongside ZIP and document attachments.</li>
<li>Plugins/install: retry managed npm plugin installs without npm alias overrides after npm's <code>Invalid comparator: npm:</code> failure, so older npm versions can install official plugins instead of aborting. (#80539) Thanks @rubencu.</li>
<li>Plugins/doctor: invalidate persisted plugin registry snapshots when plugin diagnostics point at deleted source paths, so <code>openclaw doctor</code> stops repeating stale warnings after a local extension is replaced by a managed npm plugin. Fixes #80087. (#80134) Thanks @hclsys.</li>
<li>Doctor/OpenAI Codex: preserve Codex auth intent when auto-repairing legacy <code>openai-codex/*</code> model refs to canonical <code>openai/*</code> by adding provider/model-scoped Codex runtime policy, preventing repaired configs from falling through to direct OpenAI API-key auth. Fixes #78533 and #78570. Thanks @superck110 and @Azmodump.</li>
<li>CLI/agents: surface durable message delivery status from <code>sendDurableMessageBatch</code> in <code>deliverAgentCommandResult</code> and <code>openclaw agent --json --deliver</code>, preserving suppressed hook outcomes as terminal no-retry results while exposing partial and failed sends for automation. Supersedes #53961 and #57755. Thanks @Kaspre.</li>
<li>Agents: apply the LLM idle watchdog while provider stream setup is still pending, preventing silent pre-stream model hangs from waiting for the full agent timeout.</li>
<li>Cron: let isolated self-cleanup runs inspect their own job run history while keeping other cron jobs and mutation actions blocked. Fixes #80019. Thanks @hclsys.</li>
<li>Cron: report isolated agent-turn setup and pre-model stalls with phase-specific timeout errors instead of waiting for the full job budget when no model call starts. Fixes #74803. Thanks @jeffsteinbok-openclaw and @dgkim311.</li>
<li>CLI/plugins: treat arbitrary unknown subcommands outside plugin CLI metadata as normal unknown commands instead of suggesting <code>plugins.allow</code>, while preserving allowlist guidance for real plugin command roots. Fixes #80109. (#80123) Thanks @kagura-agent.</li>
<li>CLI/config: persist explicit <code>config set</code> and <code>config patch</code> values that equal runtime defaults instead of reporting success while dropping them. Fixes #79856. (#80106) Thanks @abodanty and @hclsys.</li>
<li>OpenAI/realtime voice: accept Codex-compatible legacy audio and transcript event aliases so provider protocol drift does not drop assistant audio or captions.</li>
<li>Discord/voice: keep default agent-proxy realtime sessions from auto-speaking filler before the forced OpenClaw consult answer, finish Discord playback on realtime response completion, and queue later exact-speech answers until playback idles to avoid mid-sentence replacement.</li>
<li>Gateway: return deterministic <code>400 invalid_request_error</code> responses for malformed encoded session-kill HTTP paths instead of letting route-shaped requests fall through to later Gateway handlers. (#72439) Thanks @rubencu.</li>
<li>Control UI: serve root PWA and favicon assets from <code>/__openclaw__/</code> SPA routes so tab icons, install metadata, and the service worker do not 404 after internal navigation. Fixes #80072. Thanks @CodeNovice2017.</li>
<li>Exec/safe bins: compare trusted safe-bin dirs with path-specific case folding on case-insensitive filesystems so Windows and default macOS paths match without weakening case-sensitive mounts. (#42131) Thanks @hkochar.</li>
<li>OpenAI/realtime voice: honor disabled input-audio interruption locally so server VAD speech-start events do not clear Discord playback after operators set <code>interruptResponseOnInputAudio: false</code>.</li>
<li>Telegram: keep no-response DM turns quiet instead of rewriting them into visible silent-reply chatter. Fixes #78188. (#78228) Thanks @Beandon13.</li>
<li>Telegram: handle managed select button callbacks before the raw callback fallback while preserving delimiter-containing option values such as <code>env|prod</code>. (#79816) Thanks @moeedahmed.</li>
<li>OpenAI-compatible models: handle JSON chat-completion bodies returned to streaming requests, preserving reasoning fields and visible text instead of completing an empty agent turn. Fixes #77870.</li>
<li>Discord/models: defer model picker component interactions before loading route, model, and preference data, preventing "This interaction failed" timeouts under gateway load. Fixes #77283. Thanks @colin-chang.</li>
<li>xAI: expose <code>/think low|medium|high</code> for reasoning-capable Grok models and keep <code>reasoning.effort</code> on native Responses payloads while preserving off-only behavior for non-reasoning routes. Fixes #79210. Thanks @colinmcintosh.</li>
<li>CLI/media: let explicit image description model refs use bundled static provider catalogs and generic model-backed image hooks, so <code>openclaw infer image describe --model zai/glm-4.6v</code> works like direct model runs and Anthropic auth probes avoid stale Claude 3 Haiku catalog entries.</li>
<li>Models/Anthropic: add <code>anthropic/claude-haiku-4-5</code> to Anthropic API-key agent allowlist defaults when an Anthropic default model is configured, so cron model overrides can select the current Haiku alias. Fixes #78000.</li>
<li>Agents/compaction: initialize built-in context engines before CLI transcript compaction resolves the default engine, preventing clean-process <code>legacy</code> engine registration failures during CLI session persistence. Fixes #79446. Thanks @TurboTheTurtle.</li>
<li>Agents/Anthropic-compatible: strip replayed thinking blocks for custom Anthropic-compatible models that explicitly declare <code>supportsReasoningEffort: false</code>, preventing Kimi-compatible providers from resending unsupported <code>thinking</code> content. Fixes #47452.</li>
<li>Kimi: keep Anthropic-compatible thinking streams valid by supplying required thinking budgets and enough output room for hidden reasoning plus final text. (#80481) Thanks @InTheCloudDan.</li>
<li>Browser: wait longer for existing-session Chrome MCP status and non-deep doctor probes so slow first attaches do not falsely report offline while keeping raw CDP status probes short. (#77473) Thanks @rubencu.</li>
<li>Gateway/logging: install console capture before foreground Gateway fast-path parsing and suppress known libsignal session dumps even in verbose mode, preventing raw terminal logs from printing WhatsApp session key material. (#76306) Thanks @rubencu.</li>
<li>Exec approvals: keep <code>exec.approval.list</code> on the lightweight policy-summary path so listing pending approvals no longer loads the rich tree-sitter command explainer. (#76943) Thanks @rubencu.</li>
<li>Agents: surface concise default-visible warnings when <code>exec</code>/<code>bash</code> tool calls fail after the assistant claims success, while keeping raw stderr hidden unless verbose details are enabled. Fixes #60497. (#80003) Thanks @jbetala7.</li>
<li>Channels/iMessage: keep redacted failed probe details in non-sensitive health snapshots so Full Disk Access failures no longer appear as configured/OK in status output. Fixes #79795.</li>
<li>Agents: stop blank model-emitted tool calls before dispatch while preserving id-based tool-name recovery, preventing Kimi/NVIDIA blank-name retry loops without creating a callable <code>_blank</code> sentinel. Fixes #34129. (#56391) Thanks @smartchainark.</li>
<li>Agents/Telegram: deliver the canonical final assistant answer instead of replaying accumulated pre-tool text blocks, preventing duplicate Telegram replies and raw-looking tool-output fragments from leaking into chat delivery. Fixes #79621 and #79986. Thanks @nonzeroclaw and @dudaefj.</li>
<li>Auto-reply/TUI: keep fallback timeout recovery deliverable after a primary model lifecycle error by emitting fallback progress and deferring terminal TUI errors until recovery has a chance to finish. Fixes #80000. (#80009) Thanks @TurboTheTurtle.</li>
<li>Heartbeat: clear stale auto fallback model overrides when the configured default model changes, so heartbeat runs follow updated <code>agents.defaults.model.primary</code> without requiring a manual reset. Fixes #74284. Thanks @brtkwr and @bitloi.</li>
<li>CLI/agent: let <code>openclaw agent --model</code> use the backend/admin Gateway scope without cached device-token scopes silently downscoping the request. (#78837) Thanks @VACInc.</li>
<li>CLI/help: keep help and version invocations configless while improving shared port, channel, plugin, task, session, message, pairing, and auth recovery text.</li>
<li>CLI/config: explain strict JSON parse failures with a valid example and the plain-string escape hatch.</li>
<li>CLI/secrets: turn offline Gateway reload failures into actionable recovery text.</li>
<li>CLI/channels: explain missing or ambiguous channel selections with next commands.</li>
<li>CLI/channels: defer guided channel status collection until a channel is selected, keeping <code>openclaw channels add</code> first screen quieter.</li>
<li>CLI/channels: exit guided channel setup cleanly on cancellation instead of printing the internal wizard error.</li>
<li>Plugins/CLI: route disabled Matrix and LanceDB memory command roots to plugin-enable guidance instead of generic unknown-command errors.</li>
<li>Browser/Docker: detect Playwright-managed Chromium from <code>PLAYWRIGHT_BROWSERS_PATH</code> and the default Playwright cache on Linux, so Docker installs that persist <code>/home/node/.cache/ms-playwright</code> no longer need <code>browser.executablePath</code>.</li>
<li>Ollama: keep DeepSeek V4 cloud models thinking-capable even when Ollama Cloud <code>/api/show</code> omits the <code>thinking</code> capability, so <code>/think high</code> no longer rejects <code>ollama/deepseek-v4-*:cloud</code>.</li>
<li>ACPX/Claude ACP: keep foreground prompts waiting for their own result when autonomous task-notification results arrive during the same session, and retarget the patch for Claude Agent ACP <code>0.33.1</code>.</li>
<li>WhatsApp: keep Baileys media uploads from passing non-Dispatcher agents to undici in <code>7.0.0-rc10</code>, and patch the bundled Baileys declaration so the latest tsdown build stays warning-clean.</li>
<li>Build: keep tsdown <code>0.22.0</code> warning-clean by externalizing known third-party declaration edges and replacing relative channel config module augmentations with explicit built-in channel fields.</li>
<li>ACP sessions: map canonical runtime options to backend-advertised ACP config keys like Claude's <code>effort</code> while keeping persisted OpenClaw state canonical. (#79926) Thanks @InTheCloudDan.</li>
<li>Models/Discord: support <code>provider/*</code> entries in <code>agents.defaults.models</code> so <code>/model</code>, <code>/models</code>, and model pickers can show dynamically discovered models for selected providers without exact model allowlists. Fixes #79485. Thanks @rendrag-git.</li>
<li>Gateway/watch: rebuild or restage missing bundled-plugin dist and runtime-postbuild outputs before launching the Gateway from a source checkout, preventing incomplete watch-mode runtime trees. (#70805) Thanks @rubencu.</li>
<li>CLI/update: allow restart health probes from the previous gateway protocol during self-update, and make plugin dry-runs report exact npm target versions instead of <code>unknown</code> while preserving unchanged status.</li>
<li>OpenAI/Codex: forward persisted <code>openai-codex</code> OAuth profile metadata into Codex plugin harness attempts after canonical <code>openai/*</code> migration, so OAuth-only installs keep using native Codex auth instead of falling through to direct OpenAI API-key auth. Fixes #79978.</li>
<li>OpenAI/Codex: point gateway missing-key recovery and wizard docs at the canonical <code>openai/gpt-5.5</code> plus Codex OAuth route, and fix trajectory export errors so they suggest the valid <code>openclaw sessions</code> command.</li>
<li>Google/Gemini: normalize retired <code>google/gemini-3-pro-preview</code> primary, fallback, and model-map refs during config load and unrelated config writes so saved config keeps targeting Gemini 3.1 Pro Preview.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside emitted Google provider model config, so regenerated models.json rows test <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids for explicit OpenAI-compatible Google and Gemini CLI provider configs, so emitted config targets <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids preserved from existing merged models.json providers so config emission keeps targeting <code>google/gemini-3.1-pro-preview</code>.</li>
<li>Google/Gemini: normalize retired Gemini 3 Pro Preview ids inside provider auth config patches so setup-emitted provider catalogs test <code>google/gemini-3.1-pro-preview</code>.</li>
<li>GitHub Copilot: mint short-lived Copilot API tokens with the same <code>vscode-chat</code> integration identity used by runtime requests, and refresh legacy cached tokens missing that identity so image-capable Copilot models no longer inherit the <code>copilot-language-server</code> scope. Fixes #79946, #80074. Thanks @TurboTheTurtle.</li>
<li>Plugins/doctor: drop stale managed npm install records when <code>openclaw doctor --fix</code> removes npm packages that shadow bundled plugins, so the rebuilt registry no longer resurrects the removed package metadata.</li>
<li>Doctor: warn when a per-agent model config omits the <code>fallbacks</code> key and <code>agents.defaults.model.fallbacks</code> is non-empty. Covers both string-form (<code>"model": "..."</code>) and partial-object form (<code>"model": { "primary": "..." }</code>) — both silently clobber the defaults chain at runtime. Use <code>"fallbacks": []</code> to explicitly opt out of fallbacks, or add <code>"fallbacks": [...]</code> to inherit or override. Fixes #79369. Thanks @Kaspre.</li>
<li>Discord/voice: reuse or suppress late realtime consult tool calls without stealing newer speaker context or speaking forced fallback answers twice.</li>
<li>Discord/voice: skip likely incomplete realtime forced-consult transcript fragments and non-actionable closings so stale partial speech does not queue delayed answers over the next turn.</li>
<li>Discord/voice: keep realtime forced consults from clearing active exact-speech playback, so back-to-back voice answers queue instead of cutting each other off.</li>
<li>Discord/voice: synthesize realtime playback timestamps from emitted Discord PCM so OpenAI realtime barge-in truncation no longer sees <code>audioEndMs=0</code> and skips legitimate interruptions.</li>
<li>Plugin SDK: keep activated linked plugin runtime facades loadable when bundled plugin fallback is disabled. Thanks @shakkernerd.</li>
<li>Feishu: auto-thread <code>message(action="send")</code> replies inside the topic when the active session is group_topic or group_topic_sender, and propagate <code>replyInThread</code> through text, card, and media outbound adapters so topic-scoped sessions no longer post at the group root. Fixes #74903. (#77151) Thanks @ai-hpc.</li>
<li>WhatsApp: pass routing context into voice-note transcript echo preflight so echoed transcripts can deliver to the originating chat. Fixes #79778. (#79788) Thanks @hclsys.</li>
<li>Cron/failover: classify structured OpenAI-compatible <code>server_error</code> payloads as <code>server_error</code>, expose that reason in cron state, and let one-shot cron retry policy honor <code>retryOn: ["server_error"]</code> without requiring raw <code>5xx</code> text. (#45594) Thanks @clovericbot.</li>
<li>Slack: wake the resolved thread session after interactive reply button/select clicks and carry Slack delivery context through the queued interaction event, so clicks continue the visible conversation. Fixes #79676 and #61502. (#79836) Thanks @velvet-shark, @tianxiaochannel-oss88, and @Saicheg.</li>
<li>WhatsApp/streaming: send only the new suffix when text-end block replies repeat prior preambles across tool-call cycles, preventing cumulative WhatsApp preamble messages. Fixes #78946. (#79120) Thanks @brokemac79 and @papawattu.</li>
<li>Tests/security audit: sandbox <code>audit-exec-surface.test.ts</code> under a per-case OpenClaw home tempdir, redirecting <code>OPENCLAW_HOME</code> (which wins over <code>HOME</code>/<code>USERPROFILE</code> in <code>resolveRawHomeDir</code>) alongside <code>HOME</code> and <code>USERPROFILE</code>, so its <code>saveExecApprovals(...)</code> calls never touch the live <code>~/.openclaw/exec-approvals.json</code> on the host running the suite. Sibling exec-approvals tests already used the tempdir pattern; this file did not, so running <code>pnpm test</code> against a contributor's local checkout was silently truncating their real approvals to <code>{ "version": 1, "agents": {} }</code>. (#79885) Thanks @omarshahine.</li>
<li>ACP/gateway: preserve <code>AcpRuntimeError</code> cause chain (code/method/JSON-RPC detail) through the lifecycle boundary so gateway logs, telegram replies, and tool-result text show the actual upstream failure instead of opaque <code>Internal error</code>/<code>[object Object]</code>, with redaction applied before the chain reaches log or reply surfaces.</li>
<li>Channels/iMessage: wire <code>action: "reply"</code> attachments through <code>imsg send-rich --file</code> when the installed imsg build advertises that capability (probed once via <code>imsg send-rich --help</code> and cached on the private-API status). Reply now hydrates <code>media</code>/<code>mediaUrl</code>/<code>fileUrl</code>/<code>mediaUrls[0]</code>/<code>filePath</code>/<code>path</code>/base64 <code>buffer</code>+<code>filename</code> through the shared outbound resolver, stages buffers via the existing <code>withTempFile</code> helper, rejects <code>http(s)://</code> URL attachments with a targeted error pointing callers at <code>send</code>'s full attachment-resolver pipeline, and falls back to the explicit <code>imsg#114 not landed yet</code> error on older imsg builds. Depends on the upstream <code>openclaw/imsg#114</code> capability landing in an installable release; until then the new path stays gated and users see the same explicit fallback <code>#79822</code> introduced. (#79864) Thanks @omarshahine.</li>
<li>Telegram: preserve the first-preview debounce while appending true partial-stream deltas, so edited draft previews no longer duplicate earlier text when providers emit incremental output. (#80045) Thanks @TurboTheTurtle.</li>
<li>Agents/Anthropic: report 1M session context for Claude Opus/Sonnet 4 models even when local model config still advertises 200k, matching model discovery and preventing premature status/UI overflow. Fixes #66766.</li>
<li>Models/OpenRouter: hide missing-auth direct provider rows in <code>/model status</code> when they are only duplicated by a nested OpenRouter model id such as <code>openrouter/google/...</code>, while preserving explicitly configured direct providers. Fixes #62317.</li>
<li>Models: preserve an explicitly selected provider/model such as <code>opencode-go/deepseek-v4-pro</code> when another provider owns the same bare model alias. Fixes #79325.</li>
<li>Models/config: explain missing <code>models.providers.<provider>.models[]</code> registration when a model exists only in <code>agents.defaults.models</code>, instead of returning a bare unknown-model error. Fixes #80089.</li>
<li>MCP/tools: prefix bundle MCP server/tool fragments that would start with digits, keeping generated tool names valid for Moonshot/Kimi and other strict providers. Fixes #79179.</li>
<li>Models/OpenRouter: treat <code>403 API key budget limit exceeded</code> as billing so model fallback advances instead of retrying the exhausted primary. Fixes #60191. Thanks @omgitsgela.</li>
<li>Models/OpenRouter: repair stale session overrides that lost the outer <code>openrouter/</code> provider wrapper, so sessions return to the configured OpenRouter model instead of failing as an unknown direct-provider model. Fixes #78161. Thanks @hjamal7-bit.</li>
<li>Google/Gemini: default API-key onboarding back to <code>google/gemini-3.1-pro-preview</code> so fresh Gemini test configs exercise Gemini 3.1 Pro Preview.</li>
<li>Telegram: show full provider/model labels for nested OpenRouter model ids in the model picker, so <code>openrouter/openai/gpt-5.4-mini</code> no longer displays as <code>openai/gpt-5.4-mini</code>. Fixes #67792. (#72752) Thanks @iot2edge.</li>
<li>Models/OpenRouter: preserve live <code>supported_parameters</code> tool support metadata so non-tool Perplexity Sonar models no longer receive agent tool payloads and fall back unnecessarily. Fixes #64175. Thanks @Catfish-75.</li>
<li>Models/OpenRouter: add MoonshotAI Kimi K2.5 to the bundled OpenRouter catalog so onboarding/model pickers can offer it without waiting for live discovery. Fixes #14601.</li>
<li>Models/OpenRouter: keep keyRef/tokenRef-backed auth profiles visible to read-only PI model discovery, so OpenRouter models stay available in model pickers without storing plaintext keys. Fixes #58106. Thanks @ThalynLabs.</li>
<li>Models/list: include explicit configured provider rows and read-only auth-backed catalog rows in the default configured view without loading PI's full registry, keeping Control UI pickers aligned with usable model auth. Refs #79381. Thanks @ismael-81.</li>
<li>Security/audit: honor <code>tools.byProvider["provider/model"].deny</code> when reporting small-model web/browser exposure, so per-model OpenRouter mitigations clear the <code>models.small_params</code> exposure signal. Fixes #80118.</li>
<li>Models/Moonshot: accept direct <code>moonshotai/...</code> and <code>moonshot-ai/...</code> refs as aliases for canonical <code>moonshot/...</code>, so copied OpenRouter Kimi ids no longer fail as unknown direct models. Fixes #73876. (#74946) Thanks @jeffrey701.</li>
<li>Kimi Code: use Kimi's stable <code>kimi-for-coding</code> API model id in bundled catalog, onboarding, and docs while normalizing legacy <code>kimi-code</code> and <code>k2p5</code> refs. Fixes #79965.</li>
<li>Telegram: render cached reply targets and nearby group chatter as one selected conversation context window, so stale replies no longer split JSON reply chains from local chat context.</li>
<li>Volcengine/Kimi: strip provider-unsupported tool schema length and item constraint keywords for direct and coding-plan models so hosted Kimi runs do not reject message tools with <code>minLength</code>. Fixes #38817.</li>
<li>DeepSeek: backfill V4 <code>reasoning_content</code> replay fields for unowned OpenAI-compatible proxy providers, preventing follow-up request failures outside the bundled DeepSeek and OpenRouter routes. Fixes #79608.</li>
<li>iMessage: emit a WARN log when an action is blocked because the imsg private API bridge is not attached, so operators see the silent-drop in <code>~/.openclaw/logs/openclaw.log</code> instead of having to read per-session trajectory JSONL <code>tool.result</code> payloads. Common after a gateway restart un-injects the dylib from Messages.app. (#80035) Thanks @omarshahine.</li>
<li>Codex: cross-fill missing <code>thread.id</code> and <code>thread.sessionId</code> before schema validation so live Codex app-server responses that omit <code>sessionId</code> no longer fail <code>thread/start</code> or <code>thread/resume</code>. Fixes #80124. (#80137) Thanks @kagura-agent.</li>
<li>Agents/Pi: wait for embedded abort cleanup to settle before releasing the session write lock, preventing follow-up turns from racing previous prompt teardown. (#80239) Thanks @samzong.</li>
<li>WhatsApp: downgrade OpenClaw watchdog-triggered Web reconnects from runtime errors to recovery warnings and clear the recovered reconnect status after the next healthy connection. (#77026) Thanks @rubencu.</li>
<li>ACPX/Windows: hide the MCP proxy target child process window on Windows so ACP-backed agents do not flash or fail because of terminal window handling. Fixes #60672. (#60678) Thanks @KChow-ctrl.</li>
<li>Agents: abort generic repeated no-progress tool loops at the critical threshold when identical calls keep returning identical outcomes. (#80668) Thanks @frankekn.</li>
<li>Exec approvals: omit generated command highlights for non-POSIX Windows and shell-wrapper approval commands until those command languages have native highlighting support. (#80566) Thanks @jesse-merhi.</li>
<li>Telegram: keep verbose tool progress and result drafts separate from the final assistant answer so tool output no longer blends into the final Telegram message. (#80294) Thanks @jalehman.</li>
<li>Plugin SDK/Windows: enable the native require fast path for root <code>openclaw/plugin-sdk</code> dist aliases instead of forcing Jiti transforms. (#80878) Thanks @medns.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.12/OpenClaw-2026.5.12.zip" length="52670462" type="application/octet-stream" sparkle:edSignature="RhckloxLoZhtGQZ+0jrH0qWN3py61an+kiAdgEJY9IZGekTKmJ+DWHXY3ixQJYvKf2WLgxOzaY6Jy27pF+kECw=="/>
</item>
<item>
<title>2026.5.7</title>
<pubDate>Thu, 07 May 2026 22:36:27 +0000</pubDate>
@@ -449,368 +923,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.2/OpenClaw-2026.5.2.zip" length="51078259" type="application/octet-stream" sparkle:edSignature="NwoecacHxJOYpltNmB/y7LV5I8ZIh5pENWSydbOM1vsfgSrcb7pRP+Zm2nih1IAq7hh1tOmQ0XWnsohic7U4DA=="/>
</item>
<item>
<title>2026.4.29</title>
<pubDate>Thu, 30 Apr 2026 21:47:22 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026042990</sparkle:version>
<sparkle:shortVersionString>2026.4.29</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.29</h2>
<h3>Highlights</h3>
<ul>
<li>Messaging and automation get active-run steering by default, visible-reply enforcement, spawned subagent routing metadata, and opt-in follow-up commitments for heartbeat-delivered reminders. Thanks @vincentkoc, @scoootscooob, @samzong, and @vignesh07.</li>
<li>Memory grows into a people-aware wiki with provenance views, per-conversation Active Memory filters, partial recall on timeout, and bounded REM preview diagnostics. Thanks @vincentkoc, @quengh, @joeykrug, and @samzong.</li>
<li>Provider/model coverage expands with NVIDIA onboarding/catalogs plus faster manifest-backed model/auth paths, Bedrock Opus 4.7 thinking parity, and safer Codex/OpenAI-compatible replay and streaming behavior. Thanks @eleqtrizit, @shakkernerd, @prasad-yashdeep, @woodhouse-bot, and @LyHug.</li>
<li>Gateway and packaged-plugin reliability focuses on slow-host startup, reusable model catalogs, event-loop readiness diagnostics, runtime-dependency repair, stale-session recovery, and version-scoped update caches. Thanks @lpendeavors, @DerFlash, @vincentkoc, @pashpashpash, and @jhsmith409.</li>
<li>Channel fixes cluster around Slack Block Kit limits, Telegram proxy/webhook/polling/send resilience, Discord startup/rate-limit handling, WhatsApp delivery/liveness, and Microsoft Teams/Matrix/Feishu edge cases. Thanks @slackapi, @SymbolStar, @djgeorg3, @TinyTb, @dseravalli, @nklock, and @alex-xuweilong.</li>
<li>Security and operations add OpenGrep scanning, sharper GHSA triage policy, safer exec/pairing/owner-scope handling, Docker/onboarding automation, and web-fetch IPv6 ULA opt-in for trusted proxy stacks. Thanks @jesse-merhi, @pgondhi987, @mmaps, @jinjimz, and @jeffrey701.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Security/tools: configured tool sections (<code>tools.exec</code>, <code>tools.fs</code>) no longer implicitly widen restrictive profiles (<code>messaging</code>, <code>minimal</code>). Users who need those tools under a restricted profile must add explicit <code>alsoAllow</code> entries; a startup warning identifies affected configs. Fixes #47487. Thanks @amknight.</li>
<li>Agents/commitments: add opt-in inferred follow-up commitments with hidden batched extraction, per-agent/per-channel scoping, heartbeat delivery, CLI management, a simple <code>commitments.enabled</code>/<code>commitments.maxPerDay</code> config, and heartbeat-interval due-time clamping so magical check-ins do not echo immediately. (#74189) Thanks @vignesh07.</li>
<li>Messages/queue: make <code>steer</code> drain all pending Pi steering messages at the next model boundary, keep legacy one-at-a-time steering as <code>queue</code>, and add a dedicated steering queue docs page. Thanks @vincentkoc.</li>
<li>Messages/queue: default active-run queueing to <code>steer</code> with a 500ms followup fallback debounce, and document the queue modes, precedence, and drop policies on the command queue page. Thanks @vincentkoc.</li>
<li>Messages: add global <code>messages.visibleReplies</code> so operators can require visible output to go through <code>message(action=send)</code> for any source chat, while <code>messages.groupChat.visibleReplies</code> stays available as the group/channel override. Thanks @scoootscooob.</li>
<li>Gateway/events: surface <code>spawnedBy</code> on subagent chat and agent broadcast payloads so clients can route child session events without an extra session lookup. (#63244) Thanks @samzong.</li>
<li>Memory/wiki: add agent-facing people wiki metadata, canonical aliases, person cards, relationship graphs, privacy/provenance reports, evidence-kind drilldown, and search modes for person lookup, question routing, source evidence, and raw claims. Thanks @vincentkoc.</li>
<li>Active Memory: add optional per-conversation <code>allowedChatIds</code> and <code>deniedChatIds</code> filters so operators can enable recall only for selected direct, group, or channel conversations while keeping broad sessions skipped. (#67977) Thanks @quengh.</li>
<li>Active Memory: return bounded partial recall summaries when the hidden memory sub-agent times out, including the default temporary-transcript path, so useful recovered context is not discarded. (#73219) Thanks @joeykrug.</li>
<li>Gateway/memory: add a read-only <code>doctor.memory.remHarness</code> RPC so operator clients can preview bounded REM dreaming output without running mutation paths. (#66673) Thanks @samzong.</li>
<li>Providers/NVIDIA: add the NVIDIA provider with API-key onboarding, setup docs, static catalog metadata, and literal model-ref picker support so NVIDIA hosted models can be selected with their provider prefix intact. (#71204) Thanks @eleqtrizit.</li>
<li>Models: suppress explicitly configured openai-codex/gpt-5.4-mini inline entries so a stale models config written by <code>openclaw doctor --fix</code> cannot bypass the manifest capability block and cause repeated assistant-turn failures when the runtime switches to that model on ChatGPT-backed Codex accounts. Conditional suppressions (e.g. qwen Coding Plan endpoint guards) remain bypassable by explicit user configuration. (#74451) Thanks @0xCyda, @hclsys, and @Marvae.</li>
<li>Added SQLite-backed plugin state store (<code>api.runtime.state.openKeyedStore</code>) for restart-safe keyed registries with TTL, eviction, and automatic plugin isolation. Thanks @amknight.</li>
<li>Plugin SDK: mark remaining legacy alias exports and diffs tool/config aliases with deprecation metadata, and add a guard so future legacy alias comments require <code>@deprecated</code> tags. Thanks @vincentkoc.</li>
<li>CLI/QR/dependencies: internalize small terminal progress and QR wrapper helpers while keeping the real QR encoder dependency direct, reducing the default runtime dependency graph without changing QR output behavior. Thanks @vincentkoc.</li>
<li>Dependencies: refresh workspace runtime, plugin, and tooling packages, including ACP, Pi, AWS SDK, TypeBox, pnpm, oxlint, oxfmt, jsdom, pdfjs, ciao, and tokenjuice, while keeping patched ACP behavior and lint gates current. Thanks @mariozechner.</li>
<li>Gateway/dev: run <code>pnpm gateway:watch</code> through a named tmux session by default, with <code>gateway:watch:raw</code> and <code>OPENCLAW_GATEWAY_WATCH_TMUX=0</code> for foreground mode, so repeated starts respawn an inspectable watcher without trapping the invoking agent shell. Thanks @vincentkoc.</li>
<li>Gateway/diagnostics: emit an opt-in startup diagnostics timeline that records gateway lifecycle and plugin-load phases behind a config flag, so slow-start diagnosis no longer requires bespoke instrumentation. Thanks @shakkernerd.</li>
<li>Control UI/i18n: extend the locale registry with new Persian (fa), Dutch (nl), Vietnamese (vi), Italian (it), Arabic (ar), and Thai (th) entries and ship <code>fa</code>, <code>nl</code>, <code>vi</code>, and <code>zh-TW</code> docs glossaries, so the docs translation pipeline and the Control UI language picker stay aligned across surfaces. Thanks @vincentkoc.</li>
<li>Channels: add Yuanbao channel docs entrance so the Tencent Yuanbao bot appears in the channel listing and sidebar navigation. (#73443) Thanks @loongfay.</li>
<li>Channels/Yuanbao: update plugin GitHub location to YuanbaoTeam/yuanbao-openclaw-plugin and add "yuanbao" alias to channel catalog. (#74253) Thanks @loongfay.</li>
<li>Docker setup: add <code>OPENCLAW_SKIP_ONBOARDING</code> so automated Docker installs can skip the interactive onboarding step while still applying gateway defaults. (#55518) Thanks @jinjimz.</li>
<li>Security policy: classify media/base64 decode and format-conversion overhead after configured acceptance limits as performance-only for GHSA triage unless a report demonstrates a limit bypass, crash, exhaustion, data exposure, or another boundary bypass. (#74311)</li>
<li>Security/OpenGrep: add a precise OpenGrep rulepack, source-rule compiler, provenance metadata check, and PR/full scan workflows that validate first-party code and rulepack-only changes while uploading SARIF to GitHub Code Scanning. (#69483) Thanks @jesse-merhi.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Providers/OpenAI Codex: preserve existing wrapped Codex streams during OpenAI attribution so PI OAuth bearer injection reaches ChatGPT/Codex Responses, and strip native Codex-only unsupported payload fields without touching custom compatible endpoints. (#75111) Thanks @keshavbotagent.</li>
<li>Agents/tool-result guard: use the resolved runtime context token budget for non-context-engine tool-result overflow checks, so long tool-heavy sessions no longer compact early when <code>contextTokens</code> is larger than native <code>contextWindow</code>. Fixes #74917. Thanks @kAIborg24.</li>
<li>Gateway/systemd: exit with sysexits 78 for supervised lock and <code>EADDRINUSE</code> conflicts so <code>RestartPreventExitStatus=78</code> stops <code>Restart=always</code> restart loops instead of repeatedly reloading plugins against an occupied port. Fixes #75115. Thanks @yhyatt.</li>
<li>Agents/runtime: skip blank visible user prompts at the embedded-runner boundary before provider submission while still allowing internal runtime-only turns and media-only prompts, so Telegram/group sessions no longer leak raw empty-input provider errors when replay history exists. Fixes #74137. Thanks @yelog, @Gracker, and @nhaener.</li>
<li>Auto-reply/group chats: fall back to automatic source delivery when a channel precomputes message-tool-only replies but the <code>message</code> tool is unavailable, so Discord/Slack-style group turns do not silently complete without a visible reply. Fixes #74868. Thanks @kagura-agent.</li>
<li>Browser/gateway: share one browser control runtime across the HTTP control server and <code>browser.request</code>, and refresh browser profile config from the source snapshot, so CLI status/start honors configured <code>browser.executablePath</code>, <code>headless</code>, and <code>noSandbox</code> instead of falling back to stale auto-detection. Fixes #75087; repairs #73617. Thanks @civiltox and @martingarramon.</li>
<li>Agents/subagents: bound automatic orphan recovery with persisted recovery attempts and a wedged-session tombstone, and teach task maintenance/doctor to reconcile those sessions so restart loops no longer require manual <code>sessions.json</code> surgery. Fixes #74864. Thanks @solosage1.</li>
<li>Gateway/startup: skip pre-bind web-fetch provider discovery for credential-free <code>tools.web.fetch</code> config, so Docker/Kubernetes gateways bind even when optional fetch limits are present. Fixes #74896. Thanks @KoykL.</li>
<li>Infra/tmp: tolerate concurrent temp-dir permission repairs by rechecking directories that another process already tightened, so parallel ACP subprocess startup no longer throws <code>Unsafe fallback OpenClaw temp dir</code>. Fixes #66867. Thanks @Kane808-AI and @jarvisz8.</li>
<li>Signal: match group allowlists against inbound Signal group ids as well as sender ids, and process explicitly configured Signal groups without requiring mentions unless <code>requireMention</code> is set. Fixes #53308. Thanks @minupla and @juan-flores077.</li>
<li>Slack: require bot-authored room messages with <code>allowBots=true</code> to come from an explicitly channel-allowlisted bot or from a room where an explicit Slack owner is present, so broad bot relays cannot run unattended. Fixes #59284. Thanks @andrewhong-translucent.</li>
<li>Signal: bound <code>signal-cli</code> installer release and archive downloads with explicit timeouts, declared and streamed size checks, and partial-file cleanup. Fixes #54153. Thanks @jinduwang1001-max and @juan-flores077.</li>
<li>Signal: derive <code>getAttachment</code> HTTP response caps from <code>channels.signal.mediaMaxMb</code> with base64 headroom, so inbound photos and videos no longer drop behind the 1 MiB RPC default. Fixes #73564. Thanks @heyhudson.</li>
<li>Signal: keep the long-lived receive SSE monitor open while idle instead of applying the 10s RPC/check deadline, so <code>signal-cli</code> 0.14.3 event streams no longer reconnect before inbound messages arrive. Fixes #74741. Thanks @fgabelmannjr and @k7n4n5t3w4rt.</li>
<li>Models/OpenAI Codex: restore <code>openai-codex/gpt-5.4-mini</code> for ChatGPT/Codex OAuth PI runs after live OAuth proof, and align the manifest, forward-compat metadata, docs, and regression tests so stale cron and heartbeat configs resolve again. Fixes #74451. Thanks @0xCyda, @hclsys, and @Marvae.</li>
<li>Memory/runtime-deps: retain the native <code>node-llama-cpp</code> runtime only when local memory search is configured, so packaged installs can repair local embeddings without relying on unreachable global npm installs. Fixes #74777. Thanks @LLagoon3.</li>
<li>Plugins/runtime-deps: replace stale symlinked mirror target roots before writing runtime-mirror temp files and skip rewriting already materialized hardlinks, so cross-version container upgrades no longer crash-loop on read-only image-layer paths while warm mirrors do less churn. Fixes #75108; refs #75069. Thanks @coletebou and @xiaohuaxi.</li>
<li>Plugins/runtime-deps: keep bundled provider policy config loading from staging plugin runtime dependencies, so config reads no longer fail on locked-down <code>/var/lib/openclaw/plugin-runtime-deps</code> directories. Fixes #74971. Thanks @eurojojo.</li>
<li>Plugins/runtime-deps: always write a dependency map in generated runtime-deps install manifests, so npm does not crash or prune staged bundled-plugin packages when the plan is empty. Fixes #74949. Thanks @hclsys.</li>
<li>Security/outbound: strip re-formed HTML tags during plain-text sanitization so nested tag fragments cannot leave a CodeQL-detected <code><script></code> sequence behind. Thanks @vincentkoc.</li>
<li>Security/secrets: compare credential bytes with padded timing-safe buffers instead of hashing candidate passwords before equality checks. Thanks @vincentkoc.</li>
<li>Security/QQBot: sanitize debug log arguments before writing to <code>console.*</code>, so gateway payload fields cannot forge extra log lines when debug logging is enabled. Thanks @vincentkoc.</li>
<li>QQBot: unify slash command auth and c2cOnly gating in the command registry, pass <code>allowQQBotDataDownloads</code> when sending slash command file attachments, align clear-storage with actual downloads directory, and add <code>/bot-me</code> to display sender user ID. (#73616) Thanks @cxyhhhhh.</li>
<li>CLI/agents/status: keep <code>openclaw agents</code>, text <code>agents list</code>, and plain text <code>status</code> on read-only metadata paths so human output no longer preloads plugin runtimes or live channel scans before printing. Fixes #74195. Thanks @NianJiuZst.</li>
<li>Agents/local models: derive context-window guard thresholds from the effective model window with 4k/8k safety floors, so small local models are no longer rejected by fixed 16k/32k preflight cutoffs. Fixes #42999. Thanks @chengjialu8888.</li>
<li>PDF extraction: resolve PDF.js standard fonts from the installed package root and pass a filesystem path to the Node fallback extractor, so built-in font PDFs render without <code>file://</code> URL lookup failures. Fixes #51455; carries forward #70936, #54447, and #62175. Thanks @anyech, @JuanRdBO, and @solomonneas.</li>
<li>Media: treat legacy Word/OLE attachments with <code>application/msword</code> or <code>application/x-cfb</code> MIME as binary so printable-looking <code>.doc</code> files are not embedded into prompts as text. Fixes #54176; carries forward #54380. Thanks @andyliu.</li>
<li>Config: accept documented <code>browser.tabCleanup</code> keys in strict root config validation, so configured tab cleanup no longer fails before runtime reads it. Fixes #74577. Thanks @lonexreb and @ezdlp.</li>
<li>Cron: validate disabled job schedule edits before persisting updates, so invalid cron changes no longer partially mutate stored jobs. Fixes #74459. Thanks @yfge.</li>
<li>CLI/cron: warn when <code>openclaw cron add --message</code> omits a nonblank <code>--agent</code>, including blank agent values and session-key jobs, so scheduled agent-turn jobs make default-agent fallback explicit while system events stay quiet. Fixes #42196; carries forward #42245. Thanks @ethanclaw.</li>
<li>CLI/progress: suppress nested progress spinners and line clears while TUI input owns raw stdin, so Crestodian <code>/status</code> no longer disturbs the active input row. (#75003) Thanks @velvet-shark.</li>
<li>Channels/status: keep Telegram, Slack, and Google Chat read-only allowlist/default-target accessors on config-only paths, so status and channel summaries do not resolve SecretRef-backed runtime credentials. Thanks @eusine.</li>
<li>Telegram: use durable message edits for streaming previews instead of native draft state, so generated replies no longer flicker through draft-to-message transitions that look like duplicates. (#75073) Thanks @obviyus.</li>
<li>Telegram: clamp low long-polling client timeouts so configured <code>timeoutSeconds</code> values below the <code>getUpdates</code> poll window no longer force a fresh HTTPS connection every few seconds. Fixes #75114. Thanks @hpinho77.</li>
<li>Active Memory: clarify the deprecated <code>modelFallbackPolicy</code> warning and config help so <code>modelFallback</code> is described as a chain-resolution last resort, not runtime failover. (#74602) Thanks @jeffrey701.</li>
<li>Channels/Discord: keep read-only allowlist/default-target accessors from resolving SecretRef-backed bot tokens, so status and channel summaries no longer fail when tokens are only available in gateway runtime. (#74737) Thanks @eusine.</li>
<li>Gateway/sessions: align session abort wait semantics across <code>chat</code>, <code>agent</code>, and <code>sessions</code> server methods so abort RPCs return after the targeted sessions actually halt instead of resolving early while runs are still draining. (#74751) Thanks @BunsDev.</li>
<li>Agents/output: drop copied inbound metadata-only assistant replay turns before provider replay instead of synthesizing a placeholder, so Telegram and other channels cannot receive <code>[assistant copied inbound metadata omitted]</code> as model output. Fixes #74745. Thanks @adamwdear and @Marvae.</li>
<li>Doctor/memory: suppress skipped embedding-readiness warnings for key-optional providers such as Ollama and LM Studio while preserving timeout and not-ready diagnostics. Fixes #74608 and #73882. Thanks @hclsys.</li>
<li>Channels/groups: preserve observe-only turn suppression for prepared dispatch paths and restore deprecated channel turn runtime aliases, so passive observer/group flows stay silent while older plugins keep compiling. Thanks @vincentkoc.</li>
<li>Feishu: skip empty-text messages (e.g. <code>{"text":""}</code>) that carry no media, so no blank user turn is written to the session and downstream LLM providers cannot reject the request with "messages must not be empty". (#74634) Thanks @xdengli and @hclsys.</li>
<li>Feishu/Bitable: clean up newly created placeholder rows whose fields contain only default empty values while preserving meaningful link, attachment, user, number, boolean, and location values during create-app cleanup. (#73920) Carries forward #40602. Thanks @boat2moon.</li>
<li>macOS app: keep attach-only mode and the Debug Settings launchd toggle marker-only, so launching with <code>--attach-only</code>/<code>--no-launchd</code> no longer uninstalls the Gateway LaunchAgent or drops active sessions. (#72174) Thanks @DolencLuka.</li>
<li>macOS Canvas: stop auto-reloading the current A2UI host during push/eval/snapshot flows, so pushed A2UI content remains visible instead of returning to the empty Canvas shell. Fixes #73337. Thanks @Gr4via.</li>
<li>Plugin SDK: restore the deprecated <code>plugin-sdk/zalouser</code> command-auth facade so published Lark/Zalo plugins that import it load on current hosts. Fixes #74702. Thanks @Goron01.</li>
<li>Plugins/runtime-deps: include bundled provider plugins when <code>models.providers</code>, auth profiles, agent defaults, or subagent model refs configure that provider, while keeping inactive default-enabled provider plugins out of doctor repair. Refs #74307. Thanks @Skeptomenos.</li>
<li>Plugins/runtime: resolve relative plugin <code>api.resolvePath</code> inputs against the plugin root instead of the host working directory, while keeping absolute and home paths user-resolved. Fixes #74718. Thanks @jimdawdy-hub.</li>
<li>Plugins/runtime-deps: refresh mirrored root chunks through a temporary file before replacing the active copy, so failed refreshes do not delete chunks that running plugin imports still need. Thanks @shakkernerd.</li>
<li>Plugins/runtime-deps: prefer <code>require</code> conditional exports when building staged dependency aliases, so CommonJS-only plugin runtime deps such as <code>ws</code> do not resolve to ESM wrappers under Jiti. Fixes #74547. Thanks @aderius.</li>
<li>Bonjour/Gateway: cap flapping advertiser restarts in a sliding window, so mDNS probing/name-conflict loops disable discovery instead of churning indefinitely on constrained hosts. Refs #74209 and #74242. Thanks @ndj888 and @Sanjays2402.</li>
<li>Plugins/runtime-deps: verify staged package entry files before reusing mirrored runtime roots, so browser-control repairs incomplete <code>ajv</code>/MCP SDK installs after update instead of failing after restart on a missing <code>ajv/dist/ajv.js</code>. Refs #74630. Thanks @spickeringlr.</li>
<li>Heartbeat: resolve <code>responsePrefix</code> template variables with the selected provider, model, and thinking context before delivering alerts or suppressing prefixed <code>HEARTBEAT_OK</code> replies. Fixes #43064; repairs #43065; supersedes #46858. Thanks @yweiii and @JunJD.</li>
<li>Memory/LanceDB: show full memory UUIDs in the <code>memory_forget</code> candidate list so agents can pass the displayed ID back to targeted deletion without hitting the full-UUID validator. (#66913) Thanks @amittell.</li>
<li>File-transfer plugin: require canonical read-path preflight authorization for <code>file.fetch</code>, fail closed when <code>dir.fetch</code> preflight entries are missing, absolute, or traversing, and recheck returned archive entries before handing archive bytes to callers. Carries forward #74134. Thanks @omarshahine.</li>
<li>Channels/Feishu: retry file-typed iOS video resource downloads as <code>media</code> after a Feishu/Lark HTTP 502 and preserve the original 502 when the fallback also fails. Fixes #49855; carries forward #50164 and #73986. Thanks @alex-xuweilong.</li>
<li>Providers/Amazon Bedrock: expose the full Claude Opus 4.7 thinking profile (<code>xhigh</code>, <code>adaptive</code>, and <code>max</code>) for Bedrock model refs, while keeping Opus/Sonnet 4.6 on adaptive-by-default, so <code>/think</code> menus and validation match the Anthropic transport behavior. Fixes #74701. Thanks @prasad-yashdeep, @sparkleHazard, @Sanjays2402, and @hclsys.</li>
<li>Plugins/tokenjuice: compile the bundled plugin against tokenjuice 0.7.0's published OpenClaw host types instead of a local compatibility shim, so package contract drift fails in OpenClaw validation before release. Thanks @vincentkoc.</li>
<li>OAuth/secrets: ignore root-level Google OAuth <code>client_secret_*.json</code> downloads so local client-secret files do not appear as commit candidates. (#74689) Thanks @jeongdulee.</li>
<li>Memory: mirror <code>sqlite-vec</code> into packaged bundled-plugin runtime deps for the default memory plugin, so builtin vector search does not lose its SQLite extension after upgrading to 2026.4.27. Fixes #74692. Thanks @mozi1924.</li>
<li>Gateway/startup: bound local discovery advertisement during startup, so a stuck discovery plugin can no longer keep the Gateway from reaching ready. Fixes #73865; refs #74630 and #74633. Thanks @lpendeavors, @moltar-bot, and @Saboor711.</li>
<li>Gateway/models: serve the last successful model catalog while stale reloads refresh in the background, so Gateway control-plane and OpenAI-compatible requests no longer block behind model-provider rediscovery after model config changes. Refs #74135, #74630, and #74633. Thanks @DerFlash, @moltar-bot, and @Saboor711.</li>
<li>CLI/status: resolve read-only channel setup runtime fallback from the packaged OpenClaw dist root, so <code>status --all</code>, <code>status --deep</code>, channel, and doctor paths do not crash when an external channel plugin needs setup metadata. Fixes #74693. Thanks @giangthb.</li>
<li>SDK/events: keep per-run SDK event streams from surfacing duplicate raw chat projection frames, while normalizing chat-only projection frames and preserving raw access through <code>rawEvents</code>. Refs #74704. Thanks @BunsDev.</li>
<li>SDK: report Gateway terminal <code>agent.wait</code> timeout snapshots with lifecycle metadata as <code>timed_out</code> while keeping bare wait deadlines non-terminal. Thanks @clawsweeper.</li>
<li>Google Meet: block managed Chrome intro/test speech until browser health proves the participant is in-call, and expose <code>speechReady</code> diagnostics so login, admission, permission, and audio-bridge blockers no longer look like successful speech. Refs #72478. Thanks @DougButdorf.</li>
<li>Slack/commands: keep native command argument menus on select controls for encoded choice values up to Slack's option limit and truncate fallback button labels to Slack's button-text limit, so long valid choices no longer render invalid Slack blocks. Thanks @slackapi.</li>
<li>Agents/Codex: flush accepted debounced steering messages before normal app-server turn cleanup, so inbound follow-ups acknowledged as queued are not dropped when the turn completes before the debounce fires. Thanks @vincentkoc.</li>
<li>Slack/interactive replies: keep rendered buttons and selects within Slack Block Kit value and count limits, and align command argument select values with Slack's option limit, so overlong agent-authored choices no longer make Slack reject the whole block payload. Thanks @slackapi.</li>
<li>Slack/interactive replies: drop overlong Block Kit button URLs while preserving valid callback values, so malformed link buttons no longer make Slack reject the whole interactive reply. Thanks @slackapi.</li>
<li>Slack/commands: truncate native command argument-menu confirmation text to Slack's dialog limit, so long plugin arg names no longer make fallback buttons render invalid Block Kit payloads. Thanks @slackapi.</li>
<li>Slack/exec approvals: cap native approval metadata context to Slack's element and text limits, so large approval details no longer make Slack reject the approval card. Thanks @slackapi.</li>
<li>Slack/exec approvals: cap native approval update fallback text to Slack's message limit while preserving the rendered approval blocks, so long commands no longer make resolved or expired approval cards stay stale after <code>chat.update</code> rejects <code>msg_too_long</code>. Thanks @slackapi.</li>
<li>Slack/commands: cap native command argument-menu fallback rows to Slack's message block limit, so large plugin choice lists no longer make Slack reject the generated menu. Thanks @slackapi.</li>
<li>Slack/commands: drop fallback command argument buttons whose encoded values exceed Slack's button-value limit, so one oversized plugin choice no longer makes Slack reject the whole menu. Thanks @slackapi.</li>
<li>Slack/messages: merge message-tool presentation and interactive blocks on Slack sends, so buttons and selects are no longer dropped when a structured message body is also present. Thanks @slackapi.</li>
<li>Slack/messages: cap Block Kit fallback text to Slack's send limit while preserving the rendered blocks, so long context fallbacks no longer make rich Slack messages fail with <code>msg_too_long</code>. Thanks @slackapi.</li>
<li>Slack/messages: cap Block Kit fallback text on message edits while preserving the rendered blocks, so long context fallbacks no longer make Slack reject <code>chat.update</code> calls with <code>msg_too_long</code>. Thanks @slackapi.</li>
<li>Channels/WhatsApp: require Baileys outbound message ids before marking auto-replies delivered, so transcript text and ack reactions no longer make failed group replies look sent. Fixes #49225. Thanks @TinyTb.</li>
<li>CLI/update: scope packaged Node compile caches by OpenClaw version and install metadata, so global installs no longer reuse stale compiled chunks after package updates. Thanks @pashpashpash.</li>
<li>Channels/Voice call: keep pre-auth webhook in-flight limiting active when socket remote address metadata is missing, so slow-body requests from stripped-IP proxy paths still share the fallback bucket. (#74453) Thanks @davidangularme.</li>
<li>Plugin SDK/testing: lazy-load TypeScript from the plugin test-contract runtime and add release checks for critical SDK contract entrypoint imports and bundle size, so published packages fail preflight before shipping ESM-incompatible or oversized contract helpers. Thanks @vincentkoc.</li>
<li>Channels/Microsoft Teams: treat configured <code>19:...@thread.tacv2</code> and legacy <code>19:...@thread.skype</code> team/channel IDs as already resolved during startup, avoiding false <code>channels unresolved</code> warnings while preserving Graph name lookup for display-name entries. Fixes #74683. Thanks @dseravalli.</li>
<li>CLI/browser: preserve parent flags while lazy-loading browser subcommands, so <code>openclaw browser --json open</code> and <code>openclaw browser --json tabs</code> keep machine-readable output after reparsing. Fixes #74574. Thanks @devintegeritsm.</li>
<li>Exec/elevated: preserve <code>turnSourceChannel</code> as <code>messageProvider</code> on approval-followup runs so <code>tools.elevated.allowFrom.<provider></code> checks no longer fail with <code>provider=null</code> after the user approves an async elevated command. Fixes #74646. Thanks @xhd2015.</li>
<li>Plugins/runtime-deps: add <code>openclaw plugins deps</code> inspection and repair with script-free package-manager defaults shared across plugin installers, so operators can repair missing bundled runtime deps without corrupting JSON output or blocking unrelated conflict-free deps. Thanks @vincentkoc.</li>
<li>Agents/output: strip internal <code>[tool calls omitted]</code> replay placeholders from user-facing replies while preserving visible reply whitespace. Fixes #74573. Thanks @blaspat.</li>
<li>Providers/Google Vertex: route authorized_user ADC credentials through OpenClaw's REST transport so Docker installs using gcloud application-default credentials no longer crash in the Google SDK before requests are sent. Fixes #74628. Thanks @frankhal2001-design.</li>
<li>ACP/resolver: fall through to thread-bound session resolution when an explicit <code>--session</code> token cannot be resolved while preserving the bad-token diagnostic when no thread binding exists, so Discord slash commands that auto-fill the current thread ID as the positional ACP target no longer return "Unable to resolve session target" errors. Fixes #66299. Thanks @hclsys, @kindomLee, and @martingarramon.</li>
<li>Agents/sessions: emit a terminal lifecycle backstop when embedded timeout/error turns return without <code>agent_end</code>, so Gateway sessions no longer stay stuck in <code>running</code> after failover surfaces a timeout. Fixes #74607. Thanks @millerc79.</li>
<li>Gateway/diagnostics: include stuck-session reason hints and recovery skip causes in warnings, so operators can tell whether a lane is waiting on active work, queued work, or stale bookkeeping. Thanks @vincentkoc.</li>
<li>Providers/DeepSeek: expose native DeepSeek V4 <code>xhigh</code> and <code>max</code> thinking levels through the provider <code>resolveThinkingProfile</code> hook so <code>/think xhigh|max</code> applies the intended effort instead of falling back to base levels. (#73008) Thanks @ai-hpc.</li>
<li>Agents/Codex: bound embedded-run cleanup, trajectory flushing, and command-lane task timeouts after runtime failures, so Discord and other chat sessions return to idle instead of staying stuck in processing. Thanks @vincentkoc.</li>
<li>Heartbeat/exec: consume successful metadata-only async exec completions silently so Telegram and other chat surfaces no longer ask users for missing command logs after <code>No session found</code>. Fixes #74595. Thanks @gkoch02.</li>
<li>Web fetch: add a documented <code>tools.web.fetch.ssrfPolicy.allowIpv6UniqueLocalRange</code> opt-in and thread it through cache keys and DNS/IP checks so trusted fake-IP proxy stacks using <code>fc00::/7</code> can work without broad private-network access. Fixes #74351. Thanks @jeffrey701.</li>
<li>OpenAI Codex: restore <code>/verbose full</code> persistence and app-server tool-output forwarding, and retry Gateway E2E temp-home cleanup so debug runs do not regress on stale validation or cleanup flakes. Thanks @vincentkoc.</li>
<li>Anthropic/Meridian: preserve text and thinking content seeded on <code>content_block_start</code> in anthropic-messages streams, so <code>[thinking, text]</code> replies no longer persist as empty turns or trigger empty-response fallbacks. Fixes #74410. Thanks @vyctorbrzezowski.</li>
<li>Channels/Matrix: complete the cross-signing handshake on <code>openclaw matrix verify confirm-sas</code> so the operator's other Matrix device clears its <code>Verifying…</code> loop instead of staying stuck after the agent confirms. (#74542) Thanks @nklock.</li>
<li>CLI/status: honor channel-specific model context-window overrides when reporting effective context, so channel-scoped sessions reflect the active window in <code>openclaw status</code>. Thanks @HemantSudarshan.</li>
<li>Sandbox/Docker: tolerate Docker daemon unavailability when sandbox mode is off, so doctor and preflight checks no longer fail on installs that do not run the Docker daemon. Fixes #73671. Thanks @kaseonedge.</li>
<li>Control UI/mobile: persist mobile chat settings through Lit-managed state and route mobile navigation through the same view-state path so chat panel toggles survive transitions on small viewports. Thanks @BunsDev.</li>
<li>Control UI/exports: align sidebar trigger affordances across the resizable divider, mobile layout, and exported-HTML transcript template so the sidebar toggle and exported transcript sidebar render with consistent hit areas and styling. Thanks @BunsDev.</li>
<li>Control UI/chat: disable the page refresh affordance while a chat run is active so accidental refreshes do not abort an in-flight reply. Thanks @Angfr95 and @BunsDev.</li>
<li>Memory/LanceDB: return real memory records from <code>openclaw ltm list</code> (with optional <code>--limit</code> and createdAt ordering) instead of an empty placeholder, so the CLI surface matches the documented LTM listing contract. (#67952) Thanks @zhangyue19921010.</li>
<li>Media: include redacted per-attempt resize failures and resolved model input capabilities in vision-pipeline errors so ARM64 image failures are diagnosable without closing the remaining routing investigation. Refs #74552. Thanks @1yihui.</li>
<li>Control UI/i18n: route zh-CN agent, debug, channel-refresh, and exec-approval copy through the locale source while preserving the English <code>Cron Jobs</code> agent tab label and the security-audit command styling. Carries forward #39692 repair context. Thanks @hepeng154833488 and @vincentkoc.</li>
<li>Auto-reply: honor explicit <code>silentReply.direct: "allow"</code> for clean empty or reasoning-only direct chat turns while keeping the default direct-chat empty-response guard conservative. Fixes #74409. Thanks @jesuskannolis.</li>
<li>OpenAI Codex: send a non-empty Responses input item when a Codex turn only has systemPrompt-backed instructions, avoiding ChatGPT backend 400s from <code>input: []</code>. Fixes #73820. Thanks @woodhouse-bot.</li>
<li>Ollama: normalize provider-prefixed tool-call names at the native stream boundary so Kimi/Ollama calls such as <code>functions.exec</code> dispatch as <code>exec</code> instead of missing configured tools. Fixes #74487. Thanks @afurm and @carreipeia.</li>
<li>Security/audit: resolve configured model aliases before model-tier and small-parameter checks, so alias-based GPT-5/Codex configs no longer report false weak-model warnings. Fixes #74455. Thanks @blaspat.</li>
<li>CLI/agent: isolate Gateway-timeout embedded fallback runs under explicit <code>gateway-fallback-*</code> sessions so accepted Gateway runs cannot race transcript locks or replace the routed conversation session. Fixes #62981. Thanks @HemantSudarshan.</li>
<li>CLI/QR/device-pair: reject malformed public setup URLs before issuing mobile pairing bootstrap tokens, while keeping valid bare host:port setup URLs supported. Thanks @Lucenx9.</li>
<li>Models/UI: hide unauthenticated providers from the default Web chat, <code>/models</code>, and model setup pickers while keeping explicit full-catalog browse paths through <code>view: "all"</code>, <code>/models <provider> all</code>, and <code>models list --all</code>. Fixes #74423. Thanks @guarismo and @SymbolStar.</li>
<li>Ollama: keep explicit local model runs on target-provider runtime hooks when PI discovery is skipped, so one-shot Ollama calls no longer cold-load unrelated provider runtimes before streaming. Fixes #74078. Thanks @sakalaboator.</li>
<li>Slack/prompts: rely on Slack <code>interactiveReplies</code> guidance instead of generic <code>inlineButtons</code> config hints so enabled Slack button directives are not contradicted. Fixes #46647. Thanks @jeremykoerber.</li>
<li>Slack/reactions: treat duplicate <code>already_reacted</code> responses as idempotent success so repeated agent reaction adds no longer surface as tool failures. Fixes #69005. Thanks @shipitsteven and @martingarramon.</li>
<li>Channels/Discord: cool down Cloudflare/Error 1015 HTML 429 REST failures during startup application lookup and gateway metadata fetches, add <code>channels.discord.applicationId</code> as an app-id lookup bypass, sanitize HTML bodies before logging, and honor Retry-After before falling back to a conservative cooldown. Fixes #38853. (#74489) Thanks @djgeorg3 and @Garyko0730.</li>
<li>Slack/tools: expose <code>fileId</code> in the shared message tool schema so <code>download-file</code> can receive Slack attachment IDs from inbound placeholders. Fixes #45574. Thanks @chadvegas.</li>
<li>Exec: reject invalid per-call <code>host</code> values instead of silently falling back to the default target, so hostname-like values fail before commands run. Fixes #74426. Thanks @scr00ge-00 and @vyctorbrzezowski.</li>
<li>Google/Gemini: send non-empty placeholder content when a Gemini run is triggered with empty or filtered user content, avoiding <code>contents is not specified</code> API errors. Thanks @CaoYuhaoCarl.</li>
<li>Heartbeat: preserve non-task <code>HEARTBEAT.md</code> context around <code>tasks:</code> blocks and apply <code>agents.defaults.heartbeat</code> to all agents unless per-agent heartbeat entries restrict scope. Thanks @Sekhar03.</li>
<li>Markdown: preserve paragraph breaks inside loose list items in shared outbound formatting while keeping tight list spacing stable. Thanks @Lucenx9.</li>
<li>Build/Gateway: route restart, shutdown, respawn, diagnostics, command-queue cleanup, and runtime cleanup through one stable gateway lifecycle runtime entry so rebuilt packages do not strand long-running gateways on stale hashed chunks. Carries forward #73964. Thanks @pashpashpash.</li>
<li>Memory/wiki: keep broad shared-source and generated related-link blocks from turning every page into a search hit, cap noisy backlinks, support all-term searches such as people-routing queries, and prefer readable page body snippets over generated metadata. Thanks @vincentkoc.</li>
<li>Cron/Gateway: abort and bounded-clean up timed-out isolated agent turns before recording the timeout, so stale cron sessions cannot leave Discord or other chat lanes stuck in <code>processing</code> after a timeout. Thanks @vincentkoc.</li>
<li>Agents/errors: suppress malformed streaming tool-call JSON fragments before they reach chat surfaces while preserving provider request-validation diagnostics. Fixes #59076; keeps #59080 as duplicate coverage. (#59118) Thanks @singleGanghood.</li>
<li>CLI/models: restore provider-filtered <code>models list --all --provider <id></code> rows for providers without manifest/static catalog coverage, including Anthropic and Amazon Bedrock, while keeping the compatibility fallback off expensive availability and resolver paths. Thanks @shakkernerd.</li>
<li>CLI/models: keep manifest auth-evidence credentials visible across <code>models status</code>, auth probes, and PI model discovery so workspace-scoped provider auth does not disagree between listing, probing, and execution. Thanks @shakkernerd.</li>
<li>CLI/models: move local credential evidence such as Google Vertex ADC into generic plugin manifest setup metadata so the model-list auth index stays declarative without provider-specific runtime branches. Thanks @shakkernerd.</li>
<li>CLI/models: compute the <code>models list</code> Auth column through one command-local provider auth index so row rendering no longer repeats auth profile, env, configured-provider, AWS, or synthetic-auth checks per model row. Thanks @shakkernerd.</li>
<li>CLI/models: move the OpenAI listable catalog into the plugin manifest so <code>models list --all --provider openai</code> uses the manifest fast path instead of loading provider runtime normalization hooks. Thanks @shakkernerd.</li>
<li>CLI/tools: keep the Gateway <code>tools.*</code> RPC namespace out of plugin command discovery and managed proxy startup, so stray commands like <code>openclaw tools effective</code> fail quickly instead of cold-loading plugin metadata. Refs #73477. Thanks @oromeis.</li>
<li>CLI/status: keep default text <code>openclaw status --usage</code> on metadata-only channel scans unless <code>--deep</code> or <code>--all</code> is set, and send stray <code>openclaw tools --help</code> through the precomputed root-help fast path so latency-triage commands avoid plugin/runtime cold loads before printing. Refs #73477 and #74220. Thanks @oromeis and @NianJiuZst.</li>
<li>Agents/diagnostics: trace embedded-run startup and preparation stage timings before model I/O, and warn only on severe slow stages, so Docker/VPS latency reports can identify whether plugin loading, auth/model resolution, tool inventory, bootstrap, MCP/LSP, resource loading, or stream setup is dominating pre-run latency without noisy normal logs. Refs #73428. Thanks @Dimaoggg, @quangtran88, and @Heyvhuang.</li>
<li>Agents/subagents: cache persisted subagent run registry reads by file signature while preserving fresh-parse isolation, so busy gateways stop reparsing unchanged <code>subagents/runs.json</code> on controller/list/status hot paths. Refs #72338. Thanks @argus-as.</li>
<li>Gateway/clients: wait for the event loop to become responsive before opening Gateway WebSocket RPC/probe/client connections while charging that readiness wait to caller timeouts, so Windows deferred module-evaluation stalls no longer turn healthy loopback gateways into false handshake timeouts across status, TUI, ACP, MCP, node-host, and plugin client paths. Refs #74279 and #48270. Thanks @wongcode and @joost-heijden.</li>
<li>Gateway/Windows: read listener command lines via PowerShell before falling back to <code>wmic</code>, so restart health can recognize OpenClaw listeners on modern Windows installs and avoid long anonymous-port waits. Refs #74280. Thanks @zym951223.</li>
<li>Plugins/runtime-deps: record process start-time in bundled dependency install locks and expire recycled-PID locks, so Docker gateway restarts recover from stale <code>.openclaw-runtime-deps.lock</code> directories without waiting through repeated five-minute timeouts. Fixes #74346. (#74361) Thanks @jhsmith409.</li>
<li>Plugins/runtime-deps: memoize packaged bundled runtime dist-mirror preparation after the first successful pass while keeping source-checkout mirrors refreshable, so constrained Docker/VPS installs avoid repeated root scans before chat turns. Refs #73428, #73421, #73532, and #73477. Thanks @Dimaoggg, @oromeis, @oadiazp, @jmfraga, @bstanbury, @antoniusfelix, and @jkobject.</li>
<li>Channels/Discord: treat bare numeric outbound targets that match the effective Discord DM allowlist as user DMs while preserving account-specific legacy <code>dm.allowFrom</code> precedence over inherited root <code>allowFrom</code>. (#74303) Thanks @Squirbie.</li>
<li>Channels/Discord/Slack: share one DM policy/allowlist resolver across runtime, setup, allowlist editing, and doctor repair, so legacy <code>dm.policy</code> / <code>dm.allowFrom</code> compatibility migrates to canonical <code>dmPolicy</code> / <code>allowFrom</code> without divergent access checks. Thanks @Squirbie.</li>
<li>Control UI: make the chat sidebar split divider focusable, keyboard-resizable, ARIA-described, and pointer-event based so sidebar resizing works without a mouse. Thanks @BunsDev.</li>
<li>Agents/usage: keep PI embedded-run telemetry attributed to the resolved model provider instead of the PI harness label, so OpenRouter and other provider-backed turns report the right provider in session usage and traces. Thanks @vincentkoc.</li>
<li>Agents/attribution: send OpenClaw attribution headers on native OpenAI and Codex traffic, including SDK transports, realtime voice and TTS, device-code auth, WHAM usage, and remote embeddings, so PI-origin defaults no longer leak into provider requests. Thanks @vincentkoc.</li>
<li>Agents/auth: keep OAuth auth profiles inherited from the main agent read-through instead of copying refresh tokens into secondary agents, and refresh Codex app-server tokens against the owning store so multi-agent swarms avoid reused refresh-token failures. Fixes #74055. Thanks @ClarityInvest.</li>
<li>Channels/Telegram: honor <code>ALL_PROXY</code> / <code>all_proxy</code> and service-level <code>OPENCLAW_PROXY_URL</code> when constructing the HTTP/1-only Telegram Bot API transport, so Windows and service installs that rely on those proxy settings no longer fall back to direct egress. Fixes #74014; refs #74086. Thanks @SymbolStar.</li>
<li>Channels/Telegram: keep raw host/network-unreachable Bot API connect failures non-fatal and route tagged polling uncaught exceptions through the Telegram restart path, so transient reachability failures no longer kill the Gateway or leave long polling stuck. Fixes #60515; refs #74540. Thanks @HemantSudarshan, @thacid22, and @ewimsatt.</li>
<li>Channels/Telegram: continue polling when <code>deleteWebhook</code> hits a transient network failure but <code>getWebhookInfo</code> confirms no webhook is configured, so startup does not retry cleanup forever after the webhook was already removed. Refs #74086; carries forward #47384. Thanks @clovericbot.</li>
<li>Channels/Telegram: retry native quote replies without <code>reply_parameters.quote</code> when Telegram returns <code>QUOTE_TEXT_INVALID</code>, so stale or truncated quote excerpts no longer drop the whole reply. Fixes #74581. Thanks @moeedahmed.</li>
<li>Channels/Telegram: apply strict safe-send retry to inbound final replies when grammY wraps a pre-connect failure, while leaving ambiguous plain network envelopes single-shot to avoid duplicate visible messages. Fixes #74203. Thanks @nanli2000cn.</li>
<li>Channels/Telegram: surface polling liveness warnings in channel status and doctor when a running long-poller has not completed <code>getUpdates</code> after startup grace or its transport activity is stale, so silent polling failures no longer look clean. Refs #74299. Thanks @lolaopenclaw.</li>
<li>Channels/Telegram: publish webhook runtime state and warn when <code>setWebhook</code> has not completed after startup grace, so webhook-mode accounts no longer look healthy while registration is still failing or retrying. Refs #74299. Thanks @lolaopenclaw and @martingarramon.</li>
<li>Channels/Telegram: bound native command menu <code>deleteMyCommands</code> and <code>setMyCommands</code> Bot API calls and allow the same timeout-triggered transport fallback retry as other startup control calls, so Windows/WSL network stalls cannot leave command sync hanging behind an otherwise running provider. Refs #74086. Thanks @SymbolStar.</li>
<li>ACP/commands: accept forwarded ACP timeout config controls in the OpenClaw bridge, treat unsupported discard-close controls as recoverable cleanup, and restore native <code>/verbose full</code> plus no-arg status behavior, so Discord command menus and nested ACP turns no longer fail on supported session controls. Thanks @vincentkoc.</li>
<li>Codex harness: interrupt and release native app-server turns that go quiet after an OpenClaw dynamic-tool response without sending <code>turn/completed</code>, so Discord and other chat lanes do not stay stuck in <code>processing</code>. Thanks @vincentkoc.</li>
<li>Codex harness: bound OpenClaw dynamic tool responses to 30 seconds and fail closed with an explicit tool result when the app-server bridge would otherwise strand the turn in <code>processing</code>. Thanks @vincentkoc.</li>
<li>TUI/status: clear stale <code>streaming</code> footer state when a final event arrives after the active run was already cleared and no tracked runs remain, while preserving concurrent-run ownership and inactive local <code>/btw</code> terminal handling. Fixes #64825; carries forward #64842, #64843, #64847, and #64862. Thanks @briandevans and @Yanhu007.</li>
<li>Channels/Discord: fail startup closed when Discord cannot resolve the bot's own identity and keep mention gating active when only configured mention patterns can detect mentions, so the provider no longer continues with a missing bot id. Fixes #42219; carries forward #46856 and #49218. Thanks @education-01 and @BenediktSchackenberg.</li>
<li>Channels/Discord: split long CJK replies at punctuation and code-point-safe fallback boundaries so Discord chunking stays readable without corrupting astral characters. Fixes #38597; repairs #71384. Thanks @p3nchan.</li>
<li>TUI: keep the streaming watchdog alive across active tool/lifecycle proof-of-life, pause it during disconnects, and reload history after stale reconnect runs so long-running chats stop flipping to false idle or hanging on stale streaming. Fixes #69081. Thanks @EenvoudJasper.</li>
<li>Browser/gateway: ignore Playwright dialog-close races from <code>Page.handleJavaScriptDialog</code> so browser automation no longer crashes the Gateway when a dialog disappears before Playwright accepts it. (#40067) Thanks @randyjtw.</li>
<li>Cron/Gateway: defer missed isolated agent-turn catch-up out of the channel startup window, so overdue cron work cannot starve Discord or Telegram while providers connect after a restart. Thanks @vincentkoc.</li>
<li>Heartbeat/cron: defer heartbeat turns while cron work is active or queued, add opt-in <code>heartbeat.skipWhenBusy</code> for subagent/nested lane pressure, and retry busy skips without advancing the schedule so local Ollama hosts do not run heartbeat and cron prompts concurrently. Fixes #50773. Thanks @scottgl9.</li>
<li>Agents/thinking: honor configured model <code>compat.supportedReasoningEfforts</code> entries that include <code>xhigh</code>, so custom OpenAI-compatible provider refs expose and validate <code>/think xhigh</code> consistently across command menus, Gateway sessions, agent CLI, and <code>llm-task</code>. Carries forward #48904. Thanks @Milchstrassse and @wufunc.</li>
<li>Vercel AI Gateway: expose provider-owned <code>/think xhigh</code> for trusted OpenAI/Codex upstream refs and Claude adaptive thinking for Anthropic upstream refs, while leaving untrusted namespaced refs on base levels. Carries forward #41561. Thanks @Zcg2021.</li>
<li>Plugins/runtime-deps: prune stale <code>openclaw-unknown-*</code> bundled runtime dependency roots during Gateway startup while keeping recent or locked roots, so old staging debris cannot keep growing across restarts. Thanks @vincentkoc.</li>
<li>Plugins/runtime-deps: include ten more root-package runtime dependencies (<code>@agentclientprotocol/sdk</code>, <code>@lydell/node-pty</code>, <code>croner</code>, <code>dotenv</code>, <code>jiti</code>, <code>json5</code>, <code>jszip</code>, <code>markdown-it</code>, <code>tar</code>, <code>web-push</code>) in <code>MIRRORED_CORE_RUNTIME_DEP_NAMES</code> so they are mirrored into the runtime-deps tree alongside <code>semver</code> and <code>tslog</code>, preventing <code>Cannot find package 'X'</code> failures from core dist code (for example <code>qmd-manager</code>, <code>cron/schedule</code>, <code>infra/archive</code>, <code>infra/push-web</code>, <code>infra/backup-create</code>, <code>process/supervisor/adapters/pty</code>) when no enabled extension owns the dependency. Adds a static drift guard test that scans <code>src/</code> for value imports of root-package deps and fails CI when one is missing from the mirror allowlist or extension-owned set. Refs #74199. Thanks @maxpuppet.</li>
<li>Ollama: compose caller abort signals with guarded-fetch timeouts for native <code>/api/chat</code> streams, so <code>/stop</code> and early cancellation still interrupt local Ollama requests that also carry provider timeout budgets. Refs #74133. Thanks @obviyus.</li>
<li>Doctor/TTS: migrate legacy <code>messages.tts.enabled</code>, agent TTS, channel TTS, and voice-call plugin TTS toggles to <code>auto</code> mode during <code>openclaw doctor --fix</code>, matching the documented TTS config contract. Thanks @vincentkoc.</li>
<li>CLI/logs: fall back to the configured Gateway file log when implicit loopback Gateway connections close or time out before or during <code>logs.tail</code>, so <code>openclaw logs</code> still works while diagnosing local-model Gateway disconnects. Refs #74078. Thanks @sakalaboator.</li>
<li>MCP/plugins: stringify non-array plugin tool results with chat-content coercion instead of default object stringification, so MCP callers receive useful JSON/text content from plugin tools. Thanks @vincentkoc.</li>
<li>Active Memory/QMD: make gateway-start QMD refresh opt-in via <code>memory.qmd.update.startup</code>, keep normal memory access lazy, preserve interactive file watching, and align watcher dependency/build ignores with QMD's scanner so cold gateway startup no longer imports or initializes QMD by default. Thanks @codexGW.</li>
<li>Channels/Discord: remove Discord-owned queued-run timeout replies through the shared channel lifecycle queue while preserving message ordering and compatibility timeout constants, so long Discord turns stay governed by session/tool/runtime lifecycle instead of channel fallback errors. Thanks @codexGW.</li>
<li>Agents/tools: clamp <code>process.poll</code> waits to 30 seconds, advertise that cap in the tool schema, and honor abort signals while waiting, so long command polls cannot pin agent responsiveness after cancellation. Thanks @vincentkoc.</li>
<li>Plugin SDK: add tracked Discord component-message helpers and a Telegram account-resolution compatibility facade, so existing plugins using those subpaths resolve while new plugins stay on generic channel SDK contracts. Thanks @vincentkoc.</li>
<li>Shared labels: preserve Unicode combining marks and NFC-equivalent accented text in group/channel slug normalization so non-Latin labels no longer lose meaningful characters. Fixes #58932; carries forward #58942 and #58995. Thanks @fengqing-git, @Starhappysh, and @koen666.</li>
<li>Channels/Telegram: include probed video width and height when sending regular Telegram videos, so portrait clips render with the correct orientation instead of being stretched by clients. (#18915) Thanks @storyarcade.</li>
<li>Docs/Hetzner: clarify that SSH tunnel access requires <code>AllowTcpForwarding local</code> before running <code>ssh -L</code>, so hardened VPS sshd configs do not block loopback Gateway access. Fixes #54557; carries forward #54564; refs #54954. Thanks @satishkc7, @blackstrype, and @Aftabbs.</li>
<li>Agents/config: preserve authored <code>agents.defaults.params</code> and per-model <code>agents.defaults.models[].params</code> during narrowed internal config writes, so OpenAI transport overrides such as <code>transport: "sse"</code> and <code>openaiWsWarmup: false</code> are not stripped from <code>openclaw.json</code>. Fixes #73607; refs #73428. Thanks @quangtran88.</li>
<li>Agents/model config: resolve per-model extra params through canonical model keys while preserving legacy double-prefixed fallback entries, so provider-prefixed model ids such as <code>openrouter/auto</code> keep their configured runtime params. (#44319) Thanks @HenryXiaoYang.</li>
<li>Gateway/shutdown: report structured shutdown warnings and HTTP close timeout warnings through <code>ShutdownResult</code> while preserving lifecycle hook hardening. Carries forward #41296. Thanks @edenfunf.</li>
<li>Control UI: keep Agents Overview and config-form select dropdowns on their configured value after options render while preserving inherited agent model placeholders. Fixes #40352; carries forward #52948. Thanks @xiaoquanidea.</li>
<li>Agents/exec: launch zsh, bash, and fish host exec shells with startup files suppressed while preserving existing PATH fallbacks, so daemon env is not overridden by shell startup files. Carries forward #40200; fixes #40179. Thanks @NewdlDewdl.</li>
<li>Plugins/QA: prebuild the private QA channel runtime before plugin gauntlet source runs so wrapper CPU/RSS measurements are not polluted by private QA dist rebuild work. Thanks @vincentkoc.</li>
<li>Plugins/QA: add a Kitchen Sink plugin gauntlet that installs the external package, checks command inventory, MCP tools, channel status, provider turns, gateway RSS, CPU, and fatal log anomalies. Thanks @vincentkoc.</li>
<li>Plugins/config: reuse the bundled plugin alias scan within a single config normalization pass, so Kitchen Sink-style plugin configs no longer peg Gateway CPU by repeatedly rescanning bundled metadata before agent turns. Thanks @vincentkoc.</li>
<li>Plugins/channels: reject malformed runtime channel registrations that omit required config helpers before they can poison channel status. Thanks @vincentkoc.</li>
<li>MCP/plugins: serialize raw plugin tool return values through the plugin-tools MCP bridge so Kitchen Sink-style tools no longer surface <code>undefined</code> content. Thanks @vincentkoc.</li>
<li>Gateway/reload: bound default restart deferral and SIGUSR1 restart drain to five minutes while preserving explicit <code>deferralTimeoutMs: 0</code> indefinite waits, so stale active work accounting cannot block config reloads forever. Thanks @vincentkoc.</li>
<li>Active Memory: register the prompt-build hook with the configured recall timeout plus setup grace instead of the 150s maximum budget, so default memory recall cannot delay turn startup for multiple minutes. Thanks @vincentkoc.</li>
<li>Gateway/readiness: include an <code>eventLoop</code> diagnostic block in local or authenticated <code>/readyz</code> responses with event-loop delay (p99 and max), event-loop utilization, CPU core ratio, and a <code>degraded</code> flag, so operators can see when slow startups or runaway turns stall the event loop. Thanks @vincentkoc.</li>
<li>Gateway/agents: schedule accepted agent runs after the accepted RPC frame has a chance to flush, so pre-turn prompt/context work is less likely to starve immediate <code>agent.wait</code> callers. Thanks @vincentkoc.</li>
<li>CLI/update: tolerate stale memory-runtime import failures during best-effort CLI process teardown, so <code>openclaw update</code> replacing hashed runtime chunks before the finalizer runs no longer surfaces as exit-time <code>Cannot find module</code> noise. Thanks @vincentkoc.</li>
<li>CLI/channels logs: reuse the rolling log-file resolver so <code>openclaw channels logs</code> falls back to the active dated log across date boundaries without reading unrelated custom log files. Fixes #42875; carries forward #42904 and #43043. Thanks @ethanclaw and @wdskuki.</li>
<li>CLI/update: skip tracked plugins disabled in config during post-update plugin sync before npm, ClawHub, or marketplace update checks, preserving their install records without failing the update. Fixes #73880. Thanks @islandpreneur007.</li>
<li>Control UI: fix Peak Error Hours showing incorrect hourly rates when the browser's timezone observes DST, by storing hourly message counts with UTC date keys and using DST-aware <code>Date.getHours()</code> for local conversion. Also extract <code>accumulateMessageCounts</code> helper to reduce duplicated daily/hourly aggregation logic. (#49396) Thanks @konanok.</li>
<li>iMessage: normalize known leading attributedBody corruption markers on sent-message echo text keys so delayed reflected echoes with U+FFFD/U+FFFE/U+FFFF/FEFF prefixes are dropped without collapsing interior text. Fixes #59973; carries forward #59980 and #62191. Thanks @neeravmakwana and @maguilar631697.</li>
<li>Security/audit: recognize dangerous node command IDs as valid <code>gateway.nodes.denyCommands</code> entries, so audit only warns on real typos or unsupported patterns. (#56923) Thanks @chziyue.</li>
<li>Cron: treat implicit text payloads with agent-turn overrides as agent turns, preserving model overrides for scheduled text prompts instead of pruning them as system events. Fixes #28905. (#64060) Thanks @liaoandi.</li>
<li>Telegram/exec approvals: stop treating general Telegram chat allowlists and <code>defaultTo</code> routes as native exec approvers; Telegram now uses explicit <code>execApprovals.approvers</code> or owner identity from <code>commands.ownerAllowFrom</code>, matching the first-pairing owner bootstrap path. Thanks @pashpashpash.</li>
<li>Plugins/providers: keep Gateway startup primary-model discovery on metadata-only provider entries and reuse active non-speech capability providers even with explicit plugin entries, avoiding unnecessary provider registry loads during startup and media capability checks. Fixes #73729, #73835, and #73793; carries forward #73853 and #73794. Thanks @sg1416-zg, @brokemac79, and @poolside-ventures.</li>
<li>Chat commands: route sensitive group <code>/diagnostics</code> and <code>/export-trajectory</code> approvals and results to a private owner route, preferring same-surface DMs before falling back to the first configured owner route, so Discord group invocations can land in Telegram when that is the primary owner interface. Thanks @pashpashpash.</li>
<li>Gateway/hooks: keep successful <code>deliver:false</code> agent hooks silent, log a hook audit record for suppressed success announcements, and suppress fallback summaries after attempted hook delivery while still surfacing failed hook runs. Repairs #55761; builds on #36332 and #49234. Thanks @EffortlessSteven, @cioclawcode, and @BrennerSpear.</li>
<li>Plugin SDK/Discord: restore a deprecated <code>openclaw/plugin-sdk/discord</code> compatibility facade and the legacy compat group-policy warning export for the published <code>@openclaw/discord@2026.3.13</code> package, covering its config, account, directory, status, and thread-binding imports while keeping new plugins on generic SDK subpaths. Fixes #73685; supersedes #73703. Thanks @rderickson9 and @SymbolStar.</li>
<li>Channels/Discord: suppress duplicate gateway monitors when multiple enabled accounts resolve to the same bot token, preferring config tokens over default env fallback and reporting skipped duplicates as disabled. Supersedes #73608. Thanks @kagura-agent.</li>
<li>CLI/health: build channel health summaries from inspected credential metadata plus runtime state, so <code>openclaw health --json</code> reports Discord <code>running</code>, <code>connected</code>, and <code>tokenSource</code> consistently with channel status. Fixes #44354. Thanks @ferenc-acs.</li>
<li>Control UI/Talk: decode Google Live binary WebSocket JSON frames and stop queued browser audio on interruption or shutdown, so browser Talk leaves <code>Connecting Talk...</code> and barge-in no longer plays stale audio. Fixes #73601 and #73460; supersedes #73466. Thanks @Spolen23 and @WadydX.</li>
<li>Channels/Discord: ignore stale route-shaped conversation bindings after a Discord channel is reconfigured to another agent, while preserving explicit focus and subagent bindings. Fixes #73626. Thanks @ramitrkar-hash.</li>
<li>Agents/bootstrap: pass pending BOOTSTRAP.md contents through the first-run user prompt while keeping them out of privileged system context, and show limited bootstrap guidance when workspace file access is unavailable. Fixes #73622. Thanks @mark1010.</li>
<li>ACP/tasks: classify parent-owned ACP sessions as background work regardless of persistent runtime mode, and close terminal stale ACP sessions when no active binding remains, so delegated ACP output reports through the parent task notifier instead of acting like a normal foreground chat session. Refs #73609. Thanks @joerod26.</li>
<li>Tasks: keep terminal mirrored TaskFlow timestamps pinned to task completion time and let maintenance repair stale mirrors, so ACP terminal delivery updates no longer leave inconsistent flow audits. Refs #73609. Thanks @joerod26.</li>
<li>Gateway/sessions: add conservative stuck-session recovery that releases only stale session lanes while active embedded runs, reply operations, and lane tasks remain serialized, so queued follow-ups can drain without aborting legitimate long-running turns. Refs #73581, #73655, #73652, #73705, #73647, #73602, #73592, and #73601. Thanks @WS-Q0758, @bryangauvin, @spenceryang1996-dot, @bmilne1981, @mattmcintyre, @Vksh07, and @Spolen23.</li>
<li>Plugins: cache unchanged plugin manifest loads by file signature, reducing repeated JSON/JSON5 parsing and manifest normalization in bursty startup and runtime registry paths. Refs #73532 and #73647; carries forward #73678. Thanks @TheDutchRuler.</li>
<li>Plugins/runtime-deps: cache unchanged bundled runtime mirror dist-file materialization decisions and close file-lock handles on owner-write failures, reducing repeated startup chunk scans and avoiding FileHandle-GC recovery stalls. Refs #73532. Thanks @oadiazp and @bstanbury.</li>
<li>Plugins/runtime-deps: retry and defer transient cleanup failures for owned runtime staging directories so CLI startup no longer aborts after a successful bundled dependency swap. Refs #73903. Thanks @bobfreeman1989.</li>
<li>Plugins/runtime-deps: cache bundled runtime-deps JSON/package files by file signature, reducing repeated staged-runtime metadata reads during bundled channel startup. Refs #73647 and #73705. Thanks @mattmcintyre and @bmilne1981.</li>
<li>Plugins/runtime-deps: delegate bundled plugin dependency staging to complete npm/pnpm install plans with durable runtime state, removing retained-manifest and source-checkout cache reconciliation from Gateway startup. Refs #73532. Thanks @oadiazp, @bstanbury, and @jmfraga.</li>
<li>Plugins/runtime-deps: replace Gateway-start root chunk dependency inference with explicit mirrored-root dependency metadata, reducing staged runtime scans while preserving lazy per-plugin installs. Refs #73532. Thanks @oadiazp and @bstanbury.</li>
<li>Plugins/runtime-deps: run pnpm staged installs outside the repository workspace and disable pnpm release-age gates for exact bundled runtime dependency materialization, so bundled plugin dependency repair writes packages into the generated stage without blocking fresh packaged dependencies. Refs #73532. Thanks @oadiazp and @bstanbury.</li>
<li>CLI/TUI: keep <code>chat.history</code> off model-catalog discovery so initial Gateway-backed TUI history loads cannot block behind slow provider/plugin model scans on low-core hosts. Refs #73524. Thanks @harshcatsystems-collab.</li>
<li>Channels/WhatsApp: flag recently reconnected linked accounts in channel status even when the socket is currently healthy, so flapping WhatsApp Web sessions no longer look clean after a brief reconnect. Refs #73602. Thanks @Vksh07.</li>
<li>Channels/WhatsApp: log shared dispatcher delivery failures with reply kind, message id, chat id, and connection id, so typing-without-send reports can identify whether the WhatsApp send path rejected a generated reply. Refs #74269. Thanks @tomcosta-git.</li>
<li>Feishu: suppress distinct late <code>final</code> text deliveries after a streaming card has already closed, while keeping media attachments deliverable, so late-finals no longer reopen duplicate Feishu cards. Fixes #71977. (#72294) Thanks @MonkeyLeeT.</li>
<li>Gateway: expose <code>gateway.handshakeTimeoutMs</code> in config, schema, and docs while preserving <code>OPENCLAW_HANDSHAKE_TIMEOUT_MS</code> precedence, so loaded or low-powered hosts can tune local WebSocket pre-auth handshakes without patching dist files. Supersedes #51282; refs #73592 and #73652. Thanks @henry-the-frog.</li>
<li>Gateway/TUI/status: align configured and env-based WebSocket handshake budgets across local clients, probes, and fallback RPCs while preserving explicit status timeouts and paired-device auth fallback, so slow local gateways are not marked unreachable by a shorter client watchdog. Refs #73524, #73535, #73592, and #73602. Thanks @harshcatsystems-collab, @DJBlackhawk, and @Vksh07.</li>
<li>Gateway/startup: return retryable <code>UNAVAILABLE</code> during the sidecar startup window and keep CLI/TUI/status clients retrying inside their existing timeout budget, so early connects no longer surface as terminal handshake failures. Fixes #73652. Thanks @spenceryang1996-dot.</li>
<li>Gateway/proxy: bypass inherited proxy environment for local Gateway control-plane WebSockets to <code>localhost</code> as well as loopback IPs, so Windows/WSL proxy settings cannot intercept local CLI/TUI Gateway connections. Supersedes #73474; refs #73602. Thanks @DhtIsCoding.</li>
<li>Doctor/Gateway: use a lightweight <code>status</code> RPC without channel summary work for doctor Gateway liveness, so slow health snapshots do not falsely drive service restart repair. Fixes #64400; supersedes #64511. Thanks @CHE10X and @EronFan.</li>
<li>Agents/auth: scope external CLI credential discovery to configured providers during model auth status and startup prewarm, so opencode-only and other single-provider gateways do not block on unrelated Claude CLI Keychain probes. Fixes #73908. Thanks @Ailuras.</li>
<li>Agents/model selection: resolve slash-form aliases before provider/model parsing and keep alias-resolved primary models subject to transient provider cooldowns, so cron and persisted sessions do not retry cooled-down raw aliases. Fixes #73573 and #73657. Thanks @akai-shuuichi and @hashslingers.</li>
<li>Agents/Claude CLI: reuse already-cached macOS Keychain credentials for no-prompt Claude credential reads, so doctor/runtime checks do not miss fresh interactive Claude auth. Fixes #73682. Thanks @RyanSandoval.</li>
<li>Agents/Claude CLI doctor: scope workspace and project-dir checks to agents that actually use the Claude CLI runtime, so non-default Claude agents no longer make the default agent look Claude-backed. Fixes #73903. Thanks @bobfreeman1989.</li>
<li>Gateway/sessions: expose effective agent runtime metadata on session rows, <code>sessions.patch</code>, and local <code>openclaw sessions --json</code>, while keeping Claude CLI-backed rows on the canonical model provider so runtime backend and model identity are no longer conflated. Fixes #73090. Thanks @vishutdhar.</li>
<li>Gateway/auth status: scope external CLI credential overlays to configured providers, runtimes, or profiles and keep status reads off new Keychain prompts, so single-provider Gateway configs no longer probe unrelated Claude/Codex/MiniMax auth on startup. Fixes #73908. Thanks @Ailuras.</li>
<li>Agents/runtime status: expose effective agent runtime metadata in <code>agents.list</code>, Control UI agent panels, and <code>/agents</code>, and avoid rendering stale or cumulative CLI token totals as live context usage. Fixes #73660, #73578, and #45268. Thanks @spartman, @DashLabsDev, and @xyooz.</li>
<li>Agents/transcripts: strip empty assistant text blocks while preserving valid text, images, and signatures, so Anthropic-style providers no longer reject sanitized transcript turns. Fixes #73640. Thanks @jowhee327.</li>
<li>Gateway/sessions: preserve session keys on hidden lifecycle events so channel-routed runs still persist terminal session state and do not strand session status as running after Codex turn completion. Thanks @cathrynlavery.</li>
<li>Providers/Bedrock: omit deprecated <code>temperature</code> for Claude Opus 4.7 Bedrock model ids, named and application inference profiles, including dotted <code>opus-4.7</code> refs, and classify the nested validation response for failover. Fixes #73663. Thanks @bstanbury.</li>
<li>Gateway: raise the preauth/connect-challenge timeout to 15s so cold CLI starts on slower hosts have more time to process the WebSocket challenge before the Gateway closes the connection. Fixes #51469; refs #73592 and #62060. Thanks @GothicFox and @jackychen-png.</li>
<li>CLI/status: fall back to a bounded local <code>status</code> RPC when loopback detail probes time out or report unknown capability, so reachable local gateways are no longer marked unreachable by slow read diagnostics. Fixes #73535; refs #48360, #62762, #51357, and #42019. Thanks @RacecarGuy, @justinschille, @DJBlackhawk, @tianyaqpzm, and @0xrsydn.</li>
<li>CLI/gateway: reuse cached paired-device auth during <code>gateway probe</code> and report post-connect diagnostic failures as degraded reachability, so healthy local gateways are no longer marked unreachable after loopback auth or read timeouts. Fixes #48360. Thanks @RacecarGuy.</li>
<li>Channels/Discord: give Discord Gateway WebSocket handshakes a 30s timeout so stalled TLS/network transitions emit an error and Carbon can continue its reconnect loop instead of leaving the bot silent until restart. Refs #50046. Thanks @codexGW.</li>
<li>Mattermost/WebSocket: send protocol ping/pong keepalives and terminate stale sessions when pongs stop arriving, so silent TCP drops reconnect instead of leaving monitoring idle. Fixes #41837; carries forward #57621; refs #50138, #44160, and #51104. Thanks @JasonWang1124.</li>
<li>Channels/Telegram: suppress standalone failed edit/write warning payloads when a user-facing assistant error reply already covers the turn, while keeping unresolved mutating failures visible behind success-looking or suppressed-error replies. Fixes #39631; refs #73750; carries forward #39636 and #39717; leaves #39406 for configurable delivery policy. Thanks @Bartok9 and @Bortlesboat.</li>
<li>Control UI/agents: persist the Set Default action through <code>agents.list[].default</code> instead of writing the unsupported <code>agents.defaultId</code> field, so saved default-agent changes survive config validation. Fixes #65565; carries forward #72585. Thanks @luyao618.</li>
<li>NVIDIA/NIM: persist the <code>NVIDIA_API_KEY</code> provider marker and mark bundled NVIDIA Chat Completions models as string-content compatible, so NIM models load from <code>models.json</code> and OpenAI-compatible subagent calls send plain text content. Fixes #73013 and #50107; refs #73014. Thanks @bautrey, @iot2edge, @ifearghal, and @futhgar.</li>
<li>Channels/Discord: let text-only configs drop the <code>GuildVoiceStates</code> gateway intent and expose a bounded <code>/gateway/bot</code> metadata timeout with rate-limited fallback logs, reducing idle CPU and warning floods. Fixes #73709 and #73585. Thanks @sanchezm86 and @trac3r00.</li>
<li>Agents/sessions: mark same-turn <code>sessions_send</code> and A2A reply prompts with an inter-session <code>isUser=false</code> envelope before they reach the model, so foreign session output no longer lands as bare active user text. Fixes #73702; refs #73698, #73609, #73595, and #73622. Thanks @alvelda.</li>
<li>Channels/Telegram: fail closed when account-level public DM settings conflict with a restrictive top-level <code>allowFrom</code>, and require an effective wildcard before <code>dmPolicy="open"</code> behaves as public access. Fixes #73756; refs #73698. Thanks @Hilo-Hilo and @xace1825.</li>
<li>Channels/security: move open-DM allowlist semantics into the shared policy helpers and align Discord, Slack, Mattermost, Matrix, Feishu, LINE, IRC, Google Chat, Zalo, Zalo User, QQ Bot, and Synology Chat so <code>dmPolicy="open"</code> is public only with an effective wildcard and otherwise still respects sender allowlists. Refs #73756 and #73698. Thanks @Hilo-Hilo and @xace1825.</li>
<li>ACP/tasks: sweep orphaned parent-owned ACP sessions whose task records are gone, preserving bound persistent sessions but clearing unbound stale ACPX metadata so old child sessions cannot silently respawn into chat. Fixes #73609. Thanks @joerod26.</li>
<li>Outbound/security: strip known internal runtime scaffolding such as <code><system-reminder></code> and <code><previous_response></code> at the final channel delivery boundary and keep Discord output on targeted tag stripping, so degraded harness replies cannot leak those tags to users. Fixes #73595. Thanks @gabrielexito-stack and @martingarramon.</li>
<li>Security/Telegram: load Telegram security adapters in read-only audit/doctor, audit malformed Telegram DM <code>allowFrom</code> entries even when groups are disabled, and keep allowlist DM audits from counting stale pairing-store senders, so public/shared-DM risk checks stay accurate. Refs #73698. Thanks @xace1825.</li>
<li>Plugins: remove hidden manifest, provider-owner, bootstrap, and channel metadata caches so plugin installs, manifest edits, and bundled-root changes are visible on the next metadata read while keeping runtime/module loader caches for actual plugin code. Thanks @shakkernerd.</li>
<li>CLI/plugins: use plugin metadata snapshots for install slot selection and add opt-in plugin lifecycle timing traces, so plugin install avoids runtime-loading the plugin registry for metadata-only decisions. Thanks @shakkernerd.</li>
<li>fix(plugins): restrict bundled plugin dir resolution to trusted package roots. (#73275) Thanks @pgondhi987.</li>
<li>fix(security): prevent workspace PATH injection via service env and trash helpers. (#73264) Thanks @pgondhi987.</li>
<li>Active Memory: allow <code>allowedChatTypes</code> to include explicit portal/webchat sessions and classify <code>agent:...:explicit:...</code> session keys before opaque session ids can shadow the chat type. Fixes #65775. (#66285) Thanks @Lidang-Jiang.</li>
<li>Active Memory: allow the hidden recall sub-agent to use both <code>memory_recall</code> and the legacy <code>memory_search</code>/<code>memory_get</code> memory tool contract, so bundled <code>memory-lancedb</code> recall works without breaking the default <code>memory-core</code> path. Fixes #73502. (#73584) Thanks @Takhoffman.</li>
<li>fix(device-pairing): validate callerScopes against resolved token scopes on repair [AI]. (#72925) Thanks @pgondhi987.</li>
<li>Active Memory docs: document the <code>cacheTtlMs</code> 1000-120000 ms range and 15000 ms default so setup snippets do not lead users past the schema limit. Fixes #65708. (#65737) Thanks @WuKongAI-CMU.</li>
<li>fix(agents): canonicalize provider aliases in byProvider tool policy lookup [AI]. (#72917) Thanks @pgondhi987.</li>
<li>fix(security): block npm_execpath injection from workspace .env [AI-assisted]. (#73262) Thanks @pgondhi987.</li>
<li>Tools/web_fetch: decode response bodies from raw bytes using declared HTTP, XML, or HTML meta charsets before extraction, so Shift_JIS and other legacy-charset pages no longer return mojibake. Fixes #72916. Thanks @amknight.</li>
<li>Active Memory: skip payload-less <code>memory_search</code> transcript tool results when building debug telemetry, so newer empty entries no longer hide the latest useful debug payload. (#68773) Thanks @SimbaKingjoe.</li>
<li>Active Memory: keep recall setup time from consuming the configured model timeout while giving the hook runner an explicit bounded budget for the plugin, so slow embedded-run setup no longer causes immediate recall timeouts. Fixes #72606. (#72620) Thanks @hyspacex.</li>
<li>Channels/Discord: bound message read/search REST calls, route those actions through Gateway execution, and fall back to <code>CommandTargetSessionKey</code> for inbound hook session keys so Discord reads do not hang and hooks still fire when <code>SessionKey</code> is empty. Fixes #73431. (#73521) Thanks @amknight.</li>
<li>Plugins/media: auto-enable provider plugins referenced by <code>agents.defaults.imageGenerationModel</code>, <code>videoGenerationModel</code>, and <code>musicGenerationModel</code> primary/fallback refs, so configured Google and MiniMax media providers do not stay disabled behind a restrictive plugin allowlist. Thanks @vincentkoc.</li>
<li>Memory-core/dreaming: retry managed dreaming cron registration after startup when the cron service is not reachable yet, so the scheduled Memory Dreaming Promotion sweep recovers without waiting for heartbeat traffic. Fixes #72841. Thanks @amknight.</li>
<li>Acpx/runtime: validate the runtime session mode at the <code>AcpxRuntime.ensureSession</code> wrapper boundary so callers that pass anything other than <code>persistent</code> or <code>oneshot</code> get a clear <code>ACP_INVALID_RUNTIME_OPTION</code> error instead of silently round-tripping through the encoded handle as a default <code>persistent</code> mode and later throwing <code>SessionResumeRequiredError</code>. Investigation context: #73071. (#73548) Thanks @amknight.</li>
<li>CLI/infer: keep web-search fallback on missing provider API keys, preserve structured validation errors from the selected provider, and let per-request image describe prompts override configured media-entry prompts. (#63263) Thanks @Spolen23.</li>
<li>Chat commands: include configured model-catalog reasoning metadata when building <code>/think</code> argument menus so Ollama Cloud and other provider-owned reasoning models show supported levels instead of only <code>off</code>. Fixes #73515; supersedes #73568. Thanks @danielzinhu99 and @neeravmakwana.</li>
<li>Channels/Telegram: suppress generic tool-progress chatter when preview streaming is off, so non-streaming Telegram turns only deliver final replies while approvals, media, and errors still route normally. Refs #72363 and #72482. Thanks @neeravmakwana and @SweetSophia.</li>
<li>CLI/model probes: add repeatable image <code>--file</code> inputs to <code>infer model run</code> for local and gateway multimodal model smokes, so vision models such as Ollama Qwen VL and Gemini can be tested through the raw model-probe surface. Fixes #63700. Thanks @cedricjanssens.</li>
<li>CLI/model probes: request trusted operator scope for <code>infer model run --gateway --model <provider/model></code> so Gateway raw model smokes can use one-off provider/model overrides instead of being rejected before provider auth resolution. Fixes #73759. Thanks @chrislro.</li>
<li>CLI/image describe: pass <code>--prompt</code> and <code>--timeout-ms</code> through <code>infer image describe</code> and <code>describe-many</code>, so custom vision instructions and slow local model budgets reach media-understanding providers such as Ollama, OpenAI, Google, and OpenRouter. Refs #63700. Thanks @cedricjanssens.</li>
<li>Model selection: include the rejected provider/model ref and allowlist recovery hint when a stored session override is cleared, so local model selections such as Gemma GGUF variants do not fall back to the default with a generic message. Refs #71069. Thanks @CyberRaccoonTeam.</li>
<li>OpenAI-compatible providers: drop malformed event-only or blank-data SSE frames before the OpenAI SDK stream parser sees them, so proxies that split <code>event:</code> from <code>data:</code> no longer crash streaming runs with <code>Unexpected end of JSON input</code>. Fixes #52802. Thanks @LyHug.</li>
<li>Gateway/OpenAI-compatible streaming: strip <code><final></code> tags split across streamed model deltas before they reach SSE clients, so <code>/v1/chat/completions</code> no longer emits tag remnants or drops content when final-answer wrappers cross chunk boundaries. Fixes #63325. Thanks @tzwickl.</li>
<li>Ollama: resolve explicitly selected signed-in <code>:cloud</code> models through <code>/api/show</code> when <code>/api/tags</code> omits them, so working models such as <code>gemini-3-flash-preview:cloud</code> and <code>deepseek-v4-pro:cloud</code> do not fail dynamic model resolution before the native <code>/api/chat</code> transport runs. Fixes #73909. Thanks @chtse53.</li>
<li>Discord/exec approvals: keep the local <code>/approve</code> prompt when no native Discord approval runtime is active, and send a manual fallback notice when native approval delivery reaches no targets, so failed DM cards no longer leave approval turns silent or dependent on model-written shell commands. Fixes #73954; carries forward #74027. Thanks @guarismo and @brokemac79.</li>
<li>Local model prompt caching: keep stable Project Context above volatile channel/session prompt guidance and stop embedding current channel names in the message tool description, so Ollama, MLX, llama.cpp, and other prefix-cache backends avoid avoidable full prompt reprocessing across channel turns. Fixes #40256; supersedes #40296. Thanks @rhclaw and @sriram369.</li>
<li>Gateway/OpenAI-compatible API: guard provider policy lookup against runtime providers with non-array <code>models</code> values, so <code>/v1/chat/completions</code> no longer fails with <code>provider?.models?.some is not a function</code>. Fixes #66744; carries forward #66761. Thanks @MightyMoud, @MukundaKatta.</li>
<li>WhatsApp/Web: pass explicit Baileys socket timings into every WhatsApp Web socket and expose <code>web.whatsapp.*</code> keepalive, connect, and query timeout settings so unstable networks can avoid repeated 408 disconnect and opening-handshake timeout loops. Fixes #56365. (#73580) Thanks @velvet-shark.</li>
<li>WhatsApp/Web: recover recently active listeners when a post-408 reconnect keeps receiving transport frames but stops delivering app messages, while keeping group metadata fallback off Baileys sends. Fixes #63855 and #66920; refs #7433, #67986, #70856, #60007, and #72621. Thanks @legonhilltech-jpg, @octopuslabs-fl, @Kanorin-chan, and @stuswan.</li>
<li>Channels/Telegram: persist native command metadata on target sessions so topic, helper, and ACP-bound slash commands keep their session metadata attached to the routed conversation. (#57548) Thanks @GaosCode.</li>
<li>Channels/native commands: keep validated native slash command replies visible in group chats while preserving explicit owner allowlists for command authorization. (#73672) Thanks @obviyus.</li>
<li>Pairing/doctor: bootstrap <code>commands.ownerAllowFrom</code> from the first approved DM pairing when no command owner exists, and have doctor explain missing owners so privileged slash commands are not accidentally unusable after onboarding. Thanks @pashpashpash.</li>
<li>Telegram/exec: infer native exec approvers from <code>commands.ownerAllowFrom</code> and auto-enable the Telegram approval client when an owner is resolvable, so owner-only commands such as <code>/diagnostics</code> can be approved in Telegram without duplicate per-channel approver config. Thanks @pashpashpash.</li>
<li>Auto-reply/session: carry the tail of user/assistant turns into the freshly-rotated transcript on silent in-reply session resets (compaction failure, role-ordering conflict) so direct-chat continuity survives the rebind. Fixes #70853. (#70898) Thanks @neeravmakwana.</li>
<li>Skills: load grouped skill directories such as <code>skills/<group>/<skill>/SKILL.md</code> from configured skill roots while keeping grouped discovery capped for large directories. Fixes #56915. (#72534) Thanks @ottodeng, @MoerAI, and @i010542.</li>
<li>Config: skip malformed non-string <code>env.vars</code> entries before env-reference checks, so config loading no longer crashes on JSON values like numbers or booleans. (#42402) Thanks @MiltonHeYan.</li>
<li>Docker Compose: default missing config and workspace bind mounts to <code>${HOME:-/tmp}/.openclaw</code> so manual compose runs do not create invalid empty-source volume specs. (#64485) Thanks @jlapenna.</li>
<li>Agents/context engines: preserve the child agent's configured <code>agentDir</code> when subagent cleanup re-resolves a context engine, so <code>onSubagentEnded</code> hooks keep operating on the correct per-agent state. (#67243) Thanks @jarimustonen.</li>
<li>Channels/WhatsApp: restrict pairing verification replies to real inbound user content, preventing unsolicited prompts from receipts, typing indicators, presence updates, and other non-message Baileys upserts. Fixes #73797. (#73823) Thanks @hclsys.</li>
<li>Configure/Ollama: show the configured Ollama model allowlist after Cloud only or Cloud + Local setup and skip slow per-model cloud metadata fetches. (#73995) Thanks @obviyus.</li>
<li>Channels/WhatsApp: detect explicit group <code>@mentions</code> again when the bot's own E.164 is in <code>allowFrom</code>, so shared-number setups no longer skip group pings that directly mention the bot. Fixes #49317. (#73453) Thanks @juan-flores077.</li>
<li>WhatsApp/reliability: publish real transport-liveness into WhatsApp channel status and force earlier reconnects on silent transport stalls, so quiet healthy sessions stay connected while wedged sockets recover before the later remote 408 path. (#72656) Thanks @Sathvik-1007.</li>
<li>Core/channels: tighten selected runtime, media, and plugin edge-case handling while preserving existing behavior. Thanks @jesse-merhi.</li>
<li>Channels/WhatsApp: strip leaked plural tool-call XML wrappers on every WhatsApp-visible outbound path and keep channel error payloads out of WhatsApp chats. (#71830) Thanks @rubencu.</li>
<li>Agents/embedded-runner: inject the resolved OAuth bearer (and forward the run abort signal) on the boundary-aware embedded stream fallback so models that route through <code>openai-codex-responses</code> and other boundary-aware transports stop failing with <code>401 Unauthorized: Missing bearer or basic authentication in header</code>. Fixes #73559. (#73588) Thanks @openperf.</li>
<li>Telegram/gateway: bound outbound Bot API calls and cache bundled plugin alias lookup so slow Telegram sends or WSL2 filesystem scans no longer wedge gateway replies. (#74210) Thanks @obviyus.</li>
<li>Configure/GitHub Copilot: reuse existing Copilot auth during configure and show the provider's manifest model catalog in the model picker. (#74276) Thanks @obviyus.</li>
<li>Configure/models: keep the model picker scoped to the selected manifest provider and enable its bundled plugin before catalog lookup, so choosing GitHub Copilot no longer falls back to Ollama or skips the catalog. (#74322) Thanks @obviyus.</li>
<li>Auto-reply/subagents: reject <code>/focus</code> from leaf subagents and scope fallback target resolution to the requesting subagent's children, so subagents cannot bind conversations outside their control boundary. (#73613) Thanks @drobison00.</li>
<li>Gateway/startup: skip inherited workspace startup memory for sandboxed spawned sessions without real-workspace write access, so <code>/new</code> no longer preloads host workspace memory into isolated child runs. (#73611) Thanks @drobison00.</li>
<li>Agents/tool policy: validate caller group IDs against session or spawned context before applying group-scoped tool policies or persisting gateway group metadata, so forged group IDs cannot unlock more permissive tools. (#73720) Thanks @mmaps.</li>
<li>Commands: keep channel-prefixed owner allowlist entries scoped to matching providers so webchat command contexts cannot inherit external channel owners. Thanks @zsxsoft.</li>
<li>Auth/device pairing: bound bootstrap handoff token issuance, redemption, and approved pairing baselines to the documented per-role scope allowlist, so bootstrap approvals cannot persistently grant <code>operator.admin</code>, <code>operator.pairing</code>, or <code>node.exec</code> scopes. Thanks @eleqtrizit.</li>
<li>Providers/GitHub Copilot: support the GUI/RPC wizard device-code auth flow so onboarding from non-TTY clients (gateway RPC bridge, GUI wizards) completes instead of returning empty profiles. Dangerous-state handling now distinguishes <code>access_denied</code> and <code>expired_token</code> from transport errors. (#73290) Thanks @indierawk2k2.</li>
<li>Installer/Linux: warn before switching an unwritable npm global prefix to <code>~/.npm-global</code>, then tell users to run future global updates with <code>npm i -g openclaw@latest</code> without <code>sudo</code> so npm keeps using the redirected user prefix. Fixes #44365; carries forward #50479. Thanks @Sayeem3051.</li>
<li>Gateway/plugins: enable the native <code>require()</code> fast path on Windows for bundled plugin modules so plugin loading uses <code>require()</code> instead of Jiti's transform pipeline, reducing startup from ~39s to ~2s on typical 6-plugin setups. Fixes #68656. (#74173) Thanks @galiniliev.</li>
<li>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.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.4.29/OpenClaw-2026.4.29.zip" length="50896802" type="application/octet-stream" sparkle:edSignature="YfQ25zMGgDv8XvHbdlL/s0SMJXyu763l5ppnfjiKOjSyxZY9sfoLaoXthcctFQDXA8isR1EEb/EEausu+XkFCA=="/>
</item>
</channel>
</rss>

View File

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

View File

@@ -1612,15 +1612,6 @@ internal fun resolveOperatorSessionConnectAuth(
)
}
val explicitBootstrapToken = auth.bootstrapToken?.trim()?.takeIf { it.isNotEmpty() }
if (explicitBootstrapToken != null) {
return NodeRuntime.GatewayConnectAuth(
token = null,
bootstrapToken = explicitBootstrapToken,
password = null,
)
}
return null
}

View File

@@ -1,4 +1,4 @@
package ai.openclaw.app.gateway
const val GATEWAY_PROTOCOL_VERSION = 4
const val GATEWAY_MIN_PROTOCOL_VERSION = 3
const val GATEWAY_MIN_PROTOCOL_VERSION = 4

View File

@@ -64,6 +64,7 @@ data class GatewayConnectErrorDetails(
val code: String?,
val canRetryWithDeviceToken: Boolean,
val recommendedNextStep: String?,
val pauseReconnect: Boolean? = null,
val reason: String? = null,
)
@@ -736,6 +737,7 @@ class GatewaySession(
code = it["code"].asStringOrNull(),
canRetryWithDeviceToken = it["canRetryWithDeviceToken"].asBooleanOrNull() == true,
recommendedNextStep = it["recommendedNextStep"].asStringOrNull(),
pauseReconnect = it["pauseReconnect"].asBooleanOrNull(),
reason = it["reason"].asStringOrNull(),
)
}
@@ -1040,20 +1042,17 @@ class GatewaySession(
detailCode == "AUTH_TOKEN_MISMATCH"
}
private fun shouldPauseReconnectAfterAuthFailure(error: ErrorShape): Boolean =
when (error.details?.code) {
"AUTH_TOKEN_MISSING",
"AUTH_BOOTSTRAP_TOKEN_INVALID",
"AUTH_PASSWORD_MISSING",
"AUTH_PASSWORD_MISMATCH",
"AUTH_RATE_LIMITED",
"PAIRING_REQUIRED",
"CONTROL_UI_DEVICE_IDENTITY_REQUIRED",
"DEVICE_IDENTITY_REQUIRED",
-> true
"AUTH_TOKEN_MISMATCH" -> deviceTokenRetryBudgetUsed && !pendingDeviceTokenRetry
else -> false
}
private fun shouldPauseReconnectAfterAuthFailure(error: ErrorShape): Boolean {
val target = desired
return shouldPauseGatewayReconnectAfterAuthFailure(
error = error,
hasBootstrapToken = target?.bootstrapToken?.trim()?.isNotEmpty() == true,
role = target?.options?.role,
scopes = target?.options?.scopes ?: emptyList(),
deviceTokenRetryBudgetUsed = deviceTokenRetryBudgetUsed,
pendingDeviceTokenRetry = pendingDeviceTokenRetry,
)
}
private fun shouldClearStoredDeviceTokenAfterRetry(error: ErrorShape): Boolean = error.details?.code == "AUTH_DEVICE_TOKEN_MISMATCH"
@@ -1068,6 +1067,36 @@ class GatewaySession(
}
}
internal fun shouldPauseGatewayReconnectAfterAuthFailure(
error: GatewaySession.ErrorShape,
hasBootstrapToken: Boolean,
role: String?,
scopes: List<String>,
deviceTokenRetryBudgetUsed: Boolean,
pendingDeviceTokenRetry: Boolean,
): Boolean =
when (error.details?.code) {
"AUTH_TOKEN_MISSING",
"AUTH_BOOTSTRAP_TOKEN_INVALID",
"AUTH_PASSWORD_MISSING",
"AUTH_PASSWORD_MISMATCH",
"AUTH_RATE_LIMITED",
"CONTROL_UI_DEVICE_IDENTITY_REQUIRED",
"DEVICE_IDENTITY_REQUIRED",
-> true
"PAIRING_REQUIRED" ->
!(
hasBootstrapToken &&
role?.trim() == "node" &&
scopes.isEmpty() &&
error.details.reason == "not-paired" &&
(error.details.pauseReconnect == false ||
error.details.recommendedNextStep == "wait_then_retry")
)
"AUTH_TOKEN_MISMATCH" -> deviceTokenRetryBudgetUsed && !pendingDeviceTokenRetry
else -> false
}
internal fun buildGatewayWebSocketUrl(
host: String,
port: Int,

View File

@@ -29,14 +29,14 @@ import java.util.UUID
@Config(sdk = [34])
class GatewayBootstrapAuthTest {
@Test
fun connectsOperatorSessionWhenOnlyBootstrapAuthExists() {
assertTrue(
fun doesNotConnectOperatorSessionWhenOnlyBootstrapAuthExists() {
assertFalse(
shouldConnectOperatorSession(
NodeRuntime.GatewayConnectAuth(token = "", bootstrapToken = "bootstrap-1", password = ""),
storedOperatorToken = "",
),
)
assertTrue(
assertFalse(
shouldConnectOperatorSession(
NodeRuntime.GatewayConnectAuth(token = null, bootstrapToken = "bootstrap-1", password = null),
storedOperatorToken = null,
@@ -84,17 +84,14 @@ class GatewayBootstrapAuthTest {
}
@Test
fun resolveOperatorSessionConnectAuthUsesBootstrapWhenNoStoredOperatorTokenExists() {
fun resolveOperatorSessionConnectAuthIgnoresBootstrapWhenNoStoredOperatorTokenExists() {
val resolved =
resolveOperatorSessionConnectAuth(
auth = NodeRuntime.GatewayConnectAuth(token = null, bootstrapToken = "bootstrap-1", password = null),
storedOperatorToken = null,
)
assertEquals(
NodeRuntime.GatewayConnectAuth(token = null, bootstrapToken = "bootstrap-1", password = null),
resolved,
)
assertNull(resolved)
}
@Test
@@ -174,7 +171,7 @@ class GatewayBootstrapAuthTest {
assertEquals("fp-1", prefs.loadGatewayTlsFingerprint(endpoint.stableId))
assertEquals("setup-bootstrap-token", desiredBootstrapToken(runtime, "nodeSession"))
assertEquals("setup-bootstrap-token", desiredBootstrapToken(runtime, "operatorSession"))
assertNull(desiredBootstrapToken(runtime, "operatorSession"))
}
@Test

View File

@@ -0,0 +1,116 @@
package ai.openclaw.app.gateway
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class GatewaySessionReconnectTest {
@Test
fun bootstrapNodePairingRequiredKeepsReconnectActive() {
val error =
GatewaySession.ErrorShape(
code = "NOT_PAIRED",
message = "pairing required",
details =
GatewayConnectErrorDetails(
code = "PAIRING_REQUIRED",
canRetryWithDeviceToken = false,
recommendedNextStep = "wait_then_retry",
pauseReconnect = false,
reason = "not-paired",
),
)
assertFalse(
shouldPauseGatewayReconnectAfterAuthFailure(
error = error,
hasBootstrapToken = true,
role = "node",
scopes = emptyList(),
deviceTokenRetryBudgetUsed = false,
pendingDeviceTokenRetry = false,
),
)
}
@Test
fun bootstrapNodePairingRequiredWithoutRetryHintPausesReconnect() {
val error =
GatewaySession.ErrorShape(
code = "NOT_PAIRED",
message = "pairing required",
details =
GatewayConnectErrorDetails(
code = "PAIRING_REQUIRED",
canRetryWithDeviceToken = false,
recommendedNextStep = null,
reason = "not-paired",
),
)
assertTrue(
shouldPauseGatewayReconnectAfterAuthFailure(
error = error,
hasBootstrapToken = true,
role = "node",
scopes = emptyList(),
deviceTokenRetryBudgetUsed = false,
pendingDeviceTokenRetry = false,
),
)
}
@Test
fun nonBootstrapPairingRequiredStillPausesReconnect() {
val error =
GatewaySession.ErrorShape(
code = "NOT_PAIRED",
message = "pairing required",
details =
GatewayConnectErrorDetails(
code = "PAIRING_REQUIRED",
canRetryWithDeviceToken = false,
recommendedNextStep = "wait_then_retry",
reason = "not-paired",
),
)
assertTrue(
shouldPauseGatewayReconnectAfterAuthFailure(
error = error,
hasBootstrapToken = false,
role = "node",
scopes = emptyList(),
deviceTokenRetryBudgetUsed = false,
pendingDeviceTokenRetry = false,
),
)
}
@Test
fun bootstrapRoleUpgradeStillPausesReconnect() {
val error =
GatewaySession.ErrorShape(
code = "NOT_PAIRED",
message = "pairing required",
details =
GatewayConnectErrorDetails(
code = "PAIRING_REQUIRED",
canRetryWithDeviceToken = false,
recommendedNextStep = null,
reason = "role-upgrade",
),
)
assertTrue(
shouldPauseGatewayReconnectAfterAuthFailure(
error = error,
hasBootstrapToken = true,
role = "node",
scopes = emptyList(),
deviceTokenRetryBudgetUsed = false,
pendingDeviceTokenRetry = false,
),
)
}
}

View File

@@ -1,5 +1,9 @@
# OpenClaw iOS Changelog
## 2026.5.12 - 2026-05-12
Maintenance update for the current OpenClaw beta release.
## 2026.5.10 - 2026-05-10
Maintenance update for the current OpenClaw beta 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.10
OPENCLAW_MARKETING_VERSION = 2026.5.10
OPENCLAW_IOS_VERSION = 2026.5.16
OPENCLAW_MARKETING_VERSION = 2026.5.16
OPENCLAW_BUILD_VERSION = 1
#include? "../build/Version.xcconfig"

View File

@@ -4,15 +4,19 @@ import OpenClawKit
final class CalendarService: CalendarServicing {
func events(params: OpenClawCalendarEventsParams) async throws -> OpenClawCalendarEventsPayload {
let store = EKEventStore()
let status = EKEventStore.authorizationStatus(for: .event)
let authorized = EventKitAuthorization.allowsRead(status: status)
let authorized: Bool = if status == .notDetermined || status == .writeOnly {
await Self.requestFullEventAccess()
} else {
EventKitAuthorization.allowsRead(status: status)
}
guard authorized else {
throw NSError(domain: "Calendar", code: 1, userInfo: [
NSLocalizedDescriptionKey: "CALENDAR_PERMISSION_REQUIRED: grant Calendar permission",
])
}
let store = EKEventStore()
let (start, end) = Self.resolveRange(
startISO: params.startISO,
endISO: params.endISO)
@@ -37,15 +41,19 @@ final class CalendarService: CalendarServicing {
}
func add(params: OpenClawCalendarAddParams) async throws -> OpenClawCalendarAddPayload {
let store = EKEventStore()
let status = EKEventStore.authorizationStatus(for: .event)
let authorized = EventKitAuthorization.allowsWrite(status: status)
let authorized: Bool = if status == .notDetermined {
await Self.requestWriteOnlyEventAccess()
} else {
EventKitAuthorization.allowsWrite(status: status)
}
guard authorized else {
throw NSError(domain: "Calendar", code: 2, userInfo: [
NSLocalizedDescriptionKey: "CALENDAR_PERMISSION_REQUIRED: grant Calendar permission",
])
}
let store = EKEventStore()
let title = params.title.trimmingCharacters(in: .whitespacesAndNewlines)
guard !title.isEmpty else {
throw NSError(domain: "Calendar", code: 3, userInfo: [
@@ -95,6 +103,24 @@ final class CalendarService: CalendarServicing {
return OpenClawCalendarAddPayload(event: payload)
}
private static func requestFullEventAccess() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestFullAccessToEvents { granted, _ in
completion(granted)
}
}
}
private static func requestWriteOnlyEventAccess() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestWriteOnlyAccessToEvents { granted, _ in
completion(granted)
}
}
}
private static func resolveCalendar(
store: EKEventStore,
calendarId: String?,

View File

@@ -97,14 +97,17 @@ final class ContactsService: ContactsServicing {
return OpenClawContactsAddPayload(contact: Self.payload(from: persisted))
}
private static func ensureAuthorization(store: CNContactStore, status: CNAuthorizationStatus) async -> Bool {
private static func ensureAuthorization(status: CNAuthorizationStatus) async -> Bool {
switch status {
case .authorized, .limited:
return true
case .notDetermined:
// Dont prompt during node.invoke; the caller should instruct the user to grant permission.
// Prompts block the invoke and lead to timeouts in headless flows.
return false
return await PermissionRequestBridge.awaitRequest { completion in
let store = CNContactStore()
store.requestAccess(for: .contacts) { granted, _ in
completion(granted)
}
}
case .restricted, .denied:
return false
@unknown default:
@@ -113,15 +116,14 @@ final class ContactsService: ContactsServicing {
}
private static func authorizedStore() async throws -> CNContactStore {
let store = CNContactStore()
let status = CNContactStore.authorizationStatus(for: .contacts)
let authorized = await Self.ensureAuthorization(store: store, status: status)
let authorized = await Self.ensureAuthorization(status: status)
guard authorized else {
throw NSError(domain: "Contacts", code: 1, userInfo: [
NSLocalizedDescriptionKey: "CONTACTS_PERMISSION_REQUIRED: grant Contacts permission",
])
}
return store
return CNContactStore()
}
private static func normalizeStrings(_ values: [String]?, lowercased: Bool = false) -> [String] {

View File

@@ -52,6 +52,14 @@
</array>
<key>NSCameraUsageDescription</key>
<string>OpenClaw can capture photos or short video clips when requested via the gateway.</string>
<key>NSCalendarsUsageDescription</key>
<string>OpenClaw uses your calendars to show events and scheduling context when you enable calendar access.</string>
<key>NSCalendarsFullAccessUsageDescription</key>
<string>OpenClaw uses your calendars to show events and scheduling context when you enable calendar access.</string>
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
<string>OpenClaw uses your calendars to add events when you enable calendar access.</string>
<key>NSContactsUsageDescription</key>
<string>OpenClaw uses your contacts so you can search and reference people while using the assistant.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>OpenClaw discovers and connects to your OpenClaw gateway on the local network.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
@@ -64,6 +72,8 @@
<string>OpenClaw may use motion data to support device-aware interactions and automations.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>OpenClaw needs photo library access when you choose existing photos to share with your assistant.</string>
<key>NSRemindersFullAccessUsageDescription</key>
<string>OpenClaw uses your reminders to list, add, and complete tasks when you enable reminders access.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>OpenClaw uses on-device speech recognition for voice wake.</string>
<key>NSSupportsLiveActivities</key>

View File

@@ -1,4 +1,5 @@
import Foundation
import OpenClawKit
import SwiftUI
struct GatewayOnboardingView: View {

View File

@@ -0,0 +1,64 @@
import Foundation
enum PermissionRequestBridge {
final class Box: @unchecked Sendable {
private let lock = NSLock()
private var continuation: CheckedContinuation<Bool, Never>?
private var hasResumed = false
func install(_ continuation: CheckedContinuation<Bool, Never>) -> Bool {
self.lock.lock()
if self.hasResumed {
self.lock.unlock()
continuation.resume(returning: false)
return false
}
self.continuation = continuation
self.lock.unlock()
return true
}
func resume(_ value: Bool) {
self.lock.lock()
guard !self.hasResumed else {
self.lock.unlock()
return
}
self.hasResumed = true
let continuation = self.continuation
self.continuation = nil
self.lock.unlock()
continuation?.resume(returning: value)
}
func canStartRequest() -> Bool {
self.lock.lock()
let canStart = !self.hasResumed
self.lock.unlock()
return canStart
}
}
static func awaitRequest(
_ start: @escaping @Sendable (@escaping @Sendable (Bool) -> Void) -> Void) async -> Bool
{
let box = Box()
return await withTaskCancellationHandler {
await withCheckedContinuation(isolation: nil) { continuation in
guard !Task.isCancelled else {
continuation.resume(returning: false)
return
}
guard box.install(continuation) else { return }
Task { @MainActor in
guard box.canStartRequest() else { return }
start { granted in
box.resume(granted)
}
}
}
} onCancel: {
box.resume(false)
}
}
}

View File

@@ -4,15 +4,19 @@ import OpenClawKit
final class RemindersService: RemindersServicing {
func list(params: OpenClawRemindersListParams) async throws -> OpenClawRemindersListPayload {
let store = EKEventStore()
let status = EKEventStore.authorizationStatus(for: .reminder)
let authorized = EventKitAuthorization.allowsRead(status: status)
let authorized: Bool = if status == .notDetermined || status == .writeOnly {
await Self.requestFullReminderAccess()
} else {
EventKitAuthorization.allowsRead(status: status)
}
guard authorized else {
throw NSError(domain: "Reminders", code: 1, userInfo: [
NSLocalizedDescriptionKey: "REMINDERS_PERMISSION_REQUIRED: grant Reminders permission",
])
}
let store = EKEventStore()
let limit = max(1, min(params.limit ?? 50, 500))
let statusFilter = params.status ?? .incomplete
@@ -48,15 +52,19 @@ final class RemindersService: RemindersServicing {
}
func add(params: OpenClawRemindersAddParams) async throws -> OpenClawRemindersAddPayload {
let store = EKEventStore()
let status = EKEventStore.authorizationStatus(for: .reminder)
let authorized = EventKitAuthorization.allowsWrite(status: status)
let authorized: Bool = if status == .notDetermined {
await Self.requestFullReminderAccess()
} else {
EventKitAuthorization.allowsWrite(status: status)
}
guard authorized else {
throw NSError(domain: "Reminders", code: 2, userInfo: [
NSLocalizedDescriptionKey: "REMINDERS_PERMISSION_REQUIRED: grant Reminders permission",
])
}
let store = EKEventStore()
let title = params.title.trimmingCharacters(in: .whitespacesAndNewlines)
guard !title.isEmpty else {
throw NSError(domain: "Reminders", code: 3, userInfo: [
@@ -100,6 +108,15 @@ final class RemindersService: RemindersServicing {
return OpenClawRemindersAddPayload(reminder: payload)
}
private static func requestFullReminderAccess() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestFullAccessToReminders { granted, _ in
completion(granted)
}
}
}
private static func resolveList(
store: EKEventStore,
listId: String?,

View File

@@ -0,0 +1,298 @@
import Contacts
import EventKit
import SwiftUI
import UIKit
struct PrivacyAccessSectionView: View {
@State private var contactsStatus: CNAuthorizationStatus = CNContactStore.authorizationStatus(for: .contacts)
@State private var calendarStatus: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: .event)
@State private var remindersStatus: EKAuthorizationStatus = EKEventStore.authorizationStatus(for: .reminder)
@Environment(\.scenePhase) private var scenePhase
var body: some View {
DisclosureGroup("Privacy & Access") {
self.permissionRow(
title: "Contacts",
icon: "person.crop.circle",
status: self.statusText(for: self.contactsStatus),
detail: "Search and add contacts from the assistant.",
actionTitle: self.actionTitle(for: self.contactsStatus),
action: self.handleContactsAction)
self.permissionRow(
title: "Calendar (Add Events)",
icon: "calendar.badge.plus",
status: self.calendarWriteStatusText,
detail: "Add events with least privilege.",
actionTitle: self.calendarWriteActionTitle,
action: self.handleCalendarWriteAction)
self.permissionRow(
title: "Calendar (View Events)",
icon: "calendar",
status: self.calendarReadStatusText,
detail: "List and read calendar events.",
actionTitle: self.calendarReadActionTitle,
action: self.handleCalendarReadAction)
self.permissionRow(
title: "Reminders",
icon: "checklist",
status: self.remindersStatusText,
detail: "List, add, and complete reminders.",
actionTitle: self.remindersActionTitle,
action: self.handleRemindersAction)
}
.onAppear { self.refreshAll() }
.onChange(of: self.scenePhase) { _, phase in
if phase == .active {
self.refreshAll()
}
}
}
private func permissionRow(
title: String,
icon: String,
status: String,
detail: String,
actionTitle: String?,
action: (() -> Void)?) -> some View
{
VStack(alignment: .leading, spacing: 6) {
HStack {
Label(title, systemImage: icon)
Spacer()
Text(status)
.font(.footnote.weight(.medium))
.foregroundStyle(self.statusColor(for: status))
}
Text(detail)
.font(.footnote)
.foregroundStyle(.secondary)
if let actionTitle, let action {
Button(actionTitle, action: action)
.font(.footnote)
.buttonStyle(.bordered)
}
}
.padding(.vertical, 2)
}
private func statusColor(for status: String) -> Color {
switch status {
case "Allowed":
.green
case "Not Set":
.orange
case "Add-Only":
.yellow
default:
.red
}
}
private func statusText(for cnStatus: CNAuthorizationStatus) -> String {
switch cnStatus {
case .authorized, .limited:
"Allowed"
case .notDetermined:
"Not Set"
case .denied, .restricted:
"Not Allowed"
@unknown default:
"Unknown"
}
}
private func actionTitle(for cnStatus: CNAuthorizationStatus) -> String? {
switch cnStatus {
case .notDetermined:
"Request Access"
case .denied, .restricted:
"Open Settings"
default:
nil
}
}
private func handleContactsAction() {
switch self.contactsStatus {
case .notDetermined:
Task {
_ = await PermissionRequestBridge.awaitRequest { completion in
let store = CNContactStore()
store.requestAccess(for: .contacts) { granted, _ in
completion(granted)
}
}
await MainActor.run { self.refreshAll() }
}
case .denied, .restricted:
self.openSettings()
default:
break
}
}
private var calendarWriteStatusText: String {
switch self.calendarStatus {
case .authorized, .fullAccess, .writeOnly:
"Allowed"
case .notDetermined:
"Not Set"
case .denied, .restricted:
"Not Allowed"
@unknown default:
"Unknown"
}
}
private var calendarWriteActionTitle: String? {
switch self.calendarStatus {
case .notDetermined:
"Request Access"
case .denied, .restricted:
"Open Settings"
default:
nil
}
}
private func handleCalendarWriteAction() {
switch self.calendarStatus {
case .notDetermined:
Task {
_ = await self.requestCalendarWriteOnly()
await MainActor.run { self.refreshAll() }
}
case .denied, .restricted:
self.openSettings()
default:
break
}
}
private var calendarReadStatusText: String {
switch self.calendarStatus {
case .authorized, .fullAccess:
"Allowed"
case .writeOnly:
"Add-Only"
case .notDetermined:
"Not Set"
case .denied, .restricted:
"Not Allowed"
@unknown default:
"Unknown"
}
}
private var calendarReadActionTitle: String? {
switch self.calendarStatus {
case .notDetermined:
"Request Full Access"
case .writeOnly:
"Upgrade to Full Access"
case .denied, .restricted:
"Open Settings"
default:
nil
}
}
private func handleCalendarReadAction() {
switch self.calendarStatus {
case .notDetermined, .writeOnly:
Task {
_ = await self.requestCalendarFull()
await MainActor.run { self.refreshAll() }
}
case .denied, .restricted:
self.openSettings()
default:
break
}
}
private var remindersStatusText: String {
switch self.remindersStatus {
case .authorized, .fullAccess:
"Allowed"
case .writeOnly:
"Add-Only"
case .notDetermined:
"Not Set"
case .denied, .restricted:
"Not Allowed"
@unknown default:
"Unknown"
}
}
private var remindersActionTitle: String? {
switch self.remindersStatus {
case .notDetermined:
"Request Access"
case .writeOnly:
"Upgrade to Full Access"
case .denied, .restricted:
"Open Settings"
default:
nil
}
}
private func handleRemindersAction() {
switch self.remindersStatus {
case .notDetermined, .writeOnly:
Task {
_ = await self.requestRemindersFull()
await MainActor.run { self.refreshAll() }
}
case .denied, .restricted:
self.openSettings()
default:
break
}
}
private func refreshAll() {
self.contactsStatus = CNContactStore.authorizationStatus(for: .contacts)
self.calendarStatus = EKEventStore.authorizationStatus(for: .event)
self.remindersStatus = EKEventStore.authorizationStatus(for: .reminder)
}
private func requestCalendarWriteOnly() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestWriteOnlyAccessToEvents { granted, _ in
completion(granted)
}
}
}
private func requestCalendarFull() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestFullAccessToEvents { granted, _ in
completion(granted)
}
}
}
private func requestRemindersFull() async -> Bool {
await PermissionRequestBridge.awaitRequest { completion in
let store = EKEventStore()
store.requestFullAccessToReminders { granted, _ in
completion(granted)
}
}
}
private func openSettings() {
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url)
}
}

View File

@@ -405,6 +405,8 @@ struct SettingsTab: View {
}
}
AnyView(PrivacyAccessSectionView())
DisclosureGroup("Device Info") {
TextField("Name", text: self.$displayName)
Text(self.instanceId)
@@ -419,16 +421,7 @@ struct SettingsTab: View {
}
}
.navigationTitle("Settings")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
self.dismiss()
} label: {
Image(systemName: "xmark")
}
.accessibilityLabel("Close")
}
}
.modifier(SettingsCloseToolbar())
.sheet(isPresented: self.$showGatewayProblemDetails) {
if let gatewayProblem = self.appModel.lastGatewayProblem {
GatewayProblemDetailsSheet(
@@ -488,90 +481,91 @@ struct SettingsTab: View {
Text(self.scannerError ?? "")
}
.onAppear {
self.lastLocationModeRaw = self.locationEnabledModeRaw
self.syncManualPortText()
let trimmedInstanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmedInstanceId.isEmpty {
self.gatewayToken = GatewaySettingsStore.loadGatewayToken(instanceId: trimmedInstanceId) ?? ""
self.gatewayPassword = GatewaySettingsStore.loadGatewayPassword(instanceId: trimmedInstanceId) ?? ""
self.lastLocationModeRaw = self.locationEnabledModeRaw
self.syncManualPortText()
let trimmedInstanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmedInstanceId.isEmpty {
self.gatewayToken = GatewaySettingsStore.loadGatewayToken(instanceId: trimmedInstanceId) ?? ""
self.gatewayPassword = GatewaySettingsStore
.loadGatewayPassword(instanceId: trimmedInstanceId) ?? ""
}
self.defaultShareInstruction = ShareToAgentSettings.loadDefaultInstruction()
self.appModel.refreshLastShareEventFromRelay()
// Keep setup front-and-center when disconnected; keep things compact once connected.
self.gatewayExpanded = !self.isGatewayConnected
self.selectedAgentPickerId = self.appModel.selectedAgentId ?? ""
if self.isGatewayConnected {
self.appModel.reloadTalkConfig()
}
}
self.defaultShareInstruction = ShareToAgentSettings.loadDefaultInstruction()
self.appModel.refreshLastShareEventFromRelay()
// Keep setup front-and-center when disconnected; keep things compact once connected.
self.gatewayExpanded = !self.isGatewayConnected
self.selectedAgentPickerId = self.appModel.selectedAgentId ?? ""
if self.isGatewayConnected {
self.appModel.reloadTalkConfig()
.onChange(of: self.selectedAgentPickerId) { _, newValue in
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
self.appModel.setSelectedAgentId(trimmed.isEmpty ? nil : trimmed)
}
}
.onChange(of: self.selectedAgentPickerId) { _, newValue in
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
self.appModel.setSelectedAgentId(trimmed.isEmpty ? nil : trimmed)
}
.onChange(of: self.appModel.selectedAgentId ?? "") { _, newValue in
if newValue != self.selectedAgentPickerId {
self.selectedAgentPickerId = newValue
.onChange(of: self.appModel.selectedAgentId ?? "") { _, newValue in
if newValue != self.selectedAgentPickerId {
self.selectedAgentPickerId = newValue
}
}
}
.onChange(of: self.preferredGatewayStableID) { _, newValue in
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
GatewaySettingsStore.savePreferredGatewayStableID(trimmed)
}
.onChange(of: self.gatewayToken) { _, newValue in
guard !self.suppressCredentialPersist else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
let instanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
guard !instanceId.isEmpty else { return }
GatewaySettingsStore.saveGatewayToken(trimmed, instanceId: instanceId)
}
.onChange(of: self.gatewayPassword) { _, newValue in
guard !self.suppressCredentialPersist else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
let instanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
guard !instanceId.isEmpty else { return }
GatewaySettingsStore.saveGatewayPassword(trimmed, instanceId: instanceId)
}
.onChange(of: self.defaultShareInstruction) { _, newValue in
ShareToAgentSettings.saveDefaultInstruction(newValue)
}
.onChange(of: self.manualGatewayPort) { _, _ in
self.syncManualPortText()
}
.onChange(of: self.appModel.gatewayServerName) { _, newValue in
if newValue != nil {
self.setupCode = ""
self.setupStatusText = nil
return
.onChange(of: self.preferredGatewayStableID) { _, newValue in
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
GatewaySettingsStore.savePreferredGatewayStableID(trimmed)
}
if self.manualGatewayEnabled {
self.setupStatusText = self.appModel.gatewayStatusText
.onChange(of: self.gatewayToken) { _, newValue in
guard !self.suppressCredentialPersist else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
let instanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
guard !instanceId.isEmpty else { return }
GatewaySettingsStore.saveGatewayToken(trimmed, instanceId: instanceId)
}
}
.onChange(of: self.appModel.gatewayStatusText) { _, newValue in
guard self.manualGatewayEnabled || self.connectingGatewayID == "manual" else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
self.setupStatusText = trimmed
}
.onChange(of: self.locationEnabledModeRaw) { _, newValue in
let previous = self.lastLocationModeRaw
self.lastLocationModeRaw = newValue
guard let mode = OpenClawLocationMode(rawValue: newValue) else { return }
Task {
let granted = await self.appModel.requestLocationPermissions(mode: mode)
if !granted {
await MainActor.run {
self.locationEnabledModeRaw = previous
self.lastLocationModeRaw = previous
}
.onChange(of: self.gatewayPassword) { _, newValue in
guard !self.suppressCredentialPersist else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
let instanceId = self.instanceId.trimmingCharacters(in: .whitespacesAndNewlines)
guard !instanceId.isEmpty else { return }
GatewaySettingsStore.saveGatewayPassword(trimmed, instanceId: instanceId)
}
.onChange(of: self.defaultShareInstruction) { _, newValue in
ShareToAgentSettings.saveDefaultInstruction(newValue)
}
.onChange(of: self.manualGatewayPort) { _, _ in
self.syncManualPortText()
}
.onChange(of: self.appModel.gatewayServerName) { _, newValue in
if newValue != nil {
self.setupCode = ""
self.setupStatusText = nil
return
}
await MainActor.run {
self.gatewayController.refreshActiveGatewayRegistrationFromSettings()
if self.manualGatewayEnabled {
self.setupStatusText = self.appModel.gatewayStatusText
}
}
.onChange(of: self.appModel.gatewayStatusText) { _, newValue in
guard self.manualGatewayEnabled || self.connectingGatewayID == "manual" else { return }
let trimmed = newValue.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
self.setupStatusText = trimmed
}
.onChange(of: self.locationEnabledModeRaw) { _, newValue in
let previous = self.lastLocationModeRaw
self.lastLocationModeRaw = newValue
guard let mode = OpenClawLocationMode(rawValue: newValue) else { return }
Task {
let granted = await self.appModel.requestLocationPermissions(mode: mode)
if !granted {
await MainActor.run {
self.locationEnabledModeRaw = previous
self.lastLocationModeRaw = previous
}
return
}
await MainActor.run {
self.gatewayController.refreshActiveGatewayRegistrationFromSettings()
}
}
}
}
}
.gatewayTrustPromptAlert()
}
@@ -1138,4 +1132,21 @@ struct SettingsTab: View {
}
}
private struct SettingsCloseToolbar: ViewModifier {
@Environment(\.dismiss) private var dismiss
func body(content: Content) -> some View {
content.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
self.dismiss()
} label: {
Image(systemName: "xmark")
}
.accessibilityLabel("Close")
}
}
}
}
// swiftlint:enable type_body_length

View File

@@ -40,6 +40,7 @@ Sources/Onboarding/OnboardingStateStore.swift
Sources/Onboarding/OnboardingWizardView.swift
Sources/Onboarding/QRScannerView.swift
Sources/OpenClawApp.swift
Sources/Permissions/PermissionRequestBridge.swift
Sources/Push/ExecApprovalNotificationBridge.swift
Sources/Push/BackgroundAliveBeacon.swift
Sources/Push/PushBuildConfig.swift
@@ -60,6 +61,7 @@ Sources/Services/WatchConnectivityTransport.swift
Sources/Services/WatchMessagingPayloadCodec.swift
Sources/Services/WatchMessagingService.swift
Sources/SessionKey.swift
Sources/Settings/PrivacyAccessSectionView.swift
Sources/Settings/SettingsNetworkingHelpers.swift
Sources/Settings/SettingsTab.swift
Sources/Settings/VoiceWakeWordsSettingsView.swift

View File

@@ -0,0 +1,26 @@
import Testing
@testable import OpenClaw
@Suite(.serialized) struct PermissionRequestBridgeTests {
@Test func `box resumes immediately when cancelled before install`() async {
let box = PermissionRequestBridge.Box()
box.resume(false)
let granted: Bool = await withCheckedContinuation { continuation in
_ = box.install(continuation)
}
#expect(granted == false)
#expect(box.canStartRequest() == false)
}
@Test func `box resumes installed continuation once`() async {
let box = PermissionRequestBridge.Box()
let granted: Bool = await withCheckedContinuation { continuation in
_ = box.install(continuation)
box.resume(true)
box.resume(false)
}
#expect(granted == true)
}
}

View File

@@ -136,11 +136,16 @@ targets:
NSBonjourServices:
- _openclaw-gw._tcp
NSCameraUsageDescription: OpenClaw can capture photos or short video clips when requested via the gateway.
NSCalendarsUsageDescription: OpenClaw uses your calendars to show events and scheduling context when you enable calendar access.
NSCalendarsFullAccessUsageDescription: OpenClaw uses your calendars to show events and scheduling context when you enable calendar access.
NSCalendarsWriteOnlyAccessUsageDescription: OpenClaw uses your calendars to add events when you enable calendar access.
NSContactsUsageDescription: OpenClaw uses your contacts so you can search and reference people while using the assistant.
NSLocationWhenInUseUsageDescription: OpenClaw uses your location when you allow location sharing.
NSLocationAlwaysAndWhenInUseUsageDescription: OpenClaw can share your location in the background when you enable Always.
NSMicrophoneUsageDescription: OpenClaw needs microphone access for voice wake.
NSMotionUsageDescription: OpenClaw may use motion data to support device-aware interactions and automations.
NSPhotoLibraryUsageDescription: OpenClaw needs photo library access when you choose existing photos to share with your assistant.
NSRemindersFullAccessUsageDescription: OpenClaw uses your reminders to list, add, and complete tasks when you enable reminders access.
NSSpeechRecognitionUsageDescription: OpenClaw uses on-device speech recognition for voice wake.
NSSupportsLiveActivities: true
ITSAppUsesNonExemptEncryption: false

View File

@@ -1,3 +1,3 @@
{
"version": "2026.5.10"
"version": "2026.5.16"
}

View File

@@ -69,6 +69,17 @@ enum GatewayRemoteConfig {
}
}
static func resolveTLSFingerprint(root: [String: Any]) -> String? {
guard let gateway = root["gateway"] as? [String: Any],
let remote = gateway["remote"] as? [String: Any],
let raw = remote["tlsFingerprint"] as? String
else {
return nil
}
let trimmed = raw.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.isEmpty ? nil : trimmed
}
static func resolveGatewayUrl(root: [String: Any]) -> URL? {
guard let raw = self.resolveUrlString(root: root) else { return nil }
return self.normalizeGatewayUrl(raw)

View File

@@ -83,7 +83,9 @@ final class MacNodeModeCoordinator {
clientId: "openclaw-macos",
clientMode: "node",
clientDisplayName: InstanceIdentity.displayName)
let sessionBox = self.buildSessionBox(url: config.url)
let sessionBox = self.buildSessionBox(
url: config.url,
connectionMode: AppStateStore.shared.connectionMode)
try await self.session.connect(
url: config.url,
@@ -243,15 +245,35 @@ final class MacNodeModeCoordinator {
return true
}
private func buildSessionBox(url: URL) -> WebSocketSessionBox? {
nonisolated static func tlsParams(
for url: URL,
connectionMode: AppState.ConnectionMode,
root: [String: Any],
storedFingerprint: String?) -> GatewayTLSParams?
{
guard url.scheme?.lowercased() == "wss" else { return nil }
let stableID = Self.tlsPinStoreKey(for: url)
let configuredFingerprint = connectionMode == .remote
? GatewayRemoteConfig.resolveTLSFingerprint(root: root)
: nil
let expectedFingerprint = configuredFingerprint ?? storedFingerprint
return GatewayTLSParams(
required: true,
expectedFingerprint: expectedFingerprint,
allowTOFU: expectedFingerprint == nil,
storeKey: stableID)
}
private func buildSessionBox(url: URL, connectionMode: AppState.ConnectionMode) -> WebSocketSessionBox? {
guard url.scheme?.lowercased() == "wss" else { return nil }
let stableID = Self.tlsPinStoreKey(for: url)
let stored = GatewayTLSStore.loadFingerprint(stableID: stableID)
let params = GatewayTLSParams(
required: true,
expectedFingerprint: stored,
allowTOFU: stored == nil,
storeKey: stableID)
guard let params = Self.tlsParams(
for: url,
connectionMode: connectionMode,
root: OpenClawConfigFile.loadDict(),
storedFingerprint: stored)
else { return nil }
let session = GatewayTLSPinningSession(params: params)
return WebSocketSessionBox(session: session)
}

View File

@@ -4,6 +4,8 @@ import OpenClawIPC
import OpenClawKit
actor MacNodeRuntime {
private static let maxGatewayPayloadBytes = 25 * 1024 * 1024
private static let maxScreenSnapshotRawBytesBeforeBase64 = (maxGatewayPayloadBytes / 4) * 3
private let cameraCapture = CameraCaptureService()
private let makeMainActorServices: () async -> any MacNodeRuntimeMainActorServices
private let browserProxyRequest: @Sendable (String?) async throws -> String
@@ -363,15 +365,55 @@ actor MacNodeRuntime {
}
private func handleScreenSnapshotInvoke(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
let params = (try? Self.decodeParams(MacNodeScreenSnapshotParams.self, from: req.paramsJSON)) ??
MacNodeScreenSnapshotParams()
let params: MacNodeScreenSnapshotParams
if let paramsJSON = req.paramsJSON {
do {
params = try Self.decodeParams(MacNodeScreenSnapshotParams.self, from: paramsJSON)
} catch {
return Self.errorResponse(
req,
code: .invalidRequest,
message: "INVALID_REQUEST: invalid screen snapshot params")
}
} else {
params = MacNodeScreenSnapshotParams()
}
let services = await self.mainActorServices()
let capturedAtMs = Int64(Date().timeIntervalSince1970 * 1000)
let res = try await services.snapshotScreen(
screenIndex: params.screenIndex,
maxWidth: params.maxWidth,
quality: params.quality,
format: params.format)
let res: (data: Data, format: OpenClawScreenSnapshotFormat, width: Int, height: Int)
do {
res = try await services.snapshotScreen(
screenIndex: params.screenIndex,
maxWidth: params.maxWidth,
quality: params.quality,
format: params.format)
} catch let error as ScreenSnapshotService.ScreenSnapshotError {
switch error {
case .noDisplays:
return Self.errorResponse(
req,
code: .invalidRequest,
message: "INVALID_REQUEST: no displays available for screen snapshot")
case let .invalidScreenIndex(idx):
return Self.errorResponse(
req,
code: .invalidRequest,
message: "INVALID_REQUEST: invalid screen index \(idx)")
case .captureFailed, .encodeFailed:
return Self.errorResponse(
req,
code: .unavailable,
message: "UNAVAILABLE: screen snapshot failed")
}
} catch {
return Self.errorResponse(
req,
code: .unavailable,
message: "UNAVAILABLE: screen snapshot failed")
}
if res.data.count > Self.maxScreenSnapshotRawBytesBeforeBase64 {
return Self.screenSnapshotPayloadTooLarge(req)
}
struct ScreenSnapshotPayload: Encodable {
var format: String
var base64: String
@@ -387,6 +429,13 @@ actor MacNodeRuntime {
height: res.height,
screenIndex: params.screenIndex,
capturedAtMs: capturedAtMs))
if try Self.projectedOuterFrameBytes(
forPayloadJSON: payload,
requestId: req.id,
nodeId: req.nodeId) > Self.maxGatewayPayloadBytes
{
return Self.screenSnapshotPayloadTooLarge(req)
}
return BridgeInvokeResponse(id: req.id, ok: true, payloadJSON: payload)
}
@@ -521,7 +570,8 @@ actor MacNodeRuntime {
let sessionKey = (params.sessionKey?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false)
? params.sessionKey!.trimmingCharacters(in: .whitespacesAndNewlines)
: self.mainSessionKey
let runId = UUID().uuidString
let providedRunId = params.runId?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let runId = providedRunId.isEmpty ? UUID().uuidString : providedRunId
let envOverrideDiagnostics = HostEnvSanitizer.inspectOverrides(
overrides: params.env,
blockPathOverrides: true)
@@ -1003,6 +1053,40 @@ extension MacNodeRuntime {
return json
}
static func projectedOuterFrameBytes(
forPayloadJSON payloadJSON: String,
requestId: String,
nodeId: String?) throws -> Int
{
struct InvokeResultFrame: Encodable {
let type = "req"
let id = "00000000-0000-0000-0000-000000000000"
let method = "node.invoke.result"
let params: Params
struct Params: Encodable {
let id: String
let nodeId: String
let ok: Bool
let payloadJSON: String
}
}
let frame = InvokeResultFrame(params: InvokeResultFrame.Params(
id: requestId,
nodeId: nodeId ?? "",
ok: true,
payloadJSON: payloadJSON))
return try JSONEncoder().encode(frame).count
}
private static func screenSnapshotPayloadTooLarge(_ req: BridgeInvokeRequest) -> BridgeInvokeResponse {
self.errorResponse(
req,
code: .unavailable,
message: "UNAVAILABLE: screen snapshot payload too large; reduce maxWidth or use jpeg")
}
private nonisolated static func canvasEnabled() -> Bool {
UserDefaults.standard.object(forKey: canvasEnabledKey) as? Bool ?? true
}

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.5.10</string>
<string>2026.5.16</string>
<key>CFBundleVersion</key>
<string>2026051000</string>
<string>2026051600</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -63,7 +63,7 @@ final class ScreenSnapshotService {
contentFilter: filter,
configuration: config)
} catch {
throw ScreenSnapshotError.captureFailed(error.localizedDescription)
throw ScreenSnapshotError.captureFailed("screen capture failed")
}
let bitmap = NSBitmapImageRep(cgImage: cgImage)

View File

@@ -16,6 +16,7 @@ struct ConnectOptions {
var displayName: String?
var role: String = "operator"
var scopes: [String] = defaultOperatorConnectScopes
var scopesAreExplicit: Bool = false
var help: Bool = false
static func parse(_ args: [String]) -> ConnectOptions {
@@ -43,6 +44,7 @@ struct ConnectOptions {
"--scopes": { opts, raw in
opts.scopes = raw.split(separator: ",").map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
opts.scopesAreExplicit = true
},
]
var i = 0
@@ -126,6 +128,7 @@ func runConnect(_ args: [String]) async {
let connectOptions = GatewayConnectOptions(
role: opts.role,
scopes: opts.scopes,
scopesAreExplicit: opts.scopesAreExplicit,
caps: [],
commands: [],
permissions: [:],

View File

@@ -4,6 +4,7 @@ import OpenClawProtocol
import Testing
@testable import OpenClaw
@Suite(.serialized)
struct GatewayChannelConnectTests {
private final class ConnectParamsRecorder: @unchecked Sendable {
private let lock = NSLock()
@@ -25,6 +26,23 @@ struct GatewayChannelConnectTests {
}
}
private final class ScopeCapture: @unchecked Sendable {
private let lock = NSLock()
private var scopes: [String]?
func set(_ scopes: [String]?) {
self.lock.lock()
self.scopes = scopes
self.lock.unlock()
}
func snapshot() -> [String]? {
self.lock.lock()
defer { self.lock.unlock() }
return self.scopes
}
}
private final class TLSFailureSession: WebSocketSessioning, GatewayTLSFailureProviding, @unchecked Sendable {
private var failure: GatewayTLSValidationFailure?
@@ -92,6 +110,23 @@ struct GatewayChannelConnectTests {
})
}
private func withTemporaryStateDir<T>(_ operation: () async throws -> T) async throws -> T {
let tempDir = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: true)
try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
let previousStateDir = ProcessInfo.processInfo.environment["OPENCLAW_STATE_DIR"]
setenv("OPENCLAW_STATE_DIR", tempDir.path, 1)
defer {
if let previousStateDir {
setenv("OPENCLAW_STATE_DIR", previousStateDir, 1)
} else {
unsetenv("OPENCLAW_STATE_DIR")
}
try? FileManager.default.removeItem(at: tempDir)
}
return try await operation()
}
@Test func `concurrent connect is single flight on success`() async throws {
let session = self.makeSession(response: .helloOk(delayMs: 200))
let channel = try GatewayChannelActor(
@@ -152,6 +187,126 @@ struct GatewayChannelConnectTests {
#expect(session.snapshotMakeCount() == 1)
}
@Test func `default operator connect scopes preserve pairing and admin`() async throws {
try await self.withTemporaryStateDir {
let capture = ScopeCapture()
let session = GatewayTestWebSocketSession(
taskFactory: {
GatewayTestWebSocketTask(sendHook: { _, message, sendIndex in
if sendIndex == 0 {
capture.set(GatewayWebSocketTestSupport.connectScopes(from: message))
}
})
})
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),
token: nil,
session: WebSocketSessionBox(session: session))
try await channel.connect()
#expect(capture.snapshot() == [
"operator.admin",
"operator.read",
"operator.write",
"operator.approvals",
"operator.pairing",
])
}
}
@Test func `bootstrap token connect scopes are bootstrap-compatible`() async throws {
let capture = ScopeCapture()
let session = GatewayTestWebSocketSession(
taskFactory: {
GatewayTestWebSocketTask(sendHook: { _, message, sendIndex in
if sendIndex == 0 {
capture.set(GatewayWebSocketTestSupport.connectScopes(from: message))
}
})
})
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),
token: nil,
bootstrapToken: "setup-bootstrap-token",
session: WebSocketSessionBox(session: session))
try await channel.connect()
#expect(capture.snapshot() == [
"operator.approvals",
"operator.read",
"operator.write",
])
}
@Test func `stored device token connect scopes reuse cached scopes`() async throws {
try await self.withTemporaryStateDir {
let identity = DeviceIdentityStore.loadOrCreate()
let storedEntry = DeviceAuthStore.storeToken(
deviceId: identity.deviceId,
role: "operator",
token: "bootstrap-device-token",
scopes: ["operator.read", "operator.write", "operator.approvals"])
let capture = ScopeCapture()
let session = GatewayTestWebSocketSession(
taskFactory: {
GatewayTestWebSocketTask(sendHook: { _, message, sendIndex in
if sendIndex == 0 {
capture.set(GatewayWebSocketTestSupport.connectScopes(from: message))
}
})
})
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),
token: nil,
session: WebSocketSessionBox(session: session))
try await channel.connect()
#expect(capture.snapshot() == storedEntry.scopes)
}
}
@Test func `explicit device token connect scopes preserve requested scopes`() async throws {
try await self.withTemporaryStateDir {
let identity = DeviceIdentityStore.loadOrCreate()
_ = DeviceAuthStore.storeToken(
deviceId: identity.deviceId,
role: "operator",
token: "bootstrap-device-token",
scopes: ["operator.read", "operator.write", "operator.approvals"])
let requestedScopes = ["operator.admin", "operator.pairing"]
let capture = ScopeCapture()
let session = GatewayTestWebSocketSession(
taskFactory: {
GatewayTestWebSocketTask(sendHook: { _, message, sendIndex in
if sendIndex == 0 {
capture.set(GatewayWebSocketTestSupport.connectScopes(from: message))
}
})
})
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),
token: nil,
session: WebSocketSessionBox(session: session),
connectOptions: GatewayConnectOptions(
role: "operator",
scopes: requestedScopes,
scopesAreExplicit: true,
caps: [],
commands: [],
permissions: [:],
clientId: "openclaw-macos",
clientMode: "ui",
clientDisplayName: "OpenClaw macOS Debug CLI"))
try await channel.connect()
#expect(capture.snapshot() == requestedScopes)
}
}
@Test func `connect surfaces structured auth failure`() async throws {
let session = self.makeSession(response: .authFailed(
delayMs: 0,

View File

@@ -287,4 +287,36 @@ struct GatewayEndpointStoreTests {
let url = GatewayRemoteConfig.normalizeGatewayUrl("ws://127.attacker.example")
#expect(url == nil)
}
@Test func `resolve tls fingerprint trims remote config value`() {
let root: [String: Any] = [
"gateway": [
"remote": [
"tlsFingerprint": " sha256:ABC123 ",
],
],
]
#expect(GatewayRemoteConfig.resolveTLSFingerprint(root: root) == "sha256:ABC123")
}
@Test func `resolve tls fingerprint ignores blank or non string values`() {
let blank: [String: Any] = [
"gateway": [
"remote": [
"tlsFingerprint": " ",
],
],
]
let nonString: [String: Any] = [
"gateway": [
"remote": [
"tlsFingerprint": 123,
],
],
]
#expect(GatewayRemoteConfig.resolveTLSFingerprint(root: blank) == nil)
#expect(GatewayRemoteConfig.resolveTLSFingerprint(root: nonString) == nil)
}
}

View File

@@ -36,6 +36,15 @@ enum GatewayWebSocketTestSupport {
return obj["params"] as? [String: Any]
}
static func connectScopes(from message: URLSessionWebSocketTask.Message) -> [String]? {
guard let obj = self.requestFrameObject(from: message) else { return nil }
guard (obj["type"] as? String) == "req", (obj["method"] as? String) == "connect" else {
return nil
}
let params = obj["params"] as? [String: Any]
return params?["scopes"] as? [String]
}
static func connectOkData(id: String) -> Data {
let json = """
{

View File

@@ -35,6 +35,60 @@ struct MacNodeModeCoordinatorTests {
#expect(MacNodeModeCoordinator.tlsPinStoreKey(for: url) == "gateway.example.ts.net:443")
}
@Test func `remote tls params prefer configured fingerprint over stored pin`() throws {
let url = try #require(URL(string: "wss://gateway.example.com"))
let root: [String: Any] = [
"gateway": [
"remote": [
"tlsFingerprint": "sha256:configured",
],
],
]
let params = try #require(MacNodeModeCoordinator.tlsParams(
for: url,
connectionMode: .remote,
root: root,
storedFingerprint: "stored"))
#expect(params.expectedFingerprint == "sha256:configured")
#expect(params.allowTOFU == false)
#expect(params.storeKey == "gateway.example.com:443")
}
@Test func `remote tls params allow first use only when no configured or stored pin exists`() throws {
let url = try #require(URL(string: "wss://gateway.example.com"))
let params = try #require(MacNodeModeCoordinator.tlsParams(
for: url,
connectionMode: .remote,
root: [:],
storedFingerprint: nil))
#expect(params.expectedFingerprint == nil)
#expect(params.allowTOFU == true)
}
@Test func `local tls params ignore remote configured fingerprint`() throws {
let url = try #require(URL(string: "wss://127.0.0.1:18789"))
let root: [String: Any] = [
"gateway": [
"remote": [
"tlsFingerprint": "sha256:remote",
],
],
]
let params = try #require(MacNodeModeCoordinator.tlsParams(
for: url,
connectionMode: .local,
root: root,
storedFingerprint: "stored-local"))
#expect(params.expectedFingerprint == "stored-local")
#expect(params.allowTOFU == false)
}
@Test func `auto repairs trusted tailscale serve pin mismatch`() throws {
let url = try #require(URL(string: "wss://gateway.example.ts.net"))
let failure = GatewayTLSValidationFailure(

View File

@@ -14,6 +14,90 @@ struct MacNodeRuntimeTests {
}
}
actor ExecEventProbe {
private var captured: [(event: String, json: String)] = []
func append(event: String, json: String?) {
self.captured.append((event: event, json: json ?? ""))
}
func events() -> [(event: String, json: String)] {
self.captured
}
}
@MainActor
final class ScreenSnapshotProbeServices: MacNodeRuntimeMainActorServices, @unchecked Sendable {
typealias SnapshotResult = (
data: Data,
format: OpenClawScreenSnapshotFormat,
width: Int,
height: Int)
var snapshotCallCount = 0
var receivedSnapshotParams: MacNodeScreenSnapshotParams?
var snapshotResult: SnapshotResult
var snapshotError: Error?
init(
snapshotResult: SnapshotResult = (Data("ok".utf8), .jpeg, 10, 10),
snapshotError: Error? = nil)
{
self.snapshotResult = snapshotResult
self.snapshotError = snapshotError
}
func snapshotScreen(
screenIndex: Int?,
maxWidth: Int?,
quality: Double?,
format: OpenClawScreenSnapshotFormat?) async throws -> SnapshotResult
{
self.snapshotCallCount += 1
self.receivedSnapshotParams = MacNodeScreenSnapshotParams(
screenIndex: screenIndex,
maxWidth: maxWidth,
quality: quality,
format: format)
if let snapshotError {
throw snapshotError
}
return self.snapshotResult
}
func recordScreen(
screenIndex: Int?,
durationMs: Int?,
fps: Double?,
includeAudio: Bool?,
outPath: String?) async throws -> (path: String, hasAudio: Bool)
{
let url = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-test-screen-record-\(UUID().uuidString).mp4")
try Data("ok".utf8).write(to: url)
return (path: url.path, hasAudio: false)
}
func locationAuthorizationStatus() -> CLAuthorizationStatus {
.authorizedAlways
}
func locationAccuracyAuthorization() -> CLAccuracyAuthorization {
.fullAccuracy
}
func currentLocation(
desiredAccuracy: OpenClawLocationAccuracy,
maxAgeMs: Int?,
timeoutMs: Int?) async throws -> CLLocation
{
_ = desiredAccuracy
_ = maxAgeMs
_ = timeoutMs
return CLLocation(latitude: 0, longitude: 0)
}
}
@Test func `handle invoke rejects unknown command`() async {
let runtime = MacNodeRuntime()
let response = await runtime.handleInvoke(
@@ -45,6 +129,40 @@ struct MacNodeRuntimeTests {
#expect(response.ok == false)
}
@Test func `system run denied event preserves gateway run id`() async throws {
let stateDir = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-state-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: stateDir) }
try await TestIsolation.withEnvValues(["OPENCLAW_STATE_DIR": stateDir.path]) {
let probe = ExecEventProbe()
let runtime = MacNodeRuntime()
await runtime.setEventSender { event, json in
await probe.append(event: event, json: json)
}
let params = OpenClawSystemRunParams(
command: ["/bin/sh", "-lc", "printf ok"],
sessionKey: "agent:main:main",
runId: "gateway-run-1")
let json = try String(data: JSONEncoder().encode(params), encoding: .utf8)
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-run-id",
command: OpenClawSystemCommand.run.rawValue,
paramsJSON: json))
#expect(response.ok == false)
let denied = try #require((await probe.events()).first { $0.event == "exec.denied" })
struct Payload: Decodable {
var sessionKey: String
var runId: String
}
let payload = try JSONDecoder().decode(Payload.self, from: Data(denied.json.utf8))
#expect(payload.sessionKey == "agent:main:main")
#expect(payload.runId == "gateway-run-1")
}
}
@Test func `handle invoke rejects blocked system run env override before execution`() async throws {
let runtime = MacNodeRuntime()
let params = OpenClawSystemRunParams(
@@ -252,6 +370,199 @@ struct MacNodeRuntimeTests {
#expect(payload.capturedAtMs <= snapshotCalledAtMs!)
}
@Test func `handle invoke screen snapshot rejects malformed params before capture`() async throws {
let services = await MainActor.run { ScreenSnapshotProbeServices() }
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-invalid",
command: MacNodeScreenCommand.snapshot.rawValue,
paramsJSON: #"{"screenIndex":"#))
#expect(response.ok == false)
#expect(response.error?.code == .invalidRequest)
#expect(response.error?.message == "INVALID_REQUEST: invalid screen snapshot params")
let snapshotCallCount = await MainActor.run { services.snapshotCallCount }
#expect(snapshotCallCount == 0)
}
@Test func `handle invoke screen snapshot keeps nil params as defaults`() async throws {
let services = await MainActor.run { ScreenSnapshotProbeServices() }
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-defaults",
command: MacNodeScreenCommand.snapshot.rawValue))
#expect(response.ok == true)
let received = await MainActor.run { services.receivedSnapshotParams }
#expect(received == MacNodeScreenSnapshotParams())
}
@Test func `handle invoke screen snapshot sanitizes capture failures`() async throws {
struct SensitiveError: LocalizedError {
let detail: String
var errorDescription: String? { detail }
}
let services = await MainActor.run {
ScreenSnapshotProbeServices(snapshotError: SensitiveError(detail: "TCC_DENIED display-id=ABC123"))
}
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-error",
command: MacNodeScreenCommand.snapshot.rawValue))
#expect(response.ok == false)
#expect(response.error?.code == .unavailable)
#expect(response.error?.message == "UNAVAILABLE: screen snapshot failed")
}
@Test func `handle invoke screen snapshot reports validation failures as invalid request`() async throws {
let invalidIndexServices = await MainActor.run {
ScreenSnapshotProbeServices(
snapshotError: ScreenSnapshotService.ScreenSnapshotError.invalidScreenIndex(4))
}
let invalidIndexRuntime = MacNodeRuntime(makeMainActorServices: { invalidIndexServices })
let invalidIndexResponse = await invalidIndexRuntime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-bad-index",
command: MacNodeScreenCommand.snapshot.rawValue))
#expect(invalidIndexResponse.ok == false)
#expect(invalidIndexResponse.error?.code == .invalidRequest)
#expect(invalidIndexResponse.error?.message == "INVALID_REQUEST: invalid screen index 4")
let noDisplaysServices = await MainActor.run {
ScreenSnapshotProbeServices(snapshotError: ScreenSnapshotService.ScreenSnapshotError.noDisplays)
}
let noDisplaysRuntime = MacNodeRuntime(makeMainActorServices: { noDisplaysServices })
let noDisplaysResponse = await noDisplaysRuntime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-no-displays",
command: MacNodeScreenCommand.snapshot.rawValue))
#expect(noDisplaysResponse.ok == false)
#expect(noDisplaysResponse.error?.code == .invalidRequest)
#expect(
noDisplaysResponse.error?.message ==
"INVALID_REQUEST: no displays available for screen snapshot")
}
@Test func `handle invoke screen snapshot rejects raw payloads above base64 ceiling`() async throws {
let payloadSize = 19_660_801
let services = await MainActor.run {
ScreenSnapshotProbeServices(snapshotResult: (
Data(repeating: 0x41, count: payloadSize),
.jpeg,
4000,
3000))
}
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-too-large",
command: MacNodeScreenCommand.snapshot.rawValue))
#expect(response.ok == false)
#expect(response.payloadJSON == nil)
#expect(response.error?.code == .unavailable)
#expect(
response.error?.message ==
"UNAVAILABLE: screen snapshot payload too large; reduce maxWidth or use jpeg")
}
@Test func `handle invoke screen snapshot rejects escaped oversized outer frames`() async throws {
let payloadSize = 12 * 1024 * 1024
let services = await MainActor.run {
ScreenSnapshotProbeServices(snapshotResult: (
Data(repeating: 0xFF, count: payloadSize),
.png,
4000,
3000))
}
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-screen-snapshot-slash-heavy",
command: MacNodeScreenCommand.snapshot.rawValue,
nodeId: "node-slash-heavy"))
#expect(response.ok == false)
#expect(response.error?.code == .unavailable)
#expect(
response.error?.message ==
"UNAVAILABLE: screen snapshot payload too large; reduce maxWidth or use jpeg")
}
@Test func `handle invoke screen snapshot accepts near-limit frames that fit`() async throws {
let payloadSize = 19_660_100
let services = await MainActor.run {
ScreenSnapshotProbeServices(snapshotResult: (
Data(repeating: 0x00, count: payloadSize),
.jpeg,
4000,
3000))
}
let runtime = MacNodeRuntime(makeMainActorServices: { services })
let response = await runtime.handleInvoke(
BridgeInvokeRequest(
id: "req-fit",
command: MacNodeScreenCommand.snapshot.rawValue,
nodeId: "node-fit"))
#expect(response.ok == true)
let payloadJSON = try #require(response.payloadJSON)
let projected = try MacNodeRuntime.projectedOuterFrameBytes(
forPayloadJSON: payloadJSON,
requestId: "req-fit",
nodeId: "node-fit")
#expect(projected < 25 * 1024 * 1024)
}
@Test func `projected outer frame bytes accounts for dynamic node id escaping`() throws {
let inner = "{\"format\":\"png\",\"note\":\"\u{0001}\u{0002}\n\t\\\"raw\\\"\",\"width\":1,\"height\":1,\"capturedAtMs\":0}"
let projected = try MacNodeRuntime.projectedOuterFrameBytes(
forPayloadJSON: inner,
requestId: "req-control",
nodeId: "node-\u{0001}\u{0002}\u{0003}\n\t-id")
struct Frame: Encodable {
let type = "req"
let id = "00000000-0000-0000-0000-000000000000"
let method = "node.invoke.result"
let params: Params
struct Params: Encodable {
let id: String
let nodeId: String
let ok: Bool
let payloadJSON: String
}
}
let serialized = try JSONEncoder().encode(Frame(params: Frame.Params(
id: "req-control",
nodeId: "node-\u{0001}\u{0002}\u{0003}\n\t-id",
ok: true,
payloadJSON: inner)))
#expect(projected == serialized.count)
let controlHeavyNodeId = String(repeating: "\u{0001}", count: 5 * 1024 * 1024)
let controlHeavyProjection = try MacNodeRuntime.projectedOuterFrameBytes(
forPayloadJSON: "{}",
requestId: "req-control",
nodeId: controlHeavyNodeId)
#expect(controlHeavyProjection > 25 * 1024 * 1024)
}
@Test func `handle invoke browser proxy uses injected request`() async {
let runtime = MacNodeRuntime(browserProxyRequest: { paramsJSON in
#expect(paramsJSON?.contains("/tabs") == true)

View File

@@ -253,7 +253,11 @@ private struct ChatMessageBody: View {
guard kind == "text" || kind.isEmpty else { return nil }
return content.text
}
return parts.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines)
return OpenClawChatMessage.displayText(
contentText: parts.joined(separator: "\n"),
role: self.message.role,
stopReason: self.message.stopReason,
errorMessage: self.message.errorMessage)
}
private var inlineAttachments: [OpenClawChatMessageContent] {

View File

@@ -144,6 +144,7 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
public let toolName: String?
public let usage: OpenClawChatUsage?
public let stopReason: String?
public let errorMessage: String?
enum CodingKeys: String, CodingKey {
case role
@@ -155,6 +156,7 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
case tool_name
case usage
case stopReason
case errorMessage
}
public init(
@@ -165,7 +167,8 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
toolCallId: String? = nil,
toolName: String? = nil,
usage: OpenClawChatUsage? = nil,
stopReason: String? = nil)
stopReason: String? = nil,
errorMessage: String? = nil)
{
self.id = id
self.role = role
@@ -175,20 +178,30 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
self.toolName = toolName
self.usage = usage
self.stopReason = stopReason
self.errorMessage = errorMessage
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.role = try container.decode(String.self, forKey: .role)
self.timestamp = try container.decodeIfPresent(Double.self, forKey: .timestamp)
self.toolCallId =
let decodedRole = try container.decode(String.self, forKey: .role)
let decodedTimestamp = try container.decodeIfPresent(Double.self, forKey: .timestamp)
let decodedToolCallId =
try container.decodeIfPresent(String.self, forKey: .toolCallId) ??
container.decodeIfPresent(String.self, forKey: .tool_call_id)
self.toolName =
let decodedToolName =
try container.decodeIfPresent(String.self, forKey: .toolName) ??
container.decodeIfPresent(String.self, forKey: .tool_name)
self.usage = try container.decodeIfPresent(OpenClawChatUsage.self, forKey: .usage)
self.stopReason = try container.decodeIfPresent(String.self, forKey: .stopReason)
let decodedUsage = try container.decodeIfPresent(OpenClawChatUsage.self, forKey: .usage)
let decodedStopReason = try container.decodeIfPresent(String.self, forKey: .stopReason)
let decodedErrorMessage = try container.decodeIfPresent(String.self, forKey: .errorMessage)
self.role = decodedRole
self.timestamp = decodedTimestamp
self.toolCallId = decodedToolCallId
self.toolName = decodedToolName
self.usage = decodedUsage
self.stopReason = decodedStopReason
self.errorMessage = decodedErrorMessage
if let decoded = try? container.decode([OpenClawChatMessageContent].self, forKey: .content) {
self.content = decoded
@@ -216,6 +229,41 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
self.content = []
}
static func displayText(
contentText: String,
role: String,
stopReason: String?,
errorMessage: String?) -> String
{
let text = contentText.trimmingCharacters(in: .whitespacesAndNewlines)
guard let errorText = Self.errorDisplayText(
role: role,
stopReason: stopReason,
errorMessage: errorMessage)
else {
return text
}
if text.isEmpty || text == Self.streamErrorFallbackText {
return errorText
}
return text
}
static func errorDisplayText(role: String, stopReason: String?, errorMessage: String?) -> String? {
let normalizedRole = role.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
let normalizedStopReason = stopReason?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
guard normalizedRole == "assistant",
normalizedStopReason == "error",
let text = errorMessage?.trimmingCharacters(in: .whitespacesAndNewlines),
!text.isEmpty
else {
return nil
}
return text
}
private static let streamErrorFallbackText = "[assistant turn failed before producing content]"
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.role, forKey: .role)
@@ -224,6 +272,7 @@ public struct OpenClawChatMessage: Codable, Identifiable, Sendable {
try container.encodeIfPresent(self.toolName, forKey: .toolName)
try container.encodeIfPresent(self.usage, forKey: .usage)
try container.encodeIfPresent(self.stopReason, forKey: .stopReason)
try container.encodeIfPresent(self.errorMessage, forKey: .errorMessage)
try container.encode(self.content, forKey: .content)
}
}

View File

@@ -389,7 +389,8 @@ public struct OpenClawChatView: View {
toolCallId: last.toolCallId,
toolName: last.toolName,
usage: last.usage,
stopReason: last.stopReason)
stopReason: last.stopReason,
errorMessage: last.errorMessage)
result[result.count - 1] = merged
}
@@ -433,7 +434,11 @@ public struct OpenClawChatView: View {
guard kind == "text" || kind.isEmpty else { return nil }
return content.text
}
return parts.joined(separator: "\n").trimmingCharacters(in: .whitespacesAndNewlines)
return OpenClawChatMessage.displayText(
contentText: parts.joined(separator: "\n"),
role: message.role,
stopReason: message.stopReason,
errorMessage: message.errorMessage)
}
private func hasInlineAttachments(in message: OpenClawChatMessage) -> Bool {

View File

@@ -17,6 +17,7 @@ private let chatUILogger = Logger(subsystem: "ai.openclaw", category: "OpenClawC
// swiftlint:disable:next type_body_length
public final class OpenClawChatViewModel {
public static let defaultModelSelectionID = "__default__"
private static let maxAttachmentBytes = 5_000_000
public private(set) var messages: [OpenClawChatMessage] = []
public var input: String = ""
@@ -304,7 +305,8 @@ public final class OpenClawChatViewModel {
toolCallId: message.toolCallId,
toolName: message.toolName,
usage: message.usage,
stopReason: message.stopReason)
stopReason: message.stopReason,
errorMessage: message.errorMessage)
}
private static func messageContentFingerprint(for message: OpenClawChatMessage) -> String {
@@ -383,7 +385,8 @@ public final class OpenClawChatViewModel {
toolCallId: message.toolCallId,
toolName: message.toolName,
usage: message.usage,
stopReason: message.stopReason)
stopReason: message.stopReason,
errorMessage: message.errorMessage)
}
}
@@ -1298,11 +1301,6 @@ public final class OpenClawChatViewModel {
}
private func addImageAttachment(url: URL?, data: Data, fileName: String, mimeType: String) async {
if data.count > 5_000_000 {
self.errorText = "Attachment \(fileName) exceeds 5 MB limit"
return
}
let uti: UTType = {
if let url {
return UTType(filenameExtension: url.pathExtension) ?? .data
@@ -1314,13 +1312,33 @@ public final class OpenClawChatViewModel {
return
}
let preview = Self.previewImage(data: data)
let processed: Data
do {
processed = try await Task.detached(priority: .userInitiated) {
try ChatImageProcessor.processForUpload(data: data)
}.value
} catch {
self.errorText = "Could not process \(fileName): \(error.localizedDescription)"
return
}
if processed.count > Self.maxAttachmentBytes {
self.errorText = "Attachment \(fileName) exceeds 5 MB limit after resizing"
return
}
let outputFileName: String = {
let baseName = (fileName as NSString).deletingPathExtension
return baseName.isEmpty ? "image.jpg" : "\(baseName).jpg"
}()
let preview = Self.previewImage(data: processed)
self.attachments.append(
OpenClawPendingAttachment(
url: url,
data: data,
fileName: fileName,
mimeType: mimeType,
data: processed,
fileName: outputFileName,
mimeType: "image/jpeg",
preview: preview))
}

View File

@@ -13,12 +13,20 @@ public struct BridgeInvokeRequest: Codable, Sendable {
public let id: String
public let command: String
public let paramsJSON: String?
public let nodeId: String?
public init(type: String = "invoke", id: String, command: String, paramsJSON: String? = nil) {
public init(
type: String = "invoke",
id: String,
command: String,
paramsJSON: String? = nil,
nodeId: String? = nil)
{
self.type = type
self.id = id
self.command = command
self.paramsJSON = paramsJSON
self.nodeId = nodeId
}
}

View File

@@ -0,0 +1,44 @@
import Foundation
/// Chat-specific image upload policy built on the shared JPEG transcoder.
public enum ChatImageProcessor {
public static let maxLongEdgePx = 1600
public static let jpegQuality = 0.8
public static let maxPayloadBytes = 3_500_000
public enum ProcessError: Error, LocalizedError, Sendable {
case notAnImage
case decodeFailed
case encodeFailed
public var errorDescription: String? {
switch self {
case .notAnImage:
"The data is not a recognizable image."
case .decodeFailed:
"The image could not be decoded."
case .encodeFailed:
"The image could not be resized to fit the chat upload limit."
}
}
}
public static func processForUpload(data: Data) throws -> Data {
do {
let result = try JPEGTranscoder.transcodeToJPEG(
imageData: data,
maxLongEdgePx: self.maxLongEdgePx,
quality: self.jpegQuality,
maxBytes: self.maxPayloadBytes)
return result.data
} catch JPEGTranscodeError.decodeFailed {
throw ProcessError.notAnImage
} catch JPEGTranscodeError.propertiesMissing {
throw ProcessError.decodeFailed
} catch JPEGTranscodeError.sizeLimitExceeded {
throw ProcessError.encodeFailed
} catch {
throw ProcessError.encodeFailed
}
}
}

View File

@@ -57,7 +57,7 @@ public struct GatewayConnectDeepLink: Codable, Sendable, Equatable {
{
return link
}
return fromGatewayURLString(
return self.fromGatewayURLString(
trimmed,
bootstrapToken: nil,
token: nil,
@@ -89,7 +89,7 @@ public struct GatewayConnectDeepLink: Codable, Sendable, Equatable {
{
return link
}
for candidate in setupCodeCandidates(in: trimmed) where candidate != trimmed {
for candidate in self.setupCodeCandidates(in: trimmed) where candidate != trimmed {
if let data = decodeBase64Url(candidate),
let link = decodeSetupPayload(from: data)
{
@@ -104,7 +104,7 @@ public struct GatewayConnectDeepLink: Codable, Sendable, Equatable {
if let urlString = payload.url?.trimmingCharacters(in: .whitespacesAndNewlines),
!urlString.isEmpty
{
return fromGatewayURLString(
return self.fromGatewayURLString(
urlString,
bootstrapToken: payload.bootstrapToken,
token: payload.token,

View File

@@ -79,6 +79,7 @@ public struct WebSocketSessionBox: @unchecked Sendable {
public struct GatewayConnectOptions: Sendable {
public var role: String
public var scopes: [String]
public var scopesAreExplicit: Bool
public var caps: [String]
public var commands: [String]
public var permissions: [String: Bool]
@@ -93,6 +94,7 @@ public struct GatewayConnectOptions: Sendable {
public init(
role: String,
scopes: [String],
scopesAreExplicit: Bool = false,
caps: [String],
commands: [String],
permissions: [String: Bool],
@@ -103,6 +105,7 @@ public struct GatewayConnectOptions: Sendable {
{
self.role = role
self.scopes = scopes
self.scopesAreExplicit = scopesAreExplicit
self.caps = caps
self.commands = commands
self.permissions = permissions
@@ -132,6 +135,8 @@ private func gatewayErrorDetails(_ error: ErrorShape?) -> [String: ProtoAnyCodab
if let error {
if details["code"] == nil {
details["code"] = ProtoAnyCodable(error.code)
} else {
details["errorCode"] = ProtoAnyCodable(error.code)
}
details["message"] = ProtoAnyCodable(error.message)
if let retryable = error.retryable {
@@ -169,6 +174,7 @@ private struct SelectedConnectAuth {
let authPassword: String?
let signatureToken: String?
let storedToken: String?
let storedScopes: [String]?
let authSource: GatewayAuthSource
}
@@ -408,7 +414,19 @@ public actor GatewayChannelActor {
let clientId = options.clientId
let clientMode = options.clientMode
let role = options.role
let scopes = options.scopes
let requestedScopes = options.scopes
let scopesAreExplicit = options.scopesAreExplicit
let includeDeviceIdentity = options.includeDeviceIdentity
let identity = includeDeviceIdentity ? DeviceIdentityStore.loadOrCreate() : nil
let selectedAuth = self.selectConnectAuth(
role: role,
includeDeviceIdentity: includeDeviceIdentity,
deviceId: identity?.deviceId)
let scopes = self.resolveConnectScopes(
role: role,
requestedScopes: requestedScopes,
scopesAreExplicit: scopesAreExplicit,
selectedAuth: selectedAuth)
let reqId = UUID().uuidString
var client: [String: ProtoAnyCodable] = [
@@ -440,12 +458,6 @@ public actor GatewayChannelActor {
if !options.permissions.isEmpty {
params["permissions"] = ProtoAnyCodable(options.permissions)
}
let includeDeviceIdentity = options.includeDeviceIdentity
let identity = includeDeviceIdentity ? DeviceIdentityStore.loadOrCreate() : nil
let selectedAuth = self.selectConnectAuth(
role: role,
includeDeviceIdentity: includeDeviceIdentity,
deviceId: identity?.deviceId)
if selectedAuth.authDeviceToken != nil, self.pendingDeviceTokenRetry {
self.pendingDeviceTokenRetry = false
}
@@ -528,10 +540,11 @@ public actor GatewayChannelActor {
let explicitBootstrapToken =
self.bootstrapToken?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
let explicitPassword = self.password?.trimmingCharacters(in: .whitespacesAndNewlines).nilIfEmpty
let storedToken =
let storedEntry =
(includeDeviceIdentity && deviceId != nil)
? DeviceAuthStore.loadToken(deviceId: deviceId!, role: role)?.token
? DeviceAuthStore.loadToken(deviceId: deviceId!, role: role)
: nil
let storedToken = storedEntry?.token
let shouldUseDeviceRetryToken =
includeDeviceIdentity && self.pendingDeviceTokenRetry &&
storedToken != nil && explicitToken != nil && self.isTrustedDeviceRetryEndpoint()
@@ -563,6 +576,7 @@ public actor GatewayChannelActor {
authPassword: explicitPassword,
signatureToken: authToken ?? authBootstrapToken,
storedToken: storedToken,
storedScopes: storedEntry?.scopes,
authSource: authSource)
}
@@ -596,6 +610,27 @@ public actor GatewayChannelActor {
}
}
private func resolveConnectScopes(
role: String,
requestedScopes: [String],
scopesAreExplicit: Bool,
selectedAuth: SelectedConnectAuth) -> [String]
{
if selectedAuth.authSource == .bootstrapToken,
let filteredScopes = self.filteredBootstrapHandoffScopes(role: role, scopes: requestedScopes)
{
return filteredScopes
}
if selectedAuth.authSource == .deviceToken,
!scopesAreExplicit,
let storedScopes = selectedAuth.storedScopes,
!storedScopes.isEmpty
{
return storedScopes
}
return requestedScopes
}
private func persistBootstrapHandoffToken(
deviceId: String,
role: String,

View File

@@ -10,6 +10,7 @@ public struct GatewayConnectionProblem: Equatable, Sendable {
case gatewayAuthPasswordNotConfigured
case bootstrapTokenInvalid
case deviceTokenMismatch
case deviceTokenScopeMismatch
case pairingRequired
case pairingRoleUpgradeRequired
case pairingScopeUpgradeRequired
@@ -97,7 +98,7 @@ public struct GatewayConnectionProblem: Equatable, Sendable {
public var needsPairingApproval: Bool {
switch self.kind {
case .pairingRequired, .pairingRoleUpgradeRequired, .pairingScopeUpgradeRequired,
.pairingMetadataUpgradeRequired:
.pairingMetadataUpgradeRequired, .deviceTokenScopeMismatch:
true
default:
false
@@ -327,6 +328,20 @@ public enum GatewayConnectionProblemMapper {
retryable: false,
pauseReconnect: true,
authError: authError)
case .authScopeMismatch:
return self.problem(
kind: .deviceTokenScopeMismatch,
owner: .both,
title: authError.titleOverride ?? "Device permissions need approval",
message: authError.userMessageOverride
?? "The gateway accepted this device token but rejected the requested operator scopes.",
actionLabel: authError.actionLabel ?? "Review pairing",
actionCommand: authError.actionCommand ?? pairingCommand,
docsURL: self.docsURL(authError.docsURLString, fallback: "https://docs.openclaw.ai/gateway/pairing"),
requestId: authError.requestId,
retryable: false,
pauseReconnect: true,
authError: authError)
case .pairingRequired:
return self.pairingProblem(for: authError)
case .controlUiDeviceIdentityRequired, .deviceIdentityRequired:

View File

@@ -7,6 +7,7 @@ public enum GatewayConnectAuthDetailCode: String, Sendable {
case authTokenMismatch = "AUTH_TOKEN_MISMATCH"
case authBootstrapTokenInvalid = "AUTH_BOOTSTRAP_TOKEN_INVALID"
case authDeviceTokenMismatch = "AUTH_DEVICE_TOKEN_MISMATCH"
case authScopeMismatch = "AUTH_SCOPE_MISMATCH"
case authTokenMissing = "AUTH_TOKEN_MISSING"
case authTokenNotConfigured = "AUTH_TOKEN_NOT_CONFIGURED"
case authPasswordMissing = "AUTH_PASSWORD_MISSING"
@@ -160,6 +161,7 @@ public struct GatewayConnectAuthError: LocalizedError, Sendable {
.authPasswordMismatch,
.authPasswordNotConfigured,
.authRateLimited,
.authScopeMismatch,
.pairingRequired,
.controlUiDeviceIdentityRequired,
.deviceIdentityRequired:

View File

@@ -457,7 +457,8 @@ public actor GatewayNodeSession {
let req = BridgeInvokeRequest(
id: request.id,
command: request.command,
paramsJSON: request.paramsJSON)
paramsJSON: request.paramsJSON,
nodeId: request.nodeId)
self.logger.info("node invoke executing id=\(request.id, privacy: .public)")
let response = await Self.invokeWithTimeout(
request: req,

View File

@@ -79,6 +79,12 @@ public protocol GatewayDeviceTokenRetryTrustProviding: AnyObject {
var allowsDeviceTokenRetryAuth: Bool { get }
}
enum GatewayTLSFirstUsePolicy {
static func allowsFirstUsePin(systemTrustOk: Bool) -> Bool {
systemTrustOk
}
}
public enum GatewayTLSStore {
private static let keychainService = "ai.openclaw.tls-pinning"
@@ -159,7 +165,8 @@ public enum GatewayTLSStore {
}
}
public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLSessionDelegate, GatewayTLSFailureProviding, GatewayDeviceTokenRetryTrustProviding, @unchecked Sendable {
public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLSessionDelegate,
GatewayTLSFailureProviding, GatewayDeviceTokenRetryTrustProviding, @unchecked Sendable {
private let params: GatewayTLSParams
private let failureLock = NSLock()
private var lastTLSFailure: GatewayTLSValidationFailure?
@@ -238,12 +245,14 @@ public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLS
return
}
if self.params.allowTOFU {
if let storeKey = params.storeKey {
GatewayTLSStore.saveFingerprint(fingerprint, stableID: storeKey)
if GatewayTLSFirstUsePolicy.allowsFirstUsePin(systemTrustOk: systemTrustOk) {
if let storeKey = params.storeKey {
GatewayTLSStore.saveFingerprint(fingerprint, stableID: storeKey)
}
self.clearTLSFailure()
completionHandler(.useCredential, URLCredential(trust: trust))
return
}
self.clearTLSFailure()
completionHandler(.useCredential, URLCredential(trust: trust))
return
}
}

View File

@@ -37,6 +37,26 @@ public struct JPEGTranscoder: Sendable {
maxWidthPx: Int?,
quality: Double,
maxBytes: Int? = nil) throws -> (data: Data, widthPx: Int, heightPx: Int)
{
try self.transcodeToJPEG(
imageData: imageData,
maxWidthPx: maxWidthPx,
maxLongEdgePx: nil,
quality: quality,
maxBytes: maxBytes)
}
/// Re-encodes image data to JPEG, optionally downscaling so the *oriented* longest edge is <= `maxLongEdgePx`.
///
/// When `maxLongEdgePx` is provided it takes precedence over `maxWidthPx`.
/// - Important: This normalizes EXIF orientation (the output pixels are rotated if needed; orientation tag is not
/// relied on).
public static func transcodeToJPEG(
imageData: Data,
maxWidthPx: Int? = nil,
maxLongEdgePx: Int?,
quality: Double,
maxBytes: Int? = nil) throws -> (data: Data, widthPx: Int, heightPx: Int)
{
guard let src = CGImageSourceCreateWithData(imageData as CFData, nil) else {
throw JPEGTranscodeError.decodeFailed
@@ -63,6 +83,10 @@ public struct JPEGTranscoder: Sendable {
let maxDim = max(orientedWidth, orientedHeight)
var targetMaxPixelSize: Int = {
if let maxLongEdgePx, maxLongEdgePx > 0 {
guard maxDim > maxLongEdgePx else { return maxDim } // never upscale
return maxLongEdgePx
}
guard let maxWidthPx, maxWidthPx > 0 else { return maxDim }
guard orientedWidth > maxWidthPx else { return maxDim } // never upscale
@@ -81,6 +105,7 @@ public struct JPEGTranscoder: Sendable {
guard let img = CGImageSourceCreateThumbnailAtIndex(src, 0, thumbOpts as CFDictionary) else {
throw JPEGTranscodeError.decodeFailed
}
let opaqueImage = Self.flattenAlphaIfNeeded(img)
let out = NSMutableData()
guard let dest = CGImageDestinationCreateWithData(out, UTType.jpeg.identifier as CFString, 1, nil) else {
@@ -88,12 +113,12 @@ public struct JPEGTranscoder: Sendable {
}
let q = self.clampQuality(quality)
let encodeProps = [kCGImageDestinationLossyCompressionQuality: q] as CFDictionary
CGImageDestinationAddImage(dest, img, encodeProps)
CGImageDestinationAddImage(dest, opaqueImage, encodeProps)
guard CGImageDestinationFinalize(dest) else {
throw JPEGTranscodeError.encodeFailed
}
return (out as Data, img.width, img.height)
return (out as Data, opaqueImage.width, opaqueImage.height)
}
guard let maxBytes, maxBytes > 0 else {
@@ -132,4 +157,34 @@ public struct JPEGTranscoder: Sendable {
return best
}
/// JPEG cannot store alpha. Flatten transparent sources over white before encoding so ImageIO does not composite
/// transparent pixels onto black by default.
private static func flattenAlphaIfNeeded(_ image: CGImage) -> CGImage {
switch image.alphaInfo {
case .none, .noneSkipFirst, .noneSkipLast:
return image
default:
break
}
guard
let context = CGContext(
data: nil,
width: image.width,
height: image.height,
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)
else {
return image
}
let rect = CGRect(x: 0, y: 0, width: image.width, height: image.height)
context.setFillColor(CGColor(red: 1, green: 1, blue: 1, alpha: 1))
context.fill(rect)
context.draw(image, in: rect)
return context.makeImage() ?? image
}
}

View File

@@ -29,6 +29,7 @@ public struct OpenClawSystemRunParams: Codable, Sendable, Equatable {
public var needsScreenRecording: Bool?
public var agentId: String?
public var sessionKey: String?
public var runId: String?
public var approved: Bool?
public var approvalDecision: String?
@@ -41,6 +42,7 @@ public struct OpenClawSystemRunParams: Codable, Sendable, Equatable {
needsScreenRecording: Bool? = nil,
agentId: String? = nil,
sessionKey: String? = nil,
runId: String? = nil,
approved: Bool? = nil,
approvalDecision: String? = nil)
{
@@ -52,6 +54,7 @@ public struct OpenClawSystemRunParams: Codable, Sendable, Equatable {
self.needsScreenRecording = needsScreenRecording
self.agentId = agentId
self.sessionKey = sessionKey
self.runId = runId
self.approved = approved
self.approvalDecision = approvalDecision
}

View File

@@ -3,7 +3,7 @@
import Foundation
public let GATEWAY_PROTOCOL_VERSION = 4
public let GATEWAY_MIN_PROTOCOL_VERSION = 3
public let GATEWAY_MIN_PROTOCOL_VERSION = 4
private struct GatewayAnyCodingKey: CodingKey, Hashable {
let stringValue: String
@@ -500,6 +500,7 @@ public struct AgentEvent: Codable, Sendable {
public let stream: String
public let ts: Int
public let spawnedby: String?
public let isheartbeat: Bool?
public let data: [String: AnyCodable]
public init(
@@ -508,6 +509,7 @@ public struct AgentEvent: Codable, Sendable {
stream: String,
ts: Int,
spawnedby: String?,
isheartbeat: Bool?,
data: [String: AnyCodable])
{
self.runid = runid
@@ -515,6 +517,7 @@ public struct AgentEvent: Codable, Sendable {
self.stream = stream
self.ts = ts
self.spawnedby = spawnedby
self.isheartbeat = isheartbeat
self.data = data
}
@@ -524,6 +527,7 @@ public struct AgentEvent: Codable, Sendable {
case stream
case ts
case spawnedby = "spawnedBy"
case isheartbeat = "isHeartbeat"
case data
}
}
@@ -537,6 +541,7 @@ public struct MessageActionParams: Codable, Sendable {
public let senderisowner: Bool?
public let sessionkey: String?
public let sessionid: String?
public let inboundturnkind: String?
public let agentid: String?
public let toolcontext: [String: AnyCodable]?
public let idempotencykey: String
@@ -550,6 +555,7 @@ public struct MessageActionParams: Codable, Sendable {
senderisowner: Bool?,
sessionkey: String?,
sessionid: String?,
inboundturnkind: String? = nil,
agentid: String?,
toolcontext: [String: AnyCodable]?,
idempotencykey: String)
@@ -562,6 +568,7 @@ public struct MessageActionParams: Codable, Sendable {
self.senderisowner = senderisowner
self.sessionkey = sessionkey
self.sessionid = sessionid
self.inboundturnkind = inboundturnkind
self.agentid = agentid
self.toolcontext = toolcontext
self.idempotencykey = idempotencykey
@@ -576,6 +583,7 @@ public struct MessageActionParams: Codable, Sendable {
case senderisowner = "senderIsOwner"
case sessionkey = "sessionKey"
case sessionid = "sessionId"
case inboundturnkind = "inboundTurnKind"
case agentid = "agentId"
case toolcontext = "toolContext"
case idempotencykey = "idempotencyKey"
@@ -747,6 +755,7 @@ public struct AgentParams: Codable, Sendable {
public let internalruntimehandoffid: String?
public let internalevents: [[String: AnyCodable]]?
public let inputprovenance: [String: AnyCodable]?
public let sourcereplydeliverymode: AnyCodable?
public let voicewaketrigger: String?
public let idempotencykey: String
public let label: String?
@@ -784,6 +793,7 @@ public struct AgentParams: Codable, Sendable {
internalruntimehandoffid: String?,
internalevents: [[String: AnyCodable]]?,
inputprovenance: [String: AnyCodable]?,
sourcereplydeliverymode: AnyCodable?,
voicewaketrigger: String?,
idempotencykey: String,
label: String?)
@@ -820,6 +830,7 @@ public struct AgentParams: Codable, Sendable {
self.internalruntimehandoffid = internalruntimehandoffid
self.internalevents = internalevents
self.inputprovenance = inputprovenance
self.sourcereplydeliverymode = sourcereplydeliverymode
self.voicewaketrigger = voicewaketrigger
self.idempotencykey = idempotencykey
self.label = label
@@ -858,6 +869,7 @@ public struct AgentParams: Codable, Sendable {
case internalruntimehandoffid = "internalRuntimeHandoffId"
case internalevents = "internalEvents"
case inputprovenance = "inputProvenance"
case sourcereplydeliverymode = "sourceReplyDeliveryMode"
case voicewaketrigger = "voiceWakeTrigger"
case idempotencykey = "idempotencyKey"
case label
@@ -941,18 +953,22 @@ public struct AgentWaitParams: Codable, Sendable {
public struct WakeParams: Codable, Sendable {
public let mode: AnyCodable
public let text: String
public let sessionkey: String?
public init(
mode: AnyCodable,
text: String)
text: String,
sessionkey: String?)
{
self.mode = mode
self.text = text
self.sessionkey = sessionkey
}
private enum CodingKeys: String, CodingKey {
case mode
case text
case sessionkey = "sessionKey"
}
}
@@ -967,6 +983,7 @@ public struct NodePairRequestParams: Codable, Sendable {
public let modelidentifier: String?
public let caps: [String]?
public let commands: [String]?
public let permissions: [String: AnyCodable]?
public let remoteip: String?
public let silent: Bool?
@@ -981,6 +998,7 @@ public struct NodePairRequestParams: Codable, Sendable {
modelidentifier: String?,
caps: [String]?,
commands: [String]?,
permissions: [String: AnyCodable]?,
remoteip: String?,
silent: Bool?)
{
@@ -994,6 +1012,7 @@ public struct NodePairRequestParams: Codable, Sendable {
self.modelidentifier = modelidentifier
self.caps = caps
self.commands = commands
self.permissions = permissions
self.remoteip = remoteip
self.silent = silent
}
@@ -1009,6 +1028,7 @@ public struct NodePairRequestParams: Codable, Sendable {
case modelidentifier = "modelIdentifier"
case caps
case commands
case permissions
case remoteip = "remoteIp"
case silent
}
@@ -2086,6 +2106,8 @@ public struct SessionsPatchParams: Codable, Sendable {
public let spawndepth: AnyCodable?
public let subagentrole: AnyCodable?
public let subagentcontrolscope: AnyCodable?
public let inheritedtoolallow: AnyCodable?
public let inheritedtooldeny: AnyCodable?
public let sendpolicy: AnyCodable?
public let groupactivation: AnyCodable?
@@ -2109,6 +2131,8 @@ public struct SessionsPatchParams: Codable, Sendable {
spawndepth: AnyCodable?,
subagentrole: AnyCodable?,
subagentcontrolscope: AnyCodable?,
inheritedtoolallow: AnyCodable?,
inheritedtooldeny: AnyCodable?,
sendpolicy: AnyCodable?,
groupactivation: AnyCodable?)
{
@@ -2131,6 +2155,8 @@ public struct SessionsPatchParams: Codable, Sendable {
self.spawndepth = spawndepth
self.subagentrole = subagentrole
self.subagentcontrolscope = subagentcontrolscope
self.inheritedtoolallow = inheritedtoolallow
self.inheritedtooldeny = inheritedtooldeny
self.sendpolicy = sendpolicy
self.groupactivation = groupactivation
}
@@ -2155,6 +2181,8 @@ public struct SessionsPatchParams: Codable, Sendable {
case spawndepth = "spawnDepth"
case subagentrole = "subagentRole"
case subagentcontrolscope = "subagentControlScope"
case inheritedtoolallow = "inheritedToolAllow"
case inheritedtooldeny = "inheritedToolDeny"
case sendpolicy = "sendPolicy"
case groupactivation = "groupActivation"
}
@@ -3208,6 +3236,7 @@ public struct TalkSessionCancelTurnParams: Codable, Sendable {
public struct TalkSessionCreateParams: Codable, Sendable {
public let sessionkey: String?
public let spawnedby: String?
public let provider: String?
public let model: String?
public let voice: String?
@@ -3222,6 +3251,7 @@ public struct TalkSessionCreateParams: Codable, Sendable {
public init(
sessionkey: String?,
spawnedby: String?,
provider: String?,
model: String?,
voice: String?,
@@ -3235,6 +3265,7 @@ public struct TalkSessionCreateParams: Codable, Sendable {
ttlms: Int?)
{
self.sessionkey = sessionkey
self.spawnedby = spawnedby
self.provider = provider
self.model = model
self.voice = voice
@@ -3250,6 +3281,7 @@ public struct TalkSessionCreateParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case spawnedby = "spawnedBy"
case provider
case model
case voice
@@ -3623,18 +3655,22 @@ public struct TalkSpeakResult: Codable, Sendable {
public struct ChannelsStatusParams: Codable, Sendable {
public let probe: Bool?
public let timeoutms: Int?
public let channel: String?
public init(
probe: Bool?,
timeoutms: Int?)
timeoutms: Int?,
channel: String?)
{
self.probe = probe
self.timeoutms = timeoutms
self.channel = channel
}
private enum CodingKeys: String, CodingKey {
case probe
case timeoutms = "timeoutMs"
case channel
}
}
@@ -5196,6 +5232,7 @@ public struct CronRunsParams: Codable, Sendable {
public let scope: AnyCodable?
public let id: String?
public let jobid: String?
public let runid: String?
public let limit: Int?
public let offset: Int?
public let statuses: [AnyCodable]?
@@ -5209,6 +5246,7 @@ public struct CronRunsParams: Codable, Sendable {
scope: AnyCodable?,
id: String?,
jobid: String?,
runid: String?,
limit: Int?,
offset: Int?,
statuses: [AnyCodable]?,
@@ -5221,6 +5259,7 @@ public struct CronRunsParams: Codable, Sendable {
self.scope = scope
self.id = id
self.jobid = jobid
self.runid = runid
self.limit = limit
self.offset = offset
self.statuses = statuses
@@ -5235,6 +5274,7 @@ public struct CronRunsParams: Codable, Sendable {
case scope
case id
case jobid = "jobId"
case runid = "runId"
case limit
case offset
case statuses
@@ -5257,6 +5297,7 @@ public struct CronRunLogEntry: Codable, Sendable {
public let delivered: Bool?
public let deliverystatus: AnyCodable?
public let deliveryerror: String?
public let failurenotificationdelivery: [String: AnyCodable]?
public let sessionid: String?
public let sessionkey: String?
public let runid: String?
@@ -5279,6 +5320,7 @@ public struct CronRunLogEntry: Codable, Sendable {
delivered: Bool?,
deliverystatus: AnyCodable?,
deliveryerror: String?,
failurenotificationdelivery: [String: AnyCodable]? = nil,
sessionid: String?,
sessionkey: String?,
runid: String?,
@@ -5300,6 +5342,7 @@ public struct CronRunLogEntry: Codable, Sendable {
self.delivered = delivered
self.deliverystatus = deliverystatus
self.deliveryerror = deliveryerror
self.failurenotificationdelivery = failurenotificationdelivery
self.sessionid = sessionid
self.sessionkey = sessionkey
self.runid = runid
@@ -5323,6 +5366,7 @@ public struct CronRunLogEntry: Codable, Sendable {
case delivered
case deliverystatus = "deliveryStatus"
case deliveryerror = "deliveryError"
case failurenotificationdelivery = "failureNotificationDelivery"
case sessionid = "sessionId"
case sessionkey = "sessionKey"
case runid = "runId"
@@ -6216,12 +6260,138 @@ public struct ChatInjectParams: Codable, Sendable {
}
}
public struct ChatEvent: Codable, Sendable {
public struct ChatDeltaEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let spawnedby: String?
public let seq: Int
public let state: AnyCodable
public let state: String
public let message: AnyCodable?
public let deltatext: String
public let replace: Bool?
public let usage: AnyCodable?
public init(
runid: String,
sessionkey: String,
spawnedby: String?,
seq: Int,
state: String,
message: AnyCodable?,
deltatext: String,
replace: Bool?,
usage: AnyCodable?)
{
self.runid = runid
self.sessionkey = sessionkey
self.spawnedby = spawnedby
self.seq = seq
self.state = state
self.message = message
self.deltatext = deltatext
self.replace = replace
self.usage = usage
}
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case spawnedby = "spawnedBy"
case seq
case state
case message
case deltatext = "deltaText"
case replace
case usage
}
}
public struct ChatFinalEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let spawnedby: String?
public let seq: Int
public let state: String
public let message: AnyCodable?
public let usage: AnyCodable?
public let stopreason: String?
public init(
runid: String,
sessionkey: String,
spawnedby: String?,
seq: Int,
state: String,
message: AnyCodable?,
usage: AnyCodable?,
stopreason: String?)
{
self.runid = runid
self.sessionkey = sessionkey
self.spawnedby = spawnedby
self.seq = seq
self.state = state
self.message = message
self.usage = usage
self.stopreason = stopreason
}
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case spawnedby = "spawnedBy"
case seq
case state
case message
case usage
case stopreason = "stopReason"
}
}
public struct ChatAbortedEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let spawnedby: String?
public let seq: Int
public let state: String
public let message: AnyCodable?
public let stopreason: String?
public init(
runid: String,
sessionkey: String,
spawnedby: String?,
seq: Int,
state: String,
message: AnyCodable?,
stopreason: String?)
{
self.runid = runid
self.sessionkey = sessionkey
self.spawnedby = spawnedby
self.seq = seq
self.state = state
self.message = message
self.stopreason = stopreason
}
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case spawnedby = "spawnedBy"
case seq
case state
case message
case stopreason = "stopReason"
}
}
public struct ChatErrorEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let spawnedby: String?
public let seq: Int
public let state: String
public let message: AnyCodable?
public let errormessage: String?
public let errorkind: AnyCodable?
@@ -6233,7 +6403,7 @@ public struct ChatEvent: Codable, Sendable {
sessionkey: String,
spawnedby: String?,
seq: Int,
state: AnyCodable,
state: String,
message: AnyCodable?,
errormessage: String?,
errorkind: AnyCodable?,
@@ -6365,6 +6535,43 @@ public enum PluginsSessionActionResult: Codable, Sendable {
}
}
public enum ChatEvent: Codable, Sendable {
case delta(ChatDeltaEvent)
case final(ChatFinalEvent)
case aborted(ChatAbortedEvent)
case error(ChatErrorEvent)
private enum CodingKeys: String, CodingKey {
case discriminator = "state"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let discriminator = try container.decode(String.self, forKey: .discriminator)
switch discriminator {
case "delta": self = try .delta(ChatDeltaEvent(from: decoder))
case "final": self = try .final(ChatFinalEvent(from: decoder))
case "aborted": self = try .aborted(ChatAbortedEvent(from: decoder))
case "error": self = try .error(ChatErrorEvent(from: decoder))
default:
throw DecodingError.dataCorruptedError(
forKey: .discriminator,
in: container,
debugDescription: "Unknown ChatEvent discriminator value"
)
}
}
public func encode(to encoder: Encoder) throws {
switch self {
case .delta(let value): try value.encode(to: encoder)
case .final(let value): try value.encode(to: encoder)
case .aborted(let value): try value.encode(to: encoder)
case .error(let value): try value.encode(to: encoder)
}
}
}
public enum GatewayFrame: Codable, Sendable {
case req(RequestFrame)
case res(ResponseFrame)

View File

@@ -0,0 +1,8 @@
extension WakeParams {
public init(
mode: AnyCodable,
text: String)
{
self.init(mode: mode, text: text, sessionkey: nil)
}
}

View File

@@ -0,0 +1,187 @@
import CoreGraphics
import Foundation
import ImageIO
import Testing
import UniformTypeIdentifiers
@testable import OpenClawKit
struct ChatImageProcessorTests {
private func syntheticJPEG(width: Int, height: Int) throws -> Data {
guard
let context = CGContext(
data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
else {
throw NSError(domain: "ChatImageProcessorTests", code: 1)
}
context.setFillColor(CGColor(red: 0.8, green: 0.2, blue: 0.4, alpha: 1))
context.fill(CGRect(x: 0, y: 0, width: width, height: height))
context.setFillColor(CGColor(red: 0.1, green: 0.7, blue: 0.3, alpha: 1))
context.fill(CGRect(x: 0, y: 0, width: width / 2, height: height / 2))
guard let image = context.makeImage() else {
throw NSError(domain: "ChatImageProcessorTests", code: 2)
}
let data = NSMutableData()
guard let destination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil)
else {
throw NSError(domain: "ChatImageProcessorTests", code: 3)
}
let properties: [CFString: Any] = [
kCGImageDestinationLossyCompressionQuality: 0.95,
kCGImagePropertyExifDictionary: [
kCGImagePropertyExifDateTimeOriginal: "2026:04:20 16:30:00",
kCGImagePropertyExifLensModel: "Leaky Lens 50mm f/1.4",
] as CFDictionary,
kCGImagePropertyGPSDictionary: [
kCGImagePropertyGPSLatitude: 60.02,
kCGImagePropertyGPSLatitudeRef: "N",
kCGImagePropertyGPSLongitude: 10.95,
kCGImagePropertyGPSLongitudeRef: "E",
] as CFDictionary,
kCGImagePropertyTIFFDictionary: [
kCGImagePropertyTIFFMake: "LeakCorp",
kCGImagePropertyTIFFModel: "Privacy-Leaker-1",
] as CFDictionary,
]
CGImageDestinationAddImage(destination, image, properties as CFDictionary)
guard CGImageDestinationFinalize(destination) else {
throw NSError(domain: "ChatImageProcessorTests", code: 4)
}
return data as Data
}
private func syntheticPNGWithAlpha(width: Int, height: Int) throws -> Data {
guard
let context = CGContext(
data: nil,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: width * 4,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
else {
throw NSError(domain: "ChatImageProcessorTests", code: 5)
}
context.clear(CGRect(x: 0, y: 0, width: width, height: height))
context.setFillColor(CGColor(red: 1, green: 0, blue: 0, alpha: 1))
context.fill(CGRect(x: width / 4, y: height / 4, width: width / 2, height: height / 2))
guard let image = context.makeImage() else {
throw NSError(domain: "ChatImageProcessorTests", code: 6)
}
let data = NSMutableData()
guard let destination = CGImageDestinationCreateWithData(data, UTType.png.identifier as CFString, 1, nil)
else {
throw NSError(domain: "ChatImageProcessorTests", code: 7)
}
CGImageDestinationAddImage(destination, image, nil)
guard CGImageDestinationFinalize(destination) else {
throw NSError(domain: "ChatImageProcessorTests", code: 8)
}
return data as Data
}
private func properties(for data: Data) -> [CFString: Any] {
guard
let source = CGImageSourceCreateWithData(data as CFData, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any]
else {
return [:]
}
return properties
}
private func dimensions(for data: Data) -> (width: Int, height: Int)? {
let properties = self.properties(for: data)
guard
let width = properties[kCGImagePropertyPixelWidth] as? NSNumber,
let height = properties[kCGImagePropertyPixelHeight] as? NSNumber
else {
return nil
}
return (width.intValue, height.intValue)
}
@Test func `resizes landscape long edge to upload limit`() throws {
let source = try self.syntheticJPEG(width: 4000, height: 3000)
let output = try ChatImageProcessor.processForUpload(data: source)
let dimensions = try #require(self.dimensions(for: output))
#expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx)
#expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (4000.0 / 3000.0)) <= 0.02)
}
@Test func `resizes portrait long edge to upload limit`() throws {
let source = try self.syntheticJPEG(width: 3000, height: 4000)
let output = try ChatImageProcessor.processForUpload(data: source)
let dimensions = try #require(self.dimensions(for: output))
#expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx)
#expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (3000.0 / 4000.0)) <= 0.02)
}
@Test func `resizes narrow tall long edge to upload limit`() throws {
let source = try self.syntheticJPEG(width: 1080, height: 2400)
let output = try ChatImageProcessor.processForUpload(data: source)
let dimensions = try #require(self.dimensions(for: output))
#expect(max(dimensions.width, dimensions.height) <= ChatImageProcessor.maxLongEdgePx)
#expect(abs((Double(dimensions.width) / Double(dimensions.height)) - (1080.0 / 2400.0)) <= 0.02)
}
@Test func `small image is not upscaled`() throws {
let source = try self.syntheticJPEG(width: 400, height: 300)
let output = try ChatImageProcessor.processForUpload(data: source)
let dimensions = try #require(self.dimensions(for: output))
#expect(max(dimensions.width, dimensions.height) <= 400)
}
@Test func `output fits payload budget`() throws {
let source = try self.syntheticJPEG(width: 4000, height: 3000)
let output = try ChatImageProcessor.processForUpload(data: source)
#expect(output.count <= ChatImageProcessor.maxPayloadBytes)
}
@Test func `rejects non image data`() {
let garbage = Data("not an image".utf8)
#expect(throws: ChatImageProcessor.ProcessError.self) {
_ = try ChatImageProcessor.processForUpload(data: garbage)
}
}
@Test func `strips source metadata from output`() throws {
let source = try self.syntheticJPEG(width: 3000, height: 2000)
let output = try ChatImageProcessor.processForUpload(data: source)
let properties = self.properties(for: output)
let gps = properties[kCGImagePropertyGPSDictionary] as? [CFString: Any] ?? [:]
#expect(gps.isEmpty)
for needle in ["Leaky Lens", "LeakCorp", "Privacy-Leaker", "2026:04:20"] {
#expect(output.range(of: Data(needle.utf8)) == nil)
}
}
@Test func `flattens transparent sources to opaque JPEG`() throws {
let source = try self.syntheticPNGWithAlpha(width: 800, height: 600)
let output = try ChatImageProcessor.processForUpload(data: source)
let imageSource = try #require(CGImageSourceCreateWithData(output as CFData, nil))
let image = try #require(CGImageSourceCreateImageAtIndex(imageSource, 0, nil))
#expect([.none, .noneSkipFirst, .noneSkipLast].contains(image.alphaInfo))
}
}

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