Compare commits

..

1767 Commits

Author SHA1 Message Date
Vincent Koc
53ed753394 feat(plugins): move install records to managed ledger 2026-04-25 11:23:27 -07:00
Vincent Koc
b8a41739d5 feat(diagnostics-otel): export memory diagnostics 2026-04-25 11:22:19 -07:00
Peter Steinberger
1380dc170e fix(browser): avoid restart hint for external profiles 2026-04-25 19:18:06 +01:00
Vincent Koc
d6ef1fcf24 feat(diagnostics-otel): export tool loop events 2026-04-25 11:11:56 -07:00
Peter Steinberger
830bd2e236 fix: recover stale runtime deps locks 2026-04-25 19:09:09 +01:00
Poo-Squirry
fd3840cb00 Fix context usage display and active-run reload interruptions
Fixes context usage display regressions and prevents active runs from being interrupted by channel reloads. Adds persisted tool-result detail bounds so large tool metadata stays out of model/session payloads.
2026-04-25 19:07:52 +01:00
Chris Zhang
c3bfd328ad feat(litellm): add image generation provider (#70246)
* feat(litellm): add image generation provider

Registers litellm as an image-generation provider so model refs like
litellm/gpt-image-2 route through the LiteLLM proxy, and
agents.defaults.imageGenerationModel.fallbacks entries of the form
litellm/... resolve without "No image-generation provider registered
for litellm" errors.

Implementation uses the OpenAI-compatible /images/generations and
/images/edits endpoints that LiteLLM proxies for. BaseUrl resolves from
models.providers.litellm.baseUrl (default http://localhost:4000). Private
network is auto-allowed when baseUrl is a loopback/RFC1918 address, which
covers the common self-hosted LiteLLM proxy case without needing
OPENCLAW_PROVIDER_ALLOW_PRIVATE_NETWORK. Public baseUrls keep normal SSRF
defaults.

Default model is gpt-image-2 (matching upstream 4.21+ OpenAI default).
Advertises the same 2K/4K sizes OpenAI now exposes, plus legacy
256/512/1024 for dall-e-3. Supports both generate and edit.

Local patch. LiteLLM has no upstream image-generation support yet; revisit
if upstream adds one.

* ci: rerun after upstream main hot-fix

* fix(litellm): harden image generation provider

---------

Co-authored-by: Chris Zhang <chris@ChrisdeMac-mini.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 19:06:51 +01:00
Chunyue Wang
930d81aa41 fix(agents): prevent Bedrock replay death loop on empty assistant content (#71627)
* fix(agents): prevent Bedrock replay death loop on empty assistant content

  Fixes #71572

* docs: document Bedrock replay repair (#71627) (thanks @openperf)

* fix(diagnostics): share diagnostic event state across sdk graphs

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 19:04:40 +01:00
Vincent Koc
ff172f46a5 feat(diagnostics-otel): add context assembly spans 2026-04-25 11:03:46 -07:00
Peter Steinberger
afd6b5d6fc fix(opencode-go): route DeepSeek V4 through OpenAI transport 2026-04-25 18:58:08 +01:00
Vincent Koc
275c128e99 feat(plugins): add sanitized model call hooks 2026-04-25 10:56:40 -07:00
Peter Steinberger
9ffe764416 fix(whatsapp): send voice note text separately 2026-04-25 18:55:03 +01:00
Peter Steinberger
617e1dd6bf fix(browser): honor remote CDP open timeouts 2026-04-25 18:52:57 +01:00
Peter Steinberger
d623354a0e fix(infra): share diagnostic event state across loaders 2026-04-25 18:52:38 +01:00
Vincent Koc
44114328b4 feat(diagnostics): surface provider request id hashes 2026-04-25 10:46:10 -07:00
Peter Steinberger
2e0ae56b1a test(plugins): satisfy readonly index lint 2026-04-25 18:44:29 +01:00
Peter Steinberger
cd6c64d2ee test(plugins): avoid readonly index mutation 2026-04-25 18:42:25 +01:00
Peter Steinberger
649a645492 test(core): trim sync test overhead 2026-04-25 18:41:21 +01:00
Peter Steinberger
39488dfd68 test(pairing): reduce fixture io overhead 2026-04-25 18:41:20 +01:00
Peter Steinberger
8c93745f0f test(memory): speed up host fixture setup 2026-04-25 18:41:20 +01:00
Vincent Koc
f56bf63b06 fix(plugins): reject stale registry policy reads 2026-04-25 10:35:36 -07:00
Vincent Koc
61b3c04424 test(plugins): cover registry refresh mutations 2026-04-25 10:35:36 -07:00
Vincent Koc
3ec92dfac0 fix(plugins): deprecate registry disable break glass 2026-04-25 10:35:36 -07:00
Vincent Koc
4324855a9d docs(plugins): document persisted registry repair 2026-04-25 10:35:35 -07:00
Vincent Koc
fd8a8789d0 fix(plugins): satisfy registry lint 2026-04-25 10:35:35 -07:00
Vincent Koc
2f622acec6 fix(plugins): normalize startup config from registry 2026-04-25 10:35:35 -07:00
Vincent Koc
f14aa65bcc fix(plugins): refresh registry after chat toggles 2026-04-25 10:35:35 -07:00
Vincent Koc
29988335fc feat(plugins): resolve provider owners from registry 2026-04-25 10:35:35 -07:00
Vincent Koc
674d188153 feat(plugins): plan gateway startup from registry 2026-04-25 10:35:35 -07:00
Vincent Koc
feb8d3a4bd fix(plugins): label registry list state as enabled 2026-04-25 10:35:34 -07:00
Vincent Koc
5677a26385 docs(changelog): note registry-backed plugin list 2026-04-25 10:35:34 -07:00
Vincent Koc
5859dcd298 feat(plugins): list from registry snapshot 2026-04-25 10:35:34 -07:00
Vincent Koc
caf25fac91 feat(plugins): add registry repair command 2026-04-25 10:35:34 -07:00
Vincent Koc
521e75dea0 feat(plugins): prefer persisted registry reads 2026-04-25 10:35:09 -07:00
Vincent Koc
a7de722f4f fix(diagnostics-otel): align GenAI semconv attrs 2026-04-25 10:33:13 -07:00
Peter Steinberger
5f4bc6ec02 fix: surface external agent errors 2026-04-25 18:30:16 +01:00
Peter Steinberger
f545872cbc test(ui): streamline session controls async tests 2026-04-25 18:27:23 +01:00
Peter Steinberger
847c00d409 test(ui): speed up chat icon mocks 2026-04-25 18:27:23 +01:00
Peter Steinberger
88df8fe09d fix(browser): clarify Browserless CDP attach handling 2026-04-25 18:26:57 +01:00
Peter Steinberger
0bbb0eb735 fix(image): honor generation timeout config 2026-04-25 18:25:26 +01:00
Peter Steinberger
80739731dd docs: clarify pi-ai generic failover (#71647) 2026-04-25 18:22:06 +01:00
willamhou
4b5c2f9aa3 fix(agents/failover): classify bare pi-ai stream wrapper as timeout regardless of provider (#71620) 2026-04-25 18:22:06 +01:00
Vincent Koc
dcdf97685b fix(diagnostics): trust internal trace parents (#71574)
* fix(diagnostics): trust internal trace parents

* fix(diagnostics): harden trusted trace metadata

* fix(tooling): honor explicit oxlint threads

* fix(agents): use stable nonmutating sort helpers

* chore(plugin-sdk): refresh api baseline

* fix(diagnostics): gate internal event subscriptions

* fix(diagnostics): isolate listener event copies

* chore(plugin-sdk): refresh internal diagnostics baseline

* chore(plugin-sdk): refresh diagnostics event baseline

* fix(diagnostics): keep event state module local

* fix(diagnostics): harden internal subscription capability

* fix(diagnostics): freeze listener metadata
2026-04-25 10:18:52 -07:00
Peter Steinberger
8e7d382c37 refactor(tts): clarify text media directives 2026-04-25 18:18:34 +01:00
Peter Steinberger
67506ac2a9 fix(xai): support video reference images 2026-04-25 18:14:51 +01:00
Peter Steinberger
768bbc7cc0 docs: update OpenAI GPT-5.5 API guidance 2026-04-25 18:14:10 +01:00
Peter Steinberger
390be8138f fix: add OpenCode Go DeepSeek V4 models 2026-04-25 18:11:59 +01:00
Vincent Koc
0d274ef6c2 docs(control-ui): note assistant avatar uploads stay browser-local
Val Alexander's c65aa1d2a6 (#71639) changed assistant avatar uploads
from gateway config persistence to localStorage, mirroring the existing
user-avatar pattern. CHANGELOG covered it but docs/web/control-ui.md
'Personal identity (browser-local)' section only documented the user
identity. Add a paragraph noting the assistant avatar override follows
the same browser-local pattern, while keeping the ui.assistant.avatar
config field reachable for non-UI clients writing the field directly.
2026-04-25 10:08:59 -07:00
Peter Steinberger
6b3e4b88d6 test: update QA parity fixtures for GPT-5.5 2026-04-25 18:05:28 +01:00
Peter Steinberger
39343088ed fix(tts): keep media-only no-reply payloads 2026-04-25 18:04:54 +01:00
Peter Steinberger
f3ba962fd0 fix(subagents): explain browser tool profile filtering 2026-04-25 17:59:05 +01:00
Peter Steinberger
e27e29c66e refactor: split Crestodian planner backend selection 2026-04-25 17:56:46 +01:00
Peter Steinberger
60f9358348 fix(tts): preserve legacy tool voice hints 2026-04-25 17:56:37 +01:00
Peter Steinberger
dc7c703425 test: lazy-load global cleanup helpers 2026-04-25 17:49:16 +01:00
Peter Steinberger
8bead989da fix(telegram): frame audio transcripts as untrusted 2026-04-25 17:45:40 +01:00
Peter Steinberger
8659495384 test: make live cron probe agent-generic 2026-04-25 17:42:32 +01:00
Val Alexander
c65aa1d2a6 fix(control-ui): persist assistant avatar override locally (#71639)
* fix(control-ui): rebalance quick settings into stable 3-col bento

Pair Appearance with Automations and let Channels stand alone in the
middle column so all three top-row columns reach similar heights.
Promote Personal to a full-width row with a horizontal body
(identity tiles | emoji + actions) so the avatar block stops fighting
for half-width space. Drops the unused .qs-stack--wide hook.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(control-ui): rebalance Personal card with symmetric User↔Assistant identity pair

Restructure Personal card layout to present User and Assistant as 2 balanced identity cards instead of separate User tile + form controls. Mirrors the visual hierarchy and UI pattern across both identities.

Changes:
- Move User avatar text input into User identity card's .__repair section (mirroring Assistant's structure)
- Inline "Choose image" and "Clear avatar" buttons as flex-wrapped action group
- Remove .qs-personal-body and .qs-personal-form wrapper divs
- Update Personal card's .qs-identity-grid to 2-column layout with balanced spacing
- Responsive collapse to 1-column at ≤760px

Tests:
- config-quick.test.ts updated to expect 2 stacks (no longer wrapping Personal in form)
- config-quick.test.ts validates identity card layout now has symmetric User↔Assistant structure
- All 10 quick settings view tests passing
- All 20 schema regression tests passing

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* chore: ignore .vmux worktree paths

* fix(control-ui): persist assistant avatar override locally instead of via gateway config

Mirrors the user-avatar pattern: assistant avatar uploads now go to
localStorage and overlay the gateway-resolved identity at bootstrap and on
agent.identity.get refreshes. Sidesteps the ui.assistant.avatar zod cap
that rejected uploaded data URLs as 'Too big: expected string to have
<=200 characters', removes one config.patch RPC from the avatar path, and
collapses the upload handler from a 44-line async/loadConfig dance into a
plain synchronous setter.

Also lifts the gateway-side ui.assistant.avatar schema cap from 200 to
2,000,000 to match the user-avatar size budget for non-UI clients writing
the field directly, and adds a content-aware text/image normalizer in
ui/src/ui/assistant-identity.ts so short-text avatars stay short while
data URLs survive round-tripping.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 11:17:48 -05:00
Darshan Paccha
95b7a85f06 fix(ui): remove duplicate config section headers
Fix duplicate section title and description rendering in single-section Control UI config pages.\n\nKeeps root multi-section card headers intact, keeps single-section hero copy as the only visible section title, and adds browser coverage for both single-section and root views.\n\nFixes #68003.\n\nThanks @d1rshan.
2026-04-25 09:43:50 -05:00
Vincent Koc
c070509b7f fix(security): bound archive and MIME parser work (#71561)
* fix(security): bound archive and MIME parser work

* fix(security): harden zip preflight accounting

* fix(plugins): keep update channel sync on bundled path helpers

* fix(lint): avoid boolean literal comparisons

* fix(lint): keep agent spawn assertion immutable

* test(auto-reply): relax slow model directive regression timeout
2026-04-25 06:22:56 -07:00
Peter Steinberger
4e3bf7ce6a test: scope gateway restart signal assertion 2026-04-25 14:09:31 +01:00
Peter Steinberger
5c6a5afe81 test: use non-mutating sort in cli runner spec 2026-04-25 14:07:24 +01:00
Peter Steinberger
cd392b947c test: dedupe memory and context suites 2026-04-25 14:06:26 +01:00
Peter Steinberger
2413c0f5a5 perf: split chat UI test dependencies 2026-04-25 14:06:26 +01:00
Peter Steinberger
3db60f7eab perf: trim agent workspace imports 2026-04-25 14:06:26 +01:00
Vincent Koc
9b1dd9e573 docs(browser): document Chrome MCP per-profile mcpCommand/mcpArgs and cdpUrl mapping
Vincent's commit ab1d1a5c9e (#71560) added user-facing config keys to
existing-session profiles for the Chrome DevTools MCP launch path:

- browser.profiles.<name>.mcpCommand
- browser.profiles.<name>.mcpArgs

Plus runtime behavior changes:

- cdpUrl http(s) -> --browserUrl, cdpUrl ws(s) -> --wsEndpoint
- endpoint flags and userDataDir are mutually exclusive

The CHANGELOG entry covered the change, but docs/tools/browser.md
existing-session reference did not. Add a 'Custom Chrome MCP launch'
subsection describing the new fields and the cdpUrl endpoint mapping
rules.
2026-04-25 05:54:54 -07:00
Chunyue Wang
bc73141e82 fix(cli): key gemini cli auth epoch on google account identity (#71076)
Fixes openclaw#70973. Adds a \`google-gemini-cli\` branch to \`getLocalCliCredentialFingerprint\` that lifts OpenID \`id_token\` \`sub\`/\`email\` claims from \`~/.gemini/oauth_creds.json\` onto \`GeminiCliCredential\` so the shared \`encodeOAuthIdentity\` produces an identity-keyed auth-epoch matching the Claude/Codex contract, plus bumps \`CLI_AUTH_EPOCH_VERSION\` from 3 to 4 so existing v3 Gemini bindings without an \`authEpoch\` ride the existing \`cli-session.ts\` version-gate instead of forcing a one-time invalidation.
2026-04-25 20:47:58 +08:00
Vincent Koc
ab1d1a5c9e fix(browser): configure Chrome MCP existing-session launch (#71560) 2026-04-25 05:46:39 -07:00
Peter Steinberger
dd78b7f773 fix: harden OpenCode ACP bind dispatch 2026-04-25 13:38:58 +01:00
Peter Steinberger
42514156e0 fix: yield while waiting for subagent completions 2026-04-25 13:29:47 +01:00
skylee-01
f7b71abf48 fix(agents): pass Claude system prompt via file 2026-04-25 17:59:25 +05:30
Vincent Koc
ed650b652f fix(test): detect partial sparse core roots 2026-04-25 05:18:25 -07:00
Peter Steinberger
b26367e22f test: add Crestodian QA lab setup scenario 2026-04-25 13:15:11 +01:00
Peter Steinberger
c977643460 perf(browser): precompute browser help 2026-04-25 13:07:15 +01:00
Sahil Satralkar
3064ea78ab fix(telegram): recover incomplete preview finalization (#71554)
Fix Telegram partial-stream preview finalization so ambiguous final edit failures fall back to a final send when the visible preview is a strict prefix of the answer.

Includes archived-preview regression coverage and generated config metadata refresh.

Thanks @sahilsatralkar.

Co-authored-by: Sahil Satralkar <62758655+sahilsatralkar@users.noreply.github.com>
2026-04-25 13:01:10 +01:00
Peter Steinberger
e25b3c6056 fix(browser): align bare ws cdp readiness 2026-04-25 13:00:22 +01:00
Vincent Koc
2b822f6ed0 fix(plugins): preserve default enablement for relocation 2026-04-25 04:59:53 -07:00
Vincent Koc
f70d77b0bd docs(plugins): clarify registry-derived relocations 2026-04-25 04:59:53 -07:00
Vincent Koc
0abb2a571f fix(plugins): derive bundled relocation from registry 2026-04-25 04:59:53 -07:00
Vincent Koc
7177492487 fix(plugins): keep enabled-only registry migration fresh 2026-04-25 04:59:53 -07:00
Vincent Koc
0cc2b0e283 feat(plugins): refresh registry after plugin mutations 2026-04-25 04:59:53 -07:00
Vincent Koc
53c3c949d0 feat(plugins): bridge externalized bundled updates 2026-04-25 04:59:52 -07:00
Vincent Koc
ad8296e685 fix(plugins): harden registry migration guards 2026-04-25 04:59:52 -07:00
Vincent Koc
f22a2f7e8b fix(plugins): migrate only enabled registry entries 2026-04-25 04:59:52 -07:00
Vincent Koc
d7cf803705 fix(plugins): preflight registry install migration 2026-04-25 04:59:52 -07:00
Vincent Koc
81aefb9a18 feat(plugins): migrate plugin registry on install 2026-04-25 04:59:52 -07:00
Peter Steinberger
a48998d8c8 test(qqbot): cover voice utility contracts 2026-04-25 12:57:23 +01:00
Peter Steinberger
c307700db0 test(whatsapp): cover group generated media delivery 2026-04-25 12:56:53 +01:00
Peter Steinberger
d6e9ae53fe perf: split chat strip helper 2026-04-25 12:52:27 +01:00
Peter Steinberger
56573185f2 perf: split canvas a2ui shared imports 2026-04-25 12:52:27 +01:00
Peter Steinberger
40e4a00c8e perf: slim crestodian rescue tests 2026-04-25 12:52:27 +01:00
Peter Steinberger
2b8105598e perf: lazy load support bundle zip 2026-04-25 12:52:27 +01:00
Peter Steinberger
1888242bd3 perf: split trajectory export paths 2026-04-25 12:52:27 +01:00
Peter Steinberger
4a76a66872 perf: slim memory host imports 2026-04-25 12:52:27 +01:00
Peter Steinberger
6eec38ad5a feat(discord): allow voice model override 2026-04-25 12:47:46 +01:00
Ayaan Zaidi
d0ed938351 fix: make subagent session errors actionable (#67790) (thanks @stainlu) 2026-04-25 17:15:36 +05:30
stainlu
835f768036 fix(agents): make sessions_spawn mode=session errors actionable when thread binding is unavailable 2026-04-25 17:15:36 +05:30
Peter Steinberger
3507efa4ec fix(media): preserve oversized video generation delivery 2026-04-25 12:41:43 +01:00
Roman Godz
150f3e472b fix: sync Claude CLI OAuth credentials (#70902) (thanks @starvex) 2026-04-25 17:07:27 +05:30
Peter Steinberger
84dc9f12f1 test(agents): cover single image generation media delivery 2026-04-25 12:32:43 +01:00
Vincent Koc
e174d96cc0 refactor(media): move sharp image ops into media runtime (#71519)
* refactor(media): move sharp image ops into plugin

* fix(media): pass image pixel budget to sharp plugin

* refactor(media): reuse media understanding sharp runtime

* test(build): allow staged runtime core graphs
2026-04-25 04:31:10 -07:00
Peter Steinberger
b2b898c2a8 feat(browser): configure local startup timeouts 2026-04-25 12:30:35 +01:00
Peter Steinberger
4ac6729d12 test: expand Crestodian first-run Docker smoke 2026-04-25 12:30:26 +01:00
Peter Steinberger
9ab51bb66e test: stabilize qa lab live scenarios 2026-04-25 12:30:08 +01:00
Peter Steinberger
c5fe80ad58 fix: make qa config apply retries idempotent 2026-04-25 12:30:07 +01:00
Peter Steinberger
67436918f3 fix: deliver subagent completions via external requester route 2026-04-25 12:30:07 +01:00
Vincent Koc
924271385b fix(cron): record interrupted startup runs
* fix(cron): record interrupted startup runs

* test(cron): update interrupted startup expectations
2026-04-25 04:28:11 -07:00
Val Alexander
fc5920fb51 fix(ui): polish assistant identity settings
Polishes the basic config identity layout, aligns assistant avatar rendering with chat, and adds a Control UI assistant avatar override with IDENTITY.md fallback.
2026-04-25 06:27:22 -05:00
Vincent Koc
443b837bd5 fix(build): harden bundled plugin runtime staging
Copy bundled plugin skill trees into dist-runtime, broaden Windows symlink-copy fallbacks, and harden runtime-deps fingerprinting.
2026-04-25 04:27:17 -07:00
Donetta Flatley
f408bba9de fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode for remote embeddings in proxy environments (#71506)
* fix(memory-host-sdk): use TRUSTED_ENV_PROXY mode in withRemoteHttpResponse

When a HTTP/HTTPS proxy is configured via environment variables
(HTTPS_PROXY, HTTP_PROXY, ALL_PROXY), the withRemoteHttpResponse
function now passes mode=TRUSTED_ENV_PROXY to fetchWithSsrFGuard.

This causes DNS resolution to skip the local resolver and route
through the configured proxy, fixing 'fetch failed' errors for
remote memory embeddings (including GitHub Copilot embeddings) in
proxy environments (e.g. Clash TUN, corporate proxies).

Previously, without an explicit mode, fetchWithSsrFGuard defaulted
to STRICT mode which performs local DNS pre-resolution via
resolvePinnedHostnameWithPolicy(), failing in proxy environments
where DNS must go through the proxy.

Fixes: openclaw/openclaw#52162

* fix: harden memory env proxy guard (#71506) (thanks @DhtIsCoding)

---------

Co-authored-by: Dht <dht@openclaw.ai>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 12:24:09 +01:00
Peter Steinberger
f1470b52fb fix(agents): fall back for threadless completion delivery 2026-04-25 12:23:42 +01:00
Ayaan Zaidi
bdba4fa1bf fix: isolate active memory auth health (#71539)
* fix(agents): scope helper auth failures

* fix(active-memory): isolate recall auth health

* fix: isolate active memory auth health (#71539)

* fix: avoid auth policy import cycle (#71539)
2026-04-25 16:50:38 +05:30
Peter Steinberger
be1d716427 refactor(plugin-sdk): narrow CLI runtime exports 2026-04-25 12:20:34 +01:00
Vincent Koc
f8a41e5e9c fix(test): serialize changed checks locally 2026-04-25 04:19:09 -07:00
Peter Steinberger
b511250e5c feat(media): add voice conversion and speech plugins 2026-04-25 12:12:33 +01:00
Peter Steinberger
16b7dee1ef test(crestodian): complete tui overview mock 2026-04-25 12:07:52 +01:00
Peter Steinberger
de652afffd fix: use random restart intent temp suffix 2026-04-25 12:04:37 +01:00
Peter Steinberger
e6fd1ccfd7 perf(ui): trim chat test imports 2026-04-25 12:04:17 +01:00
Peter Steinberger
4484772e7d test(logger): isolate rolling file cleanup 2026-04-25 12:04:17 +01:00
Peter Steinberger
4d00c47072 perf(crestodian): reduce test import overhead 2026-04-25 12:04:17 +01:00
Vincent Koc
84a22a64be fix(feishu): finish streaming card closeout 2026-04-25 04:04:03 -07:00
Peter Steinberger
935cd34e9f fix(openai): omit Azure image deployment model body 2026-04-25 12:02:26 +01:00
Peter Steinberger
89755d1c79 refactor(browser): simplify lazy CLI placeholders 2026-04-25 11:48:59 +01:00
deepkilo
df6c58cf30 fix(gateway): use secure dashboard links when TLS is enabled (#71499)
Fixes #71494.

- Render Control UI links with https:// when gateway TLS is enabled.
- Render websocket links with wss:// through the shared link resolver.
- Add daemon status handoff coverage and TLS scheme docs.

Co-authored-by: deepkilord <wang_hgang@msn.com>
2026-04-25 11:45:15 +01:00
Peter Steinberger
8cbb62d93c docs(browser): document headless start override 2026-04-25 11:42:04 +01:00
Peter Steinberger
c52ec520c7 feat(browser): add one-shot headless start override 2026-04-25 11:42:03 +01:00
Peter Steinberger
51e6f9c27e fix(reply): narrow empty-body history guard 2026-04-25 11:41:36 +01:00
jindongfu
1559e28d6b fix(get-reply): include inboundUserContext in empty-body guard (#71489)
The empty-body guard only checked baseBodyFinal (current message body)
and softResetTail, ignoring inboundUserContext which includes
InboundHistory from group chat context. This caused the bot to reject
bare @mentions in Feishu group chats where prior messages provided the
conversation context via InboundHistory.

Now hasUserBody also checks whether inboundUserContext has content,
matching the behavior before the 2026.4.12 refactor.
2026-04-25 11:41:36 +01:00
Vincent Koc
1549ded4ac docs(control-ui): document PWA install and web push
Eduardo Cruz's PWA web push feat (21b7ad5805, #44590) added a substantial
user-facing surface — manifest.webmanifest, sw.js, gateway push.web.*
methods, persisted vapid-keys.json/web-push-subscriptions.json, and
OPENCLAW_VAPID_* env overrides — but did not touch any docs/.

Add a 'PWA install and web push' section to docs/web/control-ui.md
covering the new persisted state files, env vars, and the four scope-gated
gateway methods (push.web.vapidPublicKey, push.web.subscribe,
push.web.unsubscribe, push.web.test). Distinguish from the existing
APNS relay-backed iOS push path.
2026-04-25 03:40:38 -07:00
Peter Steinberger
776d2ab65d fix(browser): lazy-load browser CLI runtime
Co-authored-by: pandego <7780875+pandego@users.noreply.github.com>
Co-authored-by: Tianworld <3580442280@qq.com>
2026-04-25 11:40:20 +01:00
Ayaan Zaidi
27aae62d99 fix: stop heartbeat prompt leaking into user runs (#69278) (thanks @stainlu) 2026-04-25 16:09:56 +05:30
stainlu
06c058b21d fix(agents): stop injecting heartbeat system prompt on non-heartbeat runs (#69079) 2026-04-25 16:09:56 +05:30
Val Alexander
151befb90b chore: keep superpowers plans local (#71530)
* docs: add control ui setup guidance design

* chore: keep superpowers plans local
2026-04-25 05:35:23 -05:00
Vincent Koc
0c9dacf902 fix(test): ignore local check opt-out in dev wrappers 2026-04-25 03:32:01 -07:00
Peter Steinberger
87aa0f813c fix(cli): forward video generation options 2026-04-25 11:31:09 +01:00
Val Alexander
b85b106b10 docs: add application modernization plan (#71528)
* docs: add application modernization plan

* docs: clarify frontend skill target
2026-04-25 05:29:57 -05:00
Vincent Koc
e0546edd98 fix(cron): normalize flat legacy job rows 2026-04-25 03:29:30 -07:00
Ayaan Zaidi
bbd6dfbe92 fix: cover CLI session prompt hash reuse (#69236) (thanks @stainlu) 2026-04-25 15:58:19 +05:30
Peter Steinberger
7711df0669 fix: default proxy completions tool choice (#71472) (thanks @Speed-maker) 2026-04-25 11:23:33 +01:00
Speed-maker
9a6b769e6e fix(agents): default proxy completions tool choice 2026-04-25 11:23:33 +01:00
Peter Steinberger
6a71c19839 fix: simplify Crestodian startup greeting 2026-04-25 11:20:59 +01:00
Peter Steinberger
a0c70c4f5a fix(google): guard veo rest polling 2026-04-25 11:17:23 +01:00
Peter Steinberger
9b48e4c0b6 fix(browser): fall back to headless on Linux without display 2026-04-25 11:13:42 +01:00
Peter Steinberger
b5a1b7d44d fix(google): guard veo video downloads 2026-04-25 11:12:49 +01:00
Peter Steinberger
978f869fcd fix(google): type veo fallback operation state 2026-04-25 11:11:14 +01:00
Peter Steinberger
94686c63fb fix(google): fall back to rest for veo sdk 404 2026-04-25 11:11:14 +01:00
Vincent Koc
814409a3b3 fix(test): keep local Vitest checks serialized 2026-04-25 03:07:27 -07:00
Peter Steinberger
5e0cca5e24 fix(google): narrow veo api key for uri download 2026-04-25 11:07:16 +01:00
Peter Steinberger
c11337149b fix(google): download direct veo video uri 2026-04-25 11:07:16 +01:00
Vincent Koc
455eba7f94 fix(feishu): coalesce streaming card final delivery 2026-04-25 03:06:38 -07:00
Peter Steinberger
38703ed9a1 fix(discord): identify voice attachment metadata 2026-04-25 11:05:38 +01:00
Peter Steinberger
5985e1d8b9 test: speed up import-heavy tests 2026-04-25 11:04:16 +01:00
Peter Steinberger
b9ea631b4b fix(openai): use gpt 5.5 for codex image responses 2026-04-25 11:03:53 +01:00
Eduardo Cruz
21b7ad5805 feat: add Control UI PWA web push support (#44590)
Adds browser PWA manifest and service worker support for the Control UI, plus gateway RPC methods and persisted Web Push subscription handling.

Maintainer verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test src/infra/push-web.test.ts src/gateway/server-methods/push.test.ts src/gateway/control-ui.test.ts src/gateway/protocol/push.test.ts
- pnpm check:changed passed before final GitHub update-branch merge commit
- pnpm build

Source head: 0720024368
2026-04-25 05:03:00 -05:00
Peter Steinberger
385da2db60 feat: run Crestodian in TUI shell 2026-04-25 10:59:49 +01:00
Peter Steinberger
9fe35a0c62 fix(discord): restore voice note audio preflight 2026-04-25 10:57:37 +01:00
Peter Steinberger
936f27dcab docs: clarify minimax music changelog scope 2026-04-25 10:55:54 +01:00
Peter Steinberger
e6713c0a61 test(minimax): cover default music model normalization 2026-04-25 10:55:54 +01:00
Peter Steinberger
ed8384d32d fix(minimax): default music generation to music 2.6 2026-04-25 10:55:54 +01:00
Vincent Koc
c1f359c276 fix(test): reuse heavy-check lock in boundary prep 2026-04-25 02:49:45 -07:00
Vincent Koc
678d2c327c docs(changelog): backfill missing PR refs and reporter credits in top Unreleased
Three of my (vincentkoc) entries were missing closing PR refs, and
several maintainer-fix entries were missing credit for the user who
reported the underlying issue:

- Diagnostics/OTEL outbound delivery: add (#71471) and credit @jlapenna
  whose #70424 framed the broader tracing work.
- Cron malformed legacy jobs: add (#71509).
- OpenAI/Codex OAuth region failures: add (#71501) and credit reporter
  @wulala-xjj (#51175).
- Telegram duplicate pollers: credit reporter @Co-Messi (#56230).
- MCP/CLI one-shot retire: credit reporter @spartoviMD (#71457).
- OpenAI/Codex image baseUrl canonicalize: credit reporter @GodsBoy
  (#71460).
- Feishu TTS Ogg/Opus: credit reporters @sg1416-zg (#61249) and
  @ycjlb2023-peteryi (#37868).
- MiniMax TTS portal OAuth: credit reporter @zx15210404690-hash
  (#55017).
- MCP config reload disposal: credit reporter @xieyuanqing (#60656).
2026-04-25 02:49:37 -07:00
Peter Steinberger
815e9b493c fix: improve openrouter model scan fallback 2026-04-25 10:46:20 +01:00
Peter Steinberger
da2c61fe6e fix: render authenticated control ui avatars 2026-04-25 10:46:14 +01:00
Yunsu
9c64a0ca23 fix(google): avoid doubled media generation API version
Strip configured trailing /v1beta from Google music/video generation base URLs before calling the Google GenAI SDK.\n\nFixes #63240.\n\nThanks @Hybirdss.
2026-04-25 10:45:38 +01:00
Val Alexander
0bef73d151 chore: remove repo PR assets (#71510) 2026-04-25 04:40:29 -05:00
Vincent Koc
2896107153 fix(cron): tolerate malformed legacy jobs 2026-04-25 02:39:06 -07:00
Peter Steinberger
a7604f8170 fix(minimax): support token plan tts auth 2026-04-25 10:36:12 +01:00
Peter Steinberger
7fcefd56b7 chore: bump version to 2026.4.25 2026-04-25 10:31:52 +01:00
Vincent Koc
65ea6a0d94 fix(auth): clarify Codex OAuth region failures (#71501) 2026-04-25 02:31:42 -07:00
Peter Steinberger
c6770d3694 fix: align native think menus with session models 2026-04-25 10:30:49 +01:00
Peter Steinberger
4f91d81e1d fix(googlechat): preserve reply text after typing update failures
Preserve Google Chat reply text when typing indicator cleanup or update fails.

- Extract Google Chat reply delivery into a focused module
- Retry the failed first text chunk as a new message after placeholder update failure
- Cover media caption and chunk fallback regressions

Thanks @colin-lgtm.
2026-04-25 10:30:41 +01:00
Vincent Koc
0ee9e8188d Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  feat: add crestodian local planner fallback
  fix(control-ui): clarify chat context details
  fix(telegram): keep polling watchdog active for wedged runner
2026-04-25 02:22:02 -07:00
Peter Steinberger
9056d4f708 feat: add crestodian local planner fallback 2026-04-25 10:20:02 +01:00
Val Alexander
388270ffce fix(control-ui): clarify chat context details
Summary:
- Show full date and time in Control UI chat message footers.
- Collapse assistant model/token/context metadata behind an explicit Context disclosure.
- Update changelog attribution guidance to allow multi-author credited entries.

Validation:
- OPENCLAW_LOCAL_CHECK=0 pnpm test ui/src/ui/chat/grouped-render.test.ts
- OPENCLAW_LOCAL_CHECK=0 pnpm test src/commands/gateway-status/helpers.test.ts
- OPENCLAW_LOCAL_CHECK=0 pnpm check:changed
- GitHub CI passed on f071a38177
2026-04-25 04:19:56 -05:00
Vincent Koc
c52c161f5a refactor(plugins): compact package json index metadata 2026-04-25 02:18:56 -07:00
Vincent Koc
c959c18fc7 fix(plugins): persist registry enabled snapshot 2026-04-25 02:18:56 -07:00
Vincent Koc
00f47f01fe refactor(plugins): trim persisted plugin registry state 2026-04-25 02:18:56 -07:00
Vincent Koc
3556f8441a feat(plugins): add plugin registry facade 2026-04-25 02:18:56 -07:00
Vincent Koc
36219b0ffc fix(plugins): invalidate index on policy changes 2026-04-25 02:18:56 -07:00
Vincent Koc
b001b8c947 feat(plugins): inspect persisted plugin index state 2026-04-25 02:18:55 -07:00
Vincent Koc
74a384d887 feat(plugins): persist installed plugin index snapshots 2026-04-25 02:18:55 -07:00
Vincent Koc
dfac36ee01 feat(plugins): add cold installed index owner APIs 2026-04-25 02:18:55 -07:00
Vincent Koc
ceace83556 fix(telegram): keep polling watchdog active for wedged runner 2026-04-25 02:18:49 -07:00
Peter Steinberger
f6a3b42cfa fix(browser): keep transient fetch errors retryable
Co-authored-by: jriff <jriff@users.noreply.github.com>
2026-04-25 10:09:15 +01:00
Peter Steinberger
2483d1dc12 fix(browser): drop redundant setuid sandbox flag
Co-authored-by: Sebastian Krueger <150018+sebykrueger@users.noreply.github.com>
2026-04-25 10:09:15 +01:00
Peter Steinberger
41ed7fa535 fix(browser): manage isolated downloads
Co-authored-by: Pearce Kieser <5055971+Pearcekieser@users.noreply.github.com>
2026-04-25 10:09:13 +01:00
Peter Steinberger
b756dfcb2b perf: speed up boundary and provider tests 2026-04-25 10:08:46 +01:00
Vincent Koc
c5e6f4bbc0 docs(agents): document sparse changed gate 2026-04-25 02:07:15 -07:00
Peter Steinberger
2377f1a4cd test(elevenlabs): cover eleven_v3 tts catalog 2026-04-25 10:06:42 +01:00
itsuzef
0fc68a5ed4 feat(elevenlabs): register eleven_v3 in TTS model allowlist
eleven_v3 already works end-to-end (model_id passes through to the API
without validation), but was missing from ELEVENLABS_TTS_MODELS so it
never appeared in the in-product model picker or catalog metadata.
2026-04-25 10:06:42 +01:00
hcl
fd74fc5a4f fix(heartbeat): clamp scheduler delay to Node setTimeout cap (#71414) (#71478)
* fix(heartbeat): clamp scheduler delay to Node setTimeout cap (#71414)

When `agents.defaults.heartbeat.every` resolves to >2_147_483_647 ms
(~24.85d), the previous scheduleNext() called setTimeout with the raw
delay. Node clamps any delay > 2^31-1 to 1 ms, fires the callback, and
the heartbeat re-arms with the same oversized value - a tight loop that
floods the log with TimeoutOverflowWarning and crashes the gateway with
exit code 1.

Clamp the computed delay to HEARTBEAT_MAX_TIMEOUT_MS (2_147_483_647)
before calling setTimeout. The worst case is now one heartbeat every
~24.85d instead of crash-loop. Warn once per process when clamping
fires, so a misconfigured "365d" remains visible without flooding.

This is a defense-in-depth fix at the scheduler layer; loadConfig-level
rejection is a broader change with more blast radius and a separate
question (some users may legitimately want "every: 365d" to mean
"effectively never"). The clamped behaviour is closer to that intent
than the crash is.

Test: new scheduler test sets heartbeat.every="365d" with fake timers,
advances 60s, and asserts runSpy was never called (with the bug, it
would be called ~60_000 times).

* style: format heartbeat scheduler clamp

* fix: share safe timeout delay clamp (#71478) (thanks @hclsys)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 10:03:43 +01:00
Vincent Koc
a33f7b7d05 fix(test): make changed typechecks sparse-safe 2026-04-25 02:02:57 -07:00
Peter Steinberger
ed0210a187 test: streamline slow import-heavy suites 2026-04-25 10:02:02 +01:00
Peter Steinberger
f7d276b842 perf: cache guard inventory checks 2026-04-25 10:02:02 +01:00
Peter Steinberger
70b3ba2fed test: speed up Docker live scheduling 2026-04-25 10:01:50 +01:00
Val Alexander
6bdf87de87 fix(ui): remove quick config API keys card
Remove the misleading API Keys card from the quick settings page.

The card was hardcoded to a fixed env-var provider list and routed all actions to the broad Environment config section, which made the Add/Change affordances look more precise than they were. This removes the dead surface and keeps the quick settings grid focused on meaningful controls.

Verified:
- pnpm test ui/src/ui/views/config-quick.test.ts
- CI passed on PR #71496
2026-04-25 04:00:53 -05:00
Chinar Amrutkar
bf34fde235 fix(telegram): remove offset confirmation getUpdates call
Remove the startup persisted-offset getUpdates preflight so polling restarts do not self-conflict before the grammY runner starts.\n\nFixes #69304.\n\nThanks @chinar-amrutkar.
2026-04-25 09:53:50 +01:00
Peter Steinberger
19017bad96 docs(browser): explain actionable aria snapshot refs 2026-04-25 09:51:34 +01:00
Peter Steinberger
ec8dbc4595 feat(tts): add xiaomi mimo speech provider 2026-04-25 09:48:05 +01:00
Peter Steinberger
e10f20032a fix(browser): resolve aria snapshot refs via DOM markers
Co-authored-by: MrKipler <mrkipler@kiphausen.com>
2026-04-25 09:44:31 +01:00
Behnam Shahbazi
207f0341e0 docs: use target flag in README message example 2026-04-25 01:44:21 -07:00
Vincent Koc
01bf61fcfd fix(media): remove express from media host (#71436)
* fix(media): remove express from media host

* fix(media): harden media host responses

* fix(msteams): stage express runtime dependency

* fix(browser): align profile facade exports

* fix(msteams): keep setup entry narrow

* fix(types): satisfy extension setup gates

* fix(msteams): use generic setup config type
2026-04-25 01:39:42 -07:00
Peter Steinberger
3169886a21 fix(telegram): guard duplicate polling leases 2026-04-25 09:38:51 +01:00
Vincent Koc
c88c2328c2 docs: align Node minimum requirement 2026-04-25 01:36:01 -07:00
Vincent Koc
ec1f72b6c5 fix(gateway): preserve restart drain for active runs
Fixes https://github.com/openclaw/openclaw/issues/65485
2026-04-25 01:35:47 -07:00
Vincent Koc
734748d4f4 fix(test): cap native worker pools for serial Vitest 2026-04-25 01:31:30 -07:00
Peter Steinberger
bc21f500d4 fix: align Codex Responses instructions payload 2026-04-25 09:30:34 +01:00
Peter Steinberger
bf0221c5b3 fix(plugins): preserve bundled cli metadata skip 2026-04-25 09:29:16 +01:00
Peter Steinberger
87e92c71a4 docs(release): require changelog rewrite from commits 2026-04-25 09:29:16 +01:00
Peter Steinberger
689a353621 fix(plugins): load packaged runtime mirrors from canonical sources 2026-04-25 09:29:16 +01:00
Peter Steinberger
8503935a21 test: speed up changed unit checks 2026-04-25 09:27:59 +01:00
Peter Steinberger
9ad14f3639 fix: restore msteams channel plugin api type 2026-04-25 09:27:59 +01:00
Vincent Koc
bf0d2d70be fix(session): clean up rollover resources 2026-04-25 01:27:16 -07:00
Peter Steinberger
b0c55eb659 fix(feishu): transcode voice TTS audio 2026-04-25 09:26:42 +01:00
Vincent Koc
bd32b1a906 feat(diagnostics): add outbound delivery lifecycle events
Add bounded outbound message delivery lifecycle diagnostics and OTEL export without message body, recipient, room, media path, or raw channel result data.
2026-04-25 01:26:34 -07:00
Peter Steinberger
9e149519fe fix: keep control ui bundle browser-safe 2026-04-25 09:22:49 +01:00
Peter Steinberger
65b607245a fix(browser): ignore handled route navigation races
Co-authored-by: Richard Steadman <198648604+Steady-ai@users.noreply.github.com>
2026-04-25 09:22:31 +01:00
Val Alexander
af56926e2f Polish markdown preview chrome
Polish the Control UI markdown preview chrome and sidebar raw-text behavior.

- Add the upgraded preview dialog/sidebar chrome and tighten related CSS coverage.
- Show workspace-relative paths in the markdown preview dialog instead of absolute filesystem paths.
- Preserve raw markdown source for idempotent raw-text toggles.
- Align browser plugin-sdk facade export parity for DEFAULT_BROWSER_ACTION_TIMEOUT_MS.
- Stabilize the gateway update channel test by waiting for the async update runner call.

Validation:
- OPENCLAW_LOCAL_CHECK=0 pnpm test ui/src/ui/views/agents.test.ts ui/src/ui/views/chat.test.ts src/plugins/contracts/plugin-sdk-subpaths.test.ts src/gateway/server.roles-allowlist-update.test.ts
- OPENCLAW_LOCAL_CHECK=0 pnpm check:changed
- GitHub checks green on ebbe96fc88
2026-04-25 03:16:54 -05:00
Peter Steinberger
0e9156d205 test: stabilize Docker CLI backend lane 2026-04-25 09:12:48 +01:00
Peter Steinberger
5ac36c9719 fix(browser): detect more Linux Chromium installs (#48563)
Co-authored-by: Catalin Lupuleti <105351510+lupuletic@users.noreply.github.com>
2026-04-25 09:12:09 +01:00
Vincent Koc
0da58302cf docs(changelog): restore co-credits I dropped on Diagnostics/OTEL and tool-result pruning entries
Three entries were missing co-credits I should have preserved:

- Diagnostics/OTEL exec-process spans (#71451): @vincentkoc implemented,
  but @jlapenna's #70424 proposed the broader tracing work this entry
  builds on. Now credits both.
- Diagnostics/OTEL preloaded SDK (#71450): same pattern — credits
  @vincentkoc and @jlapenna.
- Agents/tool-result pruning (#51267): @cgdusek's PR explicitly built
  on prior work in #39331 by @alvinttang and #34980 by @coffeexcoin.
  Now credits all three.
2026-04-25 01:11:47 -07:00
Vincent Koc
56fbd72171 docs(changelog): correct PR refs and credits in top Unreleased section
- Two Diagnostics/OTEL Changes entries credited issue #70424 (jlapenna's
  open meta-tracing proposal) as the PR ref. The actual implementing
  PRs landed as #71451 (exec-process telemetry) and #71450 (preloaded
  SDK mode), both authored by @vincentkoc — corrected.
- Telegram/webhook fix had no Thanks credit. Issue #71392 reporter
  @joelforsberg46-source identified the delivery-retry behaviour, so
  credit them on the entry.
2026-04-25 01:07:48 -07:00
Peter Steinberger
24e9924d6a docs: credit blank reply recovery 2026-04-25 09:02:23 +01:00
Sanjay Santhanam
1f06dbd04c fix(agent): recover blank streamed replies from final answer 2026-04-25 09:02:23 +01:00
Quratulain-bilal
bc2d53dacd test(browser): cover tilde edge cases for executablePath (#71439)
* test(browser): cover tilde edge cases for executablePath

Adds coverage for cases the original tilde-expansion fix in 95a2c9b
intentionally supports but does not assert:

- bare "~" expands to the home directory
- Windows-style "~\AppData\..." expands to $HOME on Windows
- a stray "~" mid-path (e.g. /opt/~chromium/chrome) is preserved verbatim,
  guarding the regex anchor against future regressions

No production code changes; tests only.

* test(browser): skip Windows-style ~\ tilde test on POSIX

path.resolve treats backslashes as literal characters on POSIX, so
"~\AppData\..." cannot resolve to "$HOME/AppData/..." on Linux/macOS.
Gate that case to win32 to keep the assertion meaningful.
2026-04-25 09:01:57 +01:00
Peter Steinberger
a4fc6c2409 test: speed up slow unit checks 2026-04-25 08:59:53 +01:00
Peter Steinberger
2011de69d3 feat: add Crestodian setup helper 2026-04-25 08:58:21 +01:00
Peter Steinberger
e0bee76fb0 fix: retire one-shot agent MCP runtimes 2026-04-25 08:58:02 +01:00
a410979729-sys
8fd15ed0e5 fix(github-copilot): preserve encrypted reasoning ids with encrypted_content (#71448)
Preserve encrypted Copilot Responses reasoning item IDs during replay and harden the live Copilot replay probe.

Thanks @a410979729-sys.
2026-04-25 08:57:47 +01:00
github-actions[bot]
10ed007fb4 chore(ui): refresh th control ui locale 2026-04-25 07:57:39 +00:00
github-actions[bot]
4714a134d2 chore(ui): refresh pl control ui locale 2026-04-25 07:57:31 +00:00
github-actions[bot]
fb3efcf659 chore(ui): refresh id control ui locale 2026-04-25 07:57:27 +00:00
github-actions[bot]
6b4d8924eb chore(ui): refresh uk control ui locale 2026-04-25 07:57:12 +00:00
github-actions[bot]
4ca173a41c chore(ui): refresh tr control ui locale 2026-04-25 07:57:04 +00:00
github-actions[bot]
3019163e2e chore(ui): refresh ja-JP control ui locale 2026-04-25 07:56:53 +00:00
github-actions[bot]
e699b184af chore(ui): refresh fr control ui locale 2026-04-25 07:56:49 +00:00
github-actions[bot]
390f0487e8 chore(ui): refresh ko control ui locale 2026-04-25 07:56:45 +00:00
github-actions[bot]
2536fec538 chore(ui): refresh es control ui locale 2026-04-25 07:56:35 +00:00
github-actions[bot]
02ea62917e chore(ui): refresh zh-CN control ui locale 2026-04-25 07:56:10 +00:00
github-actions[bot]
812bc2a441 chore(ui): refresh de control ui locale 2026-04-25 07:56:06 +00:00
github-actions[bot]
7b58ffde85 chore(ui): refresh pt-BR control ui locale 2026-04-25 07:56:05 +00:00
github-actions[bot]
9dc608f54b chore(ui): refresh zh-TW control ui locale 2026-04-25 07:56:01 +00:00
Vincent Koc
ebb08dc70e fix(ui): use current context usage in Control UI 2026-04-25 00:54:33 -07:00
Vincent Koc
73d72204a0 fix(tooling): harden changed checks for sparse worktrees 2026-04-25 00:51:34 -07:00
Peter Steinberger
1ca029e888 fix: clean up infer MCP runtimes 2026-04-25 08:49:27 +01:00
Peter Steinberger
2b2a300b35 fix: align browser profile facade exports 2026-04-25 08:46:13 +01:00
Peter Steinberger
0f4b6f81d9 fix: canonicalize Codex image base URLs 2026-04-25 08:45:41 +01:00
Peter Steinberger
5163a2fbf7 docs: document Talk MLX config 2026-04-25 08:42:27 +01:00
Peter Steinberger
eafb25afc1 docs(google-meet): document dry run exports 2026-04-25 08:42:06 +01:00
Peter Steinberger
d78cef1d71 feat(google-meet): add export dry run manifests 2026-04-25 08:42:06 +01:00
Peter Steinberger
4a80e61680 fix: reap MCP runtimes on config reload 2026-04-25 08:40:45 +01:00
Peter Steinberger
7251551960 docs(google-meet): document export manifests 2026-04-25 08:38:43 +01:00
Peter Steinberger
388e0eb605 feat(google-meet): add export manifests and tool parity 2026-04-25 08:38:43 +01:00
Vincent Koc
13f4657b88 test(plugins): cover install ledger reload indexing 2026-04-25 00:37:06 -07:00
Vincent Koc
8fd3f4cef2 test(plugins): lock installed index source contract 2026-04-25 00:37:06 -07:00
Vincent Koc
28eb56dd21 fix(plugins): index install ledger source facts 2026-04-25 00:37:05 -07:00
Vincent Koc
15d27d1527 feat(channels): read setup discovery from installed index 2026-04-25 00:37:05 -07:00
Vincent Koc
0b2bc8c5f6 feat(models): read provider owners from installed index 2026-04-25 00:37:05 -07:00
Vincent Koc
ea3e390346 feat(plugins): split cold provider contributions 2026-04-25 00:37:05 -07:00
Vincent Koc
fb4eec54a7 feat(plugins): add installed plugin index 2026-04-25 00:37:04 -07:00
Peter Steinberger
7a71a66571 perf: cache provider env var lookups 2026-04-25 08:35:57 +01:00
Peter Steinberger
e9b27ed2a6 perf: speed up auth choice tests 2026-04-25 08:31:40 +01:00
Peter Steinberger
5fe333ada8 docs(google-meet): update export workflow notes 2026-04-25 08:28:34 +01:00
Peter Steinberger
03484b74ab feat(google-meet): polish exports and calendar previews 2026-04-25 08:28:34 +01:00
Peter Steinberger
e0beea97aa perf: speed up focused tests 2026-04-25 08:26:28 +01:00
Peter Steinberger
7132ca5766 feat(browser): include safe tab urls in agent responses 2026-04-25 08:24:46 +01:00
Peter Steinberger
e8191e5b8f fix: ack Telegram webhooks before update handling 2026-04-25 08:23:03 +01:00
Peter Steinberger
a44800e929 fix(google-meet): preserve lazy cli import 2026-04-25 08:17:55 +01:00
Peter Steinberger
e1cf94f49a docs(google-meet): document export and calendar lookup 2026-04-25 08:17:54 +01:00
Peter Steinberger
d3595d7c3f feat(google-meet): add calendar export attendance workflows 2026-04-25 08:17:54 +01:00
Peter Steinberger
9577de2da7 docs: reference fixed MCP lifecycle reports 2026-04-25 08:15:16 +01:00
Vincent Koc
3e3bba4f30 feat(diagnostics): emit exec process telemetry (#71451) 2026-04-25 00:12:58 -07:00
Peter Steinberger
188bce424b perf: speed up google meet tests 2026-04-25 08:12:26 +01:00
wzp
845040214e fix: recover subagent waits after transport drops
Fix subagent recovery and session state reconciliation.

Thanks @ZiPengWei.
2026-04-25 08:12:20 +01:00
Peter Steinberger
5376a4a5d6 fix(browser): default act timeout budget
Co-authored-by: Andy Lin <andyylin@users.noreply.github.com>
2026-04-25 08:11:48 +01:00
Peter Steinberger
712f7b218c test: cover bundled MCP runtime cleanup gates 2026-04-25 08:10:34 +01:00
Vincent Koc
9895ecead3 fix(memory): keep llama runtime optional (#71425)
* fix(memory): keep llama runtime optional

* fix(memory): harden optional llama runtime guard
2026-04-25 00:09:12 -07:00
Peter Steinberger
4005a4f731 feat(google-meet): default artifacts to latest record 2026-04-25 08:07:48 +01:00
Peter Steinberger
459d277076 feat(google-meet): add latest conference command 2026-04-25 08:04:29 +01:00
Vincent Koc
dfa52aaab0 docs(changelog): clean up top Unreleased section formatting and dedupe
- Remove duplicate #66884 alexlomt entry from top Unreleased > Fixes;
  the canonical entry already lives under 2026.4.24 (Unreleased) per
  Mason Huang's earlier 'move #66884 entry to 2026.4.24' commit.
- Reflow the wrapped 3-line Tool Access bullet (#71405) onto a single
  line so it matches every other bullet in the section.
2026-04-25 00:00:02 -07:00
Vincent Koc
d8a70a7e49 docs(changelog): add missing entries for 3 external-contributor PRs
Three external-contributor commits from the last day landed without
CHANGELOG entries:

- Alex Fries (#68286, @ajfonthemove): hybrid memory search component
  scores. Added under Unreleased > Changes (feat).
- Charles Dusek (#51267, @cgdusek): malformed tool-result text-block
  guard. Added under Unreleased > Fixes.
- Jerome Benoit (#59935, @jerome-benoit): Nix Home Manager daemon PATH
  support. Added under Unreleased > Fixes.

Also drop a duplicate raw-subject changelog line for #66884 that
restated alexlomt's already-formatted entry one line above.
2026-04-24 23:56:46 -07:00
Ayaan Zaidi
8e40bdba90 fix(cli): scope dev reset to active profile 2026-04-25 12:25:45 +05:30
Vincent Koc
56eb1ffabf fix(diagnostics-otel): support preloaded sdk mode (#71450) 2026-04-24 23:55:34 -07:00
Peter Steinberger
417b1c5507 feat(google-meet): export artifacts reports 2026-04-25 07:53:31 +01:00
Peter Steinberger
bb5e278f63 fix(feishu): stabilize topic group session keys 2026-04-25 07:53:05 +01:00
Peter Steinberger
d068cb960d fix: stabilize qa lab memory and thinking scenarios 2026-04-25 07:50:04 +01:00
Peter Steinberger
b34ece705f fix: retire idle bundled MCP runtimes 2026-04-25 07:49:12 +01:00
Alex Fries
66e66f19c6 feat(memory-core): expose hybrid search component scores
Expose raw `vectorScore` and `textScore` alongside the combined hybrid memory search `score`.

- Preserve vector/text component scores from `mergeHybridResults` output.
- Add optional component-score fields to both memory host SDK type surfaces.
- Extend hybrid merge tests for vector-only, text-only, and overlapping result cases.
- Document that component scores remain raw retrieval diagnostics while temporal decay/MMR only adjust or reorder the combined ranking `score`.

Closes #68166.

Maintainer verification:
- `pnpm test extensions/memory-core/src/memory/hybrid.test.ts`
- `pnpm check:changed`
- Fresh GitHub checks passed.

Co-authored-by: Alex Fries <alex@engramlabs.io>
2026-04-25 01:46:03 -05:00
Peter Steinberger
a983ea61ac feat(google-meet): include transcript entries in artifacts 2026-04-25 07:43:49 +01:00
Ayaan Zaidi
356530598a docs(changelog): note restart continuation recovery (#70780) (thanks @fuller-stack-dev) 2026-04-25 12:12:52 +05:30
Ayaan Zaidi
a903df02f5 fix(gateway): bound restart continuation recovery 2026-04-25 12:12:52 +05:30
FullerStackDev
03addfe9ba fix(gateway): tighten session delivery recovery 2026-04-25 12:12:52 +05:30
FullerStackDev
2261550633 fix(gateway): address restart continuation review comments 2026-04-25 12:12:52 +05:30
FullerStackDev
0ac81d41b6 fix(gateway): durably hand off restart continuations 2026-04-25 12:12:52 +05:30
Vincent Koc
4df0e10623 fix(feishu): back off failed streaming card starts 2026-04-24 23:41:01 -07:00
Peter Steinberger
d37f165bee feat(google-meet): add oauth doctor 2026-04-25 07:40:25 +01:00
Peter Steinberger
2ff7eb36cf fix(models): expose codex runtime context caps 2026-04-25 07:38:31 +01:00
Vincent Koc
3d554aefdf fix(logging): keep log transport internals private (#71322)
* fix(logging): share transports across module instances

* fix(logging): share transports across module instances

* fix(logging): share transports across module instances

* fix(logging): remove global log transport hooks

* test(agents): capture diagnostic logs after module reset
2026-04-24 23:36:57 -07:00
Charles Dusek
6b38714cb9 fix(agents): guard malformed tool result text blocks
Harden context pruning and tool-result character estimation against malformed `{ type: "text" }` blocks created by void/undefined tool handler results.

- Require text blocks to carry a string before using `.length` in the tool-result estimator.
- Guard context-pruning text/image loops against malformed and null content entries.
- Serialize malformed non-string text blocks for pruning size accounting so they cannot bypass trimming as zero-sized.
- Add regression coverage for malformed text blocks, null entries, and non-string text payloads.

Closes #34979.

Maintainer verification:
- `pnpm test src/agents/pi-embedded-runner/tool-result-char-estimator.test.ts src/agents/pi-hooks/context-pruning/pruner.test.ts`
- `pnpm check:changed`
- GitHub checks passed, including the OpenAI / Opus 4.6 parity gate.

Based on prior work by #39331 and #34980.

Co-authored-by: Charles Dusek <cgdusek@gmail.com>
Co-authored-by: alvinttang <alvinttang@users.noreply.github.com>
Co-authored-by: coffeexcoin <coffeexcoin@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-25 01:36:40 -05:00
Peter Steinberger
1752b15a21 feat(google-meet): add artifacts and attendance commands 2026-04-25 07:36:10 +01:00
Peter Steinberger
209d50b52c feat(browser): add coordinate click action
Co-authored-by: Daniel Lutts <daniellutts@10-19-94-204.dynapool.wireless.nyu.edu>
2026-04-25 07:31:33 +01:00
Val Alexander
982230f460 Refine tool access controls (#71405)
* feat(ui): refine tool access controls

* fix(ui): tighten tool access scanning

* fix(ui): keep tool access toggles visible (#71405)

* test(daemon): cover launchd restart fallback plist reads (#71405)

* test(daemon): drop duplicate launchd read mock (#71405)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 07:22:53 +01:00
Vincent Koc
d7fae7a5e7 docs(changelog): note Feishu streaming dedupe fix (#71431) 2026-04-24 23:21:40 -07:00
Vincent Koc
b59ba1dc8e docs: cover new contextInjection 'never' mode and Nix daemon PATH support
Two recent code changes lacked or had only partial doc coverage:

- contextInjection 'never' (#65006, xDarkicex): the new mode is now
  documented under agents.defaults.contextInjection, alongside the
  existing 'continuation-skip' mode, with guidance on when to use it
  (custom context engines, native runtimes that own their prompt).
- Nix Home Manager daemon PATH (#44402, jerome.benoit): document the
  service PATH auto-discovery (NIX_PROFILES right-to-left precedence
  and ~/.nix-profile/bin fallback) under the Nix install page.

Also sentence-case three Title-Cased headings on the Nix page ('What
You Get', 'Quick Start', 'Nix Mode Runtime Behavior') and drop a
duplicate body H1 that restated the frontmatter title.
2026-04-24 23:19:06 -07:00
ToToKr
2aa313cd90 fix(feishu): prevent duplicate message after streaming card close (#67791) (#68491)
* fix(feishu): prevent duplicate message after streaming card close (#67791)

When onIdle closed the streaming card before the final delivery arrived, the streamed text was not tracked in deliveredFinalTexts. The subsequent final payload bypassed the streaming?.isActive() guard (already closed) and fell through to the non-streaming path, sending the same content as a redundant text/card message. Track raw streamText in deliveredFinalTexts when closeStreaming finalizes the card so the duplicate-final check catches it.

* test(feishu): cover idle streaming final dedupe

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-24 23:18:10 -07:00
Peter Steinberger
36eae5a2c7 fix: tighten silent cron exec notifications 2026-04-25 07:15:08 +01:00
Mark Goldenstein
bd60df3e53 fix: silence cron exec completion noise 2026-04-25 07:15:08 +01:00
Peter Steinberger
017252e4f8 test(daemon): remove duplicate launchd read mock 2026-04-25 07:12:17 +01:00
Jérôme Benoit
b8b270d5b8 fix(daemon): add Nix Home Manager PATH support
Add Nix Home Manager profile bin directories to generated gateway service PATHs on macOS and Linux.

Includes ~/.nix-profile/bin fallback when NIX_PROFILES is absent, honors NIX_PROFILES right-to-left precedence when present, and covers the service PATH resolver with focused unit tests.

Closes #44402.
2026-04-25 01:12:10 -05:00
Peter Steinberger
33d5ebbff7 test(daemon): read launchd fixture files 2026-04-25 07:11:33 +01:00
Peter Steinberger
2a96ea4d72 test(agents): cover committed delivery fallback 2026-04-25 07:11:33 +01:00
Peter Steinberger
07cf1dd65c test: remove duplicate launchd read mock 2026-04-25 07:10:32 +01:00
Peter Steinberger
85cab8b516 test: fix launchd restart mock state 2026-04-25 07:09:47 +01:00
Peter Steinberger
22aa402b64 test(daemon): mock launchd plist reads 2026-04-25 07:08:36 +01:00
Peter Steinberger
d957401c7e test(daemon): type launchd kickstart code fake 2026-04-25 07:08:36 +01:00
Peter Steinberger
a7c8a1ba0d fix(browser): finish existing-session attach port (#57245) 2026-04-25 07:08:36 +01:00
Peter Steinberger
998e09ee00 docs(changelog): note browser existing-session fixes (#57245) 2026-04-25 07:08:36 +01:00
Peter Steinberger
ad8737af2c fix(browser): tighten WS3 status probes
# Conflicts:
#	extensions/browser/src/browser/chrome-mcp.test.ts
#	extensions/browser/src/browser/chrome-mcp.ts
#	extensions/browser/src/browser/routes/basic.ts
2026-04-25 07:08:35 +01:00
Peter Steinberger
3c31facfa2 Fix sticky Chrome MCP status probes
# Conflicts:
#	extensions/browser/src/browser/chrome-mcp.ts
#	extensions/browser/src/browser/server-context.ts
2026-04-25 07:08:35 +01:00
Peter Steinberger
8e18b3cc20 fix(browser): report attach-only profile transport truthfully
# Conflicts:
#	extensions/browser/src/browser/routes/basic.ts
2026-04-25 07:08:35 +01:00
Peter Steinberger
0ff7aa5c3d fix(browser): retry stale cached playwright attach once
(cherry picked from commit ec252ebd7b45d54e431e0d7599532e5a0c1a9b73)

# Conflicts:
#	extensions/browser/src/browser/pw-session.ts
2026-04-25 07:08:35 +01:00
Peter Steinberger
d6a9165b9e test: stabilize gateway and TTS tests 2026-04-25 07:07:58 +01:00
Peter Steinberger
996ec2dd76 fix(agents): key fallback on committed delivery 2026-04-25 07:06:46 +01:00
Valentinws
4a68fa3962 fix(ui): keep tmp-dir resolver browser-import safe
Defers the Node fs.constants lookup until tmp-dir resolution actually runs, adds browser-shim import regression coverage, and records the fix in the changelog.\n\nLocal verification:\n- pnpm test src/infra/tmp-openclaw-dir.browser-import.test.ts src/infra/tmp-openclaw-dir.test.ts src/logging/logger.browser-import.test.ts\n- pnpm test src/infra/run-node.test.ts -t "serializes runtime postbuild restaging|forwards wrapper SIGTERM"\n- pnpm build\n\nCo-authored-by: Valentinws <Valentinws@users.noreply.github.com>
2026-04-25 07:02:10 +01:00
Vincent Koc
f5868ad1f8 fix(daemon): refresh launchd plist before restart bootstrap (#71421) 2026-04-24 22:59:21 -07:00
xDarkicex
cc0992564b fix: add contextInjection never mode (#65006) (thanks @xDarkicex) 2026-04-25 11:26:21 +05:30
Peter Steinberger
18ffa81564 fix(agents): suppress delivered messaging fallback 2026-04-25 06:55:47 +01:00
Vincent Koc
47a4124dc3 fix(daemon): tolerate loaded launchctl bootstrap (#71413) 2026-04-24 22:54:12 -07:00
Peter Steinberger
cfb551c709 test(openrouter): cover DeepSeek live cache hits 2026-04-25 06:49:08 +01:00
Peter Steinberger
2cd2732ab6 docs: document trusted CIDR node auto-approval 2026-04-25 06:46:26 +01:00
Peter Steinberger
537a8e25ed fix(signal): classify filename-only voice notes 2026-04-25 06:45:54 +01:00
Peter Steinberger
f44759073b feat(gateway): auto-approve trusted CIDR node pairing (#61004) (thanks @sahilsatralkar) 2026-04-25 06:40:25 +01:00
Sukhdeep
6c1d4414d9 fix(browser): dedupe concurrent lazy start (#61772) (#61772)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 06:39:14 +01:00
Peter Steinberger
d79b9e0af4 fix(openrouter): allow DeepSeek cache-ttl eligibility 2026-04-25 06:38:34 +01:00
Peter Steinberger
29f7a2f441 docs(cron): clarify isolated session context 2026-04-25 06:37:18 +01:00
Peter Steinberger
f2745aa03a refactor(cron): clarify ambient session context rollover 2026-04-25 06:37:18 +01:00
Ziy
eaf6d3c146 fix(dashboard): keep bearer token out of runtime logs
Avoid logging tokenized Control UI URLs or SSH hints while preserving clipboard/browser token handoff.\n\nThanks @Ziy1-Tan!
2026-04-25 06:36:11 +01:00
Peter Steinberger
c2a2a481b2 fix(whatsapp): preserve audio-as-voice payload intent 2026-04-25 06:35:57 +01:00
monsonego
80b6da72f5 test(ui): cover nested qualified chat model refs (#65340)
Adds regression coverage for provider-qualified nested model ids such as nvidia/deepseek-ai/deepseek-v3.2.

Validated:
- pnpm test ui/src/ui/chat-model-ref.test.ts ui/src/ui/chat-model-select-state.test.ts

Thanks @monsonego.
2026-04-25 06:32:47 +01:00
Peter Steinberger
0970fc5da7 ci: relax bundled channel fast smoke timeout 2026-04-25 06:31:39 +01:00
Mason Huang
d4ed19dafc chore(changelog): move #66884 entry to 2026.4.24 (#71410) 2026-04-25 13:31:33 +08:00
Peter Steinberger
5b59079fd4 fix(tts): preserve audio-only hook transcript 2026-04-25 06:28:54 +01:00
Vincent Koc
88ea3d839b docs: sentence-case Title Case table headers in Codex/runtime docs
Three table headers introduced in recent agent-runtime / Codex-harness
doc commits used Title Case despite the surrounding house style:

- agent-runtimes.md L17: 'What It Means' -> 'What it means'
- agent-runtimes.md L100: 'Why It Matters' -> 'Why it matters'
- codex-harness.md L615: 'V1 Boundary' / 'Future Path' ->
  'V1 boundary' / 'Future path' (V1 stays as the recognized acronym)
2026-04-24 22:27:10 -07:00
Vincent Koc
57f5b3b201 fix(daemon): harden launchd restart handoff (#71409) 2026-04-24 22:27:05 -07:00
Vincent Koc
44ad970e48 docs: replace generic 'this page covers' intros with direct openings
Four pages started with weak meta-descriptions ('This page covers...')
that restate the frontmatter summary. Replace with direct content-first
openings, and sentence-case a stray 'Slash Commands' link in
configuration-reference.
2026-04-24 22:25:03 -07:00
Vincent Koc
93346b00fb docs: drop redundant body H1s that duplicated frontmatter title
- concepts/streaming.md: remove '# Streaming + chunking'.
- reference/session-management-compaction.md: remove Title Case H1
  '# Session Management & Compaction (Deep Dive)'.
- plugins/voice-call.md: remove '# Voice Call (plugin)'.

CLI pages keep their command-formatted body H1s since that is the repo
convention and the formatting is not expressible in frontmatter.
2026-04-24 22:23:45 -07:00
Peter Steinberger
f9c268cf56 ci: keep fast fixture edits on narrow path 2026-04-25 06:22:57 +01:00
Peter Steinberger
576c6c240f fix(discord): collapse cron announce text 2026-04-25 06:22:30 +01:00
Vincent Koc
ee3c32c103 docs(plugins): clarify inspector package boundary 2026-04-24 22:21:53 -07:00
Sean Coley
a35333abe1 fix(browser): recover stale Chromium profile locks (#62935) (#62935)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 06:21:49 +01:00
Peter Steinberger
f00d65a304 test: align status scan compatibility fixture 2026-04-25 06:18:32 +01:00
Peter Steinberger
2f097c47f8 ci: route narrow ci changes through fast path 2026-04-25 06:18:32 +01:00
Vincent Koc
c948c63bbd docs: unify casing and replace path-as-text links across recent doc surfaces
Sweep recent (last ~5h) doc edits for two readability/uniformity issues:

- Replace 42 path-as-text links of the form '[/foo/bar](/foo/bar)' with
  descriptive labels derived from each target page's frontmatter title
  (e.g. '[Anthropic]', '[Token use and costs]', '[OpenAI-compatible
  endpoints]'). Affected files include gateway/troubleshooting,
  concepts/oauth, reference/session-management-compaction, and
  reference/transcript-hygiene.
- Sentence-case Title-Cased headings and link text in Related sections
  across codex-harness, model-providers, tools/plugin, sdk-runtime,
  sdk-setup, prompt-caching, ci, cli/config, google-meet, browser,
  rich-output-protocol, subagents, web/control-ui, while preserving
  brand and proper-noun capitalization (OpenAI, Codex, Chrome, Parallels,
  Z.AI, etc.).
2026-04-24 22:18:22 -07:00
Peter Steinberger
88ca1859ed fix(discord): use undici multipart form data (#71383) 2026-04-25 06:18:10 +01:00
Peter Steinberger
439f353cf6 fix(discord): bridge undici multipart types 2026-04-25 06:18:10 +01:00
TC500
52ebdabcfd fix(discord): use undici form data for multipart uploads 2026-04-25 06:18:10 +01:00
Peter Steinberger
1afbfdf451 fix(control-ui): preserve optimistic chat tail 2026-04-25 06:15:55 +01:00
Vincent Koc
86dc820560 feat(plugins): add compatibility registry 2026-04-24 22:15:41 -07:00
Vincent Koc
f0ceb4b68f fix(cron): isolate fresh cron session state
* fix(cron): isolate fresh cron session state

* fix(cron): deep-copy isolated session state

* fix(cron): reset isolated session context

* test(providers): avoid shared mock races

* test(providers): type injected stream fakes

* ci: refresh package boundary on reply runtime changes

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 22:15:19 -07:00
alexlomt
7a9584f0f9 fix(ci): harden release checks workflow inputs (#66884)
Merged via squash.

Prepared head SHA: d4e0097301
Co-authored-by: alexlomt <181166594+alexlomt@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-25 13:13:30 +08:00
Peter Steinberger
8acc92c881 feat(google): support Gemini TTS style profile 2026-04-25 06:11:23 +01:00
Peter Steinberger
3f63ba8fd8 fix(webchat): hide heartbeat history artifacts 2026-04-25 06:10:57 +01:00
Peter Steinberger
a2a49b430c test(plugins): route tts contract helper changes narrowly 2026-04-25 06:05:00 +01:00
Mason Huang
b79272baad CI: increase CodeQL JavaScript runner size (#71402)
* CI: increase CodeQL JavaScript runner size

* CI: trim CodeQL JavaScript scope further

* ci: keep CodeQL extension coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 13:04:48 +08:00
Peter Steinberger
104a8f3f52 test(browser): handle oom wrapper in chrome launch assertion 2026-04-25 06:02:03 +01:00
Peter Steinberger
fa22ca8883 test(qa): cover stale subagent child links 2026-04-25 05:59:42 +01:00
Peter Steinberger
7f6452897e fix(agents): repair strict provider tool replay 2026-04-25 05:56:13 +01:00
Peter Steinberger
e31aef7e19 fix(tts): migrate legacy edge config in doctor 2026-04-25 05:55:54 +01:00
Peter Steinberger
b0e834b2d9 fix(browser): support per-profile executable paths
Co-authored-by: nobrainer-tech <nobrainer-tech@users.noreply.github.com>
2026-04-25 05:50:20 +01:00
Peter Steinberger
759fe0bf95 docs: cover reply media and voice-call fixes 2026-04-25 05:48:29 +01:00
Peter Steinberger
938b53698e test(voice-call): cover tunnel startup 2026-04-25 05:43:42 +01:00
Peter Steinberger
2b87d9f3ec fix(voice-call): reject local webhook fallback 2026-04-25 05:41:29 +01:00
Peter Steinberger
2f39e6df59 fix(tts): prefer active speech provider lookup 2026-04-25 05:39:10 +01:00
Peter Steinberger
2033075570 fix(sessions): hide stale subagent child links 2026-04-25 05:39:10 +01:00
Peter Steinberger
c11730fd09 fix(tts): keep speech fallback discovery scoped 2026-04-25 05:38:45 +01:00
Peter Steinberger
b8239be46b fix(voice-call): settle cleared tts queue 2026-04-25 05:38:36 +01:00
Jamil Zakirov
52267a6b75 fix(auto-reply): run message_sending before inbound delivery
Run inbound auto-reply delivery through message_sending hooks before sending replies.

Co-authored-by: Jamil Zakirov <15848838+jzakirov@users.noreply.github.com>
2026-04-25 10:07:35 +05:30
Peter Steinberger
04c5bbf33d fix(reply): dedupe block-streamed media 2026-04-25 05:35:31 +01:00
Peter Steinberger
98a99765af fix(gateway): invoke plugin-backed catalog tools
Co-authored-by: chat2way <chat2way@users.noreply.github.com>
2026-04-25 05:28:03 +01:00
Peter Steinberger
6602092a40 fix(browser): require admin scope for browser request
Co-authored-by: RichardCao <RichardCao@users.noreply.github.com>
2026-04-25 05:27:20 +01:00
Peter Steinberger
b84e57fca3 fix(tts): use resolved config for tool synthesis 2026-04-25 05:18:49 +01:00
Peter Steinberger
c2139635ff fix: format acpx doctor details safely 2026-04-25 05:15:00 +01:00
Peter Steinberger
757aee4cdd fix(subagents): retire stale unended runs
Co-authored-by: HCL <chenglunhu@gmail.com>
2026-04-25 05:14:41 +01:00
Peter Steinberger
97fd45a8c1 fix: honor acp allowed agents for acpx probe 2026-04-25 05:10:49 +01:00
Peter Steinberger
14eab13ab4 fix(agents): keep voice media with no-reply sentinel 2026-04-25 05:09:58 +01:00
Peter Steinberger
85db7af8d9 test: cover opencode-go image default pairing 2026-04-25 05:06:17 +01:00
Peter Steinberger
fa976e5b93 feat: update opencode-go default model
Co-authored-by: masrlinu <5259918+masrlinu@users.noreply.github.com>
2026-04-25 05:03:32 +01:00
Ted Li
8cc38c1b86 fix: stop session lock failover (#68700) (thanks @MonkeyLeeT)
* fix(agents): stop treating session lock waits as timeout

* fix(agents): ignore abort-wrapped session lock waits

* fix(agents): keep explicit failover metadata authoritative

* fix(agents): respect inferred failover metadata

* fix(agents): ignore generic abort codes for lock waits

* fix(agents): suppress cause-based lock wait fallback

* fix(agents): type session lock timeout errors

* fix: stop session lock failover (#68700) (thanks @MonkeyLeeT)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-25 09:33:19 +05:30
Peter Steinberger
c03e5b3c3a docs(tts): clarify legacy provider migration 2026-04-25 05:01:09 +01:00
Michiel van den Donker
2c716f5677 fix: enforce memory search session visibility (#70761) (thanks @nefainl)
* [EV-001] memory-core: filter memory_search session hits by visibility

- Move session visibility + listSpawnedSessionKeys to plugin-sdk; sync test
  hook with sessions-resolution __testing.setDepsForTest
- Extract loadCombinedSessionStoreForGateway to config/sessions; re-export
  from gateway session-utils
- Add session-transcript-hit stem resolver for builtin + QMD paths
- Post-filter memory_search results before citations/recall; fail closed when
  requester session key missing; optional corpus=sessions
- Tests: stem extraction, visibility filter smoke, existing suites green

* chore: sync plugin-sdk exports for session-transcript-hit and session-visibility

Run pnpm plugin-sdk:sync-exports so package.json exports match
scripts/lib/plugin-sdk-entrypoints.json. Fixes contract tests and
lint:plugins:plugin-sdk-subpaths-exported for memory-core imports.

* fix(EV-001): cross-agent session memory hits + hoist combined store load

- resolveTranscriptStemToSessionKeys: stop filtering by requester agentId so
  keys from other agents reach createSessionVisibilityGuard (a2a + visibility=all).
- Re-export loadCombinedSessionStoreForGateway from session-transcript-hit;
  filterMemorySearchHitsBySessionVisibility loads the combined store once per pass.
- Drop unused agentId from filter params; extend tests (Greptile/Codex review).

* fix(memory_search): honor corpus=sessions before maxResults cap

Pass sources into MemoryIndexManager.search so FTS/vector queries add
source IN (...) before ranking and top-N slice (Codex: non-session hits
could fill the window).

QMD path: oversample fetch limit for single-source recall, filter by
source, then diversify/clamp to the requested maxResults.

Wire corpus=sessions from tools; extend MemorySearchManager opts and
wrappers.

* fix(memory_search): apply corpus=memory source filter like sessions

Pass sources: ["memory"] into manager.search so maxResults applies only
within the memory index; post-filter for defense in depth. Document
corpus=memory in the tool description.

* fix: scope qmd session memory search

* fix: enforce memory search session visibility (#70761) (thanks @nefainl)

---------

Co-authored-by: NefAI <info@nefai.nl>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-25 09:30:21 +05:30
Peter Steinberger
978a50a3c5 fix(minimax): normalize tts pitch for api 2026-04-25 04:58:20 +01:00
Peter Steinberger
5d724863bb test: show live Docker profile mount 2026-04-25 04:57:20 +01:00
Peter Steinberger
b9da7cbf01 test: strip live gateway reasoning wrappers 2026-04-25 04:57:20 +01:00
Peter Steinberger
0f0c855a8b fix(google-meet): surface browser create manual actions 2026-04-25 04:57:06 +01:00
Peter Steinberger
70fd1c91aa fix(channels): harden tool progress previews 2026-04-25 04:54:29 +01:00
Peter Steinberger
da89108b82 docs(minimax): document tts env vars 2026-04-25 04:53:33 +01:00
Peter Steinberger
225ff9a866 fix(minimax): transcode voice-note tts to opus 2026-04-25 04:52:25 +01:00
Ayaan Zaidi
f3cc74ec5d fix: include exec completion payloads (#71213) (thanks @GodsBoy) 2026-04-25 09:21:29 +05:30
Ayaan Zaidi
a8f9e29e1a fix(heartbeat): classify untrusted exec completions 2026-04-25 09:21:29 +05:30
GodsBoy
724692bb8c chore(ci): refresh raw fetch allowlist 2026-04-25 09:21:29 +05:30
GodsBoy
349749f73d fix(heartbeat): include exec completion payloads 2026-04-25 09:21:29 +05:30
Peter Steinberger
7e52223d32 fix: register opencode image understanding 2026-04-25 04:50:01 +01:00
Ayaan Zaidi
398496c45b test(config): cover agent context token validation 2026-04-25 09:17:47 +05:30
statxc
ed03d91ae0 fix(config): allow per-agent contextTokens override in agents.list 2026-04-25 09:17:47 +05:30
Peter Steinberger
391289564c fix(media): validate managed reply media aliases 2026-04-25 04:47:25 +01:00
Peter Steinberger
a31374f097 fix: allow managed media from sandbox replies 2026-04-25 04:39:11 +01:00
Peter Steinberger
7875092f4d feat(openrouter): add tts provider 2026-04-25 04:36:49 +01:00
Peter Steinberger
c7f18a6b9d test(agents): cover Gemini incomplete-turn guard 2026-04-25 04:35:53 +01:00
Peter Steinberger
6f72b74cec fix: strip opencode image reasoning none 2026-04-25 04:35:12 +01:00
Peter Steinberger
96515891a2 fix: keep agent json stdout clean 2026-04-25 04:32:18 +01:00
Peter Steinberger
b0709a894d test(deepseek): cover V4 replay live 2026-04-25 04:30:38 +01:00
pashpashpash
6cfe810402 Refresh the Codex runtime docs
Refresh the Codex runtime docs and cross-link the Codex harness, OpenAI provider, agent runtime, plugin hook, ACP agent, and status pages.
2026-04-24 20:30:33 -07:00
Peter Steinberger
05fbdd4b28 fix: handle missing tailscale binary 2026-04-25 04:28:32 +01:00
Peter Steinberger
678ed5d512 fix(deepseek): normalize V4 tool-call replay 2026-04-25 04:25:44 +01:00
Peter Steinberger
c81b3ab6b9 fix(minimax): mark tts output voice-compatible 2026-04-25 04:25:12 +01:00
Ayaan Zaidi
de07739e40 docs: update changelog for gateway status perf 2026-04-25 08:52:52 +05:30
Ayaan Zaidi
2bf2fd6c3d fix(cli): preserve gateway status rpc probe semantics 2026-04-25 08:52:52 +05:30
Andy Lin
43beceaee7 perf(cli): trim gateway status startup work 2026-04-25 08:52:52 +05:30
Peter Steinberger
cc0f3e0e40 docs: add changelog for Gemini incomplete-turn recovery (#71362) 2026-04-25 04:21:35 +01:00
Neerav Makwana
0ec3b79c07 refactor: reuse model-id prefix helper for Gemini guard 2026-04-25 04:21:35 +01:00
Neerav Makwana
0ce93c9f1a fix: enable incomplete-turn recovery for Gemini 2026-04-25 04:21:35 +01:00
Peter Steinberger
73a6a2a6ab fix(tts): merge allowlisted speech providers 2026-04-25 04:20:04 +01:00
Peter Steinberger
cf07f01d0d docs(plugin-sdk): document browser tab cleanup config type 2026-04-25 04:19:50 +01:00
Peter Steinberger
5699209d00 fix: match bare exec allowlist commands
Co-authored-by: Kengwei Lu <kengwei@kvvlu.com>
Co-authored-by: ZC <chenzhangcode@163.com>
Co-authored-by: dengluozhang <275862143+dengluozhang@users.noreply.github.com>
2026-04-25 04:18:24 +01:00
Peter Steinberger
cb9c927ca6 docs: document config recovery policy 2026-04-25 04:18:24 +01:00
Peter Steinberger
0764f86e18 test(memory): keep embedding provider selection isolated 2026-04-25 04:17:27 +01:00
Peter Steinberger
8b31ba93b5 fix(plugin-sdk): align browser profile facade exports 2026-04-25 04:17:27 +01:00
Peter Steinberger
f1154fc5ed docs: note codex elicitation approval sanitization (#71343) (thanks @Lucenx9) 2026-04-25 04:17:27 +01:00
Lucenx9
e098a439c4 fix(codex): sanitize elicitation approval text 2026-04-25 04:17:27 +01:00
Peter Steinberger
972d8fc1cf fix(agents): keep reply tool snapshots aligned 2026-04-25 04:15:47 +01:00
Peter Steinberger
b13545355d fix(tts): parse bare tags and ignore code examples 2026-04-25 04:13:12 +01:00
Peter Steinberger
a126a9013d feat(plugins): expose nodes runtime to cli commands 2026-04-25 04:12:50 +01:00
Peter Steinberger
3731a7c8f2 fix(macos): retry talk tts via gateway 2026-04-25 04:09:43 +01:00
Peter Steinberger
9a0b26cafc test: cover config recovery policy edges 2026-04-25 04:06:35 +01:00
Josh Lehman
f369939fed fix: avoid plugin-local config recovery rollback (#71289) 2026-04-25 04:06:35 +01:00
Shakker
306c0f73bf feat: add manifest model catalog planner (#71368) (thanks @shakkernerd) 2026-04-25 04:05:30 +01:00
Shakker
b6c24e5322 fix: report model catalog manifest conflicts 2026-04-25 04:05:30 +01:00
Shakker
9e190f1f6a test: cover manifest model catalog planner 2026-04-25 04:05:30 +01:00
Shakker
dabdc779be feat: add manifest model catalog planner 2026-04-25 04:05:30 +01:00
Peter Steinberger
7920f8d4fd fix(compaction): honor manual keepRecentTokens 2026-04-25 04:03:09 +01:00
Peter Steinberger
92b17af817 fix(tts): honor legacy edge voice config 2026-04-25 04:02:17 +01:00
Peter Steinberger
5569d6d9d3 fix: accept singular tool_call finish reason 2026-04-25 04:00:03 +01:00
Shakker
8a14328c69 fix: normalize manifest catalog provider ids 2026-04-25 03:58:44 +01:00
Peter Steinberger
455e84f776 fix(voice-call): start listening after telnyx greetings 2026-04-25 03:57:47 +01:00
Peter Steinberger
344ee3782d fix(google-meet): guide timeout recovery 2026-04-25 03:57:26 +01:00
Peter Steinberger
37c2450124 fix: support draft 2020 mcp tool schemas 2026-04-25 03:56:35 +01:00
Peter Steinberger
9fbfedf12a fix: skip invalid completions stream chunks 2026-04-25 03:55:21 +01:00
Peter Steinberger
5381625f45 fix(voice-call): terminate expired restored calls 2026-04-25 03:55:01 +01:00
Peter Steinberger
fe930b987e fix(plugin-sdk): align browser tab cleanup type exports 2026-04-25 03:53:21 +01:00
Peter Steinberger
250acdd2a2 test(voice-call): cover cloudflare twilio signatures 2026-04-25 03:52:31 +01:00
Peter Steinberger
355c92d69b fix(sessions): honor load-time maintenance config 2026-04-25 03:52:25 +01:00
Peter Steinberger
26f06afb90 fix: forward completions prompt cache keys 2026-04-25 03:51:51 +01:00
Peter Steinberger
24fdfdba6e test: disable Docker CLI image probe by default 2026-04-25 03:51:41 +01:00
Peter Steinberger
a669ba7df1 fix(voice-call): reap stale pre-answer calls 2026-04-25 03:50:27 +01:00
Peter Steinberger
a98a0b94d1 fix: isolate browser proxy routing
Co-authored-by: Sanjays2402 <Sanjays2402@users.noreply.github.com>
2026-04-25 03:49:06 +01:00
Peter Steinberger
9e5d09c962 fix(config): reject legacy secretref env markers 2026-04-25 03:48:11 +01:00
Peter Steinberger
7dc005fab6 fix(voice-call): honor telephony tts timeout 2026-04-25 03:47:56 +01:00
Peter Steinberger
e5babbb5e7 test: cover openai-compatible usage chunks 2026-04-25 03:45:16 +01:00
Ada
413e407fb8 fix(whatsapp): deliver tool replies that include media (#60968)
Merged via squash.

Prepared head SHA: 26704020a4
Co-authored-by: adaclaw <266167987+adaclaw@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-24 23:44:59 -03:00
Peter Steinberger
8f11e5ad18 fix(voice-call): scope sandbox session to agent 2026-04-25 03:43:01 +01:00
Peter Steinberger
460720d0a1 perf(feishu): avoid unconditional lifecycle waits 2026-04-25 03:41:18 +01:00
Peter Steinberger
a6d16a2153 perf(plugins): skip registry expansion for explicit document extractor allowlists 2026-04-25 03:41:18 +01:00
Peter Steinberger
28de3e1e5c perf(test): isolate core test hotspots 2026-04-25 03:41:17 +01:00
Peter Steinberger
c150110e02 test(voice-call): cover inbound transcript response handoff 2026-04-25 03:39:07 +01:00
Peter Steinberger
893c1d61ee fix: honor sandbox browser SSRF policy 2026-04-25 03:37:08 +01:00
Peter Steinberger
1906dc01bf fix(elevenlabs): omit mp3 accept for pcm tts 2026-04-25 03:36:54 +01:00
Peter Steinberger
7d5a7c4343 test(openai): preserve zero realtime transcription vad config 2026-04-25 03:34:41 +01:00
Shakker
55d3e7bc47 refactor: centralize model catalog normalization (#71360) (thanks @shakkernerd) 2026-04-25 03:34:36 +01:00
Shakker
c0bda91641 refactor: use shared model catalog normalization in manifests 2026-04-25 03:34:36 +01:00
Shakker
31f4991205 test: cover model catalog normalization 2026-04-25 03:34:36 +01:00
Shakker
b9da940813 feat: add model catalog normalizer 2026-04-25 03:34:36 +01:00
Shakker
efcd96a8eb feat: add model catalog shared types 2026-04-25 03:34:36 +01:00
Peter Steinberger
9a3dece879 fix(voice-call): allow dedicated response agent 2026-04-25 03:32:09 +01:00
Peter Steinberger
e442065970 feat(google-meet): add browser recovery diagnostics 2026-04-25 03:31:11 +01:00
Peter Steinberger
996e9226e5 fix(skills): restore legacy skill metadata fallback (#71346) 2026-04-25 03:30:51 +01:00
chen-zhang-cs-code
bb5f523068 fix(skills): honor legacy clawdbot metadata 2026-04-25 03:30:51 +01:00
Peter Steinberger
49f72b332f fix: harden openai-compatible completions payloads 2026-04-25 03:29:26 +01:00
Peter Steinberger
4302f6ea20 docs: credit codex bound-turn fix (#71317) 2026-04-25 03:29:14 +01:00
Lucenx9
cc87c9b120 fix(codex): reject unscoped bound turn events 2026-04-25 03:29:14 +01:00
Peter Steinberger
f7caf83da4 fix(voice-call): coalesce webhook server starts 2026-04-25 03:27:33 +01:00
Gustavo Madeira Santana
53618cca0d docs: clarify plugin discovery loading 2026-04-24 22:26:52 -04:00
Peter Steinberger
1bdf5307d9 refactor(discord): split outbound payload helpers 2026-04-25 03:24:42 +01:00
Peter Steinberger
30aa7e0d4d fix: harden Windows browser open 2026-04-25 03:24:00 +01:00
Peter Steinberger
31d8fdb525 fix(voice-call): answer telnyx inbound calls 2026-04-25 03:23:45 +01:00
Gustavo Madeira Santana
282c32db7c fix(cli): sanitize plugin command descriptors 2026-04-24 22:23:28 -04:00
Peter Steinberger
4da25d0125 fix: keep session store live during rotation 2026-04-25 03:21:49 +01:00
Peter Steinberger
f29e15c05d fix(telegram): bound tool progress preview formatting
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
2026-04-25 03:19:01 +01:00
Neerav Makwana
e54a37a91e fix(telegram): harden progress preview rendering 2026-04-25 03:19:01 +01:00
Neerav Makwana
c4a8b80dfa fix(telegram): hide tool progress by default 2026-04-25 03:19:01 +01:00
Peter Steinberger
95a2c9bcdc fix: expand browser executable home paths 2026-04-25 03:16:14 +01:00
Peter Steinberger
4a7ddd7ff5 test(agents): slim embedded runner hotspot coverage 2026-04-25 03:15:23 +01:00
Vincent Koc
f9ac92d1cc fix(deps): keep plugin ownership records live (#71331) 2026-04-24 19:15:12 -07:00
Peter Steinberger
f550aa7622 refactor(outbound): plan text and media sends 2026-04-25 03:12:59 +01:00
Peter Steinberger
a3862ffdf1 feat(voice-call): add setup smoke checks 2026-04-25 03:12:21 +01:00
Peter Steinberger
f9f7d6ffb5 fix(google-meet): reuse meet tabs across retries 2026-04-25 03:11:58 +01:00
Peter Steinberger
ba4cd90dbc fix(voice-call): share webhook runtime across contexts 2026-04-25 03:11:21 +01:00
Peter Steinberger
250d13de53 fix(agents): trust-gate tts transcript suppression
Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
2026-04-25 03:11:17 +01:00
Neerav Makwana
628f0e8055 fix: gate tts output suppression on deliverable media 2026-04-25 03:11:17 +01:00
Neerav Makwana
db8f7478b4 fix: suppress tts transcript tool output 2026-04-25 03:11:17 +01:00
Gustavo Madeira Santana
6abab7555e test(plugins): align loader channel entry fixture 2026-04-24 22:10:58 -04:00
Peter Steinberger
713807b55d fix: harden openai auth and reasoning replay 2026-04-25 03:10:24 +01:00
Peter Steinberger
ae5c657367 fix: clean up idle browser tabs 2026-04-25 03:08:24 +01:00
Peter Steinberger
d99d9eda37 fix: honor media SSRF policy for PDF inputs (#71321) 2026-04-25 03:08:19 +01:00
Neerav Makwana
f9cb942aa9 fix(music): bound reference image fetches 2026-04-25 03:08:19 +01:00
Neerav Makwana
1bb5a96577 fix(media): cover generation reference media ssrf policy 2026-04-25 03:08:19 +01:00
Neerav Makwana
86556fcd47 fix(media): apply web fetch ssrf policy to media 2026-04-25 03:08:19 +01:00
Gustavo Madeira Santana
a5db42862d fix(plugins): expose channel CLI metadata in discovery (#71309)
Merged via squash.

Prepared head SHA: ce6bb35812
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-24 22:06:57 -04:00
Peter Steinberger
7ef4ecf499 refactor(outbound): share reply fanout policy 2026-04-25 03:05:22 +01:00
Peter Steinberger
2f23511ffa test: accept staged bundled runtime deps proof 2026-04-25 03:05:04 +01:00
Peter Steinberger
a5ab488691 fix(voice-call): pin response model sessions 2026-04-25 03:02:30 +01:00
Mason Huang
5d4931cc3f CI: trim CodeQL JavaScript scope (#71347) 2026-04-25 09:57:12 +08:00
Peter Steinberger
5e640b93da fix(discord): preserve outbound reply threading 2026-04-25 02:54:37 +01:00
Shakker
6d271762ab feat: add modelCatalog manifest contract (#71342) (thanks @shakkernerd) 2026-04-25 02:54:32 +01:00
Shakker
1f4dab2c37 fix: tighten model catalog manifest normalization 2026-04-25 02:54:32 +01:00
Shakker
a5d46c4567 fix: require complete model catalog pricing tiers 2026-04-25 02:54:32 +01:00
Shakker
8fa1052838 fix: tighten model catalog manifest validation 2026-04-25 02:54:32 +01:00
Shakker
d39e89e6b0 docs: document model catalog manifest metadata 2026-04-25 02:54:32 +01:00
Shakker
5e715de6c5 test: preserve model catalog manifest metadata 2026-04-25 02:54:32 +01:00
Shakker
61fcbe7dce feat: add model catalog manifest contract 2026-04-25 02:54:32 +01:00
Gustavo Madeira Santana
fd65caf4b0 chore: tighten changelog unreleased detection 2026-04-24 21:52:00 -04:00
Peter Steinberger
2a0a76f876 fix(browser): extend existing-session manage timeouts 2026-04-25 02:50:36 +01:00
Peter Steinberger
2ec70e6770 fix(browser): recover stale chrome mcp sessions 2026-04-25 02:50:11 +01:00
Luka Dolenc
325e5e921f fix: preserve thread-bound subagent completion fallback
Preserve the requester-agent announce path for thread-bound subagent completions, while falling back to direct thread delivery only when the announce fails or produces no visible output.\n\nThanks @DolencLuka.
2026-04-25 02:49:50 +01:00
Peter Steinberger
5865197ec1 test: relax bundled channel Docker readiness 2026-04-25 02:48:02 +01:00
Peter Steinberger
1eef6df5f5 test(auto-reply): reset inbound dedupe for acp abort 2026-04-25 02:47:52 +01:00
Peter Steinberger
69c258f9dc test(auto-reply): keep hook runner mock aligned 2026-04-25 02:47:52 +01:00
Peter Steinberger
f70e439699 fix(amazon-bedrock): skip auto memory embeddings without credentials (#71245)
Co-authored-by: bitloi <raphaelaloi.eth@gmail.com>
2026-04-25 02:47:52 +01:00
pashpashpash
42ec7a868f Document agent runtimes and the Codex v1 contract (#71270)
* Document agent runtimes and Codex v1 contract

* Document agent runtimes and Codex v1 contract

* Clarify Codex runtime fallback docs

* Clarify runtime and harness terminology
2026-04-25 10:46:24 +09:00
Peter Steinberger
0970507078 test(auto-reply): allow ACP abort dispatch in regression test 2026-04-25 02:45:07 +01:00
Peter Steinberger
56de930628 fix: honor codex approval decisions (#71338) (thanks @Lucenx9) 2026-04-25 02:44:55 +01:00
Lucenx9
453789914b fix(codex): respect command approval decisions 2026-04-25 02:44:55 +01:00
Peter Steinberger
d4a9b28d0c test: add agents delete Docker smoke 2026-04-25 02:43:11 +01:00
Peter Steinberger
32dd1ffc5a refactor(approvals): unify structured path display 2026-04-25 02:41:24 +01:00
Peter Steinberger
52ea8eadcb fix(codex): normalize compacted Windows permission paths 2026-04-25 02:40:57 +01:00
Peter Steinberger
e68b2269b9 test(telegram): avoid current marker in model display regression (#71016) (thanks @iskim77) 2026-04-25 02:38:14 +01:00
Peter Steinberger
a9c46d5b1a test(telegram): cover model picker display names (#71016) (thanks @iskim77) 2026-04-25 02:38:14 +01:00
Atlas Bot
d1386ada5a fix(telegram): pass modelNames to buildModelsKeyboard in button-click callback
When navigating the /models picker via provider button click, the model
list showed raw model IDs (e.g. gemini-3.1-pro-preview) instead of
configured display names (e.g. Gemini 3.1 Pro (Bridge)).

Root cause: the button-click callback handler destructured modelData as
{ byProvider, providers } omitting modelNames, then called
buildModelsKeyboard() without it. buildModelsKeyboard falls back to the
raw model ID via modelNames?.get(...) ?? model when modelNames is absent.

The text-command path (/models <provider>) already passes modelNames
correctly through buildTelegramModelsListChannelData, confirming the fix.

Fix: destructure modelNames from modelData and forward it to
buildModelsKeyboard in the button-click callback handler.

Closes #70560
2026-04-25 02:38:14 +01:00
Val Alexander
ead8be96fd Add tweakcn custom theme import
Adds a browser-local custom tweakcn theme slot while preserving the existing built-in themes.

Includes:
- tweakcn share-link import, validation, persistence, and custom theme rendering
- Custom option in Appearance and Quick Settings
- responsive/config toolbar and chat tool-card polish from follow-up review
- security hardening for bounded fetches, CSS token validation, redirect handling, and fail-closed unreadable payloads

Verification:
- OPENCLAW_LOCAL_CHECK=0 pnpm check:changed
- GitHub CI clean on 6ff13a1b33
2026-04-24 20:36:45 -05:00
Peter Steinberger
835c4e053c test: stabilize Docker live service lanes 2026-04-25 02:33:10 +01:00
Peter Steinberger
3a7ee209c9 fix: harden browser screenshot timeouts 2026-04-25 02:32:29 +01:00
Peter Steinberger
41f9768cd8 fix: preserve context engine safeguard compaction 2026-04-25 02:30:41 +01:00
Peter Steinberger
a9a308becd fix: recover restart-aborted main sessions 2026-04-25 02:25:54 +01:00
Peter Steinberger
50d3bd638a docs(changelog): note codex permission path compaction 2026-04-25 02:24:31 +01:00
Peter Steinberger
f86f8400f5 fix(codex): compact home permission paths 2026-04-25 02:24:00 +01:00
Peter Steinberger
0d3a5c3101 fix(codex): preserve approval permission paths 2026-04-25 02:24:00 +01:00
edge_kase
2cacd2097b fix: retain shared agent workspaces (#70897)
Fixes #70889 and #70890.

Retains overlapping/shared agent workspaces during `openclaw agents delete`, keeps `--json` output machine-readable, and repairs the stale hook-runner test harness mock that blocked CI.

Thanks @kaseonedge.
2026-04-25 02:22:06 +01:00
Peter Steinberger
52cc1ebac7 fix(google-meet): surface chrome node readiness in setup 2026-04-25 02:18:08 +01:00
Peter Steinberger
d9bd010e5e test: cover codex harness session history pinning 2026-04-25 02:15:33 +01:00
Vincent Koc
0bd8d0bba0 fix(plugins): remove Pi tool result compat 2026-04-24 18:13:35 -07:00
Roger Deng
ea168c22ce WhatsApp: add preflight audio transcription for DM voice notes (#64120)
Merged via squash.

Prepared head SHA: 7480b339da
Co-authored-by: rogerdigital <13251150+rogerdigital@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-24 22:13:25 -03:00
Peter Steinberger
c018e73475 docs: document google adaptive thinking 2026-04-25 02:10:49 +01:00
Peter Steinberger
e2ade56952 test(deepseek): cover v4 reasoning replay payload 2026-04-25 02:09:51 +01:00
Peter Steinberger
8262735354 fix(plugins): harden runtime dependency repair 2026-04-25 02:07:19 +01:00
Peter Steinberger
cc0f3067a0 fix: map google adaptive thinking dynamically 2026-04-25 02:04:40 +01:00
Vincent Koc
f3330f5db6 docs(changelog): backfill 91 author credits and dedupe duplicate Thanks lines
- Expand author->handle map with maintainers from docs/CONTRIBUTING.md
  (Robin Waslander/@hydro13, Josh Lehman/@jalehman, Radek/@velvet-shark,
  Muhammed/@mukhtharcm, Tengji/@odysseus0, Sliverp, Mason Huang/@hxy91819)
  and PR-author lookups via gh for two dozen one-off contributors.
- Strip duplicate trailing 'Thanks @x' lines that prior backfill chunks
  had introduced when an existing lowercase 'thanks @y' credit was already
  present (case-sensitive skip check missed them); preserve the original
  contributor credit.
- Dedupe doubled '(#NNNN)' tokens introduced by the same bug.
2026-04-24 18:04:06 -07:00
Peter Steinberger
019ef71fe8 docs: require source-backed maintainer answers 2026-04-25 02:02:22 +01:00
Peter Steinberger
9ca1f1a64e fix(plugins): refresh gateway hooks before inbound dispatch 2026-04-25 02:01:48 +01:00
Peter Steinberger
fde4bf7fc1 docs: document packaged runtime dependency staging 2026-04-25 01:59:13 +01:00
Peter Steinberger
d42b0e043c fix: stage packaged bundled runtime deps externally 2026-04-25 01:58:44 +01:00
Vincent Koc
2d2402cee8 test(plugins): assert legacy channel schema exports 2026-04-24 17:58:04 -07:00
Vincent Koc
3a14a95085 fix(plugins): harden manifest channel metadata 2026-04-24 17:58:04 -07:00
Matt Van Horn
b33eb93aac fix(cron): default missing sessionTarget on load and guard assertSupportedJobSpec (#70367)
* fix(cron): default missing sessionTarget on load and guard assertSupportedJobSpec

* fix(cron): use Object.hasOwn for payload.kind check and log the backfill

Address review feedback on #70367:
- Switch the new payload.kind lookup from `in` to `Object.hasOwn` so
  prototype pollution cannot drive the defaulter (Aisle Low finding).
- Log a warning when a job is auto-defaulted at load time, matching the
  adjacent legacyJobIdIssue pattern so operators can run `openclaw
  doctor --fix` to persist the canonical shape (Greptile P2).

* fix(cron): dedupe sessionTarget backfill warn per jobId and sharpen crash site reference

Address deep-review feedback on #70367:

- The code comment referenced assertSupportedJobSpec as the tick-time
  crash site, but that function is only called from create/patch
  (jobs.ts:607, 686) and manual-run preflight (ops.ts:516). The actual
  on-tick TypeError surfaces in runIsolatedAgentJob (server-cron.ts).
  Update the comment to say so.

- ensureLoaded runs with forceReload:true on every onTimer tick (~60s).
  Before this change, a persistent legacy job missing sessionTarget
  produced one warn line per tick, forever. Add a per-jobId dedupe set
  on CronServiceState (mirroring the existing warnedDisabled flag) so
  the warn fires once per job per process.

- Drop the 'run openclaw doctor --fix' remediation from the warn
  message. Doctor's cron-store migration has no trackIssue entry for
  missing sessionTarget (doctor-cron-store-migration.ts CronStoreIssueKey),
  so doctor --fix on a store whose only defect is missing sessionTarget
  silently returns without writing anything. Point operators at
  jobs.json directly until that gap is closed.

* docs(changelog): note cron session target repair

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-24 17:57:39 -07:00
Peter Steinberger
c9b9d33451 docs(changelog): mark 2026.4.24 unreleased 2026-04-25 01:56:22 +01:00
Peter Steinberger
5086069c94 fix(cli-runtime): merge user mcp servers 2026-04-25 01:56:22 +01:00
Kei Shingu
b86a04262d fix(cli-runtime): replace overlapping user mcp servers 2026-04-25 01:56:22 +01:00
kei shingu
d8ae63e7a2 test(cli-runtime): add coverage for user mcp.servers merge in prepareCliBundleMcpConfig 2026-04-25 01:56:22 +01:00
kei shingu
61250e2bea fix(cli-runtime): merge user mcp.servers into claude-cli bundle config
prepareCliBundleMcpConfig was not including cfg.mcp.servers when building
the temporary mcp.json that gets passed to claude-cli via --mcp-config.
This meant user-defined MCP servers (e.g. mcp.servers.omi in openclaw.json)
were silently dropped, even though --strict-mcp-config prevents any other
path for those servers to reach the CLI session.

The Pi runtime path (loadEmbeddedPiMcpConfig) already merges cfg.mcp.servers
after the bundle layer. This commit applies the same merge to the CLI runtime
path, with identical precedence: bundle defaults < user mcp.servers <
additionalConfig (loopback). The loopback entry remains last so it cannot be
overridden by user config.

Fixes: user-configured MCP servers not appearing as mcp__<name>__* tools in
claude-cli sessions started by OpenClaw.
2026-04-25 01:56:22 +01:00
Vincent Koc
718dffd2f2 fix(diagnostics): harden capture redaction and discord metadata fetch (#71303) 2026-04-24 17:51:12 -07:00
Peter Steinberger
25a02825a5 test(google-meet): share plugin harness 2026-04-25 01:50:28 +01:00
Gforce10-design
5a202f6f90 fix(auth): bootstrap codex cli credential without clobbering local (#71310)
* fix(auth): bootstrap codex cli credential without clobbering local

readCodexCliCredentialsCached was imported but never registered in
EXTERNAL_CLI_SYNC_PROVIDERS, so overlayExternalAuthProfiles could not
seed openai-codex:default on fresh agents and runtime surfaced
"No API key found for provider openai-codex" even after a successful
codex login.

Register the provider with a new bootstrapOnly flag. Providers flagged
bootstrapOnly are adopted only to fill an empty slot: the overlay skips
them when a local OAuth credential already exists for the profile, and
readExternalCliBootstrapCredential returns null so the refresh path
never replaces the locally stored canonical refresh token with stale
CLI state. Minimax keeps its existing replace-on-expiry behavior.

* test(auth): cover codex cli bootstrap

---------

Co-authored-by: sudol <sudol@A8Max.localdomain>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-25 01:50:01 +01:00
Vincent Koc
6d49681a62 docs(changelog): backfill 104 more author credits with expanded handle map 2026-04-24 17:49:39 -07:00
Peter Steinberger
d610e2cc6c feat(browser): support per-profile headless
Co-authored-by: nakamotoliu <nakamotoliu2026@gmail.com>
Co-authored-by: Nakamoto <nakamoto@claude.ai>
2026-04-25 01:49:22 +01:00
Vincent Koc
5ea0ded5a5 docs(changelog): backfill 1471 author credits across all releases via git blame 2026-04-24 17:47:52 -07:00
Peter Steinberger
664b9fe7eb docs: note safe GitHub comment quoting 2026-04-25 01:44:55 +01:00
Peter Steinberger
867b4c2a32 fix(plugins): log runtime deps staging progress 2026-04-25 01:42:54 +01:00
Peter Steinberger
f9207e5d39 test(agents): cover defaults fallback timeout 2026-04-25 01:42:38 +01:00
Peter Steinberger
63dc5089b2 refactor(google-meet): split create browser flow 2026-04-25 01:40:50 +01:00
Peter Steinberger
8a0cb03300 fix(agents): skip empty embedded prompts 2026-04-25 01:39:28 +01:00
Peter Steinberger
ae57a7998e fix(telegram): persist accepted update offsets 2026-04-25 01:35:05 +01:00
Peter Steinberger
7c0549bd9f fix(google-meet): join created meetings by default 2026-04-25 01:31:51 +01:00
Peter Steinberger
d12987d725 fix(agents): fail fast on terminal provider 429s 2026-04-25 01:31:01 +01:00
Peter Steinberger
26bc5e47ee fix(browser): stabilize doctor diagnostics 2026-04-25 01:30:47 +01:00
Vincent Koc
df5abf9a98 docs(changelog): backfill 40 more 2026.4.22 authors via CHANGELOG diff matching 2026-04-24 17:27:45 -07:00
Peter Steinberger
554f93a999 fix(providers): keep minimax chat models text-only 2026-04-25 01:27:34 +01:00
Peter Steinberger
377e254f6a fix(config): avoid env-ref reload restarts 2026-04-25 01:23:15 +01:00
Peter Steinberger
8a490f4509 fix(browser): break doctor client import cycle 2026-04-25 01:22:47 +01:00
Peter Steinberger
4e42a4cfe8 fix(browser): preserve explicit ai snapshot refs
Fixes #62550.

Co-authored-by: ly85206559 <ly85206559@163.com>
2026-04-25 01:20:42 +01:00
Val Alexander
da773175f2 fix(control-ui): keep context usage fresh (#71297)
Patch live session usage metadata into the Control UI session list, coalesce overlapping refreshes, and add a compact action when fresh context usage is high.

Keep session refresh loading separate from session mutation ownership so background refreshes cannot re-enable mutation UI or overwrite delete/restore state mid-flight.

Co-authored-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
2026-04-25 01:20:12 +01:00
Peter Steinberger
d399ac74f7 fix(slack): hash token cache keys 2026-04-25 01:17:55 +01:00
Vincent Koc
b7c8c53af2 docs(plugins): define config ownership contract
* fix(plugins): flag channel config metadata gaps

* docs(plugins): clarify config ownership
2026-04-24 17:17:10 -07:00
Chris Zhang
de8a00d922 fix(plugins): preserve tokenjuice runtime rule data
Preserve tokenjuice runtime rule JSON under dist/rules/tests during bundled plugin runtime dependency staging while continuing to prune unrelated tests directories.
2026-04-24 17:16:06 -07:00
Peter Steinberger
30aa1f890a feat(browser): expose doctor diagnostics to agents
Co-authored-by: Sean Coley <github@seancoley.me>
2026-04-25 01:15:31 +01:00
Vincent Koc
b5a5b59742 docs(changelog): backfill 2026.4.21 + 2026.4.20 authors (gpt-image-2, presentation SDK, Kimi K2.6, wizard, LINE media, avatar auth, thread routing, YOLO exec, anthropic-messages, DevToolsActivePort) 2026-04-24 17:15:27 -07:00
Vincent Koc
e3cba98f39 refactor(pdf): move document extraction to plugin
* refactor(pdf): move document extraction to plugin

* fix(deps): sync document extract lockfile

* fix(pdf): harden document extraction plugin
2026-04-24 17:15:05 -07:00
Peter Steinberger
915931aa38 fix(agents): use captured cli lifecycle hook runner 2026-04-25 01:14:16 +01:00
Peter Steinberger
b69e3b633b refactor(slack): reuse default write clients 2026-04-25 01:13:55 +01:00
Vincent Koc
492dfdc7f2 docs(changelog): backfill 2026.4.22 authors (WeCom, Matrix DM, Claude CLI verify, LanceDB retry, Codex serviceTier) 2026-04-24 17:12:57 -07:00
Peter Steinberger
61ee67aecc fix(agents): fail empty explicit tool allowlists 2026-04-25 01:11:36 +01:00
Peter Steinberger
107d2b7a09 fix(slack): preserve rapid send ordering
Co-authored-by: nightq <zengwei@nightq.cn>
Co-authored-by: xydt cqh <cui.qianhong@xydigit.com>
2026-04-25 01:11:10 +01:00
Peter Steinberger
5f81147c4d fix: persist embedded runtime context budget 2026-04-25 01:09:45 +01:00
Vincent Koc
59f8a2c3fa docs(changelog): backfill 2026.4.22 authors (streaming STT, onboarding, Pi, Thai, status, transcript locks, uuid, MCP cleanup, Jiti) 2026-04-24 17:09:34 -07:00
Peter Steinberger
db958463f6 fix(codex): emit app-server final chat events (#71293)
Fix live webchat finalization for Codex app-server runs by emitting standard assistant and lifecycle completion events on the global agent event bus, instead of relying on a message-less chat.final fallback.

Replaces #70815. Closes #71183.

Co-authored-by: Lēsa <260982214+lesaai@users.noreply.github.com>
2026-04-25 01:09:11 +01:00
Peter Steinberger
f4add8047b test: relax Docker service command timeouts 2026-04-25 01:07:23 +01:00
Marcus Castro
a580db58ca docs(whatsapp): correct replyToMode values 2026-04-24 21:06:00 -03:00
Coy Geek
8ca66cad68 fix(browser): scope control auth to active gateway mode (#65639)
Browser control now authorizes only the resolved active gateway credential and fails closed when password mode lacks a resolved password.

Also removes the duplicate Slack test-helper middleware stub that kept current CI red after the base rebase.

Fixes #65626.

Co-authored-by: Coy Geek <65363919+coygeek@users.noreply.github.com>
2026-04-25 01:03:39 +01:00
Peter Steinberger
ea74e01ed6 fix(slack): resolve native approval buttons
Co-authored-by: Motoki Maruyama <motoki.maruyama@kiconiaworks.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 01:02:51 +01:00
Vincent Koc
e625651de8 feat(plugins): derive setup auth choices
* feat(plugins): derive setup auth choices

* fix(plugins): sanitize derived provider auth choices

* fix(plugins): clean up extension gate regressions
2026-04-24 16:57:39 -07:00
Peter Steinberger
fb80405693 test: fix slack bolt mock middleware 2026-04-25 00:57:09 +01:00
Peter Steinberger
829ace53d3 docs: note inbound media ref handling 2026-04-25 00:57:09 +01:00
Peter Steinberger
ddedcac54a test: stabilize full-suite lanes 2026-04-25 00:57:08 +01:00
Peter Steinberger
741d5d3231 fix(providers): narrow staged anthropic client type 2026-04-25 00:57:08 +01:00
Peter Steinberger
45730f6117 fix(gateway): resolve inbound assistant media refs 2026-04-25 00:57:07 +01:00
Peter Steinberger
14e0a8c2bc fix(agents): accept inbound media refs across tools 2026-04-25 00:57:07 +01:00
Peter Steinberger
4e9c83d4d8 fix(media): centralize inbound media reference resolution 2026-04-25 00:57:07 +01:00
Vincent Koc
aa27e27f36 fix(models): normalize provider runtime selection (#71259)
* fix(models): normalize provider runtime selection

* fix(models): reverse codex-only runtime migration

* fix(models): default runtime selection to pi

* fix(status): label model runtime clearly

* fix(status): align pi runtime label

* fix(plugins): align tool result middleware runtime naming

* fix(models): validate runtime overrides
2026-04-24 16:56:49 -07:00
Peter Steinberger
60e7b692cc docs(browser): document inspection diagnostics 2026-04-25 00:56:35 +01:00
Peter Steinberger
1d4859dc53 feat(browser): add doctor and richer inspection helpers 2026-04-25 00:56:35 +01:00
Peter Steinberger
d1cc54866d fix(slack): return non-image downloads as files 2026-04-25 00:55:57 +01:00
Peter Steinberger
cc2b4cf125 test(parallels): update npm smoke guard expectation 2026-04-25 00:53:01 +01:00
Peter Steinberger
b9b97f2653 test: raise Docker aggregate resource caps 2026-04-25 00:52:52 +01:00
Peter Steinberger
a1087ea7a6 fix(parallels): harden npm update smoke 2026-04-25 00:49:57 +01:00
Peter Steinberger
c12af80b5b fix(github-copilot): move pi-ai to dev dependency 2026-04-25 00:44:29 +01:00
Peter Steinberger
a57fbc8026 test(slack): cover fast draft preview finalization 2026-04-25 00:42:55 +01:00
Vincent Koc
d4d4a8c14e feat(diagnostics-otel): add content capture controls
Add opt-in diagnostics OTEL content capture controls, keep raw content export default-off, and guard the content-capture tests against magic truncation bounds.
2026-04-24 16:41:28 -07:00
Peter Steinberger
fbf8b216c6 fix: keep explicit image generation model exact 2026-04-25 00:39:07 +01:00
Peter Steinberger
e40d7abda9 fix(slack): preserve real thread anchors 2026-04-25 00:38:19 +01:00
Peter Steinberger
82020bd787 feat(browser): prefer suggested tab targets 2026-04-25 00:35:26 +01:00
Peter Steinberger
acb10cd21c fix(skills): honor default-enabled plugin skills 2026-04-25 00:35:26 +01:00
Vincent Koc
f6504ceb1d fix(discord): guard gateway metadata fetches 2026-04-24 16:33:54 -07:00
Peter Steinberger
b3db7c6987 fix: expose dynamic thinking options to UI 2026-04-25 00:33:42 +01:00
Peter Steinberger
5dab0dae56 test(cli): mock runtime plugin registry resolver 2026-04-25 00:32:02 +01:00
Peter Steinberger
0376987691 fix(plugins): preserve gateway hook runner
Co-authored-by: lanzhi-lee <36190508+lanzhi-lee@users.noreply.github.com>
2026-04-25 00:28:51 +01:00
Peter Steinberger
2b5c719a62 fix(slack): process thread broadcasts as messages 2026-04-25 00:26:31 +01:00
Peter Steinberger
dea05aae6b docs(browser): explain automation skill and tab handles 2026-04-25 00:24:33 +01:00
Peter Steinberger
45e2a15e29 feat(browser): add stable tab handles and automation skill 2026-04-25 00:23:55 +01:00
Peter Steinberger
86856b88e3 fix(slack): suppress reasoning in native streams 2026-04-25 00:23:16 +01:00
wei
3dba3d8b35 fix(discord): run message_sending hooks for replies
Fixes Discord reply delivery so `message_sending` plugin hooks can transform or cancel outbound Discord replies, including DM targets.

Fixes #59350.
Thanks @wei840222.
2026-04-25 00:19:24 +01:00
Peter Steinberger
4693d20cad fix(slack): keep block replies in first thread 2026-04-25 00:17:56 +01:00
Peter Steinberger
989193b4b4 test(discord): share empty config fixture 2026-04-25 00:16:18 +01:00
Peter Steinberger
0270428645 fix(plugins): reuse gateway boot registry for runtime ensures
Co-authored-by: Mark Ramos <6416874+markthebest12@users.noreply.github.com>
2026-04-25 00:14:31 +01:00
Peter Steinberger
c735b59043 fix(browser): remove stale snapshotForAI references 2026-04-25 00:10:03 +01:00
Peter Steinberger
5d9941c36d fix(discord): require runtime config in helpers 2026-04-25 00:09:45 +01:00
Peter Steinberger
beefcda68f fix: keep copilot on boundary-aware stream path 2026-04-25 00:06:40 +01:00
Peter Steinberger
1787ae0f5d fix(google-meet): reuse create tabs on retry 2026-04-25 00:04:01 +01:00
Peter Steinberger
50e484b22e fix(browser): use current aria snapshot refs 2026-04-25 00:04:01 +01:00
Peter Steinberger
272a72b716 test: relax Docker host command caps 2026-04-25 00:03:52 +01:00
Peter Steinberger
2a4fa8ffe8 fix(slack): scope assistant self-event bypass 2026-04-25 00:03:23 +01:00
Peter Steinberger
893a18ff5c fix(slack): accept assistant dm message edits 2026-04-25 00:00:17 +01:00
Peter Steinberger
3a6d50deb3 fix: satisfy Discord gateway fetch boundary (#70945) 2026-04-24 23:55:48 +01:00
Peter Steinberger
21162233d5 fix: harden Discord subagent thread config (#70945) 2026-04-24 23:55:48 +01:00
Jai Govindani
84571e45ce fix(discord): pass config to subagent thread binding 2026-04-24 23:55:48 +01:00
Peter Steinberger
0c46e8000e fix(plugins): cache discovery registration snapshots
Co-authored-by: junpei.o <14040213+livingghost@users.noreply.github.com>
Co-authored-by: Yoshiaki Okuyama <okuyam2y@gmail.com>
Co-authored-by: Shion Eria <shioneria@foxmail.com>
Co-authored-by: Billy Shih <1472300+bbshih@users.noreply.github.com>
2026-04-24 23:55:29 +01:00
Peter Steinberger
9eeceaca43 fix: send copilot headers during compaction 2026-04-24 23:54:58 +01:00
Devin Robison
a35c166348 fix(gateway): restart channels after secret reload (#70720)
* fix(gateway): restart channels after secret reload

* fix(gateway): serialize secrets.reload and isolate channel restart errors

Address review feedback from Greptile (P1), Codex (P2), and Aisle (Medium,
CWE-362) on #70720:

- Serialize the entire secrets.reload path through a promise tail lock so
  concurrent callers cannot overlap the stop/start loop or diff against a
  stale pre-activation snapshot.
- Wrap each channel's stop/start pair in a try/catch so one channel failing
  to restart does not leave other changed channels unrestarted.
- Register slack/zalo/discord channel plugins with reload.configPrefixes in
  the test setup so channels.<id>.* diff paths actually match a restart rule
  (without this, the diff falls through to restart-gateway and the handler
  never enters the per-channel restart branch).
- Add tests covering concurrent-reload serialization and per-channel
  restart-failure isolation.

* fix(gateway): surface channel restart failures from secrets.reload

Address review feedback on the previous commit:

- Codex P1: `secrets.reload` swallowed per-channel restart failures and
  still returned `{ ok: true }`, so a rotation that left a channel on the
  old secret looked successful to the caller. The handler now collects
  restart failures during the loop and throws an aggregate error after
  attempting every channel, so the client-side RPC response surfaces the
  partial failure while unaffected channels still restart (preserving the
  original Greptile P1 non-cascading semantic).
- Greptile P2: test mock-call assertions sorted the captured channel
  arguments so they no longer depend on `Set`/object-key iteration order,
  which is not a stable contract of the handler.

* fix(gateway): harden secrets reload followups

* docs(changelog): note secret-backed channel restart on secrets.reload

* test(gateway): align secrets reload snapshot activation

* test(gateway): reset plugin runtime state in aux handlers

* fix(gateway): refresh reload rules and roll back channels

* fix(gateway): harden secrets.reload rollback tests

* test(gateway): inject aux handler reload plan

* test(gateway): avoid resettable reload-plan mocks

* test(gateway): isolate aux handler tests from skip env-var leakage

test-helpers.mocks.ts and test-helpers.server.ts set
OPENCLAW_SKIP_CHANNELS=1 / OPENCLAW_SKIP_PROVIDERS=1 at module load. When
a shared vitest worker imports those helpers before this file's tests
run, the leaked env vars route the secrets.reload skip-mode branch and
the channel restart loop never fires. Add a beforeEach that clears both
env vars so the suite is independent of worker import order.

* fix(gateway): restore required generation on secrets.reload rollback

setCurrentSharedGatewaySessionGeneration can clear `required` as a side
effect of activating a new generation. The previous rollback path
restored only `current`, leaving `required` cleared and weakening
shared-gateway auth-generation enforcement after a failed reload (Aisle
CWE-287). Capture both fields before activation and restore both in the
catch block. Add a focused regression test that locks in the contract.

* fix(gateway): track restart channels for rollback before stopChannel awaits

Pushing to stoppedChannels only after `await stopChannel` succeeded meant
that if stopChannel rejected mid-call (for example, a plugin stopAccount
hook throws after the runtime already closed the socket), the rollback
loop skipped that channel entirely. A failed secrets.reload could then
leave the channel down. Track the channel before awaiting so rollback
always attempts to bring it back, and add a regression test.
2026-04-24 16:54:16 -06:00
Vincent Koc
2d53ad5cb6 fix(channels): harden manifest read-only metadata 2026-04-24 15:50:46 -07:00
Peter Steinberger
0c54254231 fix(discord): record gateway transport activity 2026-04-24 23:48:41 +01:00
Peter Steinberger
719d6df156 fix: align github copilot request headers 2026-04-24 23:47:43 +01:00
Peter Steinberger
304126ad79 refactor(realtime-voice): centralize consult policy helpers 2026-04-24 23:45:49 +01:00
Peter Steinberger
a7696b496a test: improve Docker aggregate scheduling 2026-04-24 23:44:02 +01:00
Peter Steinberger
99cfa50451 test(slack): cover first native stream thread target 2026-04-24 23:42:50 +01:00
Patrick Erichsen
137f5c3a8b fix(agents): repair stale bootstrap completion (#71230)
* fix(agents): repair stale bootstrap completion

* fix: reconcile stale workspace bootstrap explicitly

* fix: keep bootstrap reconciliation in workspace lifecycle
2026-04-24 15:41:11 -07:00
Vincent Koc
5d1568963b docs(changelog): backfill 2026.4.23 authors (media-image routing, codex oauth, approvals) 2026-04-24 15:39:56 -07:00
Vincent Koc
adccd0d75e docs(changelog): backfill Thanks @ on confirmed 2026.4.23 authors 2026-04-24 15:38:07 -07:00
Altay
9d3c56d236 fix: don't classify 400/422 with no body as format error (#67024)
* fix: keep no-body 400/422 failover errors out of format

* fix: keep failover changelog entry in unreleased fixes
2026-04-25 01:37:28 +03:00
Peter Steinberger
9613a0759c refactor(google-meet): tidy browser create control 2026-04-24 23:34:33 +01:00
Peter Steinberger
5c445f7842 fix(slack): suppress block streaming during previews 2026-04-24 23:34:04 +01:00
Vincent Koc
5009c588d9 docs(changelog): backfill missing authors on 2026.4.24 security, setup, browser, Meet, fallback, Telnyx, Codex, sidecar entries 2026-04-24 15:32:27 -07:00
Vincent Koc
ee3bb1f36b docs(changelog): backfill missing Thanks @ and PR links (Control UI, Google Meet, DeepSeek, Pi, Models) 2026-04-24 15:29:29 -07:00
Vincent Koc
5394efe71f feat(channels): use manifest configs for read-only discovery 2026-04-24 15:18:45 -07:00
Peter Steinberger
d4a8fdb6ce fix(discord): supervise gateway registration failures 2026-04-24 23:15:28 +01:00
Vincent Koc
4de80807b9 fix(plugins): bound tool result middleware details 2026-04-24 15:11:51 -07:00
Peter Steinberger
e2f13959d4 feat(voice-call): share realtime agent consult tool
Centralize the shared realtime agent consult tool for browser Talk, Google Meet, and Voice Call.
2026-04-24 23:11:18 +01:00
Peter Steinberger
900ba7cf33 fix(google-meet): handle browser mic prompt 2026-04-24 23:06:58 +01:00
Peter Steinberger
8a7d67f305 docs: require PR review evidence checklist 2026-04-24 23:06:31 +01:00
Peter Steinberger
535a1d699e fix(plugins): preserve interactive dedupe on cache restore 2026-04-24 23:02:21 +01:00
Gustavo Madeira Santana
2f23b84dc4 fix(changelog): remove duplicate diagnostics entry 2026-04-24 18:01:18 -04:00
Gustavo Madeira Santana
72731a37d2 Require full Matrix identity trust (#70401)
Merged via squash.

Prepared head SHA: d13a729681
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-24 17:58:57 -04:00
Peter Steinberger
0cce4cf8f6 refactor(slack): share stream fallback delivery bookkeeping 2026-04-24 22:55:39 +01:00
Peter Steinberger
4cca309657 docs: update changelog for PR 71242 2026-04-24 22:54:36 +01:00
RenzoMXD
bad38150cb fix(gateway): fall back to lastCallUsage on /v1/chat/completions 2026-04-24 22:54:36 +01:00
Vincent Koc
139dfd97bb fix(diagnostics-otel): export logs from diagnostic events
Export diagnostics OTEL logs through bounded diagnostic log events while keeping core log records off the public plugin diagnostic stream.\n\nIncludes security hardening for log payload redaction, bounded attributes, prototype-pollution keys, OTEL export failure reporting, and extension SDK seam usage.
2026-04-24 14:51:45 -07:00
martingarramon
150053bc86 fix(slack): route stream-fallback delivery through chunked sender (follow-up to #70370) (#71124)
* fix(slack): route stream-fallback delivery through chunked sender

deliverPendingStreamFallback was calling chat.postMessage directly for
err.pendingText, which bypasses the chunked reply path used everywhere
else. For Slack Connect cases where appendSlackStream throws
SlackStreamNotDeliveredError with a large pending buffer, the single
raw post could fail (msg_too_long) and drop the unsent tail.

Two changes:

1. deliverPendingStreamFallback now routes through deliverReplies so
   long pendingText is chunked by the normal sender and the fallback
   honors the configured replyToMode / identity.

2. The non-benign streaming-error branch in deliverWithStreaming now
   clears the session via markSlackStreamFallbackDelivered before
   falling back to deliverNormally. Without this, pendingText stays
   populated and the post-loop finalize (stopSlackStream →
   SlackStreamNotDeliveredError → fallback) re-posts the same chunk
   that deliverNormally already sent.

Addresses the three Codex P1 findings on #70370 about bypassing the
chunked sender, and the related "avoid reposting buffered text after
append fallback" P1 about duplicate delivery. Tests updated to assert
deliverReplies routing (instead of raw postMessage) and a new case
covers the non-benign-error dedup.

Follow-up to #70370.

* fix(slack): preserve pending buffered text on non-benign stream errors

Address Codex P1 on #71124: `markSlackStreamFallbackDelivered` was
clearing `pendingText` before `deliverNormally` ran, so any earlier
buffered chunk was lost. E.g. chunk A buffered in the SDK, then
appending chunk B throws a generic network error → previous fix
dropped A+B and only sent B via `deliverNormally`, silently truncating
the final reply.

Route the full buffered `pendingText` through
`deliverPendingStreamFallback` with a synthetic
`SlackStreamNotDeliveredError`, then skip `deliverNormally` entirely
(pendingText already contains this payload's text, per
`appendSlackStream` accumulating before throw). If the chunked
fallback fails, fall back to `deliverNormally` so at least the current
payload lands.

Test updated to assert the full pendingText ("first buffered\nsecond
payload") gets routed through the chunked sender, not the
chunk-B-only partial send.

* fix(slack): harden stream fallback docs and chunking test (#71124)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 22:50:18 +01:00
Peter Steinberger
b0c9810b0f fix(plugins): restore cached command registries 2026-04-24 22:49:40 +01:00
Peter Steinberger
cabdf5bbc4 fix: match codex openai websocket continuation 2026-04-24 22:47:25 +01:00
Peter Steinberger
95a2b0d799 docs(changelog): prepare 2026.4.24 notes 2026-04-24 22:41:12 +01:00
Peter Steinberger
55318df83f fix(slack): share HTTP route registry across module loads
Fixes #67955, #46245, #46246.

Co-authored-by: Axel <axel@kaleidoscope.studio>

Co-authored-by: Cesar Arevalo <cesar@cesararevalo.com>
2026-04-24 22:41:12 +01:00
pashpashpash
11804a484d Fail closed when an explicit agent harness is missing (#71265)
* Fail closed for explicit agent harness selection

* Scope explicit harness fallback opt in
2026-04-25 06:39:57 +09:00
IVY
5adf9d2619 fix(discord): prevent identify race (#68159)
Verified against Carbon 0.16.0 source:
- Client constructor calls plugin.registerClient(this) without awaiting it.
- GatewayPlugin.registerClient publishes client before its awaited metadata fetch.
- identify() silently returns when client is missing.

This patch matches Carbon's ordering in OpenClaw's subclass, avoids a second super.registerClient call if lifecycle connect already opened the socket during metadata loading, and keeps regression coverage for both ws and isConnecting cases.

Local proof:
- pnpm test extensions/discord/src/monitor/provider.proxy.test.ts extensions/discord/src/monitor/gateway-plugin.test.ts
- pnpm lint:tmp:no-raw-channel-fetch
- pnpm check:changed
- pnpm check
- pnpm test

GitHub checks green for 72547825e1.
2026-04-24 22:39:44 +01:00
Peter Steinberger
78b9890ae1 feat(google-meet): add browser create fallback 2026-04-24 22:36:22 +01:00
Peter Steinberger
8a9d02dd82 fix(voice-call): keep outbound realtime streams attached (#71266)
Fixes outbound Twilio realtime conversations so the TwiML fetch returns the realtime <Connect><Stream> path for outbound directions and the answered-call path does not overwrite it with legacy <Say> TwiML.

Local proof:
- pnpm test extensions/voice-call/src/manager.notify.test.ts extensions/voice-call/src/webhook.test.ts
- pnpm check:changed
- pnpm check
- pnpm build
- local VoiceCallWebhookServer + CallManager smoke for Direction=outbound-api

Closes #68713.
2026-04-24 22:35:26 +01:00
Vincent Koc
5b8bd6371c feat(plugins): warn on ignored setup runtime (#71253)
* feat(plugins): warn on ignored setup runtime

* fix(plugins): avoid fallback setup runtime diagnostics

* refactor(plugins): clarify setup runtime lookup
2026-04-24 14:23:19 -07:00
Peter Steinberger
6e985a421d fix(webchat): keep runtime context out of visible transcripts
Keep WebChat runtime context available to the model while persisting only the transcript-facing user prompt across gateway, CLI, queued follow-up, and embedded Pi paths.

Adds regression coverage for history sanitization, CLI transcript persistence, media-only auto-reply prompts, and embedded Pi prompt rewrite against a real SessionManager file.

Co-authored-by: 91wan <91wan@users.noreply.github.com>
2026-04-24 22:17:03 +01:00
Peter Steinberger
b20208fa4c feat(google-meet): create meeting spaces 2026-04-24 22:11:16 +01:00
Val Alexander
86f8c826e2 fix(ui): render assistant identity avatars in chat
Render assistant text avatars from IDENTITY.md consistently in the Control UI chat welcome state and transcript groups.

Also supports authenticated blob avatar URLs in grouped messages and rejects bidi/invisible controls in assistant text avatars.

Verification:
- pnpm test ui/src/ui/chat/grouped-render.test.ts ui/src/ui/views/chat.test.ts ui/src/styles/chat/layout.test.ts
- pnpm check:changed
- GitHub CI green
- Review threads resolved
2026-04-24 15:50:27 -05:00
Peter Steinberger
af46830927 test: split bundled Docker aggregate shards 2026-04-24 21:43:43 +01:00
Val Alexander
245451b6a9 fix(whatsapp): keep QR login state in sync
Keep WhatsApp QR login state synced across gateway, macOS, and UI wait flows.

- Preserve the latest QR data URL/version while login polling rotates codes.
- Keep the wait-result protocol bounded to current QR metadata.
- Stabilize QR rendering and media fixture coverage after rebasing on main.

Validation:
- pnpm test extensions/whatsapp/src/login-qr.test.ts extensions/whatsapp/src/media.test.ts extensions/whatsapp/src/agent-tools-login.test.ts src/gateway/protocol/channels.schema.test.ts src/gateway/server-methods/web.start.test.ts ui/src/ui/controllers/channels.test.ts
- pnpm test:extension whatsapp
- cd apps/macos && swift test --filter ChannelsSettingsSmokeTests
- GitHub PR checks: 62 success, 5 skipped
2026-04-24 15:37:16 -05:00
Vincent Koc
86099ec62a refactor(web-fetch): move readability extraction to plugin
* refactor(web-fetch): move readability extraction to plugin

* fix(web-fetch): cache extractor resolution by config

* fix(test): remove redundant stat assertions
2026-04-24 13:34:37 -07:00
github-actions[bot]
f102ddad0c chore(ui): refresh th control ui locale 2026-04-24 20:30:42 +00:00
github-actions[bot]
b885aa7cd3 chore(ui): refresh pl control ui locale 2026-04-24 20:30:15 +00:00
github-actions[bot]
4b1395b251 chore(ui): refresh uk control ui locale 2026-04-24 20:30:12 +00:00
github-actions[bot]
a7f48b6c6c chore(ui): refresh id control ui locale 2026-04-24 20:30:10 +00:00
github-actions[bot]
58a2bfeb7a chore(ui): refresh tr control ui locale 2026-04-24 20:29:58 +00:00
github-actions[bot]
e228c92e84 chore(ui): refresh fr control ui locale 2026-04-24 20:29:35 +00:00
github-actions[bot]
105aeac48e chore(ui): refresh ko control ui locale 2026-04-24 20:29:28 +00:00
github-actions[bot]
5e14663ed9 chore(ui): refresh ja-JP control ui locale 2026-04-24 20:29:08 +00:00
github-actions[bot]
db551c4274 chore(ui): refresh es control ui locale 2026-04-24 20:27:56 +00:00
github-actions[bot]
967c6bd785 chore(ui): refresh zh-TW control ui locale 2026-04-24 20:27:09 +00:00
github-actions[bot]
ffd76d6aee chore(ui): refresh pt-BR control ui locale 2026-04-24 20:27:06 +00:00
github-actions[bot]
bcd915dab1 chore(ui): refresh de control ui locale 2026-04-24 20:27:02 +00:00
github-actions[bot]
913f4e61a9 chore(ui): refresh zh-CN control ui locale 2026-04-24 20:26:35 +00:00
Vincent Koc
7bd74758c5 fix(plugins): harden tool result middleware (#71241) 2026-04-24 13:23:18 -07:00
547895019
272313877d fix(comfy): read config from plugins.entries instead of models.providers (openclaw#63058)
Verified:
- pnpm test -- extensions/comfy/image-generation-provider.test.ts extensions/comfy/music-generation-provider.test.ts extensions/comfy/video-generation-provider.test.ts
- rg -n "models\\.providers\\.comfy" docs extensions/comfy src -g '*.{ts,md,json}'
- pnpm check -- --help
- gh pr checks 63058 --repo openclaw/openclaw --watch --fail-fast

Co-authored-by: 547895019 <7350824+547895019@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-24 15:23:13 -05:00
Patrick Erichsen
f896c3935e ci: centralize workflow openai model defaults (#70845) 2026-04-24 13:22:35 -07:00
Vincent Koc
cf858258c7 feat(plugins): surface manifest provider setup choices (#71240) 2026-04-24 13:14:49 -07:00
Vincent Koc
8154337cb6 fix(whatsapp): emit message received hooks (#71217)
* fix(whatsapp): emit message received hooks

* fix(whatsapp): harden message received hooks
2026-04-24 13:05:10 -07:00
Peter Steinberger
7a168150e6 test: tune Docker aggregate service pressure 2026-04-24 21:04:39 +01:00
Vincent Koc
ff8b7145d7 docs(plugins): catalog active deprecations in sdk-migration and cross-link from hooks 2026-04-24 13:04:07 -07:00
Michael Yagudaev
c997a9f978 feat(gateway): add VoiceClaw realtime brain endpoint (#70938)
Adds the VoiceClaw-compatible realtime brain WebSocket endpoint backed by Gemini Live, with owner-auth gating, async OpenClaw tool handoff, docs, and lifecycle tests.

Maintainer fixup: terminal upstream errors now send the error, emit session.ended while the client socket is still open, then close the client-facing socket.

Co-authored-by: Michael Yagudaev <1386966+yagudaev@users.noreply.github.com>
2026-04-24 21:00:04 +01:00
Vincent Koc
7536993397 feat(plugins): read setup provider env vars (#71226)
* feat(plugins): read setup provider env vars

* fix(plugins): mark provider env compat deprecation
2026-04-24 12:59:02 -07:00
Peter Steinberger
b4d756c746 docs: trim root agent guide 2026-04-24 20:54:59 +01:00
Peter Steinberger
037d12974c test: bound Docker smoke host commands 2026-04-24 20:54:06 +01:00
Peter Steinberger
0e23107ffb feat(google-meet): format setup status by default 2026-04-24 20:52:39 +01:00
Peter Steinberger
02112803b5 test: cover OpenAI thinking payload contract 2026-04-24 20:51:58 +01:00
Peter Steinberger
7425cb0549 fix: guard speech provider fetches 2026-04-24 20:51:18 +01:00
Peter Steinberger
25ad66520b docs: add ci wait matrix 2026-04-24 20:50:17 +01:00
Peter Steinberger
ecac696643 docs: condense agent instructions 2026-04-24 20:47:21 +01:00
Peter Steinberger
588e59db26 docs: clarify post-land ci waiting 2026-04-24 20:45:55 +01:00
Peter Steinberger
c3f4c75d39 ci: give lint enough blacksmith cpu 2026-04-24 20:45:32 +01:00
Peter Steinberger
d43b3b3b70 fix: preserve live runtime dependency locks 2026-04-24 20:44:56 +01:00
Peter Steinberger
56e299cbca fix: serialize bundled runtime dependency repair 2026-04-24 20:44:56 +01:00
Peter Steinberger
def392ad7d test: add provider HTTP live coverage 2026-04-24 20:44:56 +01:00
Peter Steinberger
2c516fe516 refactor: share provider HTTP error parsing 2026-04-24 20:44:56 +01:00
Yao
37d5c34749 fix(matrix): pass loaded cfg to verify CLI subcommands (#70992) [AI-assisted] (#71102)
Merged via squash.

Prepared head SHA: 9fffdf2ca6
Co-authored-by: luyao618 <17723416+luyao618@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-24 15:44:22 -04:00
Patrick Erichsen
8226a3f8fe feat(onboard): add skip bootstrap flag (#71218) 2026-04-24 12:42:00 -07:00
Peter Steinberger
0f689d22f4 test: add weighted Docker aggregate scheduler 2026-04-24 20:41:27 +01:00
Peter Steinberger
88c91675e2 test: stabilize qa suite concurrency 2026-04-24 20:39:33 +01:00
Vincent Koc
47f6a98909 feat(plugins): add harness tool result middleware (#71021) 2026-04-24 12:39:13 -07:00
Peter Steinberger
e471d40942 ci: run preflight on github hosted ubuntu 2026-04-24 20:37:02 +01:00
Peter Steinberger
c2a353a3bd perf: shorten extension ci tail 2026-04-24 20:35:55 +01:00
BillChirico
51dd4f288f fix(config): allow plugin conversation access hook policy (#71221) 2026-04-24 20:28:42 +01:00
Peter Steinberger
ef9ca09b8e docs(google-meet): add setup troubleshooting 2026-04-24 20:28:00 +01:00
Peter Steinberger
b9cc293167 test: wait for ACPX in cron Docker smoke 2026-04-24 20:27:24 +01:00
Peter Steinberger
14934f0b7c test(google-meet): verify twilio setup readiness 2026-04-24 20:25:46 +01:00
Tak Hoffman
5c8a5fa8fa fix: tweak group silent caution prompt (#71209)
* Tighten group silent caution prompt

* Deduplicate group silent caution prompt
2026-04-24 14:20:01 -05:00
Peter Steinberger
e6d04682d3 ci: tune oxlint threads 2026-04-24 20:17:42 +01:00
Michael Appel
8b76392e3e fix(gateway): enforce owner-only tool policy and before-tool-call hook on MCP loopback surface (#71159)
* fix: address issue

* fix: address review feedback

* fix: address PR review feedback

* changelog: PR #71159 MCP loopback owner-only policy + before-tool-call hook

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-24 13:16:45 -06:00
bitloi
8cae2ed645 fix(gateway): allow chat.abort to stop agent RPC runs
Register agent RPC runs in the shared abort controller map so chat.abort and sessions.abort can interrupt them like chat.send runs.

Also centralize abort-controller registration/owned cleanup, preserve agent timeout semantics for maintenance expiry, and cover pre-dispatch failure cleanup with regression tests.

Fixes #71128.
2026-04-24 20:15:56 +01:00
Yao
0e50fee996 fix(googlechat): log webhook auth reject reasons and warn on appPrincipal misconfig (#71145)
* fix(googlechat): log webhook auth reject reasons and warn on appPrincipal misconfig

Closes #71078

Webhook auth failures previously returned 401 with no log line, leaving
operators no signal to diagnose. Additionally, app-url audience requires
a numeric OAuth 2.0 client ID as appPrincipal, but a misconfigured email
or empty value silently caused all requests to be rejected.

Changes:
- Log a WARN with accountId and reject reason when verifyGoogleChatRequest fails.
- Add warnAppPrincipalMisconfiguration() called at provider init: warns when
  audienceType=app-url and appPrincipal is missing or contains '@'.

Tests: +9 cases in monitor-webhook.test.ts (3 reject-reason scenarios + 4 warner cases).

* fix(googlechat): defer auth rejection logs

* docs: note googlechat webhook auth fix

---------

Co-authored-by: luyao618 <luyao618@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 20:10:57 +01:00
Peter Steinberger
0651e5dc97 fix: restore reliable live Docker staging 2026-04-24 20:10:28 +01:00
Peter Steinberger
65c9cb852e ci: keep only fast core on blacksmith 2026-04-24 20:07:56 +01:00
Peter Steinberger
ed7ea75fc0 perf: speed up live Docker staging 2026-04-24 20:03:08 +01:00
Peter Steinberger
c9998af44d ci: move node fanout to blacksmith 2026-04-24 20:02:48 +01:00
Peter Steinberger
7b5307acfc ci: move fast bundled checks to blacksmith 2026-04-24 20:00:12 +01:00
Peter Steinberger
d12b523611 fix(elevenlabs): use guarded TTS fetch 2026-04-24 19:55:20 +01:00
Sathvik-1007
8d57d745cf fix: wizard no clobber model.primary on re-run
two bugs. both squash user model choice silently.

bug 1: applyDefaultModel() unconditional primary: model overwrite.
wizard calls with setDefaultModel=true, provider returns its default
(e.g. openrouter/auto), bam user primary gone. fix: existingPrimary ?? model.

bug 2: applyModelFallbacksFromSelection() phantom primary injection.
when no primary configured, resolvedKey (hardcoded default) written as
primary via nullish coalescing fallback. fix: conditional spread — only
include primary key when one actually existed.

tests for both. closes #70696
2026-04-24 19:55:20 +01:00
Vincent Koc
d795000377 refactor(anthropic-vertex): move SDK runtime to plugin (#71174)
* refactor(anthropic-vertex): move sdk runtime to plugin

* fix(anthropic-vertex): stage provider runtime deps

* fix(anthropic-vertex): reuse stream factory wrapper
2026-04-24 11:52:35 -07:00
Peter Steinberger
07f33b2909 test: speed up embedded run orchestration specs 2026-04-24 19:47:53 +01:00
Peter Steinberger
59523e66da refactor: remove old provider error utility path 2026-04-24 19:40:25 +01:00
Peter Steinberger
70f5c26a71 refactor: move provider HTTP errors out of tts 2026-04-24 19:40:25 +01:00
Peter Steinberger
bc0f54bd04 fix(models): separate Codex harness from model choices (#71193)
* fix: separate Codex harness from model choices

* docs: note Codex harness model choice fix
2026-04-24 19:40:23 +01:00
Peter Steinberger
dcf01ce72f perf: speed up Docker aggregate smokes 2026-04-24 19:38:25 +01:00
Vincent Koc
3bd2ee78b6 feat(plugins): expose hook correlation fields
Expose first-class hook correlation fields for plugin message and run lifecycle hooks, including frozen diagnostic trace copies for plugin-facing events.
2026-04-24 11:37:34 -07:00
Peter Steinberger
a43c1f8807 refactor: share provider HTTP errors with google 2026-04-24 19:33:44 +01:00
Peter Steinberger
b1016c39fd refactor: share speech provider HTTP errors 2026-04-24 19:33:44 +01:00
Peter Steinberger
e54c04f495 test: stabilize qa lab scenarios 2026-04-24 19:23:37 +01:00
Vincent Koc
6bc0dc8fb6 feat(plugins): report setup descriptor drift (#71194) 2026-04-24 11:15:30 -07:00
Peter Steinberger
3ffd944e6b test: isolate doctor switch shell profiles 2026-04-24 19:10:15 +01:00
Peter Steinberger
926068b14f test(deepseek): add live model smoke 2026-04-24 19:07:41 +01:00
Vincent Koc
5d7d5ca2a9 docs(plugins/hooks): regroup hook catalog by surface, mark decision hooks, sync before_tool_call result type with code 2026-04-24 11:02:46 -07:00
Vincent Koc
7418adf875 fix(plugins): honor descriptor-only setup flag
Honor explicit setup.requiresRuntime: false as a descriptor-only setup contract while preserving omitted values as the legacy setup-api fallback path.
2026-04-24 11:02:38 -07:00
Peter Steinberger
a16f8dff15 test: fold tiny media fallback specs 2026-04-24 19:01:18 +01:00
Peter Steinberger
7a63dd3f12 ci: rebase docs sync with source preference 2026-04-24 18:58:53 +01:00
Peter Steinberger
f07b00de66 refactor(gateway): rename startup sidecar deferral option 2026-04-24 18:58:36 +01:00
Peter Steinberger
3bc99bc70e docs: add reliable taskflow workflow pattern 2026-04-24 18:55:05 +01:00
Peter Steinberger
6fea42fc2d ci: skip stale docs sync publishes 2026-04-24 18:54:01 +01:00
Vincent Koc
9439d633ef docs(nav): surface orphan pages in sidebar (message-presentation, skill-workshop, qa-e2e-automation, proxy, gpt54-codex-agentic-parity) 2026-04-24 10:53:32 -07:00
Peter Steinberger
c2bffc6033 docs: clarify google meet mode choice 2026-04-24 18:51:39 +01:00
Peter Steinberger
94275f13fb fix: keep disabled channel doctor probes lazy 2026-04-24 18:51:19 +01:00
Vincent Koc
1042b893f6 docs: drop parenthetical H1s across gateway, channels, providers, concepts, and reference pages 2026-04-24 10:49:23 -07:00
Peter Steinberger
a155b84cda test: remove duplicate direct chat mock 2026-04-24 18:45:32 +01:00
Peter Steinberger
8207567cba docs(release): prefer npm token workflow for dist-tags 2026-04-24 18:45:06 +01:00
Peter Steinberger
62adf6349d docs(release): require tmux for 1password fallback 2026-04-24 18:44:43 +01:00
Laurent Mazare
d7e2939791 feat: add Gradium text-to-speech provider (#64958)
Adds the Gradium bundled plugin with TTS and speech-provider registration, docs, label routing, and focused/live coverage.

Also carries the current main lint cleanup needed for the rebased CI lane.

Co-authored-by: laurent <laurent.mazare@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 18:43:53 +01:00
Peter Steinberger
2495886287 perf: shrink Docker dependency build contexts 2026-04-24 18:42:25 +01:00
Peter Steinberger
67a2b187b7 docs: fix gateway security accordion 2026-04-24 18:42:07 +01:00
Peter Steinberger
80608ae26c fix: prevent malformed docs accordions 2026-04-24 18:42:07 +01:00
Peter Steinberger
1cfebfe0e1 test: cover Telegram topic model switches 2026-04-24 18:36:23 +01:00
EVA
860dad268d [codex] Add contract-first Pi/Codex runtime plan suite (#71096)
* test: add pi codex runtime contract coverage

* test: expand pi codex tool runtime contracts

* test: tighten tool runtime contracts

* test: reset tool contract param cache

* test: document codex tool middleware fixture

* test: type pi tool contract events

* test: satisfy pi tool contract test types

* test: cover tool media telemetry contracts

* test: reset plugin runtime after tool contracts

* test: add auth profile runtime contracts

* test: strengthen auth profile runtime contracts

* test: clarify auth profile contract fixtures

* test: expand auth profile contract matrix

* test: assert unrelated cli auth isolation

* test: expand auth profile contract matrix

* test: tighten auth profile contract expectations

* test: add outcome fallback runtime contracts

* test: strengthen outcome fallback contracts

* test: isolate outcome fallback contracts

* test: cover codex terminal outcome signals

* test: expand terminal fallback contracts

* test: add delivery no reply runtime contracts

* test: document json no-reply delivery gap

* test: align delivery contract fixtures

* test: add transcript repair runtime contracts

* test: tighten transcript repair contracts

* test: add prompt overlay runtime contracts

* test: tighten prompt overlay contract scope

* test: type prompt overlay contracts

* test: add schema normalization runtime contracts

* test: clarify schema normalization contract gaps

* test: simplify schema normalization contracts

* test: tighten schema normalization contract gaps

* test: cover compaction schema contract

* test: satisfy schema contract lint

* test: add transport params runtime contracts

* test: tighten transport params contract scope

* test: isolate transport params contracts

* test: lock exact transport defaults

* feat: add agent runtime plan foundation

* fix: preserve codex harness auth profiles

* fix: route followup delivery through runtime plan

* fix: normalize parameter-free openai tool schemas

* fix: satisfy runtime plan type checks

* fix: narrow followup delivery runtime planning

* fix: apply codex app-server auth profiles

* fix: classify codex terminal outcomes

* fix: prevent harness auth leakage into unrelated cli providers

* feat: expand agent runtime plan policy contract

* fix: route pi runtime policy through runtime plan

* fix: route codex runtime policy through runtime plan

* fix: route fallback outcome classification through runtime plan

* refactor: make runtime plan contracts topology-safe

* fix: restore runtime plan test type coverage

* fix: align runtime plan schema contract assertions

* fix: stabilize incomplete turn runtime tests

* fix: stabilize codex native web search test

* fix: preserve codex auth profile secret refs

* fix: keep runtime resolved refs canonical

* fix: preserve permissive nested openai schemas

* fix: accept Codex auth provider aliases

* test: update media-only groups mock

* fix: resolve runtime plan rebase checks

* fix: resolve runtime plan rebase checks

---------

Co-authored-by: Eva <eva@100yen.org>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 18:34:01 +01:00
Peter Steinberger
ec3dbd22a4 test: type legacy codex model fixture 2026-04-24 18:30:51 +01:00
Peter Steinberger
0c70cb3b9c fix: report google meet manual actions 2026-04-24 18:26:51 +01:00
Peter Steinberger
cba92f893d fix(gateway): await startup sidecars by default
Co-authored-by: 忻役 <xinyi@mininglamp.com>
2026-04-24 18:25:50 +01:00
Peter Steinberger
129f548c44 fix: export diagnostic error category once 2026-04-24 18:24:24 +01:00
Peter Steinberger
95db5966a0 docs: add plugin hook glossary labels 2026-04-24 18:23:44 +01:00
Peter Steinberger
7330a0c7e0 docs: add plugin hooks reference 2026-04-24 18:22:47 +01:00
Peter Steinberger
342583348d test: fix models list e2e static catalog mock
(cherry picked from commit 3385d10ee5)
2026-04-24 18:22:24 +01:00
Peter Steinberger
5738201b22 test: make bundled channel docker lane resumable
(cherry picked from commit 5b1bd58bd0)
2026-04-24 18:22:24 +01:00
Peter Steinberger
712b7c6637 ci(release): configure shared docker e2e builder
(cherry picked from commit 6f948d925e)
2026-04-24 18:22:24 +01:00
Peter Steinberger
6b4f6ca20c fix(plugins): avoid plugin sdk alias rewrite races 2026-04-24 18:22:24 +01:00
Peter Steinberger
bbef1c5557 fix(release): harden subagent completion delivery
(cherry picked from commit 855872986e)
2026-04-24 18:22:24 +01:00
Peter Steinberger
da36c1967f fix(release): accept logged cross-os agent output
(cherry picked from commit a58ee7c8bc)
2026-04-24 18:22:24 +01:00
Peter Steinberger
042c031c5c ci(release): parse logged agent payload text
(cherry picked from commit c52a16989e)
2026-04-24 18:22:24 +01:00
Peter Steinberger
f191dd3d53 fix(release): preserve plugin-local runtime deps in postpublish verify 2026-04-24 18:22:24 +01:00
Peter Steinberger
5b0ee04c0d fix(release): harden packed runtime smoke
(cherry picked from commit 5ab5dc3900)
2026-04-24 18:22:24 +01:00
Peter Steinberger
3eb7605318 docs(release): restore 2026.4.23 notes on main 2026-04-24 18:22:23 +01:00
Tak Hoffman
59e2825274 fix: deprecate models add command (#71175) 2026-04-24 12:20:59 -05:00
Peter Steinberger
e35e6e1d15 ci: try blacksmith preflight runner 2026-04-24 18:20:36 +01:00
Peter Steinberger
78a431ed22 fix(discord): require real gateway readiness 2026-04-24 18:16:58 +01:00
Peter Steinberger
a08a2e381f fix: resolve bare fallback model providers 2026-04-24 18:16:25 +01:00
Peter Steinberger
1981622b92 test: update ci shard and reply mocks 2026-04-24 18:14:24 +01:00
Peter Steinberger
560b04d4c6 perf: avoid slow Docker live lane cleanup 2026-04-24 18:09:04 +01:00
Tak Hoffman
cc57d56b92 fix: Align silent reply prompt guidance (#70954)
* Align silent reply prompt guidance

* Pass explicit silent reply conversation types

* Handle dm alias in direct prompt guidance

* Respect policy session type for routed replies

* Preserve routed silent reply policy type

* Propagate silent reply dispatcher chat type

* Align prompt silent reply target policy

* Avoid direct silent fallback prompt token

* Use inbound key for prompt silent policy

* Rewrite direct silent replies in dispatcher
2026-04-24 12:06:54 -05:00
Peter Steinberger
c9f2403547 ci: pass node shard runner overrides 2026-04-24 18:05:29 +01:00
Peter Steinberger
660cea680a ci: move tail node shards to blacksmith 2026-04-24 18:03:29 +01:00
Peter Steinberger
11cffb2300 fix: remove duplicate diagnostic category export 2026-04-24 17:58:22 +01:00
Peter Steinberger
afc0c32bd0 ci: try larger blacksmith lint lane 2026-04-24 17:55:44 +01:00
Peter Steinberger
b2352c3e24 docs: improve 2026.4.23 release docs 2026-04-24 17:55:03 +01:00
Peter Steinberger
51c11cfd90 fix: export diagnostic error category 2026-04-24 17:54:44 +01:00
Peter Steinberger
769ab4a91c docs: clarify beta Telegram release verification 2026-04-24 17:52:13 +01:00
Peter Steinberger
c15edc3641 ci: try smaller blacksmith support lanes 2026-04-24 17:50:46 +01:00
Peter Steinberger
f6dcf968ca fix: honor disabled plugin runtime deps 2026-04-24 17:46:35 +01:00
Ron Cohen
3de44fe593 fix(whatsapp): setting systemPrompt to "" suppresses the wildcard prompt (#70381)
* fix(whatsapp): setting systemPrompt to "" suppresses the wildcard instead of falling through to it

* test(whatsapp): reset mocks instead of only clearing call history

* docs(changelog): note WhatsApp empty systemPrompt suppresses wildcard

* test(whatsapp): preserve real module exports in process-message mocks

* test(whatsapp): whitespace-only systemPrompt also suppresses wildcard

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-04-24 09:45:58 -07:00
Peter Steinberger
11ad1919ed test: stabilize Docker MCP lanes under load 2026-04-24 17:41:37 +01:00
Peter Steinberger
5deef28b7a ci: split docs-only push checks 2026-04-24 17:41:04 +01:00
Peter Steinberger
11abe5ec49 docs: clarify plugin api extension path 2026-04-24 17:36:39 +01:00
Vincent Koc
f8573fe9c2 feat(diagnostics): export lifecycle OTEL spans
Export diagnostics OTEL lifecycle spans for runs, model calls, and tool executions while avoiding retained live span state and high-cardinality/sensitive exported attributes.
2026-04-24 09:36:35 -07:00
Peter Steinberger
0340321c12 docs: clarify plugin style preference 2026-04-24 17:35:00 +01:00
Peter Steinberger
2fe7c6fed4 docs: simplify mcp vision 2026-04-24 17:34:15 +01:00
Peter Steinberger
f738b73107 docs: clarify clawhub plugin promotion 2026-04-24 17:31:49 +01:00
Vincent Koc
4d1ee3a73e fix(plugins): warn on install source package drift
Warn when provider or channel catalog package identity drifts from openclaw.install.npmSpec while keeping compatible catalogs non-fatal.
2026-04-24 09:31:40 -07:00
Peter Steinberger
90877e0d42 docs: update mcp vision 2026-04-24 17:29:42 +01:00
Peter Steinberger
3df9fd4354 ci: keep preflight off congested blacksmith 2026-04-24 17:28:11 +01:00
Vincent Koc
06d46869f8 refactor(tui): remove cli-highlight dependency
Remove direct cli-highlight usage from the TUI renderer and drop the now-unused root ownership record.
2026-04-24 09:25:25 -07:00
Peter Steinberger
f4ffed8482 ci: reduce ubuntu preflight queue 2026-04-24 17:24:37 +01:00
Peter Steinberger
27b348b3e5 perf: reuse Docker aggregate package tarball 2026-04-24 17:20:56 +01:00
Vincent Koc
1cf79803d7 docs: normalize Title Case H2 headings to sentence case in recent files 2026-04-24 09:17:47 -07:00
Vincent Koc
c1ad8076a3 docs(standing-orders): drop duplicate H1 where frontmatter title already covers it 2026-04-24 09:17:16 -07:00
Vincent Koc
32163e0e98 docs(google-meet): drop duplicate H1 and merge intro sentences 2026-04-24 09:16:27 -07:00
Peter Steinberger
16c7de085c ci: move long tail checks to blacksmith 2026-04-24 17:16:18 +01:00
Peter Steinberger
d9c5479029 fix: remove google meet sync await 2026-04-24 17:16:18 +01:00
Vincent Koc
12f7de3ef3 docs(capability-cookbook): normalize Provider and Harness Seams heading to sentence case 2026-04-24 09:15:22 -07:00
Peter Steinberger
7e49cc87f9 perf: parallelize Docker aggregate image builds 2026-04-24 17:10:50 +01:00
Peter Steinberger
d3e66e36f6 fix: export model diagnostic error category 2026-04-24 17:10:46 +01:00
Peter Steinberger
d5880ae6a5 fix: restore diagnostic error export 2026-04-24 17:09:22 +01:00
Peter Steinberger
23c7a7d557 test: harden Docker lanes for 10-way runs 2026-04-24 17:08:18 +01:00
Peter Steinberger
cbfc21badb test: shard Docker aggregate lanes 2026-04-24 17:08:18 +01:00
Vincent Koc
58f54801b7 feat(deps): add SBOM risk report
* feat(deps): add sbom risk report

* feat(deps): add sbom risk report
2026-04-24 09:08:07 -07:00
Peter Steinberger
c05791f619 ci: split blacksmith node lanes by runner size 2026-04-24 17:05:09 +01:00
Peter Steinberger
f7a426d516 fix: stage WhatsApp runtime deps before setup login 2026-04-24 17:04:31 +01:00
Vincent Koc
7ba13fbc2b fix(diagnostics): harden event emission (#71164) 2026-04-24 09:02:14 -07:00
Peter Steinberger
bda391e4c2 fix: use browser automation for Google Meet join 2026-04-24 17:01:57 +01:00
Vincent Koc
bbe0234720 fix(plugins): warn on orphan install integrity (#71163) 2026-04-24 09:01:15 -07:00
Vincent Koc
5dfc1b90e1 fix(plugins): warn on invalid install default choice (#71011) 2026-04-24 08:56:42 -07:00
Peter Steinberger
1b997bebd0 build(a2ui): refresh bundled canvas host asset 2026-04-24 16:55:08 +01:00
Peter Steinberger
27c61ed0d4 chore(deps): update workspace dependencies 2026-04-24 16:55:08 +01:00
pashpashpash
7a958d920c Bridge Codex native hooks into OpenClaw
Bridge Codex-native tool events into the OpenClaw plugin hook surface, including native permission approval routing, bounded relay payloads, approval spam protection, and docs/changelog updates.\n\nCo-authored-by: pashpashpash <nik@vault77.ai>
2026-04-24 16:48:26 +01:00
Peter Steinberger
3a64aa49a9 docs(deepseek): expand v4 testing notes 2026-04-24 16:30:35 +01:00
Peter Steinberger
aef0bb4915 test(deepseek): add live v4 model coverage 2026-04-24 16:30:35 +01:00
Peter Steinberger
6b618f0635 ci: offload selected node lanes to blacksmith 2026-04-24 16:23:24 +01:00
Peter Steinberger
f3bcea8732 build: preserve staged plugin runtime deps 2026-04-24 16:18:26 +01:00
Peter Steinberger
2b45a112cb feat: harden Google Meet realtime join 2026-04-24 16:18:26 +01:00
Peter Steinberger
2c701ab296 test: speed discord queue waits 2026-04-24 16:14:15 +01:00
lsdsjy
7d1891e6e6 feat(deepseek): support v4 models
Add DeepSeek V4 Flash/Pro support, update Pi packages to 0.70.2, and handle disabled thinking/None by stripping replayed reasoning content.
2026-04-24 16:09:36 +01:00
Peter Steinberger
4f4288e3b5 test: speed zalo polling waits 2026-04-24 16:07:53 +01:00
Peter Steinberger
50667db297 test: speed matrix verification waits 2026-04-24 16:04:51 +01:00
wangshu94
1ff07245f3 fix(gateway): surface chat.send lifecycle errors to clients (#69747)
Merged via squash.

Prepared head SHA: 75b403b2de
Co-authored-by: wangshu94 <53429538+wangshu94@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-24 22:59:47 +08:00
Peter Steinberger
7130e56f87 ci: avoid scarce runners for node fanout 2026-04-24 15:54:44 +01:00
Peter Steinberger
a3ae336c51 perf: slim browser test imports 2026-04-24 15:42:52 +01:00
Peter Steinberger
d3d9b5738f docs: clarify live plugin runtime reloads 2026-04-24 15:38:56 +01:00
Peter Steinberger
5ca6b3568c perf: slim whatsapp test imports 2026-04-24 15:27:52 +01:00
Peter Steinberger
34896839ba perf: slim irc inbound imports 2026-04-24 15:12:37 +01:00
Peter Steinberger
a6aa151653 perf: avoid redundant device pairing writes 2026-04-24 15:01:38 +01:00
Peter Steinberger
8f64cd3e4d test: wait for ACPX runtime in MCP docker lane 2026-04-24 14:00:20 +01:00
Peter Steinberger
8866544ffe test: slim browser and msteams imports 2026-04-24 13:33:48 +01:00
Peter Steinberger
60f7a59f5e test: bridge xai test helper imports 2026-04-24 13:18:21 +01:00
Peter Steinberger
aa3a5f9ff7 test: narrow xai test helper imports 2026-04-24 13:07:35 +01:00
Peter Steinberger
55c45307d0 test: narrow matrix client runtime import 2026-04-24 13:04:45 +01:00
Peter Steinberger
577ff767fa test: extend Open WebUI docker startup wait 2026-04-24 13:02:40 +01:00
Peter Steinberger
608c08fc54 test: narrow slack inbound contract imports 2026-04-24 13:00:05 +01:00
Peter Steinberger
0783090da0 test: split slack client option imports 2026-04-24 12:58:28 +01:00
Peter Steinberger
04a54cf54e test: slim slack media imports 2026-04-24 12:56:16 +01:00
Peter Steinberger
6944d7025d test: narrow mattermost nested runtime barrel 2026-04-24 12:43:06 +01:00
Peter Steinberger
68b9ad4205 test: slim feishu monitor handler imports 2026-04-24 12:36:50 +01:00
Peter Steinberger
ebd7f19a3b test: avoid whatsapp setup jiti load 2026-04-24 12:26:48 +01:00
Peter Steinberger
11fa1d2dc7 test: mock secrets apply runtime preflight 2026-04-24 12:22:49 +01:00
Peter Steinberger
9faa9d33e6 test: mock web tools manifest lookup 2026-04-24 12:19:50 +01:00
Peter Steinberger
9b7f6250f4 test: bypass discord monitor barrel in tests 2026-04-24 12:13:44 +01:00
Peter Steinberger
2e2a134489 perf: lazy load bluebubbles catchup 2026-04-24 12:08:34 +01:00
Peter Steinberger
4514691300 test: narrow provider discovery test imports 2026-04-24 12:03:50 +01:00
Peter Steinberger
fcaf6a23dd test: retry Claude capacity failures in live backend 2026-04-24 12:00:39 +01:00
Peter Steinberger
9ece33c505 test: slim google oauth project discovery 2026-04-24 11:50:12 +01:00
Peter Steinberger
320d52a23e test: narrow oauth lock timeout coverage 2026-04-24 11:43:22 +01:00
Peter Steinberger
3814dc860b test: mock acp spawn config load 2026-04-24 11:35:56 +01:00
Peter Steinberger
f3c37a946c test: fold sandbox skill sync coverage 2026-04-24 11:30:49 +01:00
Peter Steinberger
daed93dd30 test: harden live docker aggregate flakes 2026-04-24 11:25:27 +01:00
Peter Steinberger
a8edf29bd0 test: slim pty fallback coverage 2026-04-24 11:19:31 +01:00
Peter Steinberger
01bc49c88c test: move pty cleanup coverage to adapter 2026-04-24 11:09:55 +01:00
cxy
4013c65853 fix(qqbot): enable qqbot plugin by default so runtime deps install be… (#71051)
* fix(qqbot): enable qqbot plugin by default so runtime deps install before QR-code setup

The qqbot plugin manifest was missing the enabledByDefault: true flag.
Without it, ensureBundledPluginRuntimeDeps treats qqbot as bundled-but-
disabled-by-default (isBundledPluginConfiguredForRuntimeDeps returns
false when no qqbot channel/account is configured yet), so
@tencent-connect/qqbot-connector is never installed into
dist/extensions/qqbot/node_modules on first launch.

This creates a chicken-and-egg failure for the QR-code binding flow:
finalize.ts dynamically imports @tencent-connect/qqbot-connector to run
qrConnect(), but the package isn't present yet because no account is
configured — binding is exactly the step that configures the first
account. Users hit:

  QQ Bot 绑定失败: Error [ERR_MODULE_NOT_FOUND]: Cannot find package
  '@tencent-connect/qqbot-connector' imported from
  .../dist/extensions/qqbot/channel-*.js

Adding enabledByDefault: true makes the host install qqbot's runtime
deps eagerly on first launch, mirroring the pattern already used by
mistral / groq / deepgram / amazon-bedrock-mantle and other bundled
plugins whose providers must be available before any channel config
exists. No code changes required; the existing runtime-deps install
pipeline handles everything once the gate is opened.

* fix(qqbot): changelog for enable-by-default fix (#71051) (thanks @cxyhhhhh)

---------

Co-authored-by: sliverp <870080352@qq.com>
2026-04-24 17:58:14 +08:00
Peter Steinberger
ed51963c47 test: slim pi auth discovery tests 2026-04-24 10:50:43 +01:00
Peter Steinberger
b453293349 test: isolate provider provenance aliases 2026-04-24 10:45:42 +01:00
Peter Steinberger
83370f0021 test: remove duplicate qianfan auth marker case 2026-04-24 10:37:49 +01:00
Peter Steinberger
d38ed0831d perf: slim sandbox registry tests 2026-04-24 10:33:50 +01:00
Frank Yang
934dd5b3a7 [codex] fix agent session-id routing (#70985)
Merged via squash.

Prepared head SHA: f092b0c5c8
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Co-authored-by: frankekn <4488090+frankekn@users.noreply.github.com>
Reviewed-by: @frankekn
2026-04-24 17:31:34 +08:00
Vincent Koc
0e7250f37b feat(diagnostics): emit model call events
Emit structured diagnostic events for embedded run and model-call lifecycle with trace context, duration, and safe error categories.
2026-04-24 02:17:07 -07:00
Peter Steinberger
e5f55dd024 docs: document Google realtime voice support 2026-04-24 10:14:55 +01:00
Peter Steinberger
6831579267 perf: skip provider plugin loading in extra param tests 2026-04-24 10:02:57 +01:00
Peter Steinberger
b7b66a6047 test: relax live cli backend wording 2026-04-24 09:51:48 +01:00
Peter Steinberger
56fe2aab9c fix: attach Google Meet realtime bridge 2026-04-24 09:41:33 +01:00
Peter Steinberger
b5e5f2cede feat(google): add realtime voice provider 2026-04-24 09:36:20 +01:00
EVA
c138368040 feat: add Codex harness extension seams
Co-authored-by: Eva <100yenadmin@users.noreply.github.com>
2026-04-24 09:32:27 +01:00
Peter Steinberger
d85dc46e37 perf: narrow telegram reply imports 2026-04-24 09:31:47 +01:00
Peter Steinberger
a79c40a789 test: harden docker live readiness 2026-04-24 09:28:59 +01:00
Peter Steinberger
f03252aaf9 fix: keep telegram dispatch eager 2026-04-24 09:17:33 +01:00
Vincent Koc
cead2ea4b1 feat(diagnostics): emit tool execution events
Emit structured diagnostic events for tool execution lifecycle, with trace context, safe parameter summaries, and non-message error metadata.
2026-04-24 01:16:13 -07:00
Peter Steinberger
447105a278 perf: slim telegram bot imports 2026-04-24 09:12:28 +01:00
Peter Steinberger
028b6c9b13 perf: trim sandbox context tests 2026-04-24 08:56:32 +01:00
EVA
40be5ad581 fix: harden GPT-5 runtime paths
Co-authored-by: EVA <100yenadmin@users.noreply.github.com>
2026-04-24 08:55:52 +01:00
Vincent Koc
4630ce3d9e fix(diagnostics): make otel service restart safe
Make diagnostics-otel startup restart-safe by tearing down stale SDK, log transport, and diagnostic-event listener handles before reinitializing or disabling the service. Adds regression coverage for repeated start and disabled restart paths.\n\nThanks @vincentkoc.
2026-04-24 00:53:04 -07:00
Peter Steinberger
cc92699ff7 fix: guard openai tts fetch 2026-04-24 08:50:35 +01:00
Peter Steinberger
6a61cb73c5 build: exclude docker test artifacts 2026-04-24 08:50:07 +01:00
Vincent Koc
a52b50ef3c docs(changelog): note plugin architecture source work 2026-04-24 00:48:44 -07:00
Peter Steinberger
0a3da5cd8a perf: slim auth profile test imports 2026-04-24 08:45:26 +01:00
Peter Steinberger
38caa6832d test: stagger docker aggregate starts 2026-04-24 08:38:41 +01:00
Peter Steinberger
665cc3d537 fix: guard openai tts fetch 2026-04-24 08:37:41 +01:00
Vincent Koc
c1b9aa7d96 fix(plugins): pin official external channel source (#70997) 2026-04-24 00:35:03 -07:00
Peter Steinberger
a437666a37 fix(browser): reject existing-session type timeouts 2026-04-24 08:29:25 +01:00
Peter Steinberger
aa21d4ea7e fix(browser): clarify existing-session timeout limits 2026-04-24 08:27:12 +01:00
Vincent Koc
1e8dc2389e feat(plugins): record local onboarding installs
Record onboarding plugin install source metadata for npm and local paths, while keeping local path install records portable and preserving uninstall cleanup for relative source paths.
2026-04-24 00:27:09 -07:00
Peter Steinberger
69196670b7 refactor: dedupe shared helpers 2026-04-24 08:26:37 +01:00
Peter Steinberger
661f11b947 test: align codex auth hint expectation 2026-04-24 08:25:07 +01:00
Vincent Koc
bcdacfa1b3 feat(diagnostics): carry trace context through hooks
Pass immutable diagnostic trace contexts through agent and tool hook surfaces, emit model usage with the run trace, and parent OTEL spans/logs from validated trace context without retained global state.\n\nThanks @vincentkoc.
2026-04-24 00:24:32 -07:00
Peter Steinberger
33c0cd1378 fix: improve codex model discovery 2026-04-24 08:17:01 +01:00
pashpashpash
81666e586a fix codex dynamic tool hooks (#70965) 2026-04-24 16:14:06 +09:00
Peter Steinberger
4e4aeacae4 perf: slim hot test imports 2026-04-24 08:13:51 +01:00
Peter Steinberger
50e36983bb fix: harden codex verbose tool progress (#70966) (thanks @jalehman) 2026-04-24 08:10:04 +01:00
Ayaan Zaidi
f353a61bab ci(release): use blacksmith docker cache for npm telegram 2026-04-24 12:36:50 +05:30
Ayaan Zaidi
e30837910b ci(release): set up buildx for npm telegram image 2026-04-24 12:33:42 +05:30
Ayaan Zaidi
512d3d2287 ci(release): prebuild npm telegram docker image 2026-04-24 12:29:54 +05:30
Peter Steinberger
28fc03c386 perf: slim reset model selection imports 2026-04-24 07:56:32 +01:00
Peter Steinberger
9f8b400630 perf: slim directive parse test imports 2026-04-24 07:50:46 +01:00
Ayaan Zaidi
a02a54ff13 ci(release): clarify npm telegram approval label 2026-04-24 12:20:14 +05:30
Peter Steinberger
5b3952e857 test: relax live tail readiness checks 2026-04-24 07:48:36 +01:00
Ayaan Zaidi
8ba22ca0dc ci(release): use release approval for npm telegram e2e 2026-04-24 12:15:09 +05:30
pashpashpash
41c5ffc5d5 Project Codex hook notifications into agent events (#70969)
* project codex hook notifications

* keep codex hook duration strict

* include thread scoped codex hook notifications
2026-04-24 15:43:03 +09:00
Josh Lehman
925d11d890 fix: match codex verbose tool logs to pi (#70966) 2026-04-23 23:42:09 -07:00
Vincent Koc
8fade9df27 feat(diagnostics): attach trace context to otel logs (#70961)
* feat(diagnostics): attach trace context to otel logs

* fix(diagnostics): satisfy trace flags lint
2026-04-23 23:40:42 -07:00
Vincent Koc
48b9452c07 docs(faq): tighten FAQ stub pointers and Related cards 2026-04-23 23:37:56 -07:00
Vincent Koc
bc195b8f53 docs(help): rewrite help index to match new tab structure, drop redundant troubleshooting H1 2026-04-23 23:36:49 -07:00
Ayaan Zaidi
972c7112a2 refactor(release): distill npm telegram docker runner 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
02d7215005 ci(release): gate npm telegram e2e by release team 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
ed6b487e20 ci(release): harden npm telegram beta e2e 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
5dd3c37fce test(release): address npm telegram e2e review 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
3d8e6a3aa3 test(release): avoid docker argv secret values 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
0baa8c1763 ci(release): add manual npm telegram beta e2e 2026-04-24 12:06:33 +05:30
Ayaan Zaidi
bd1b8448a5 test(release): support convex npm telegram credentials 2026-04-24 12:06:33 +05:30
Peter Steinberger
b7fba2100f docs: clarify private ws node setup 2026-04-24 07:32:29 +01:00
Peter Steinberger
f85806b6d7 fix: filter gateway node list locally 2026-04-24 07:32:28 +01:00
Vincent Koc
cb4fc58547 feat(plugins): move Bonjour discovery into bundled plugin
* fix(deps): detect constant dynamic imports in ownership audit

* feat(plugins): move bonjour discovery into bundled plugin

* test(plugins): remove moved bonjour core tests

* fix(plugins): harden bonjour disable and console restore

* fix(plugins): split gateway discovery ids from services

* fix(plugins): harden bonjour advertiser shutdown

* fix(plugins): clean up bonjour split lint
2026-04-23 23:29:51 -07:00
Peter Steinberger
564f820efa perf: reuse subagent spawn test module 2026-04-24 07:26:15 +01:00
Peter Steinberger
fa139b4fca fix(voice-call): handle Telnyx callback payloads 2026-04-24 07:25:44 +01:00
Peter Steinberger
ad0fcf9143 perf: tighten auto-reply command tests 2026-04-24 07:22:08 +01:00
Vincent Koc
37c37eecfb feat(plugins): expose install source facts
* feat(plugins): expose install source facts

* fix(plugins): normalize install integrity facts

* fix(plugins): guard install source string fields

* fix(plugins): keep install source facts additive
2026-04-23 23:21:43 -07:00
Peter Steinberger
b588b5a230 fix(channels): accept setup aliases for add 2026-04-24 07:20:45 +01:00
Patrick Erichsen
d29eaeafc1 fix(cli-runner): fire before_agent_reply on cron-triggered turns (#70950)
* test(cli-runner): RED — assert before_agent_reply fires on cron triggers

Mirrors src/agents/pi-embedded-runner/run.before-agent-reply-cron.test.ts
for the CLI runner. Asserts:

1. When trigger=cron and a before_agent_reply hook claims the turn
   (handled: true), runCliAgent must NOT invoke the codex subprocess and
   must return the hook's reply text in payloads[0].
2. When the hook claims without a reply body, the synthesized payload
   uses SILENT_REPLY_TOKEN.
3. Non-cron triggers do not invoke the hook (no behavior change for
   normal user/heartbeat traffic).
4. Without a registered hook, falls through to the CLI subprocess.

Currently fails (RED): tests 1 and 2 fail because runCliAgent never
fires before_agent_reply — the hook gate exists only in the embedded PI
runner (src/agents/pi-embedded-runner/run.ts:326). This is the
CLI-backed-agent dreaming gap reported in #70940 and identified in
PR #70737 review.

Next commit: implement the hook gate in runPreparedCliAgent (GREEN).

* fix(cli-runner): GREEN — fire before_agent_reply for cron-triggered turns

Mirrors the embedded PI runner gate from
src/agents/pi-embedded-runner/run.ts:326 so plugin-managed cron jobs
(notably memory-core dreaming) can short-circuit a CLI-backed agent
turn before the codex/claude/gemini subprocess is spawned.

Without this, configuring a default agent's model to a CLI backend
(codex-cli, claude-cli, gemini-cli, or any third-party
`registerCliBackend` provider) silently broke dreaming: the cron
sentinel was sent to the underlying LLM as a literal user prompt and
the dreaming hook never executed. See openclaw/openclaw#70940 for the
empirical repro (codex-cli observed sending the dream-token to GPT-5.5
with no `memory-core: dreaming promotion complete` line).

Also extracts `buildHandledReplyPayloads` locally; eventually that
should be unified with the embedded PI runner's helper, but that's a
mechanical refactor for a follow-up.

Closes #70940 once both this PR and #70737 land — this fix is only
useful if cron-driven dreaming exists, which is what #70737 introduces.

TDD trail:
- prior commit: RED test asserting the hook gate (4 cases)
- this commit: implementation that turns those tests green (4/4 pass).

Verified: pnpm test src/agents/cli-runner.before-agent-reply-cron.test.ts
4/4 passed; pnpm test src/agents/cli-runner 21/21 passed; lint clean
on touched files; pre-existing tsgo failure in
src/plugin-sdk/provider-tools.ts is unrelated to these changes.
2026-04-23 23:16:26 -07:00
Peter Steinberger
7d9172d5e0 perf: speed up slow extension tests 2026-04-24 07:13:46 +01:00
Peter Steinberger
bcea5e75eb test: harden Docker E2E readiness 2026-04-24 07:10:56 +01:00
Peter Steinberger
7ac35b4f69 perf: merge cron direct delivery tests 2026-04-24 06:54:36 +01:00
Vincent Koc
350d322180 fix(diagnostics): harden trace context parsing (#70955) 2026-04-23 22:47:54 -07:00
Peter Steinberger
bae7b54a85 fix(agents): detect codex cli auth in status
Fixes #70688.
Co-authored-by: Jon Brown <801241+jb510@users.noreply.github.com>
2026-04-24 06:47:28 +01:00
Peter Steinberger
a53fea3905 test: skip ACP marker probes without transcript 2026-04-24 06:42:28 +01:00
Peter Steinberger
c3138e372c chore: remove dead registry aliases 2026-04-24 06:41:49 +01:00
Peter Steinberger
bff212822c fix: restore models list registry fallback 2026-04-24 06:40:38 +01:00
Peter Steinberger
73288c20bd fix(channels): defer setup runtime deps until login 2026-04-24 06:40:25 +01:00
Peter Steinberger
6c509d8d4b docs: clarify codex plugin auto-enable boundary 2026-04-24 06:38:54 +01:00
Peter Steinberger
cc28989b4b test(config): cover codex plugin auto-enable boundaries 2026-04-24 06:38:54 +01:00
Peter Steinberger
4f4d2ef1df chore: remove dead compat barrels 2026-04-24 06:37:43 +01:00
Peter Steinberger
e94c0bf515 perf: trim control ui auth tests 2026-04-24 06:29:12 +01:00
Patrick Erichsen
aca92b2906 memory/dreaming: decouple managed cron from heartbeat (#70737)
* Revert "fix(memory/dreaming): surface blocked status when heartbeat is disabled for main (#69875)"

This reverts commit 529577e045.

Making way for the dreaming-vs-heartbeat decoupling from Josh's
josh/dreaming-isolated-cron-fix branch, which moves the managed dreaming
cron to isolated agent turns (sessionTarget: "isolated") so dreaming no
longer requires heartbeat to fire. Once the cron no longer rides the
heartbeat path, the blocked-reason observability has nothing left to
report — removing it cleanly here before the cherry-picks land.

* openclaw-3ba.1: move managed dreaming cron to isolated agent turns

* openclaw-46d: claim cron runs before embedded attempts

* openclaw-575: disable managed dreaming cron delivery

* openclaw-575: accept wrapped dreaming cron tokens

* openclaw-ccd: filter cron and wrapper transcript noise from dreaming corpus

* openclaw-cd9: filter archived, cron, and heartbeat transcript noise from dreaming corpus

* openclaw-cd9: suppress role-label reflection tags in rem dreaming

* openclaw-b49: stop narrative timeouts from blocking dreaming cron

* openclaw-b49: keep managed dreaming cron out of diary subagents

* openclaw-ff9: restore cron dream diary generation without serial waits

* openclaw-ff9: run dreaming narratives with lightweight isolated subagent lanes

* openclaw-ff9: detach cron dream diary generation from run completion

* openclaw-ff9: defer cron diary task startup until after cron completion

* doctor/cron: migrate stale managed dreaming jobs to isolated agent turns

After the dreaming cron moved off the heartbeat path to sessionTarget:
"isolated" + payload.kind: "agentTurn" (see the preceding memory-core
changes), users with existing ~/.openclaw/cron/jobs.json entries in the
old sessionTarget: "main" + payload.kind: "systemEvent" shape still
carry stale jobs until the gateway restart reconcile rewrites them.

Add a dreaming-specific cron migration to the existing
maybeRepairLegacyCronStore doctor path so "openclaw doctor" (and
"openclaw doctor --fix") rewrites those jobs without needing a gateway
restart. Match lives in a new doctor-cron-dreaming-payload-migration
helper alongside the existing legacy-delivery and store-migration files.

The matching uses the memory-core managed-job name and description tag
plus the short-term-promotion payload token. Constants are mirrored
from extensions/memory-core/src/dreaming.ts and commented so a future
rename in memory-core is a visible drift point here too.

* memory/dreaming: tighten cron-token match to known wrapper, not substring

The previous match relaxed the line check from 'trimmed line equals token'
to 'line contains token anywhere as a substring' to accept the
`[cron:<id>] <token>` wrapper that isolated-cron turns add. Substring
matching also let any user message embedding the token mid-sentence
trigger the dream-promotion hook, and was flagged by both Greptile and
Aisle on PR #70737.

Replace it with strip-the-known-prefix-then-exact-match: keep the
`[cron:<id>]` wrapper case working, reject every other variant. Add
focused unit coverage that the bare token, the wrapped token, and bare
multiline cases match while embedded / code-fenced / arbitrarily-wrapped
variants do not.

* memory/dreaming: drop assistant followup only on assistant-side signals

Per PR #70737 review (aisle-research-bot, Medium): the previous logic
suppressed the next assistant message whenever the prior user message
matched a 'generated prompt' pattern (`[cron:...]`,
`System (untrusted): ...`, heartbeat prompts, exec-completion events).
Real users can type those same patterns, which let a user exfiltrate
real assistant replies from the dreaming corpus by prefixing their own
prompt — the assistant's reply would be silently dropped.

Remove the cross-message coupling. Assistant-side machinery (silent
replies, system wrappers) is already dropped by sanitizeSessionText,
which is the right layer for that filter. Add an explicit assistant-side
HEARTBEAT_TOKEN check to keep the legitimate `HEARTBEAT_OK` ack drop
working without depending on the prior user message. Add a regression
test exercising the spoofing scenario.

* doctor/cron: assert mirrored dreaming constants stay in sync

Per PR #70737 review (greptile-apps): the doctor migration mirrors three
constants (MANAGED_DREAMING_CRON_NAME, MANAGED_DREAMING_CRON_TAG,
DREAMING_SYSTEM_EVENT_TEXT) from extensions/memory-core/src/dreaming.ts.
A future rename in either file would silently break the migration.

Add a vitest unit that reads both files and asserts the literals match.
Manually verified the assertion fires with a clear error when one side
diverges. Adds no runtime cost; sits in the regular test pipeline.

* fix(memory): stabilize dreaming CI checks

* memory/dreaming: skip eager narrative session cleanup when detached

Per PR #70737 review (chatgpt-codex-connector, P2): runDreamingSweepPhases
called deleteNarrativeSessionBestEffort synchronously right after each
phase. Once narrative generation moved to detached mode (queued via
queueMicrotask), the eager cleanup races the writer: the session is
deleted before the queued subagent run reads it, silently dropping cron
diary entries.

Skip the eager cleanup branch when params.detachNarratives is true.
generateAndAppendDreamNarrative still runs its own deleteSession in the
finally{} block, so the cleanup intent is preserved without the race.
Heartbeat-driven (non-detached) runs keep the original eager-cleanup
behavior.

* fix(plugin-sdk): restore heartbeat-summary re-export

Per PR #70737 review (chatgpt-codex-connector, P1): the revert of
PR #69875 dropped the `heartbeat-summary` re-export from
`openclaw/plugin-sdk/infra-runtime`. That subpath shipped publicly two
days earlier, so removing it is technically a breaking change to a
public SDK surface — third-party plugins importing
`isHeartbeatEnabledForAgent` / `resolveHeartbeatIntervalMs` from this
path would fail with no replacement contract introduced.

Restore the re-export. Costs nothing to keep; the helpers are already
public via `../infra/heartbeat-summary.ts`. SDK additions are by
default backwards-compatible (CLAUDE.md), so removing within days of
introduction violates that intent.

* changelog: note dreaming decoupling from heartbeat

Refs PR #70737.

---------

Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-04-23 22:23:19 -07:00
Peter Steinberger
acbceb8a76 docs(qa): record convex telegram live testing notes 2026-04-24 06:22:30 +01:00
Peter Steinberger
b0d2003fe6 docs: document Meet node command allowlist 2026-04-24 06:19:12 +01:00
Peter Steinberger
99d8f699aa fix: use absolute system profiler for Meet audio checks 2026-04-24 06:18:43 +01:00
Vincent Koc
0ad058a9cb feat(diagnostics): add trace context carrier (#70924) 2026-04-23 22:18:21 -07:00
Peter Steinberger
5f702b464b test: skip ACP bind probes without transcript 2026-04-24 06:12:46 +01:00
Peter Steinberger
a62a7f2945 test(channels): cover staged setup entry dependency loading 2026-04-24 06:10:07 +01:00
Peter Steinberger
d32fdcebc1 fix(channels): keep bundled setup entries dependency-light 2026-04-24 06:10:07 +01:00
Peter Steinberger
d91f6a05c6 docs(qa): note tmux op credential lookup 2026-04-24 06:09:52 +01:00
Peter Steinberger
9f4ef6162d test(gateway): trust codex guardian status 2026-04-24 06:07:36 +01:00
Peter Steinberger
d4e93e791b fix: persist private ws opt-in for node services 2026-04-24 06:07:22 +01:00
Peter Steinberger
171322644d fix: use openclaw temp root for telegram live preflight 2026-04-24 06:07:17 +01:00
Vincent Koc
799a42bd13 feat(plugins): expose activation plan reasons (#70943) 2026-04-23 22:06:07 -07:00
Peter Steinberger
b2840b93c8 test(gateway): harden codex live harness 2026-04-24 06:00:45 +01:00
Peter Steinberger
6f80082028 test: default live model concurrency 2026-04-24 05:57:57 +01:00
Peter Steinberger
0304d0ce4e test: stabilize gateway test helpers 2026-04-24 05:55:27 +01:00
Peter Steinberger
c45e4c3cf4 fix: pass Gemini trust flag 2026-04-24 05:55:27 +01:00
Peter Steinberger
1e83357abe test: harden live docker lanes 2026-04-24 05:55:27 +01:00
Peter Steinberger
01e4824fd3 test: parallelize docker aggregate lanes 2026-04-24 05:55:27 +01:00
Peter Steinberger
960f3b07b1 fix: refresh protocol models and cron test lint 2026-04-24 05:54:13 +01:00
Ayaan Zaidi
63653f51d8 test(qa): wait for lab abort marker content 2026-04-24 10:23:56 +05:30
Ayaan Zaidi
da129727c5 test(release): forward gemini key to npm telegram smoke 2026-04-24 10:23:56 +05:30
Ayaan Zaidi
864de4a2e9 test(qa): decouple mock telegram preflight auth 2026-04-24 10:23:56 +05:30
Ayaan Zaidi
f7157958de test(release): harden npm telegram smoke inputs 2026-04-24 10:23:56 +05:30
Ayaan Zaidi
9755c8a05f test(release): add npm telegram live smoke 2026-04-24 10:23:56 +05:30
Ayaan Zaidi
95f6697bd7 test(qa): support packaged gateway live lanes 2026-04-24 10:23:56 +05:30
Peter Steinberger
b98a6a46fb docs: raise live model sweep concurrency 2026-04-24 05:52:06 +01:00
Peter Steinberger
bfa6708c03 perf: narrow gateway runtime reset imports 2026-04-24 05:48:32 +01:00
Peter Steinberger
24bf56ce60 test: stabilize live model sweeps 2026-04-24 05:48:01 +01:00
Shakker
9d445f4d68 perf: speed up provider-filtered models list (#70632) (thanks @shakkernerd) 2026-04-24 05:46:25 +01:00
Shakker
a29233c9af test: fix gateway session lint 2026-04-24 05:46:25 +01:00
Shakker
da6c29b3d9 fix: bound unscoped provider discovery fallback 2026-04-24 05:46:25 +01:00
Shakker
d3fe591853 test: update models list static fast path expectation 2026-04-24 05:46:25 +01:00
Shakker
2e45218ae8 fix: keep live catalog providers on registry path 2026-04-24 05:46:25 +01:00
Shakker
9941393c7a fix: keep third party provider filters on registry path 2026-04-24 05:46:25 +01:00
Shakker
6f04eee2a1 fix: keep static provider entries out of live discovery 2026-04-24 05:46:25 +01:00
Shakker
4737a86071 fix: preserve provider filtered catalog correctness 2026-04-24 05:46:25 +01:00
Shakker
3254e961e9 refactor: expose bundled static provider catalogs 2026-04-24 05:46:25 +01:00
Shakker
29d0e930bb test: cover provider-filtered catalog fast path 2026-04-24 05:46:25 +01:00
Shakker
a50aef82ba perf: generalize provider-filtered catalog fast path 2026-04-24 05:46:25 +01:00
Vincent Koc
959dedb7cf docs(help): move help/scripts out of Testing group into Reference/Release and CI 2026-04-23 21:45:53 -07:00
Peter Steinberger
a903438707 perf: trim chat history limit fixture 2026-04-24 05:43:03 +01:00
Peter Steinberger
bfc9cb92c5 perf: bypass gateway server in cron validation tests 2026-04-24 05:40:47 +01:00
Peter Steinberger
22f23fa5ab perf: speed up gateway session tests 2026-04-24 05:38:06 +01:00
Peter Steinberger
cb2c36b049 fix: lock realtime talk instructions 2026-04-24 05:33:11 +01:00
Peter Steinberger
569290c36d feat: add Google Meet paired-node Chrome transport 2026-04-24 05:31:32 +01:00
Simone
098557623f fix(codex): require final approval decisions (#70751)
Require the Codex app-server bridge to wait for the final two-phase approval decision, while preserving the explicit no-route sentinel behavior.

Local gate on rebased branch: pnpm check:changed (20 files, 157 tests).

Thanks @Lucenx9.

Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
2026-04-24 05:30:59 +01:00
Simone
ed6094b301 fix(codex): sanitize approval preview text (#70569)
Harden Codex app-server approval preview text sanitization and truncation handling.

Thanks @Lucenx9.

Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
2026-04-24 05:23:29 +01:00
Peter Steinberger
d3dd61f2c5 perf: slim whatsapp test helper imports 2026-04-24 05:22:02 +01:00
Peter Steinberger
c971c58fc7 docs: clarify control ui talk status 2026-04-24 05:21:40 +01:00
Patrick Erichsen
4d7c4b3298 fix(memory-core): harden singleton cache recovery (#70925)
* fix memory cache singleton hardening

* refactor(memory-core): simplify singleton cache repair

Co-authored-by: BirdSong <88885494+fire-mirror@users.noreply.github.com>

---------

Co-authored-by: BirdSong <88885494+fire-mirror@users.noreply.github.com>
2026-04-23 21:21:04 -07:00
Peter Steinberger
84fc00afda perf: narrow whatsapp test imports 2026-04-24 05:19:36 +01:00
Peter Steinberger
a7c1376b20 fix(block-streaming): dedupe aborted final text 2026-04-24 05:18:45 +01:00
Vincent Koc
deb300d905 docs(nav): normalize sidebar group names to sentence case 2026-04-23 21:16:27 -07:00
Vincent Koc
1e24d95c54 docs(nav): sub-group macOS companion app pages (Setup / Runtime / Features), add qwen_modelstudio redirect 2026-04-23 21:15:17 -07:00
Vincent Koc
5aa5c4eff2 docs: tidy nav — macOS app sub-groups, drop qwen_modelstudio stub with redirect 2026-04-23 21:15:17 -07:00
Peter Steinberger
1a002b021f fix(codex): sanitize context-engine assemble warnings (#70809) (thanks @jalehman)
Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-04-24 05:13:23 +01:00
Peter Steinberger
c7ee5d8ecf perf: narrow inbound debounce sdk imports 2026-04-24 05:07:28 +01:00
Josh Lehman
51186d2725 feat(codex): run context-engine lifecycle in app-server harness (#70809)
Port the Codex app-server harness onto the context-engine lifecycle, add Codex context projection and compaction integration, and cover bootstrap/history/compaction fallback behavior.

Thanks @jalehman.
2026-04-24 05:06:45 +01:00
Peter Steinberger
ac063568d3 test: speed up live model sweeps 2026-04-24 05:05:28 +01:00
Vincent Koc
d717dbba51 Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix(whatsapp): canonicalize outbound media delivery (#69813)
2026-04-23 21:05:10 -07:00
Marcus Castro
18c98316f7 fix(whatsapp): canonicalize outbound media delivery (#69813)
* fix(whatsapp): normalize outbound media payloads

* fix(embedded-runner): preserve final media directives

* fix(auto-reply): keep non-streaming media on final path

* fix(auto-reply): warn when reply media is dropped

* fix(whatsapp): align auto-reply media delivery

* docs(changelog): note whatsapp media normalization
2026-04-24 01:04:28 -03:00
Vincent Koc
e2c3225636 Merge branch 'main' of https://github.com/openclaw/openclaw
* 'main' of https://github.com/openclaw/openclaw:
  fix(codex): resolve Windows app-server shims
2026-04-23 21:02:11 -07:00
Vincent Koc
7acaebeaac Revert "refactor(plugins): track activation compat hints"
This reverts commit b1d0c14d38.
2026-04-23 21:01:53 -07:00
Peter Steinberger
5b34082106 fix(codex): resolve Windows app-server shims 2026-04-24 05:01:46 +01:00
Vincent Koc
b1d0c14d38 refactor(plugins): track activation compat hints 2026-04-23 20:59:34 -07:00
Peter Steinberger
76a4c167f7 fix(slack): suppress verbose progress in rooms 2026-04-24 04:52:21 +01:00
Vincent Koc
c1dfaef0a0 docs(channels,gateway): split heavy sidebar groups (channels by region, gateway config by concern) 2026-04-23 20:50:25 -07:00
Vincent Koc
38bb4fefb9 docs(help): restructure Help tab sidebar and shorten FAQ / live-tests titles 2026-04-23 20:48:42 -07:00
Peter Steinberger
c21c8f3059 perf: narrow mattermost setup imports 2026-04-24 04:45:29 +01:00
Vincent Koc
627c19c5cb docs: add Related sections to remaining CLI, gateway API, and help pages 2026-04-23 20:41:35 -07:00
Peter Steinberger
53aac30f51 fix: bridge codex request user input 2026-04-24 04:40:47 +01:00
Peter Steinberger
eb6e1245ac perf: narrow zalo monitor imports 2026-04-24 04:40:42 +01:00
Vincent Koc
2fb9c7e3e5 docs: add Related sections to remaining platform, reference template, and misc pages 2026-04-23 20:40:15 -07:00
Vincent Koc
ed286078d6 docs(concepts): expand agent runtime opening with contract orientation 2026-04-23 20:36:40 -07:00
Patrick Erichsen
88fb6518c2 test(qa): validate Discord Convex credential payloads (#70910) 2026-04-23 20:35:54 -07:00
Vincent Koc
ae609e0249 docs(gateway): split configuration-reference by extracting tools and custom providers into config-tools 2026-04-23 20:34:46 -07:00
Dranbo Fieldston
977a4b24af fix: propagate timeoutMs to guarded dispatchers (local LLM 60s timeout) (#70831)
* fix: propagate timeoutMs to guarded dispatchers

Thread timeoutMs through the dispatcher creation chain so that
per-request (guarded) dispatchers honor the configured LLM timeout
instead of falling back to undici's hardcoded 60s bodyTimeout/headersTimeout.

Changes:
- undici-runtime.ts: createHttp1Agent/ProxyAgent/EnvHttpProxyAgent now accept
  timeoutMs and apply bodyTimeout/headersTimeout to dispatcher options
- ssrf.ts: createPinnedDispatcher accepts timeoutMs and passes it through
- fetch-guard.ts: fetchWithSsrFGuard reads timeout from params or falls back
  to global dispatcher bodyTimeout via getGlobalDispatcher()
- provider-transport-fetch.ts: buildGuardedModelFetch accepts optional
  timeoutMs and passes it to fetchWithSsrFGuard

The global dispatcher timeout (set by ensureGlobalUndiciStreamTimeouts)
is still applied to non-guarded requests. Guarded requests (used by LLM
transports) now also receive the timeout via a fallback to the global
dispatcher when not explicitly provided.

Fixes #70829

* fix: resolve fallback timeout via module-level bridge variable

Replace dead-code .options.bodyTimeout read in resolveDispatcherTimeoutMs
with a module-level bridge (_globalUndiciStreamTimeoutMs) set by
ensureGlobalUndiciStreamTimeouts. This avoids reliance on Undici's
non-public .options field and ensures guarded dispatchers inherit the
configured stream timeout instead of falling back to undici's 60s default.

Fixes Greptile P1 and Codex comments on PR #70831

* chore: re-run CI smoke tests

* test: cover guarded dispatcher timeout propagation

* test: align timeout bridge expectation

* docs: note guarded dispatcher timeout fix

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 04:34:11 +01:00
Vincent Koc
86fa8eeb68 docs: add Related to google-meet, fix Remote control title case 2026-04-23 20:33:01 -07:00
Vincent Koc
867714ca45 docs(help): split FAQ by extracting models, failover, and auth profiles Q&A into faq-models 2026-04-23 20:31:27 -07:00
Peter Steinberger
55389f4be2 perf: narrow msteams attachment imports 2026-04-24 04:29:12 +01:00
Vincent Koc
248baba54b docs(faq): fix stale openai fast-mode anchor 2026-04-23 20:29:01 -07:00
Peter Steinberger
88b53b7f0a docs: align talk silence defaults 2026-04-24 04:26:47 +01:00
Peter Steinberger
9ac52e0737 test: remove duplicate telegram retry tests 2026-04-24 04:26:31 +01:00
Vincent Koc
031c3b22de docs: clarify pruning behavior and setup TL;DR orientation 2026-04-23 20:26:26 -07:00
Peter Steinberger
a42bd94b21 ci: keep install smoke off pull requests 2026-04-24 04:24:58 +01:00
Peter Steinberger
b5779b992f fix(plugins): mirror SDK alias for staged sidecars 2026-04-24 04:24:58 +01:00
Peter Steinberger
e0d3256311 test(codex): cover app-server Docker flows 2026-04-24 04:24:08 +01:00
Peter Steinberger
69566e43cb feat(codex): add app-server protocol bridge 2026-04-24 04:24:08 +01:00
Peter Steinberger
553162c998 feat(agents): support Codex app-server runs 2026-04-24 04:24:07 +01:00
Peter Steinberger
5d0887574b feat(plugin-sdk): add conversation binding hooks 2026-04-24 04:24:07 +01:00
Vincent Koc
ffa5f4514f docs: unify See also/Related headings across remaining pages 2026-04-23 20:23:06 -07:00
Peter Steinberger
e93113db09 perf: lazy reply dispatch sdk runtime 2026-04-24 04:22:56 +01:00
Vincent Koc
34f7a93c04 docs(channels): rewrite passive-voice notes in msteams UPN and whatsapp fromMe bullets 2026-04-23 20:20:36 -07:00
Vincent Koc
3a5e535bed docs(help): split FAQ by extracting quick start and first-run Q&A into faq-first-run 2026-04-23 20:19:28 -07:00
Peter Steinberger
7d47183736 docs: fix config agent defaults link 2026-04-24 04:15:52 +01:00
Peter Steinberger
dbdf2863d6 docs: fix broken internal links 2026-04-24 04:13:20 +01:00
Vincent Koc
ed7033bc0a docs(providers): add Related sections to remaining provider pages 2026-04-23 20:12:50 -07:00
Vincent Koc
f051204bea docs(gateway): split configuration-reference by extracting channels cluster into config-channels 2026-04-23 20:12:09 -07:00
Vincent Koc
07cee914aa docs(gateway): split configuration-reference by extracting agent-defaults cluster into config-agents 2026-04-23 20:11:12 -07:00
Vincent Koc
72a8e4e5db docs(codex): clarify hook layering
Clarify Codex hook layering in the harness docs.
2026-04-23 20:09:46 -07:00
Peter Steinberger
60956ba6ac perf: narrow telegram bot test imports 2026-04-24 04:09:13 +01:00
Vincent Koc
8d1f98ef08 docs(gateway,platforms,cli): add Related sections to entry and reference pages 2026-04-23 20:08:26 -07:00
Vincent Koc
f0b6c65e3b docs(install,reference): add Related sections to pages missing them 2026-04-23 20:07:25 -07:00
Vincent Koc
b5120ab22a docs(platforms): link Bun warning to the Bun install page for context 2026-04-23 20:06:34 -07:00
Vincent Koc
78e4f5188a docs(install): move system requirements above the installer script section 2026-04-23 20:06:06 -07:00
Vincent Koc
1dfc84d0a4 docs(video-generation): convert provider notes table to accordion for scannability 2026-04-23 20:05:13 -07:00
Vincent Koc
9153598e65 docs(plugins): split architecture by extracting internals (load pipeline, runtime hooks, HTTP routes, schemas) 2026-04-23 20:03:22 -07:00
Peter Steinberger
47372a5567 fix: point minimax live docs test at split guide 2026-04-24 03:55:06 +01:00
Peter Steinberger
c6684af682 fix: guard openai realtime browser fetch 2026-04-24 03:50:43 +01:00
Patrick Erichsen
3a18801343 Add Discord live QA lane (#70792)
* Add Discord live QA lane

* Add Discord native command QA coverage
2026-04-23 19:48:37 -07:00
Peter Steinberger
1616510996 perf: narrow memory core test imports 2026-04-24 03:46:18 +01:00
Peter Steinberger
feb3cc70fb perf: narrow qa bus test imports 2026-04-24 03:44:56 +01:00
Peter Steinberger
85a2d1d05e fix: update realtime protocol swift models 2026-04-24 03:44:52 +01:00
Peter Steinberger
913f97c956 perf: lazy codex app server test imports 2026-04-24 03:42:00 +01:00
Vincent Koc
d3f6783b16 docs(tools): convert perplexity-search params to ParamField 2026-04-23 19:41:09 -07:00
Vincent Koc
5f19e288b1 docs(tools): convert search and web-fetch param tables to ParamField 2026-04-23 19:40:05 -07:00
Vincent Koc
f4b61e7277 docs(help): split testing by extracting live (network-touching) test suites 2026-04-23 19:38:59 -07:00
Vincent Koc
f4d73e1dcd docs(tools): split ACP agents by extracting acpx harness, plugin setup, and permissions 2026-04-23 19:36:19 -07:00
Vincent Koc
743b69d307 docs(tools): split browser docs by extracting control API and CLI reference 2026-04-23 19:34:50 -07:00
Vincent Koc
60d892d700 fix(reply): parse markdown image replies as media
* fix(reply): parse markdown image replies as media

* fix(reply): preserve inline markdown image captions

* fix(reply): harden markdown image parsing
2026-04-23 19:34:30 -07:00
Peter Steinberger
04066d246a feat: add browser realtime talk 2026-04-24 03:33:36 +01:00
Vincent Koc
d42069b11e fix(replay): preserve synthetic tool repair aliases
* fix(replay): preserve synthetic tool repair aliases

* test(replay): cover Bedrock repair ownership
2026-04-23 19:33:05 -07:00
Truffle
a958b6e723 fix(runner): surface provider errors to webchat (#70848)
Surface non-retryable assistant provider failures from the embedded runner instead of letting surface_error fall through to continue_normal.

- Preserve external abort and plain timeout fall-through paths.
- Preserve raw provider error diagnostics on surfaced FailoverError.
- Add regression coverage for billing/auth/rate-limit/null-reason/error fall-through cases.
- Update changelog.

Fixes #70124.
Thanks @truffle-dev.
2026-04-24 03:28:38 +01:00
Peter Steinberger
7c18b765e8 perf: reduce discord provider test imports 2026-04-24 03:27:31 +01:00
Peter Steinberger
dd1576204a docs(changelog): credit bundled runtime deps fix 2026-04-24 03:27:04 +01:00
Peter Steinberger
0daf51d645 fix(plugins): mirror sdk alias for external bundled deps 2026-04-24 03:27:04 +01:00
Peter Steinberger
49c95b31c0 test(e2e): run root-owned gateway logging as appuser 2026-04-24 03:27:04 +01:00
Peter Steinberger
b0244f613e fix(plugins): clean bundled runtime install stage 2026-04-24 03:27:04 +01:00
simonemacario
02a9dd0ddc fix(plugins): stage bundled-plugin runtime-dep install outside the plugin root
When a packaged bundled plugin's `pluginRoot` is used directly as the npm
execution cwd, `npm install <specs>` resolves the plugin's own
`package.json` as the project manifest and fails with
`EUNSUPPORTEDPROTOCOL: Unsupported URL Type "workspace:": workspace:*`
whenever that manifest declares a `workspace:` runtime dep (e.g.
`"@openclaw/plugin-sdk": "workspace:*"`). This takes out every plugin
with any runtime deps at gateway startup.

`ensureBundledPluginRuntimeDeps` already filters `workspace:` specs from
the CLI arguments, but npm's own resolver reads the cwd manifest
regardless, so the filter alone is not enough. The existing isolated
execution-root + `replaceNodeModulesDir` machinery handles this exact
problem for source-checkout + cache-hit installs. This change activates
the same staging path for the packaged case: when `installRoot ===
pluginRoot` and we are not in the source-checkout cache path, stage the
install inside `<pluginRoot>/.openclaw-install-stage` (which has a
minimal generated `package.json`) and move the produced `node_modules/`
back to the plugin root as before.

- Add regression test `stages plugin-root install when the plugin's own
  package.json declares workspace:* deps` covering the Docker scenario
  (mixed `workspace:*` + concrete runtime dep, e.g. anthropic-style
  `@openclaw/plugin-sdk` + `@anthropic-ai/sdk`).
- Update existing plugin-root-install expectations (`installs
  plugin-local runtime deps when one is missing`, `skips workspace-only
  runtime deps before npm install`, `installs deps that are only present
  in the package root`, `does not trust runtime deps that only resolve
  from the package root`, `does not treat sibling extension runtime deps
  as satisfying a plugin`) to assert the new `installExecutionRoot`.

Reported in #70844; same root cause as #70701, #70756, #70773, #70818,
#70839 which see the downstream "Cannot find package 'openclaw' from
plugin-runtime-deps" symptom because their
`resolveBundledRuntimeDependencyInstallRoot` resolves to an external
stage dir (clean manifest) so the install succeeds but the resulting
node_modules tree cannot satisfy the filtered-out workspace packages at
ESM import time.

## AI assistance

This PR was AI-assisted with Claude Code.

Testing degree: fully tested for the touched `bundled-runtime-deps`
install staging surface.

- `pnpm exec vitest run --config test/vitest/vitest.plugins.config.ts src/plugins/bundled-runtime-deps.test.ts` (31/31)
- `pnpm exec vitest run --config test/vitest/vitest.plugins.config.ts src/plugins/` (43/43 across 8 files)
- `pnpm exec tsgo --noEmit -p tsconfig.core.json`, `pnpm exec tsgo --noEmit -p tsconfig.core.test.json` (clean)
- `pnpm exec oxlint src/plugins/bundled-runtime-deps.ts src/plugins/bundled-runtime-deps.test.ts` (0 warnings, 0 errors)
- `node scripts/check-src-extension-import-boundary.mjs --json` and `node scripts/check-sdk-package-extension-import-boundary.mjs --json` (both `[]`)

I understand the code path changed here: packaged bundled plugins now
stage their runtime-dep install one directory below `pluginRoot` so npm
never reads the plugin's `workspace:*`-containing manifest during
install; after install completes, the produced `node_modules/` is moved
back to `pluginRoot` via the existing `replaceNodeModulesDir` helper.

Signed-off-by: Simone Macario <simone@sharly.ai>
2026-04-24 03:27:04 +01:00
Shakker
64ed439ad0 perf: avoid broad models list enumeration (#70883) (thanks @shakkernerd) 2026-04-24 03:25:26 +01:00
Shakker
c93f053f80 test: cover default models list registry narrowing 2026-04-24 03:25:26 +01:00
Shakker
a6a2516cd8 perf: narrow default models list registry loading 2026-04-24 03:25:26 +01:00
Peter Steinberger
f9b33b7d96 fix: disable bundled plugins during Parallels update 2026-04-24 03:23:14 +01:00
Peter Steinberger
a59d1bd46d perf: narrow slack test imports 2026-04-24 03:17:32 +01:00
Peter Steinberger
3aa3551491 test: cover OpenAI server compaction docs 2026-04-24 03:15:47 +01:00
Peter Steinberger
467f839198 docs(plugins): explain google meet audio install 2026-04-24 03:14:25 +01:00
Peter Steinberger
2af88fab6c docs: document local memory embedding provider 2026-04-24 03:11:22 +01:00
Matt Znoj Assist
e069d03945 fix(memory-core): declare local memoryEmbeddingProviders contract (#70873)
Fix standalone memory CLI resolution for the built-in local embedding provider by declaring the memory-core capability contract.\n\nFixes #70836.\nThanks @mattznojassist.
2026-04-24 03:09:49 +01:00
Peter Steinberger
272bd59e7a docs(plugins): clarify google meet quick start 2026-04-24 03:05:42 +01:00
Peter Steinberger
0c9659b70c feat(plugins): simplify google meet realtime defaults 2026-04-24 03:03:21 +01:00
Peter Steinberger
28299a94ba fix: escape Parallels config scrub script 2026-04-24 03:02:12 +01:00
Peter Steinberger
e41298f501 docs(plugins): expand google meet realtime consult docs 2026-04-24 02:56:25 +01:00
Peter Steinberger
e314190403 feat(plugins): give google meet realtime agent consult 2026-04-24 02:55:43 +01:00
Peter Steinberger
3361593442 perf: reduce feishu monitor import drag 2026-04-24 02:55:09 +01:00
Peter Steinberger
68e2d6f088 fix: use node for Parallels config scrub 2026-04-24 02:50:42 +01:00
Peter Steinberger
903308dbf2 fix: stabilize qa lab mock suite 2026-04-24 02:46:33 +01:00
Peter Steinberger
2779020cbe perf: lazy load browser test server 2026-04-24 02:45:25 +01:00
Peter Steinberger
86f69ba5a0 fix: preserve gateway image refs for text-only models 2026-04-24 02:40:10 +01:00
Peter Steinberger
92a42413df perf: lazy load discord inbound runtimes 2026-04-24 02:36:36 +01:00
Peter Steinberger
1a8a6f8fba feat(ui): steer queued chat messages 2026-04-24 02:35:40 +01:00
Shakker
7dc1aeebbf refactor: split models list row sources (#70867) (thanks @shakkernerd) 2026-04-24 02:34:36 +01:00
Shakker
a606838b4b refactor: plan models list registry loading 2026-04-24 02:34:36 +01:00
Shakker
0af56c8ba6 refactor: split models list row sources 2026-04-24 02:34:36 +01:00
Peter Steinberger
07cb18ca04 fix: scrub future plugin entries in Parallels update smoke 2026-04-24 02:33:21 +01:00
Peter Steinberger
794437a730 ci: keep full install smoke off merge pushes 2026-04-24 02:31:36 +01:00
Peter Steinberger
754acc4478 perf: reduce telegram test import drag 2026-04-24 02:28:38 +01:00
Peter Steinberger
d268c850e6 fix: honor explicit media image model routing 2026-04-24 02:21:30 +01:00
Vincent Koc
c0a7b6a510 fix(plugins): align provider auth metadata 2026-04-23 18:16:20 -07:00
Peter Steinberger
8129ac0f26 docs: add Google Meet changelog entry 2026-04-24 02:15:53 +01:00
Peter Steinberger
e63b16cf46 refactor: centralize realtime voice resolution 2026-04-24 02:15:53 +01:00
Peter Steinberger
09a79bf499 refactor: share realtime voice bridge sessions 2026-04-24 02:15:53 +01:00
Peter Steinberger
15a82d4536 refactor: share provider selection runtime helper 2026-04-24 02:15:53 +01:00
Peter Steinberger
051c543bcb fix: guard Google Meet API fetches 2026-04-24 02:15:53 +01:00
Peter Steinberger
59a8afe6fa feat: add Google Meet participant plugin 2026-04-24 02:15:53 +01:00
Peter Steinberger
e0072ef91a chore: bump version to 2026.4.24 2026-04-24 02:13:50 +01:00
Peter Steinberger
b2cface9d5 perf: consolidate browser test entrypoints 2026-04-24 02:08:38 +01:00
Peter Steinberger
27b8aa1ddf perf: consolidate extension test entrypoints 2026-04-24 02:03:00 +01:00
Shakker
c42ae0afd8 docs: update changelog for models list 2026-04-24 02:01:58 +01:00
Shakker
19f9b69586 fix: include configured provider rows in all models list 2026-04-24 02:01:58 +01:00
Shakker
d289e400d5 fix: keep model catalog reads read-only 2026-04-24 02:01:58 +01:00
Shakker
097a81fbe7 docs: document read-only models list 2026-04-24 02:01:58 +01:00
Shakker
dcc180f14f test: cover read-only models list 2026-04-24 02:01:58 +01:00
Shakker
c7af4dcb31 fix: make models list read-only 2026-04-24 02:01:58 +01:00
Peter Steinberger
93e95a2057 perf: speed up cli prepare tests 2026-04-24 01:55:02 +01:00
Peter Steinberger
b164bb3717 refactor: centralize realtime voice resolution 2026-04-24 01:50:43 +01:00
Peter Steinberger
57e139100b refactor: share realtime voice bridge sessions 2026-04-24 01:50:43 +01:00
Peter Steinberger
958afeb397 refactor: share provider selection runtime helper 2026-04-24 01:50:43 +01:00
Peter Steinberger
3caaba79bc ci: keep installer smoke dependencies installed 2026-04-24 01:50:43 +01:00
Peter Steinberger
d1ea58fdbf ci: limit bun install smoke to release gates 2026-04-24 01:50:42 +01:00
Peter Steinberger
3a2f0e7a1a ci: split install smoke fast path 2026-04-24 01:50:42 +01:00
Peter Steinberger
4ca5ef694f test: restore split docs CI parity 2026-04-24 01:50:42 +01:00
Peter Steinberger
8e87768419 ci: run telegram extension-fast with forks 2026-04-24 01:50:42 +01:00
Peter Steinberger
b22bf36bc4 ci: throttle telegram extension-fast tests 2026-04-24 01:50:42 +01:00
Peter Steinberger
7c19c31144 feat: support DTMF for voice-call 2026-04-24 01:50:42 +01:00
Peter Steinberger
79066f5cab fix(openai): synthesize codex gpt-5.5 oauth model 2026-04-24 01:49:00 +01:00
Peter Steinberger
cec3482175 fix: support codex app-server image understanding 2026-04-24 01:43:30 +01:00
Peter Steinberger
df58839a59 perf: fold slack http route test 2026-04-24 01:43:04 +01:00
Peter Steinberger
382952a9e1 docs: mark auto-response non-blocking 2026-04-24 01:42:14 +01:00
Gabriel Kripalani
0f026addaa feat: add OpenRouter image generation (#67668)
Adds OpenRouter image generation support for image_generate. Fixes #55066. Thanks @notamicrodose.
2026-04-24 01:39:19 +01:00
Peter Steinberger
3c5ee63c66 perf: consolidate feishu lifecycle test entry 2026-04-24 01:33:24 +01:00
Peter Steinberger
a2221d6b47 test: extend changed-check watchdog 2026-04-24 01:31:32 +01:00
Peter Steinberger
d4d307e07a test: cover OpenAI GPT xhigh reasoning 2026-04-24 01:30:44 +01:00
Peter Steinberger
f04a3dced0 build: update Pi model dependencies 2026-04-24 01:24:46 +01:00
Peter Steinberger
7e16e3d077 perf: narrow slack monitor imports 2026-04-24 01:09:28 +01:00
Peter Steinberger
716a3a5865 fix: honor Google image private-network opt-in 2026-04-24 01:04:13 +01:00
Peter Steinberger
cc295fb8c9 perf: dedupe telegram dispatch tests 2026-04-24 00:59:44 +01:00
Peter Steinberger
37c250695b perf: mock vllm provider setup contract 2026-04-24 00:52:53 +01:00
Peter Steinberger
b312e2e617 perf: split slack reply action constants 2026-04-24 00:47:52 +01:00
Peter Steinberger
cd8822cc5f fix: preserve OpenAI-compatible image parts 2026-04-24 00:45:42 +01:00
Peter Steinberger
178a314a4c fix: restore OpenRouter vision prompts 2026-04-24 00:42:45 +01:00
Peter Steinberger
d16b879334 fix: allow private OpenAI image endpoints 2026-04-24 00:36:00 +01:00
Peter Steinberger
5be5233250 perf: narrow slack command imports 2026-04-24 00:35:52 +01:00
Peter Steinberger
a3aa13df9b fix: prevent embedded runs from lowering undici timeouts 2026-04-24 00:34:47 +01:00
Patrick Erichsen
ef88cabe39 fix(control ui): accept paired device token for assistant media auth (#70741)
* fix control ui assistant media auth

* test control ui device token read routes

* defer assistant attachment blob downloads

* fix grouped render rebase merge

* evict stale assistant attachment blob urls

* fix assistant media device token query auth
2026-04-23 16:31:11 -07:00
Peter Steinberger
d3997bcf7a perf: narrow slack prepare ack import 2026-04-24 00:30:30 +01:00
Peter Steinberger
f7c4d7a5f0 ci: throttle docs agent workflow 2026-04-24 00:27:01 +01:00
Peter Steinberger
1e24bee879 perf: slim telegram target normalization import 2026-04-24 00:24:56 +01:00
Peter Steinberger
697fc38d1a perf: remove telegram dispatch polling waits 2026-04-24 00:21:12 +01:00
Peter Steinberger
db17b8cc4a docs: clarify landpr docs CI wait scope 2026-04-24 00:18:04 +01:00
Otto Deng
de3f3b8f93 feat(openai): pass image output options (#70503)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Otto Deng <ottodeng@users.noreply.github.com>
2026-04-24 00:17:12 +01:00
Peter Steinberger
b9a0795761 fix: route slack media auth fetch through runtime 2026-04-24 00:13:37 +01:00
Peter Steinberger
6f139dee2e perf: trim msteams authz graph mock 2026-04-24 00:09:16 +01:00
Peter Steinberger
0ad82bbbd1 chore(plugin-sdk): update API baseline 2026-04-24 00:05:38 +01:00
Peter Steinberger
f0a7a85e7a feat(agents): add generation tool timeouts 2026-04-24 00:05:38 +01:00
Peter Steinberger
bd49117a50 perf: slim msteams hot test imports 2026-04-24 00:04:48 +01:00
Tak Hoffman
07049c8eba fix(models): support Codex model add metadata (#70820) 2026-04-23 18:02:04 -05:00
Peter Steinberger
8549ddce81 docs: mark background workflows non-blocking 2026-04-23 23:59:47 +01:00
Peter Steinberger
9cc67fecaf docs(openai): clarify image generation oauth auth 2026-04-23 23:59:10 +01:00
Vincent Koc
3ce326168a docs(plugins): split SDK overview by moving subpath catalog into sdk-subpaths 2026-04-23 15:57:39 -07:00
Vincent Koc
0054818772 docs(tools): split exec-approvals into core + advanced (safe bins, forwarding, native delivery) 2026-04-23 15:56:08 -07:00
Peter Steinberger
e28fca2e11 chore: separate commit formatting from changed gate 2026-04-23 23:55:52 +01:00
Peter Steinberger
d8eb5ffef0 docs: fix typebox rpc link 2026-04-23 23:51:50 +01:00
Vincent Koc
c843c5b4ac docs: tighten passive voice and hedging on context-engine, xai, anthropic, building-plugins 2026-04-23 15:50:43 -07:00
Vincent Koc
c72329a1bb docs(pdf): convert Input reference to ParamField 2026-04-23 15:49:33 -07:00
Peter Steinberger
14c4143723 docs: clarify OpenAI GPT-5.5 auth routes 2026-04-23 23:49:17 +01:00
Vincent Koc
367b9721b6 docs(concepts,automation,plugins): add Related sections to pages missing them 2026-04-23 15:48:46 -07:00
Peter Steinberger
6259f6addc fix: harden provider and gateway test seams 2026-04-23 23:48:04 +01:00
Peter Steinberger
0999fec19b perf: slim slack media test imports 2026-04-23 23:48:02 +01:00
Vincent Koc
789e71cdb8 docs: remove H1 on pages where frontmatter + summary already cover the parenthetical 2026-04-23 15:47:48 -07:00
Vincent Koc
41448da417 docs: gloss agentDir, BOOT.md, and ambiguous dashboard pronoun 2026-04-23 15:45:29 -07:00
Vincent Koc
ac76c5aba7 docs(tools): convert exec and image-generation params to ParamField 2026-04-23 15:44:41 -07:00
Vincent Koc
d71518b1eb docs(channels,nodes): add Related sections to pages missing them 2026-04-23 15:43:47 -07:00
Vincent Koc
ba55448163 docs(providers): standardize models-section heading to Built-in catalog 2026-04-23 15:42:56 -07:00
Vincent Koc
6667f66fd8 docs(tools): add Related sections and unify See also to Related 2026-04-23 15:41:56 -07:00
Vincent Koc
1daa552d5f refactor(qr): share PNG data URL helpers (#70784) 2026-04-23 15:41:45 -07:00
Peter Steinberger
707e13f966 perf: slim vllm discovery contract test 2026-04-23 23:39:59 +01:00
Peter Steinberger
c2cf3c49d3 fix(openai): harden image auth fallback
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-23 23:38:04 +01:00
openclaw-docs-agent[bot]
539083811e docs: refresh documentation 2026-04-23 22:36:56 +00:00
Peter Steinberger
28484c71bb perf: trim telegram dispatch test imports 2026-04-23 23:29:20 +01:00
Peter Steinberger
dfe75db09d fix(discord): surface final reply permission context 2026-04-23 23:28:16 +01:00
Peter Steinberger
5d3aba2052 fix: preserve codex raw assistant replies 2026-04-23 23:22:31 +01:00
Peter Steinberger
7ec48b24a3 perf: inline browser ws decoder 2026-04-23 23:20:27 +01:00
Peter Steinberger
467fcb1791 test(openai): add docker image auth e2e 2026-04-23 23:13:19 +01:00
Peter Steinberger
f523bbfcd1 fix: align claude cli permissions with exec policy
Derive Claude CLI bypass mode from OpenClaw exec YOLO policy, preserve raw Claude permission-mode overrides, update docs/changelog, and cover global/per-agent policy behavior.
2026-04-23 23:11:34 +01:00
Peter Steinberger
999caf530b perf: slim browser test imports 2026-04-23 23:09:39 +01:00
openclaw-docs-agent[bot]
452a1b6341 docs: refresh documentation 2026-04-23 22:08:58 +00:00
Peter Steinberger
ededff4bc3 fix(memory): recreate stale qmd collections 2026-04-23 23:00:55 +01:00
Peter Steinberger
38f157a148 fix(openai): prefer configured Codex OAuth for images 2026-04-23 22:49:37 +01:00
Peter Steinberger
68cb054d20 perf: slim telegram sticker tests 2026-04-23 22:48:47 +01:00
Devin Robison
36c4a372a0 fix(webhooks): reload route secrets per request (#70727)
* fix(webhooks): reload route secrets per request

* docs(changelog): note webhook secret reload fix
2026-04-23 15:48:10 -06:00
Peter Steinberger
e64da8bde0 ci: rebase test performance agent updates 2026-04-23 22:46:38 +01:00
openclaw-docs-agent[bot]
58dc22c099 docs: refresh documentation 2026-04-23 21:43:52 +00:00
Peter Steinberger
9632283d5d test: update browser changed-run expectation 2026-04-23 22:35:33 +01:00
Vincent Koc
f718ba6601 fix(agents): preserve Codex model capacity guidance 2026-04-23 14:29:34 -07:00
Peter Steinberger
f0300253c1 fix: add agent hook history helpers 2026-04-23 22:29:26 +01:00
Vincent Koc
51f9f94cc3 fix(hooks): harden cli transcript loading (#70786) 2026-04-23 14:25:27 -07:00
Devin Robison
bceda6089a fix(gateway): fail closed on runtime config edits (#70726)
* fix(gateway): fail closed on runtime config edits

* changelog + telegram topic requireMention depth

Append a user-facing Unreleased/Fixes entry describing the fail-closed
gateway config-mutation allowlist, and extend the allowlist so Telegram
topic-level paths like
channels.telegram.groups.<group>.topics.<topic>.requireMention stay
agent-tunable instead of being rejected as protected after this change.
2026-04-23 15:23:44 -06:00
Peter Steinberger
02a8c13501 fix(codex): stop materializing auth bridges 2026-04-23 22:23:21 +01:00
Peter Steinberger
908335025f test: route browser changed tests to browser lane 2026-04-23 22:22:49 +01:00
Peter Steinberger
34c14843af perf: avoid browser text runtime import 2026-04-23 22:22:49 +01:00
Peter Steinberger
096d2688b7 test: fix openai image auth mock typing 2026-04-23 22:22:49 +01:00
aalekh-sarvam
d40dd9088e feat(memory): configurable local embedding contextSize (default 4096) (#70544)
node-llama-cpp defaults contextSize to "auto", which on large embedding
models like Qwen3-Embedding-8B (trained context 40,960) inflates gateway
VRAM from ~8.8 GB to ~32 GB and causes OOM on single-GPU hosts that share
the gateway with an LLM runtime.

Expose memorySearch.local.contextSize in openclaw.json (number | "auto"),
default to 4096 which comfortably covers typical memory-search chunks
(128–512 tokens) while keeping non-weight VRAM bounded.

Closes #69667.
2026-04-23 14:21:53 -07:00
Peter Steinberger
88b3fa14f0 test(openai): type image auth readiness mock 2026-04-23 22:19:13 +01:00
Peter Steinberger
5867207521 docs: balance skill descriptions 2026-04-23 22:18:56 +01:00
Peter Steinberger
2f14461976 test(openai): cover automatic image auth readiness 2026-04-23 22:14:55 +01:00
Peter Steinberger
c952379419 perf: split feishu lifecycle tests 2026-04-23 22:12:27 +01:00
Peter Steinberger
58bde71908 fix: collapse qmd startup memory log 2026-04-23 22:12:01 +01:00
Peter Steinberger
f3aaafbd70 ci: use latest stable install smoke baseline 2026-04-23 22:11:53 +01:00
Olabode Felix Akinyemi
b686f56b23 fix(ui): add aria-label to STT button and aria-expanded to pinned toggle (#70593)
- Voice input button had title= but no aria-label, so screen readers
  announced it without context. Add aria-label mirroring the title,
  toggling between "Voice input" and "Stop recording".
- Pinned messages toggle lacked aria-expanded, so screen readers could
  not announce the collapsed/expanded state of the section.

Co-authored-by: akinshaywai <akinshaywai@users.noreply.github.com>
2026-04-23 14:10:59 -07:00
cathywzeng
5a97c0d5fd fix(ui): add position: relative; z-index: 1 to .dreams-diary__daychips (#70705)
Fix synthesis tab button being clipped/hidden at certain viewport zoom levels.

Co-authored-by: cathz <14934105@qq.com>
2026-04-23 14:10:07 -07:00
Vincent Koc
d4f2edbe70 docs(changelog): note OpenAI capacity error copy 2026-04-23 14:07:01 -07:00
Peter Steinberger
ddcc39de91 fix(openai): reuse Codex OAuth for OpenAI images 2026-04-23 22:06:36 +01:00
Vincent Koc
f1ad5e27e0 fix(agents): surface OpenAI model capacity errors 2026-04-23 14:04:35 -07:00
openclaw-docs-agent[bot]
76276b876d docs: refresh documentation 2026-04-23 21:04:33 +00:00
EVA
137dbc71f0 feat: expose harness selection decisions (#70760)
Codex harness selection now keeps the decision helper internal, logs debug-only selection reasons and candidates, and documents `/status` as the primary user-facing signal.

Thanks @100yenadmin.

Co-authored-by: Eva <eva@100yen.org>
2026-04-23 21:57:09 +01:00
Peter Steinberger
235e17a08f docs: update config baseline 2026-04-23 21:55:36 +01:00
Peter Steinberger
10202f9279 fix(codex): approve bundled MCP loopback tools 2026-04-23 21:55:36 +01:00
Peter Steinberger
5314042990 fix(gateway): normalize MCP object schemas 2026-04-23 21:55:36 +01:00
Peter Steinberger
61c25704e6 fix: harden realtime voice setup (#70764) 2026-04-23 21:54:50 +01:00
Peter Steinberger
11e95a49d0 test: name contract vitest projects 2026-04-23 21:54:05 +01:00
Peter Steinberger
e1f5494636 ci: fix test performance agent run lookup 2026-04-23 21:52:31 +01:00
Devin Robison
873dce178d fix(gateway): block webchat session compaction mutations (#70716)
* fix(gateway): block webchat session compaction mutations

* docs(changelog): note webchat compaction guard (#70716)
2026-04-23 14:50:35 -06:00
Peter Steinberger
8af3d91668 docs(openai): clarify codex oauth image generation 2026-04-23 21:47:33 +01:00
Peter Steinberger
59cffb43f7 perf: avoid broad testing barrel in moonshot test 2026-04-23 21:44:17 +01:00
Peter Steinberger
d9aacbd3f9 ci: skip duplicate npm global install smoke 2026-04-23 21:43:06 +01:00
Peter Steinberger
a5ea24757c fix: enforce silent group replies after reactions 2026-04-23 21:42:17 +01:00
Peter Steinberger
e66a08658a perf: stub unused msteams handlers in invoke tests 2026-04-23 21:41:48 +01:00
Peter Steinberger
3fbe191ecc perf: narrow slack tool result test import 2026-04-23 21:38:30 +01:00
Peter Steinberger
c84a2f5244 feat(openai): add codex oauth image generation 2026-04-23 21:34:24 +01:00
Peter Steinberger
7ce36b4d12 ci: isolate non-root install smoke cache 2026-04-23 21:31:13 +01:00
Peter Steinberger
8b9e46a099 perf: slim mattermost helper imports 2026-04-23 21:29:35 +01:00
Peter Steinberger
f5042adf27 feat: add forked subagent context 2026-04-23 21:28:58 +01:00
Peter Steinberger
abedf9c1f4 fix(acpx): remove codex auth file fallback 2026-04-23 21:26:46 +01:00
Peter Steinberger
fc39f10130 docs(changelog): note removed Codex Spark model 2026-04-23 21:21:12 +01:00
Peter Steinberger
78fe353995 ci: harden install smoke npm cache cleanup 2026-04-23 21:19:20 +01:00
Vincent Koc
c5c163d078 docs: standardize frontmatter field order (summary before title) 2026-04-23 13:18:17 -07:00
Peter Steinberger
79112f207d ci: keep test performance agent focused on failures 2026-04-23 21:18:02 +01:00
Peter Steinberger
bb63f3c26b docs: document embedded harness status indicator 2026-04-23 21:17:20 +01:00
Peter Steinberger
1ea02db8a3 perf: skip browser routes in auth tests 2026-04-23 21:17:15 +01:00
Vincent Koc
82a847f3b4 docs(providers): standardize Related card titles, config-reference links, and Advanced heading 2026-04-23 13:16:53 -07:00
Peter Steinberger
f6336c5521 fix(openai): retire removed Codex Spark model 2026-04-23 21:16:46 +01:00
Vincent Koc
2777b089b5 docs: normalize frontmatter titles to sentence case 2026-04-23 13:15:17 -07:00
Peter Steinberger
831d6c3bbe docs: fix msteams federated auth link 2026-04-23 21:12:00 +01:00
Vincent Koc
4a2cd533ac docs: remove duplicate H1 where frontmatter title already sets it 2026-04-23 13:11:14 -07:00
Vincent Koc
219a11d2bd docs: fix googlechat entity and dedup gateway multiple-gateways section 2026-04-23 13:08:13 -07:00
Vincent Koc
0905e5f7b6 docs(channels): msteams - drop duplicate minimal-setup block, cardify related, accordion env vars, remove H1 and dante quote 2026-04-23 13:07:23 -07:00
Peter Steinberger
8407c60824 perf: slim browser tab tests 2026-04-23 21:07:11 +01:00
Vincent Koc
ea25d7ed5b fix(qr): replace qrcode-terminal with qrcode-tui
Replace legacy qrcode-terminal usage with shared qrcode-tui media helpers, bound QR PNG rendering options, and raise bundled plugin host floors for the new SDK runtime surface.
2026-04-23 13:06:14 -07:00
Peter Steinberger
6f74763f1d perf: slim msteams store imports 2026-04-23 21:04:40 +01:00
Peter Steinberger
058e6f588a fix(openai): align Codex fallback with GPT-5.5 2026-04-23 21:03:26 +01:00
Peter Steinberger
956350bb9c ci: share npm cache in install smoke 2026-04-23 20:57:31 +01:00
Vincent Koc
f02fcba21f fix(test): throttle local vitest under memory pressure 2026-04-23 12:56:28 -07:00
Peter Steinberger
629ed9f702 ci: run test performance agent on hosted ubuntu 2026-04-23 20:51:40 +01:00
Peter Steinberger
648422a6c1 fix(openai): send image edits as multipart uploads (#70657) 2026-04-23 20:48:55 +01:00
Peter Steinberger
ff56a9d41b test(openai): prefer canonical GPT refs 2026-04-23 20:47:39 +01:00
Peter Steinberger
384eb6bc66 feat(openai): use canonical GPT refs for Codex OAuth 2026-04-23 20:47:38 +01:00
Peter Steinberger
a8173276bf docs(openai): canonicalize GPT model refs 2026-04-23 20:47:38 +01:00
Peter Steinberger
17830983ce perf: slim feishu debounce test imports 2026-04-23 20:46:27 +01:00
Peter Steinberger
6471e0cdce ci: isolate manual install smoke runs 2026-04-23 20:44:11 +01:00
Peter Steinberger
010b13e6e9 test: update lint suppression allowlist 2026-04-23 20:43:42 +01:00
Peter Steinberger
6586cfa6f5 perf: avoid heavy slack provider chunk import 2026-04-23 20:42:24 +01:00
Peter Steinberger
360cb3dbf1 ci: add test performance agent 2026-04-23 20:40:52 +01:00
Peter Steinberger
6fc8913223 refactor(auto-reply): extract effective reply route resolution 2026-04-23 20:40:27 +01:00
Peter Steinberger
72b0e3d033 ci: run install smoke on manual dispatch 2026-04-23 20:40:14 +01:00
Vincent Koc
5930292524 fix(format): cap oxfmt threads 2026-04-23 12:36:46 -07:00
Peter Steinberger
fd581b849d perf: slim slack provider helper tests 2026-04-23 20:36:05 +01:00
Vincent Koc
f40f8a60cc fix(agents): harden cli runner hook followups (#70747)
* fix(agents): harden cli runner hook followups

* fix(agents): harden cli runner hook followups

* fix(agents): harden cli runner hook followups

* fix(agents): harden cli runner hook followups

* fix(agents): harden cli runner hook followups

* fix(agents): harden cli runner hook followups
2026-04-23 12:32:30 -07:00
Peter Steinberger
e93b3f60fa fix: harden openclaw peer dependency installs (#70462) 2026-04-23 20:28:02 +01:00
Anish Kataria
44820f859e fix(plugin-sdk): scan dependency tree before materialising openclaw symlink
The dependency-tree security scan rejects node_modules symlinks whose
targets resolve outside the install root. Our trusted host-to-plugin
symlink violates that rule by design, so running the scan AFTER
linkOpenClawPeerDependencies would fail every install with
SECURITY_SCAN_FAILED.

Reorder afterInstall so the scan runs first (walking only the plugin's
own staged source, catching any pre-existing malicious openclaw-named
symlink a source might smuggle in), then the trusted link is
materialised on the now-safe tree.

Also use braces on guard clauses in the new unit tests to satisfy the
oxlint no-unreachable-single-statement-if rule.
2026-04-23 20:28:02 +01:00
Anish Kataria
56dd249a07 test(plugin-sdk): add unit tests for linkOpenClawPeerDependencies
Tests three cases via installPluginFromDir:
- symlink created when peerDependencies declares openclaw
- no symlink when peer list is empty
- idempotent re-install replaces existing symlink
- warns and skips when host root cannot be resolved

Also removes the single-element Set in favour of a direct name
comparison (peerName === "openclaw"), and adds Closes #54428 to
address the same root cause in the weixin connector.

Closes #54428
2026-04-23 20:28:02 +01:00
anish k
2e9c1faef6 fix(plugin-sdk): symlink openclaw peerDependencies after plugin install
## Summary

Signed-off-by: anish k <ak8686@princeton.edu>
2026-04-23 20:28:02 +01:00
Peter Steinberger
2b45bc1fd3 fix(auto-reply): restore exec-event route replies (#70258) 2026-04-23 20:27:39 +01:00
Peter Steinberger
ce933f3bbc fix(auto-reply): honor recovered system-event reply routes 2026-04-23 20:27:39 +01:00
wzfukui
87a08dd4c2 fix(auto-reply): route exec-event replies via persisted delivery context 2026-04-23 20:27:39 +01:00
Peter Steinberger
aad31817ef ci: add bun global install smoke 2026-04-23 20:27:04 +01:00
Vincent Koc
6896692111 docs(sidebar): sort tools group alphabetically 2026-04-23 12:25:25 -07:00
Vincent Koc
ba890a4578 docs(channels): telegram - collapse prose field list into accordion summary, cardify related, remove H1 2026-04-23 12:22:02 -07:00
Vincent Koc
c43a447b38 docs(channels): slack - collapse duplicate HTTP slash-commands JSON, cardify related, accordion config pointers, remove H1 2026-04-23 12:20:25 -07:00
Peter Steinberger
89051c6bf6 docs(openai): document GPT-5.5 defaults 2026-04-23 20:19:15 +01:00
Peter Steinberger
cd5bc2fc93 test(openai): cover GPT-5.5 defaults 2026-04-23 20:19:15 +01:00
Peter Steinberger
a36903b94c feat(openai): default to GPT-5.5 2026-04-23 20:19:15 +01:00
Peter Steinberger
54731492a2 fix(gateway): persist webchat images as managed media (#70719)
* fix(gateway): persist webchat images as managed media

* fix(ui): keep managed image auth same-origin

* docs: note managed webchat image fix
2026-04-23 20:17:41 +01:00
Peter Steinberger
f2f475e869 perf: run ui node tests without jsdom 2026-04-23 20:17:37 +01:00
Peter Steinberger
b957493ef7 docs: update changelog for plugin setup fix (#70718) 2026-04-23 20:17:21 +01:00
Devin Robison
4c09f4a812 test(plugins): place shadow setup-api where the old cwd-fallback would actually resolve it 2026-04-23 20:17:21 +01:00
Devin Robison
993781e6e6 fix(plugins): ignore cwd setup-api fallback 2026-04-23 20:17:21 +01:00
Vincent Koc
15ff8619d1 fix(qa-channel): reject non-http attachment urls 2026-04-23 12:15:22 -07:00
Peter Steinberger
44144cbd06 fix: use module path for bundled jiti loads (#70073) (thanks @yidianyiko) 2026-04-23 20:13:13 +01:00
YDYK
61e9e86d69 fix(plugins): use module path for bundled jiti loads 2026-04-23 20:13:13 +01:00
Peter Steinberger
1d980cca6f perf: trim cli prepare hook tests 2026-04-23 20:07:35 +01:00
Vincent Koc
e1840b8581 fix(msteams): bind global audience tokens to app id 2026-04-23 12:05:35 -07:00
Vincent Koc
7d30894c4a fix(anthropic): stop forcing claude permission bypass 2026-04-23 12:03:00 -07:00
Peter Steinberger
8a4761fe95 test: align approval and pairing expectations 2026-04-23 20:01:57 +01:00
Vincent Koc
b122a325cd fix(android): require loopback cleartext gateways 2026-04-23 11:59:17 -07:00
Peter Steinberger
efd5eb231a perf: trim feishu extension tests 2026-04-23 19:57:08 +01:00
Vincent Koc
cad102c3ca fix(android): require private IP cleartext pairing 2026-04-23 11:56:47 -07:00
Deepak Jain
a63939d295 fix(logging): tolerate malformed subsystem labels (#70502) (#70535)
* fix(logging): tolerate malformed subsystem labels

Guard console subsystem filtering and probe suppression against malformed subsystem labels, and normalize bad subsystem names to a stable fallback during console emission.

Fixes #70502

* test(plugins): ignore extension test-support helpers in seam guardrail

Exclude extension files named *.test-support.ts from the plugin sdk seam guardrail so test-only helpers do not trip public seam enforcement on unrelated PRs.
2026-04-23 11:51:54 -07:00
Vincent Koc
b201589ae1 fix(discord): require explicit native approval enablement 2026-04-23 11:51:17 -07:00
Vincent Koc
527d7211e0 fix(approvals): require explicit chat exec enablement 2026-04-23 11:51:17 -07:00
Tak Hoffman
7651a03424 Add packed CLI smoke checks for release packaging (#70685)
* Add packed CLI smoke release checks

* Address PR review feedback

* Harden packed CLI smoke checks

* Tighten release verifier parsing

* Scan root dist module files in release verifier
2026-04-23 13:50:15 -05:00
Peter Steinberger
c151956782 refactor(discord): simplify native command auth selection 2026-04-23 19:50:12 +01:00
Peter Steinberger
1f06073fe8 perf: trim slack extension test setup 2026-04-23 19:45:53 +01:00
Peter Steinberger
bfcae63373 fix: harden Discord native command auth (#70711) (thanks @vincentkoc) 2026-04-23 19:44:12 +01:00
Peter Steinberger
6590bc9037 fix: harden image generation directive output (#70710)
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-23 19:44:06 +01:00
Peter Steinberger
e2f2deae78 fix: fail fast on silent changed-test hangs 2026-04-23 19:40:25 +01:00
Peter Steinberger
e9405318b4 fix(openai): default realtime voice to gpt-realtime-1.5 2026-04-23 19:39:24 +01:00
Peter Steinberger
42d1ff8433 perf: narrow grouped render test imports 2026-04-23 19:36:32 +01:00
Peter Steinberger
c96da8ea18 docs: update PR closure instructions 2026-04-23 19:35:08 +01:00
Vincent Koc
a32fe807f4 fix(discord): block channel policy auth bypass 2026-04-23 11:34:44 -07:00
Andrey Gerasimov
9cae47a956 fix: preserve Kimi tool call ids (#70693) (#70693)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: geri4 <2748115+geri4@users.noreply.github.com>
2026-04-23 19:34:09 +01:00
Vincent Koc
f7537faa21 fix(agents): emit cli runner llm lifecycle hooks (#70731) 2026-04-23 11:33:27 -07:00
zhang-guiping
c1f423f845 fix(secrets): harden Windows ACL fallback and strip BOM (#70662)
Fail closed when Windows ACL checks cannot be verified for file and exec secret providers unless the provider explicitly opts into allowInsecurePath. Strip UTF-8 BOMs from file-backed secrets and document the trusted-path override.\n\nThanks @zhanggpcsu.
2026-04-23 19:32:15 +01:00
Peter Steinberger
884d7929d1 docs: format testing accordion notes 2026-04-23 19:28:24 +01:00
Peter Steinberger
e03b9647ad perf: split acp client test helpers 2026-04-23 19:26:30 +01:00
Vincent Koc
5b3e73e099 fix(android): disable auto-send for ASK_OPENCLAW 2026-04-23 11:26:10 -07:00
Peter Steinberger
fd1d6b0241 ci: serialize extension shard batches 2026-04-23 19:25:14 +01:00
Peter Steinberger
f9da326c88 fix: repair generated docs accordion indentation 2026-04-23 19:20:35 +01:00
Vincent Koc
314041a885 docs(channels): discord - drop duplicate developer-portal block, cardify related, accordion config pointers, remove H1 2026-04-23 11:19:28 -07:00
Peter Steinberger
36c89ecaf6 ci: cap extension shard vitest workers 2026-04-23 19:14:15 +01:00
Peter Steinberger
95448d27ae fix: narrow Mintlify accordion guard 2026-04-23 19:14:12 +01:00
Vincent Koc
e4534efe8e docs(help): testing - drop redundant H1, progressive-disclose unit/integration maintainer notes into AccordionGroup 2026-04-23 11:13:14 -07:00
Chinar Amrutkar
8513a14406 fix: queue chat aborts across reconnect (#70673) (thanks @chinar-amrutkar) 2026-04-23 19:12:39 +01:00
Vincent Koc
b0efa8d43d docs(gateway): security — sentence-case headings, remove manual TOC and H1, drop custom anchors, tuck triage notes into Accordion 2026-04-23 11:09:33 -07:00
Peter Steinberger
a89d4ab979 test: stabilize acp bind live probe 2026-04-23 19:07:10 +01:00
Peter Steinberger
3e2bc28e51 fix: forward chat images to acp dispatch 2026-04-23 19:06:19 +01:00
Peter Steinberger
32a38f125e fix: keep codex cli images in workspace 2026-04-23 19:06:19 +01:00
Peter Steinberger
feecc53b6b test: stabilize codex harness probes 2026-04-23 19:06:19 +01:00
Peter Steinberger
802646e004 fix: catch Mintlify accordion parse hazards 2026-04-23 19:04:35 +01:00
Peter Steinberger
43c5650475 perf: avoid eager trajectory session manager import 2026-04-23 19:00:35 +01:00
Peter Steinberger
cbc88fb92d test: trim system run runtime duplicate 2026-04-23 18:55:19 +01:00
Peter Steinberger
75df14cbbc test: mark video capability mirror intentional 2026-04-23 18:54:33 +01:00
Peter Steinberger
ccbc3bc3ff test: share export command session mocks 2026-04-23 18:54:33 +01:00
Peter Steinberger
c7408f1cf2 test: trim system run handler coverage 2026-04-23 18:53:53 +01:00
Peter Steinberger
bcde76a898 docs: add efficient gh triage guide 2026-04-23 18:53:31 +01:00
Peter Steinberger
7a9df89d26 test: trim skill scanner branch coverage 2026-04-23 18:51:20 +01:00
Peter Steinberger
393a71991f fix: decouple approval startup from replay 2026-04-23 18:49:57 +01:00
Peter Steinberger
62a0cd8acd test: slim status fast-mode label coverage 2026-04-23 18:49:25 +01:00
Peter Steinberger
310b1eea4a test: stabilize full-suite flakes 2026-04-23 18:48:07 +01:00
Peter Steinberger
d0303e2a97 test: reuse CLI runtime mock in daemon tests 2026-04-23 18:46:43 +01:00
Peter Steinberger
42c6e2d031 test: reuse CLI runtime mock in gateway tests 2026-04-23 18:46:43 +01:00
Peter Steinberger
140a8cf5fb test: share CLI runtime mock helper 2026-04-23 18:46:43 +01:00
Peter Steinberger
bd2553e126 test: share gateway live env helpers 2026-04-23 18:46:43 +01:00
Peter Steinberger
9d8690d6b3 test: share temp plugin extension fixtures 2026-04-23 18:46:42 +01:00
Peter Steinberger
fd3bb6f084 test: reuse channel plugin fixture 2026-04-23 18:46:42 +01:00
Peter Steinberger
961ab165ad test: dedupe coding tool session store fixtures 2026-04-23 18:46:42 +01:00
Peter Steinberger
ce681be084 test: dedupe subagent announcement fixtures 2026-04-23 18:46:42 +01:00
Peter Steinberger
844f1dd87a test: dedupe session lock symlink fixtures 2026-04-23 18:46:42 +01:00
Peter Steinberger
359a656fdf test: dedupe Anthropic cache policy fixtures 2026-04-23 18:46:42 +01:00
Vincent Koc
9694a4501f fix(qqbot): require auth for bot-approve 2026-04-23 10:45:30 -07:00
Peter Steinberger
604ce85ce0 test: use lightweight install version fixture 2026-04-23 18:45:06 +01:00
Peter Steinberger
7c974ca1af perf: reduce installer version parsing overhead 2026-04-23 18:44:26 +01:00
Andrej Trogrlić
23c90aeed4 fix(feishu): keep setup entry off runtime SDK (#70339)
Load Feishu setup surfaces through a setup-only barrel so onboarding does not import the Lark SDK before bundled runtime deps are staged.\n\nThanks @andrejtr.\n\nCo-authored-by: andrejtr <64274971+andrejtr@users.noreply.github.com>
2026-04-23 18:42:06 +01:00
Peter Steinberger
184c4e3788 ci: add duplicate PR cleanup workflow 2026-04-23 18:41:32 +01:00
Vincent Koc
12de62bfd8 docs(plugins): architecture — sentence-case title, CardGroup intro, dedup provider-hook prose list, progressive-disclose bundled-provider examples 2026-04-23 10:39:57 -07:00
Peter Steinberger
bff9f10ea6 test: remove canvas reload sleep 2026-04-23 18:37:29 +01:00
Tak Hoffman
d39e34d31f fix(gateway): disarm wrapper timeout before teardown (#70704) 2026-04-23 12:36:30 -05:00
Peter Steinberger
5c229e32b7 test: remove websocket polling waits 2026-04-23 18:30:30 +01:00
Peter Steinberger
09331543db test: dedupe gateway hook session key cases 2026-04-23 18:29:32 +01:00
Peter Steinberger
4e97b57c17 refactor: share interactive payload normalizers 2026-04-23 18:29:32 +01:00
Peter Steinberger
61ab68f5c9 refactor: share MCP tools stdio server 2026-04-23 18:29:32 +01:00
Peter Steinberger
73e247321b test: share channel audit plugin fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
9ee800e81d test: share security audit temp fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
4acae5b281 test: dedupe skill scanner stat mocks 2026-04-23 18:29:32 +01:00
Peter Steinberger
fc3aa07fbc test: dedupe CLI attempt setup 2026-04-23 18:29:32 +01:00
Peter Steinberger
060467ef83 test: dedupe OpenAI stream wrapper assertions 2026-04-23 18:29:32 +01:00
Peter Steinberger
50acb50fb5 test: dedupe reply media fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
1630607463 test: dedupe cron and channel fixtures 2026-04-23 18:29:32 +01:00
Peter Steinberger
0397cad89b test: normalize safe-bin docs parity indentation 2026-04-23 18:27:56 +01:00
Peter Steinberger
b3d32a995d docs: align safe-bin denied flag list 2026-04-23 18:27:56 +01:00
Vincent Koc
8f3b99c512 fix(mcp): block owner-only tools in ACPX bridge 2026-04-23 10:24:36 -07:00
Peter Steinberger
91a165c6af test: align group prompt invariant 2026-04-23 18:21:05 +01:00
Peter Steinberger
5ebef46183 perf: speed up hot test paths 2026-04-23 18:17:09 +01:00
Vincent Koc
27d6b8db5b docs(plugins): sdk-overview — sentence-case title, tighten intro into Warning, Related as CardGroup, progressive-disclose embedded-factory note 2026-04-23 10:15:58 -07:00
Peter Steinberger
e0f5961e28 fix: harden group chat prompt metadata 2026-04-23 18:15:49 +01:00
ZC
6415e35f55 fix(ui): include cached tokens in context usage (#70532)
Fixes #70491.

Includes cached prompt tokens in the Control UI context percent and keeps output tokens out of the percentage.

Thanks @chen-zhang-cs-code.
2026-04-23 18:13:31 +01:00
Vincent Koc
4792a50710 docs(tools): exec-approvals — sentence-case title, restructure intro, dedup Related, progressive-disclose safe-bins nuances 2026-04-23 10:09:25 -07:00
Peter Steinberger
23b751b112 test: dedupe command fixtures 2026-04-23 18:09:20 +01:00
Peter Steinberger
7a8d304a65 refactor: share core helper logic 2026-04-23 18:09:20 +01:00
Peter Steinberger
2045c0977e refactor: dedupe tooling helpers 2026-04-23 18:09:20 +01:00
Peter Steinberger
f98f93c29a test: cover non-command pairing auth 2026-04-23 18:06:05 +01:00
Peter Steinberger
eb937089d5 docs: update security triage discussion flow 2026-04-23 18:06:05 +01:00
Vincent Koc
1f5df4fbfd docs(gateway): protocol — sentence-case title, collapse RPC method families into AccordionGroup 2026-04-23 10:04:37 -07:00
Tak Hoffman
77a1cbd5ff fix(cli): wait for gateway client teardown before exit (#70691)
Verified:
- pnpm test src/gateway/call.test.ts

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-23 12:03:37 -05:00
Peter Steinberger
fb47c1d6bf fix: harden WhatsApp structured object prompts 2026-04-23 18:03:16 +01:00
Peter Steinberger
3ae15cd746 test: cover codex transport fallback path 2026-04-23 17:58:19 +01:00
Sk7n4k3d
f4891b083d fix(agents/failover): classify undici terminated and codex Request failed as timeout (#69368) 2026-04-23 17:58:19 +01:00
Peter Steinberger
79d8ce730a docs: fix OpenAI provider compaction reference 2026-04-23 17:53:36 +01:00
Vincent Koc
c7d1f532a2 docs(plugins): manifest — sentence-case title, compress What-this-file-does, prune trailing Notes duplication, CardGroup Related 2026-04-23 09:50:17 -07:00
Vincent Koc
b3ca4e088e docs(providers): openai — drop stray anchor tag, consolidate trailing azure notes 2026-04-23 09:48:48 -07:00
Peter Steinberger
8997df5c45 ci: increase checkout retry budget 2026-04-23 17:48:21 +01:00
Peter Steinberger
0da17e4f74 ci: retry docs publish clone failures 2026-04-23 17:44:41 +01:00
Vincent Koc
94ff5a93c0 docs(plugins): fix broken provider-hook table, tabulate family bundled examples, progressive-disclose extra capabilities 2026-04-23 09:41:43 -07:00
Peter Steinberger
884c117785 ci: harden docs agent fetch retries 2026-04-23 17:31:32 +01:00
Peter Steinberger
a10c495f29 ci: retry docs publish fetch failures 2026-04-23 17:26:31 +01:00
Vincent Koc
ed52e2ec91 docs(concepts): compress model-providers reference — move SDK hook list to provider plugins doc, tabulate bundled providers 2026-04-23 09:20:59 -07:00
Peter Steinberger
382c87c5f2 fix: preserve Gemini compat tool signatures 2026-04-23 17:17:07 +01:00
Vincent Koc
167eee19af docs(tools): trim ACP agents reference, merge quick-start flows, accordion smoke test, dedupe command cookbook 2026-04-23 09:13:38 -07:00
Peter Steinberger
32de558f47 docs(changelog): align 2026.4.22 and unreleased notes 2026-04-23 16:58:59 +01:00
Peter Steinberger
d913fd57a2 test: skip remaining stale live probe routes 2026-04-23 16:58:36 +01:00
Peter Steinberger
bc6cefd2ac fix: repair 2026.4.22 appcast list item 2026-04-23 16:56:58 +01:00
Peter Steinberger
b75a80f6d1 chore(release): prepare 2026.4.23 2026-04-23 16:56:44 +01:00
Peter Steinberger
47f131f6ae test(gateway): harden live docker harness probes 2026-04-23 16:56:44 +01:00
Peter Steinberger
af03832134 test(docker): make e2e temp logs portable 2026-04-23 16:56:44 +01:00
Peter Steinberger
e204a31831 fix(discord): keep subagent hooks lazy in channel entry 2026-04-23 16:56:44 +01:00
Peter Steinberger
4df0d55f06 fix: skip stale opencode live file probes 2026-04-23 16:55:36 +01:00
Peter Steinberger
1713839288 fix: pin embedded harness selection per session 2026-04-23 16:53:32 +01:00
Peter Steinberger
7248a7749f docs(release): clarify mac source variation policy 2026-04-23 16:51:06 +01:00
Peter Steinberger
baab065f05 test(qa): isolate matrix stale sync replay 2026-04-23 16:49:53 +01:00
Peter Steinberger
248b1b420a ci(qa): trust release branch heads 2026-04-23 16:49:53 +01:00
Peter Steinberger
f96a8f6e4f docs(release): document mac source ref fallback 2026-04-23 16:49:53 +01:00
Peter Steinberger
eecd029f17 fix(macos): derive correction sparkle build 2026-04-23 16:49:53 +01:00
Peter Steinberger
9fe74e391d fix(macos): sign mlx tts helper before app binary 2026-04-23 16:49:53 +01:00
Peter Steinberger
bdb6aebff4 docs(release): document npm dist-tag fallback auth 2026-04-23 16:49:53 +01:00
Peter Steinberger
edb466ee16 docs(release): document light stable promotion testing 2026-04-23 16:49:53 +01:00
Peter Steinberger
64fc449591 ci(release): use github runner for npm release gate 2026-04-23 16:49:53 +01:00
Peter Steinberger
599dd383e6 docs(release): decouple npm publish from mac release 2026-04-23 16:49:53 +01:00
Peter Steinberger
2be2b24b37 docs(release): require full GitHub release notes 2026-04-23 16:49:53 +01:00
Peter Steinberger
53cc5085c7 docs: refine release tweet guidance 2026-04-23 16:49:43 +01:00
Vincent Koc
ecefe1c39c fix(scripts): reap child check processes 2026-04-23 08:44:58 -07:00
Peter Steinberger
5071c58346 ci: run live model matrix on github runners 2026-04-23 16:44:11 +01:00
Vincent Koc
f58e0176ca docs(start): rewrite showcase with standard Mintlify components, sentence case, and trimmed hero noise 2026-04-23 08:44:04 -07:00
Peter Steinberger
deb1364dfb refactor: centralize root memory file policy 2026-04-23 16:40:41 +01:00
Peter Steinberger
14808371a6 test: improve macos parallels update smoke 2026-04-23 16:35:39 +01:00
Vincent Koc
f1662bff92 docs(tools): restructure browser reference with tabs/accordions and trim redundant prose 2026-04-23 08:34:16 -07:00
Peter Steinberger
c5ab0963c9 fix: tolerate post-update json in install smoke 2026-04-23 16:33:41 +01:00
Peter Steinberger
226e116de6 docs: expand Tencent Hy3 provider guide 2026-04-23 16:28:03 +01:00
Peter Steinberger
d8c724c60f test: skip flaky live probe routes 2026-04-23 16:25:10 +01:00
Peter Steinberger
4064c9b75c docs: add gateway diagnostics guide 2026-04-23 16:21:23 +01:00
Peter Steinberger
6c090c5150 chore(release): update appcast for 2026.4.22 2026-04-23 16:20:20 +01:00
Vincent Koc
fda09c4806 docs(plugins): trim skill-workshop headings and collapse example variants; tighten codex-harness guardian explainer 2026-04-23 08:16:26 -07:00
Mariano
10a9acbf29 fix: keep root memory uppercase (#70621)
Thanks @mbelinky.
2026-04-23 16:10:36 +01:00
Peter Steinberger
645294510c fix: restore bundled plugin SDK alias 2026-04-23 16:10:23 +01:00
Peter Steinberger
0fd0a69399 test: skip additional stale live probe routes 2026-04-23 16:10:04 +01:00
Vincent Koc
b7cc9d2d28 docs: msteams restructure - Azure Bot Steps, sentence-case headings, grouped config 2026-04-23 08:02:24 -07:00
Peter Steinberger
7b6b7d53fc build: update tsgo native preview 2026-04-23 15:59:49 +01:00
Vincent Koc
da3e9ded19 docs: collapse Slack manifest duplication and trim noise bullets 2026-04-23 07:57:04 -07:00
Peter Steinberger
be87068f02 test: skip stale live probe routes 2026-04-23 15:54:38 +01:00
Vincent Koc
99e8ede76c docs: extract Matrix push rules runbook, table verify CLI, merge E2EE H3s 2026-04-23 07:51:42 -07:00
Peter Steinberger
e460afd654 docs: add GitHub API polling guidance 2026-04-23 15:51:22 +01:00
Peter Steinberger
5feedbf4b6 fix: honor explicit CI timing run id 2026-04-23 15:43:50 +01:00
Peter Steinberger
3fa089de19 ci: validate docs mdx before publish 2026-04-23 15:41:47 +01:00
Peter Steinberger
dbd7966cfd ci: remove runner caps after timing review 2026-04-23 15:41:32 +01:00
Mariano
3e956a4982 fix: align claude-cli prompt hooks (#70625)
Merged via squash.

Prepared head SHA: 3de89da38f
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-04-23 16:34:16 +02:00
Peter Steinberger
74bb617889 ci: reduce live model runner size 2026-04-23 15:31:13 +01:00
Peter Steinberger
8435cb80ac test: stop macOS VM after Discord smoke 2026-04-23 15:29:34 +01:00
Peter Steinberger
b2bbe61571 ci: trigger runner fanout measurement 2026-04-23 15:28:00 +01:00
Peter Steinberger
1e1aaa51e1 test: harden live model extra probes 2026-04-23 15:27:50 +01:00
Peter Steinberger
6532ee0c39 ci: reduce node runner fanout 2026-04-23 15:25:28 +01:00
Peter Steinberger
b4d1992338 test: accept current web search reasoning floor 2026-04-23 15:11:32 +01:00
Peter Steinberger
3e834f2f83 perf(test): skip sandbox prune in context smoke 2026-04-23 15:09:49 +01:00
Peter Steinberger
e050e18945 test: add live model file and image probes 2026-04-23 15:09:43 +01:00
Peter Steinberger
4a4e56e8f3 perf(test): lazy load sandbox context helpers 2026-04-23 15:07:00 +01:00
Peter Steinberger
63a88ff1df perf(test): slim exec preflight imports 2026-04-23 15:04:20 +01:00
Pengfei Ni
be4920f9bc fix(anthropic-vertex): resolve model discovery and auth for GCP ADC (openclaw#65716)
Verified:
- pnpm test extensions/anthropic-vertex/index.test.ts extensions/anthropic-vertex/region.adc.test.ts src/plugins/manifest-registry.test.ts src/plugins/provider-runtime.synthetic-auth-discovery.test.ts

Co-authored-by: feiskyer <676637+feiskyer@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-23 09:03:16 -05:00
Peter Steinberger
5743d7c8f5 perf(test): narrow subagent spawn limit tests 2026-04-23 15:01:24 +01:00
Peter Steinberger
0839617711 perf(test): drop obsolete docker fs bridge smoke 2026-04-23 14:58:08 +01:00
Peter Steinberger
c1ba7f718b perf(test): remove docker from fs bridge smoke 2026-04-23 14:57:40 +01:00
Peter Steinberger
4dcd6b8dc4 perf(test): slim gateway live connect smoke 2026-04-23 14:45:06 +01:00
Peter Steinberger
7dd37bda4f perf(test): trim hot gateway and infra tests 2026-04-23 14:33:37 +01:00
Peter Steinberger
1bbca1d910 ci: run full docker checks daily 2026-04-23 14:32:30 +01:00
Peter Steinberger
be81fa4424 test: stabilize live docker probes 2026-04-23 14:31:18 +01:00
Peter Steinberger
e98331b0be test: parallelize docker aggregate 2026-04-23 14:31:18 +01:00
Peter Steinberger
d3dc890821 fix: allow installed plugins through allowlist 2026-04-23 14:31:18 +01:00
Sliverp
e6d1ce943c fix:update wecom blurb (#70614) 2026-04-23 21:18:14 +08:00
openclaw-docs-agent[bot]
70d41130ff docs: refresh documentation 2026-04-23 13:08:56 +00:00
Tak Hoffman
87eee6e640 fix(thinking): default implicit reasoning models to medium (#70601)
* fix(thinking): default implicit reasoning models to medium

* fix(thinking): preserve reasoning metadata during default resolution
2026-04-23 07:55:47 -05:00
Otto Deng
bc01cbb8a2 docs(providers/openai): document Azure OpenAI endpoint usage for image generation (#70501)
Verified:
- pnpm lint:docs
- Resolved bot review comments around Azure docs scope and accuracy
2026-04-23 07:48:54 -05:00
openclaw-docs-agent[bot]
0372f4d540 docs: refresh documentation 2026-04-23 12:39:50 +00:00
Tak Hoffman
03477ccb82 fix: Add runner label to /status (#70595)
* Add runner label to status output

* Add changelog entry for status runner label

* Fix status runner detection and sanitization
2026-04-23 07:30:09 -05:00
Peter Steinberger
d330ad65e5 test(line): trim outbound payload coverage 2026-04-23 13:16:41 +01:00
Peter Steinberger
2e0e0654ce test(extensions): trim hot extension imports 2026-04-23 13:06:19 +01:00
Peter Steinberger
547b0c201d test(config): avoid ignored baseline artifact 2026-04-23 12:56:23 +01:00
Peter Steinberger
c5b7810563 test(config): read generated talk baseline 2026-04-23 12:52:13 +01:00
Peter Steinberger
09a118c57e test(config): avoid module resets in pruning tests 2026-04-23 12:46:41 +01:00
Peter Steinberger
5c9233c64e ci: shorten gateway watch readiness wait 2026-04-23 12:39:51 +01:00
zhang-guiping
62262d493b fix #70487: OpenAI image generation provider does not support Azure OpenAI endpoints (openclaw#70570)
Verified:
- pnpm install --frozen-lockfile
- pnpm check:changed
- pnpm test extensions/openai/image-generation-provider.test.ts

Co-authored-by: zhang-guiping <275915537+zhanggpcsu@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-04-23 06:36:57 -05:00
Peter Steinberger
818d903caa test: align build artifact profile expectation 2026-04-23 12:32:56 +01:00
Peter Steinberger
57ce4fb402 ci: keep sdk export check with build artifacts 2026-04-23 12:28:16 +01:00
Peter Steinberger
bd8fc86cf3 ci: skip duplicate strict smoke build 2026-04-23 12:24:21 +01:00
Peter Steinberger
b3ebbe5ba0 test(slack): narrow event runtime mocks 2026-04-23 11:50:48 +01:00
Peter Steinberger
aa95428265 test(msteams): mock oauth token network guard 2026-04-23 11:44:24 +01:00
Peter Steinberger
477a77284a test(mattermost): drop duplicate api smoke 2026-04-23 11:38:51 +01:00
Peter Steinberger
7b5b21c0e1 test(agents): avoid auth cache module resets 2026-04-23 11:33:56 +01:00
Peter Steinberger
1412ee8a85 test(hooks): remove duplicate loader cases 2026-04-23 11:31:47 +01:00
Peter Steinberger
39a907d7f4 test(hooks): drop unobservable loader smoke 2026-04-23 11:30:15 +01:00
Peter Steinberger
158a0d4ab4 test: trim duplicate runtime smoke work 2026-04-23 11:28:26 +01:00
Peter Steinberger
0da53b54a0 test(browser): drop flaky duplicate cdp health case 2026-04-23 11:20:02 +01:00
Peter Steinberger
8084bbf8ed ci: save pnpm store cache explicitly 2026-04-23 11:09:37 +01:00
Peter Steinberger
9191fbe2b5 perf(test): reuse plugin validation fixtures 2026-04-23 11:04:07 +01:00
Sliverp
d634380304 fix (#70562) 2026-04-23 17:58:16 +08:00
Peter Steinberger
a11bb792e4 perf(test): use gateway harness for cli connect smoke 2026-04-23 10:54:13 +01:00
Peter Steinberger
a8d337b360 perf(test): remove gateway method wait debt 2026-04-23 10:37:42 +01:00
Peter Steinberger
007fb0458e perf(test): speed up secrets and mattermost lanes 2026-04-23 10:27:28 +01:00
Peter Steinberger
d1ff0caecb test(telegram): reduce reply runtime imports 2026-04-23 10:20:53 +01:00
Peter Steinberger
0a7668595c test(telegram): reset forum metadata cache 2026-04-23 10:11:12 +01:00
Peter Steinberger
e880eab486 test(tui): narrow embedded backend mocks 2026-04-23 10:05:32 +01:00
Ayaan Zaidi
57f28285be fix: place telegram rtt changelog entry (#70550) 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
ed4c3cb484 fix: finalize telegram rtt changelog (#70550) 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
8a078acaa6 perf(telegram): bound forum metadata cache 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
1bd8c5f362 fix(qa): timestamp telegram update batches 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
50e6c0a3b2 perf(telegram): cache forum metadata lookup 2026-04-23 14:33:17 +05:30
Ayaan Zaidi
c22a21759b test(qa): report telegram reply rtt 2026-04-23 14:33:17 +05:30
Peter Steinberger
6e971454ec perf(test): skip unused binding placement hints 2026-04-23 09:56:38 +01:00
Peter Steinberger
df2f025194 fix: verify pinned macOS smoke baseline 2026-04-23 09:52:48 +01:00
openclaw-docs-agent[bot]
c45026e5cc docs: refresh documentation 2026-04-23 08:50:54 +00:00
Peter Steinberger
885bf1c5d8 ci: parallelize core test configs 2026-04-23 09:42:14 +01:00
Peter Steinberger
7f64a3c4ca fix: accept Discord smoke nonce directly 2026-04-23 09:40:59 +01:00
Vincent Koc
68e7db753b docs: trim Telegram webhook/exec approvals/forum topic ACP verbosity 2026-04-23 01:39:05 -07:00
Peter Steinberger
855912b25c test(matrix): harden live QA waits 2026-04-23 09:36:48 +01:00
Peter Steinberger
6094358311 ci: avoid blacksmith queue for core checks 2026-04-23 09:36:29 +01:00
Peter Steinberger
4b1577b339 fix: harden Discord roundtrip smoke 2026-04-23 09:28:28 +01:00
Peter Steinberger
3110840eba test: skip stale openrouter live routes 2026-04-23 09:27:00 +01:00
Peter Steinberger
461deb8d8a test(feishu): coalesce lifecycle monitor cases 2026-04-23 09:25:58 +01:00
Vincent Koc
2b292faece docs: merge Discord Voice sections and trim thread/streaming/ACP verbosity 2026-04-23 01:23:22 -07:00
openclaw-docs-agent[bot]
e69e90786d docs: refresh documentation 2026-04-23 08:18:14 +00:00
Vincent Koc
a2d91a1a9a docs: trim gateway configuration and plugin architecture reference dumps 2026-04-23 01:12:16 -07:00
Peter Steinberger
1263d4278e fix(sessions): preserve active route updates during maintenance 2026-04-23 09:10:51 +01:00
Eliot
94f703a845 fix(sessions): updateLastRoute must not bump updatedAt (#49515) (#49588)
updateLastRoute() used mergeSessionEntry which bumps updatedAt to
Date.now() on every inbound message. This prevented session idle
and daily reset from ever firing, since evaluateSessionFreshness()
always saw a fresh updatedAt.

The fix from #32379 patched recordSessionMetaFromInbound to use
mergeSessionEntryPreserveActivity, but missed updateLastRoute() in
the same inbound pipeline.

Changes:
- Remove explicit updatedAt from updateLastRoute basePatch
- Switch from mergeSessionEntry to mergeSessionEntryPreserveActivity
- Add regression test verifying updatedAt is preserved
- Update existing test assertion to match corrected behavior

Fixes #49515
2026-04-23 03:05:05 -05:00
Peter Steinberger
60341689fe test(telegram): keep session support inside package 2026-04-23 09:04:57 +01:00
Peter Steinberger
c1f777fed2 fix: update Discord smoke channel config 2026-04-23 09:03:52 +01:00
Vincent Koc
b7506521e6 docs: restructure gateway security page and extract audit checks reference 2026-04-23 01:01:12 -07:00
Peter Steinberger
25039e973e test(gateway): avoid send handler reimports 2026-04-23 08:59:41 +01:00
Peter Steinberger
eb4bd4de5d test(whatsapp): coalesce monitor inbox cases 2026-04-23 08:56:47 +01:00
Peter Steinberger
4100bea888 test(telegram): hide split message context files 2026-04-23 08:54:09 +01:00
Peter Steinberger
40b40752be test(telegram): coalesce message context cases 2026-04-23 08:54:09 +01:00
Peter Steinberger
98c8920729 ci: add focused live model dispatch 2026-04-23 08:47:44 +01:00
Peter Steinberger
f8894d5b3e docs: align cli index with command surface 2026-04-23 08:46:14 +01:00
Peter Steinberger
d85819d867 perf(config): skip redundant setup auto-enable probes 2026-04-23 08:44:01 +01:00
Vincent Koc
d1f91b52fa docs: restructure cli index and active memory pages 2026-04-23 00:42:08 -07:00
Peter Steinberger
14e69146e6 ci: use smaller live model runners 2026-04-23 08:41:23 +01:00
Peter Steinberger
dbcee0bc76 ci: shard docker live model checks 2026-04-23 08:40:18 +01:00
Peter Steinberger
fc4295f562 perf(whatsapp): narrow inbound dedupe imports 2026-04-23 08:37:56 +01:00
Peter Steinberger
1ea058345a ci: simplify docs agent node restore 2026-04-23 08:37:18 +01:00
Peter Steinberger
107fbe88a8 test(zalo): cache lifecycle monitor imports 2026-04-23 08:31:07 +01:00
Peter Steinberger
ceadb9ddc4 ci: document docs agent workflow-run guard 2026-04-23 08:30:48 +01:00
Vincent Koc
ce4bb8f638 fix(onboarding): surface official WeCom channel install 2026-04-23 00:29:34 -07:00
Peter Steinberger
1f91af17fd ci: let docs agent runs finish 2026-04-23 08:29:06 +01:00
scoootscooob
46a70a7992 docs: add trajectory export changelog entry 2026-04-23 00:28:45 -07:00
Peter Steinberger
6129dfe590 test(matrix): extend live QA waits 2026-04-23 08:25:32 +01:00
Vincent Koc
daaedf37b7 docs: prune recent additions for readability 2026-04-23 00:23:18 -07:00
Peter Steinberger
252e4dde39 ci: add docs agent workflow 2026-04-23 08:22:47 +01:00
Peter Steinberger
e88d8512a7 perf(discord): narrow monitor runtime imports 2026-04-23 08:21:01 +01:00
Peter Steinberger
966e814c5e fix: defer model pricing refresh 2026-04-23 08:15:36 +01:00
Peter Steinberger
8714badc0c fix: show fast mode in status 2026-04-23 08:04:24 +01:00
Vincent Koc
2d7a4edba3 test(plugins): pin live provider config guards 2026-04-23 00:00:32 -07:00
Peter Steinberger
dfca707e4b fix: resolve implicit default Telegram status sessions 2026-04-23 07:57:38 +01:00
Peter Steinberger
9dd097a7a5 test: harden docker live backend probes 2026-04-23 07:57:00 +01:00
Vincent Koc
91c795cee0 docs: MCP + cron + plugin lifecycle plus channel env-block cross-links 2026-04-22 23:56:53 -07:00
Peter Steinberger
dd17dea761 docs: align pairing metadata upgrade approval 2026-04-23 07:56:16 +01:00
Vincent Koc
526a8bdc3f fix(codex): refresh live discovery config 2026-04-22 23:53:41 -07:00
Vincent Koc
c8aec6b951 docs: Control UI identity + gateway pairing hardening + release verification 2026-04-22 23:52:37 -07:00
Vincent Koc
ea3970f138 docs: CLI + gateway + plugin harness coverage for 48h changes 2026-04-22 23:49:06 -07:00
Peter Steinberger
eb2cb7834e fix(amazon-bedrock): type live plugin config 2026-04-23 07:47:59 +01:00
Vincent Koc
02da7350ad test(telegram): pin outbound hook routing fields 2026-04-22 23:47:06 -07:00
Peter Steinberger
a3b6f9dc73 ci: cover OpenAI web search minimal smoke 2026-04-23 07:46:08 +01:00
Peter Steinberger
5b39be3653 fix(agents): preserve raw fallback schema errors 2026-04-23 07:44:39 +01:00
Vincent Koc
da8993203c fix(amazon-bedrock): refresh live discovery and guardrail config 2026-04-22 23:41:27 -07:00
Peter Steinberger
d8db122a23 docs: document trajectory bundles 2026-04-23 07:39:49 +01:00
Vincent Koc
30a5c441f3 docs(channels): cover WhatsApp replyToMode, Discord inheritParent, Slack HTTP/ACP/downloadFile, Telegram webhook+picker auth, Mattermost reasoning suppression, workspace .env block for channel endpoints 2026-04-22 23:39:38 -07:00
Peter Steinberger
6929fa764c test(browser): avoid flaky CDP SSRF timeout 2026-04-23 07:37:50 +01:00
Vincent Koc
abb32e39b5 fix(openai): refresh live prompt overlay config 2026-04-22 23:37:16 -07:00
Peter Steinberger
938af16289 docs: deep audit documentation against source 2026-04-23 07:32:58 +01:00
Peter Steinberger
9f19e5be52 feat(i18n): add Thai control UI locale 2026-04-23 07:32:58 +01:00
Vincent Koc
9be0601b20 fix(ollama): refresh live discovery config 2026-04-22 23:30:28 -07:00
Peter Steinberger
a81c475731 fix(openai): raise minimal reasoning for native web search 2026-04-23 07:29:44 +01:00
Vincent Koc
21a16349f2 docs(providers): cover Opus 4.7 1M, Mantle Anthropic Messages, Codex device-code/CLI-import removal, Moonshot tool-id sanitization, LM Studio streaming-usage, Tencent bundled plugin 2026-04-22 23:29:36 -07:00
scoootscooob
a3d9c53db2 feat: add trajectory bundle export and default-on runtime capture (#70291)
* Trajectory: export session bundles by default

* Harden trajectory export diagnostics integration

* Address trajectory export review feedback

* Share diagnostics and trajectory bundle plumbing

* Harden trajectory recording and export

* Confine trajectory export outputs

* Document trajectory export command

* Harden trajectory export bundle privacy

* Redact trajectory sidecar paths

* Fix plugin install checks after rebase

* Keep queued writers working without O_NOFOLLOW

* Keep Codex trajectory writes without O_NOFOLLOW

* Harden trajectory export path handling

* Redact mixed trajectory export paths
2026-04-22 23:29:01 -07:00
Vincent Koc
6dba5cc2a0 fix(copilot): refresh live discovery config 2026-04-22 23:28:27 -07:00
Peter Steinberger
834fdc4832 docs: align documentation with current surfaces 2026-04-23 07:25:06 +01:00
Shakker
25451c9639 docs: add models provider changelog 2026-04-23 07:24:49 +01:00
Alex Knight
d75725e658 fix: clear embedded runs before lifecycle end (#70187)
* fix: clear embedded runs before lifecycle end

* fix: guard onBeforeLifecycleTerminal against synchronous throws

Wrap the hook invocation in try/catch so a synchronous exception
cannot skip emitLifecycleTerminal() after lifecycleTerminalEmitted
is already set to true. This preserves the best-effort contract
documented in the JSDoc.
2026-04-23 16:23:52 +10:00
Shakker
a92fe5ee40 fix: harden external auth fallback loading 2026-04-23 07:22:24 +01:00
Shakker
d87587b136 fix: align models provider help and auth warnings 2026-04-23 07:22:24 +01:00
Shakker
0e1407362d docs: mark external oauth hook deprecated 2026-04-23 07:22:24 +01:00
Shakker
bd4cfe0e7e docs: document provider ids and auth contracts 2026-04-23 07:22:24 +01:00
Shakker
db1e4f811d perf: scope models list discovery by provider 2026-04-23 07:22:24 +01:00
Shakker
3ec5558f53 fix: preserve external auth hook compatibility 2026-04-23 07:22:24 +01:00
Shakker
47ae15c059 feat: add external auth provider contracts 2026-04-23 07:22:24 +01:00
Peter Steinberger
4d1d0cd021 fix: stabilize gateway watch runtime deps 2026-04-23 07:22:10 +01:00
Peter Steinberger
33d9e1aa83 perf(test): narrow security audit plugin scope test 2026-04-23 07:21:46 +01:00
Vincent Koc
a35ed6b170 fix(ci): avoid duplicate install smoke docker build 2026-04-22 23:17:27 -07:00
Peter Steinberger
96ad6f53a2 test(models/auth): mark migration replacement fixture 2026-04-23 07:16:24 +01:00
Peter Steinberger
a7871d8212 fix(models/auth): sanitize replacement config patches 2026-04-23 07:16:24 +01:00
Neerav Makwana
a849283f80 harden: drop prototype-pollution keys in configPatch merge
Skip `__proto__`, `prototype`, and `constructor` keys while recursively
merging provider-auth `configPatch` payloads. Plugins construct the
patch in-process today, but JSON-parsed sources can preserve these keys
and the assignment `next[key] = value` would otherwise mutate the
merge target's prototype chain.

Made-with: Cursor
2026-04-23 07:16:24 +01:00
Neerav Makwana
14d1c9c4f0 fix(models/auth): merge agents.defaults.models on provider login
`openclaw models auth login` was replacing `agents.defaults.models`
wholesale whenever a provider returned a `configPatch` with that key,
even if the patch only listed the new default model. Re-authenticating
an OAuth provider such as OpenAI Codex wiped aliases and per-model
params for every other provider.

Make replacement opt-in via `ProviderAuthResult.replaceDefaultModels`.
Ordinary logins merge their allowlist patch so unrelated entries
survive; the Anthropic -> Claude CLI migration opts in because it
renames keys the merge path would otherwise keep stale.

Fixes #69414.

Made-with: Cursor
2026-04-23 07:16:24 +01:00
Peter Steinberger
5bd8254f61 fix(docs): keep source dirs in i18n route index 2026-04-23 07:15:46 +01:00
Peter Steinberger
3ccaa1b2f1 docs: prepare 2026.4.22 changelog 2026-04-23 07:15:23 +01:00
Vincent Koc
a3d0b4307b docs(release): use QA Lab all lanes gate 2026-04-22 23:13:29 -07:00
Peter Steinberger
c23ad91a14 fix(matrix): keep DM allowlist out of room commands 2026-04-23 07:09:34 +01:00
Vincent Koc
912dcfbc2b test(plugins): guard startup-gated hook wiring 2026-04-22 23:08:08 -07:00
Vincent Koc
3dc3bf65d2 fix(memory): support live lancedb hook enablement 2026-04-22 23:06:39 -07:00
Peter Steinberger
4e259b0461 fix: harden parallels update smoke 2026-04-23 07:05:37 +01:00
Peter Steinberger
cc343febfb fix: tolerate runtime deps temp cleanup races 2026-04-23 07:01:27 +01:00
Peter Steinberger
acb8fe986d build: keep runtime dep stamps out of dist 2026-04-23 06:55:07 +01:00
Peter Steinberger
bb55e23c67 test(e2e): cover OpenAI web search minimal reasoning 2026-04-23 06:51:29 +01:00
Peter Steinberger
f600e98e5b fix(agents): handle OpenAI web search schema rejects 2026-04-23 06:51:29 +01:00
Peter Steinberger
87c85c507a fix: align docs with cli and provider surfaces 2026-04-23 06:39:11 +01:00
joshavant
d3a8480093 qa-live: simplify telegram pass progress log lines 2026-04-23 00:37:03 -05:00
Peter Steinberger
2194be201d test(slack,line): reduce hot extension test imports 2026-04-23 06:28:06 +01:00
Peter Steinberger
a46d41156d fix(matrix): ignore stale no-reply events 2026-04-23 06:27:20 +01:00
Peter Steinberger
6b126cd0de feat(docs): add Thai translation support 2026-04-23 06:23:02 +01:00
Peter Steinberger
ebf351b138 fix(test): prevent Vitest shard stalls 2026-04-23 06:20:34 +01:00
joshavant
e6d0342629 qa-live: stream telegram scenario progress logs in realtime 2026-04-23 00:19:43 -05:00
Peter Steinberger
c78562d8a2 ci: fan out qa lab lanes 2026-04-23 06:15:01 +01:00
Peter Steinberger
76ab7c5b05 test: align channel plugin install fixtures 2026-04-23 06:13:31 +01:00
Vincent Koc
4955e57024 fix(skill-workshop): support live hook enablement 2026-04-22 22:09:10 -07:00
Peter Steinberger
db332aa8e9 ci: schedule qa lab gates 2026-04-23 06:08:29 +01:00
Peter Steinberger
e62431fd7f test: type onboarding plugin enable mock 2026-04-23 06:07:35 +01:00
Vincent Koc
f67e48e6a0 feat(onboarding): auto-install missing provider and channel plugins
Squash-merge PR 70012.
2026-04-22 22:05:00 -07:00
Peter Steinberger
86ace805b7 fix(qa): align telegram commands live assertion 2026-04-23 06:04:06 +01:00
Peter Steinberger
a2db4c9cdd ci: reuse docker e2e image across matrix 2026-04-23 06:02:51 +01:00
Peter Steinberger
66f94104c6 test: trim slow CI hotspot coverage 2026-04-23 06:02:26 +01:00
Peter Steinberger
e3caacd530 lint: enforce exhaustive switches 2026-04-23 06:02:12 +01:00
Peter Steinberger
4aa35d85fa test: clean up voice-call event timers 2026-04-23 06:02:12 +01:00
Vincent Koc
9f437549d3 fix(scripts): guard core test tsgo in sparse worktrees 2026-04-22 22:00:17 -07:00
Peter Steinberger
404c4c1f86 docs: document fast committer escape hatch 2026-04-23 05:57:53 +01:00
Peter Steinberger
112f6e1622 test: reuse prebuilt docker e2e image 2026-04-23 05:55:42 +01:00
Peter Steinberger
61dfbd78d5 test: add npm tarball onboarding docker e2e 2026-04-23 05:52:43 +01:00
joshavant
c2f0559829 qa-live: tag telegram observed messages with scenario context 2026-04-22 23:52:06 -05:00
Peter Steinberger
6163cfffdf test: update misc extension routing expectation 2026-04-23 05:50:57 +01:00
Peter Steinberger
69a4977fc7 fix(tooling): keep gitignore changes scoped 2026-04-23 05:50:14 +01:00
Peter Steinberger
e763ea1119 fix(plugins): stop tracking runtime deps manifests 2026-04-23 05:48:49 +01:00
Vincent Koc
ccde1c4707 fix(tooling): drop stale oxlint unicorn rule 2026-04-22 21:46:29 -07:00
Peter Steinberger
56c7ed0f8a test(codex): mock lightweight app-server runtime 2026-04-23 05:46:00 +01:00
Vincent Koc
d5c0f70e95 refactor(hooks): share live config fallback handling 2026-04-22 21:42:53 -07:00
Vincent Koc
4984cad5ae fix(test): route misc extension targets to the misc shard 2026-04-22 21:42:53 -07:00
joshavant
754577b43e qa-live: keep telegram failure details with public metadata redaction 2026-04-22 23:36:07 -05:00
Peter Steinberger
0be2b85951 test: avoid slow followup fallback fixture 2026-04-23 05:35:34 +01:00
Peter Steinberger
01ba0fa663 docs: update changelog for codex fixes 2026-04-23 05:35:18 +01:00
Peter Steinberger
d88d6a3c8b fix: complete codex app-server turns in docker 2026-04-23 05:35:17 +01:00
Peter Steinberger
20b05f220e fix: expose codex provider catalog 2026-04-23 05:35:17 +01:00
Peter Steinberger
0585e181f8 fix(media): prefer provider stt before local whisper 2026-04-23 05:30:57 +01:00
Peter Steinberger
fdf97a8784 chore: enable additional oxlint rules 2026-04-23 05:30:49 +01:00
Peter Steinberger
0b0662b1c9 chore: apply extension lint cleanups 2026-04-23 05:30:49 +01:00
Peter Steinberger
596b88986d chore: apply core lint cleanups 2026-04-23 05:30:49 +01:00
Peter Steinberger
cc9dcd3d69 fix(gateway): prefer linux child OOM victims
Raise eligible Linux child processes own oom_score_adj from a child-side /bin/sh exec shim so cgroup memory pressure prefers transient workers over the long-lived gateway. Cover supervisor children, PTY shells, MCP stdio servers, and OpenClaw-launched browser processes through the shared process runtime seam.

Harden the wrapper for distroless images, shell startup env, per-child and process-level opt-outs, dash-compatible exec, and leading-dash command names. Document Linux verification and OOM behavior.

Fixes #70404.

Co-authored-by: Neerav Makwana <261249544+neeravmakwana@users.noreply.github.com>
2026-04-23 05:23:40 +01:00
Peter Steinberger
d3a2e993a8 test(gateway): stabilize codex acp bind live 2026-04-23 05:22:37 +01:00
Peter Steinberger
3105ff2dda fix(acpx): preserve codex acp auth env 2026-04-23 05:22:37 +01:00
Peter Steinberger
e29abb2606 test: slim live auth staging 2026-04-23 05:22:37 +01:00
Peter Steinberger
f3c60e9c0d fix(lint): remove unsupported no-empty-pattern options 2026-04-23 05:22:37 +01:00
Peter Steinberger
4ad8ed2cbe refactor: type config schemas as typebox-compatible 2026-04-23 05:22:16 +01:00
Peter Steinberger
cf1e48672b fix: clean up acpx probe agent config 2026-04-23 05:20:53 +01:00
Peter Steinberger
6fb55f8959 extensions/acpx: align probeAgent with current config surface
Keep the acpx runtime type shim compatible with upstream probeAgent support and de-duplicate the rebased config/service wiring against current main. Normalize probeAgent the same way agent registry keys are normalized so mixed-case config resolves consistently.

Refs #68409
2026-04-23 05:20:53 +01:00
Sean Sun
eab26aca9b extensions/acpx: expose probeAgent config so non-codex ACP stacks stay available
Add optional probeAgent field to acpx plugin config, carry through
resolveAcpxPluginConfig, forward to AcpxRuntime constructor so users
can set plugins.entries.acpx.config.probeAgent to any configured agent
id instead of hardcoding codex.

Refs #68409
2026-04-23 05:20:53 +01:00
Marcus Castro
f5f0235bb1 feat(whatsapp): adopt replyToMode quoting (#62305)
* fix(core): align auto-reply threading behavior

* fix(core): propagate reply threading through outbound and gateway

* fix(whatsapp): use cached metadata for native quoted replies

* feat(whatsapp): add configurable native reply quoting
2026-04-23 01:19:47 -03:00
Shakker
728c644e4b cli: add temporary debug timing helper (#70469) (thanks @shakkernerd) 2026-04-23 05:17:17 +01:00
Shakker
d60eb9a4a4 fix: harden CLI debug timing helper 2026-04-23 05:17:17 +01:00
Shakker
106f0f0821 docs: document temporary CLI debug timing 2026-04-23 05:17:17 +01:00
Shakker
8273f5fc0a feat: add CLI debug timing helper 2026-04-23 05:17:17 +01:00
Josh Avant
01e18b6e3b Add maintainer-gated Telegram live QA workflow with Convex hardening (#70427) 2026-04-22 23:17:09 -05:00
Peter Steinberger
6317eda3fe ci: rebalance browser extension shard 2026-04-23 05:16:54 +01:00
Peter Steinberger
b5a7532022 build: finish typebox runtime migration 2026-04-23 05:12:32 +01:00
Peter Steinberger
33aea44fe5 refactor: tighten tool schema types 2026-04-23 05:06:58 +01:00
Peter Steinberger
675cf823fd fix(protocol): keep Swift array item types stable 2026-04-23 05:06:50 +01:00
Peter Steinberger
2c25e1d58d fix(openai): align auth picker copy metadata 2026-04-23 05:06:16 +01:00
Peter Steinberger
9937452405 build: enable more zero-baseline oxlint rules 2026-04-23 05:03:58 +01:00
Peter Steinberger
b2472d6560 build: migrate schema deps to typebox 2026-04-23 04:59:42 +01:00
Peter Steinberger
dd1ba0296c test: update lint suppression allowlist 2026-04-23 04:59:19 +01:00
Peter Steinberger
35ec4a9991 fix: make session write locks non-reentrant by default 2026-04-23 04:57:30 +01:00
Neerav Makwana
d878cf026c fix(pi-embedded-runner): address greptile review on incomplete-turn gate
- Drop redundant !lastToolError check from the messaging-tool clean-stop
  early return; the earlier lastToolError early return already handles
  that case, so the extra condition was dead and misleading.
- Update the CHANGELOG entry to reference only stopReason=stop; the pi-ai
  StopReason type does not include end_turn, so the earlier mention was
  a documentation-only discrepancy.
2026-04-23 04:57:09 +01:00
Neerav Makwana
6cd9136f2d fix(pi-embedded-runner): suppress incomplete-turn warning after clean messaging-tool delivery
The agent runner was surfacing a '⚠️ Agent couldn't generate a response'
warning even when the assistant had already sent user-visible content
through a messaging tool and the turn ended cleanly. Treat that path as
a successful delivery and skip the warning while keeping real failure
modes (tool errors, stopReason=error, interrupted tool use) intact.

Fixes #70396.
2026-04-23 04:57:09 +01:00
Peter Steinberger
93a1f5b3fa test(discord,zalo): trim slow extension tests 2026-04-23 04:54:49 +01:00
tm.lxrd
edea0cba7a fix(openai): align auth picker labels for API key vs Codex OAuth
Lock regression coverage for current OpenAI API key, Codex browser login, and Codex device pairing auth picker labels.\n\nThanks @tmlxrd.
2026-04-23 04:48:55 +01:00
Peter Steinberger
fab76f3d70 build: refresh bundled plugin runtime deps 2026-04-23 04:43:25 +01:00
Peter Steinberger
e61eba11e6 fix: avoid plugin normalization in status model refs 2026-04-23 04:43:25 +01:00
Peter Steinberger
2e40ca2c15 build: enable additional oxlint rules 2026-04-23 04:42:54 +01:00
Ayaan Zaidi
dc5ab602df docs(cli): credit oauth session continuity PR 2026-04-23 09:06:56 +05:30
Ayaan Zaidi
97e9e05f8c docs(cli): clarify oauth session continuity 2026-04-23 09:06:56 +05:30
Ayaan Zaidi
3eb6edc67c fix(cli): key oauth session epochs on identity 2026-04-23 09:06:56 +05:30
Peter Steinberger
c866820fed refactor(stt): share transcription helpers 2026-04-23 04:29:35 +01:00
Super Zheng
a58633d809 test: fix ui presenter next run test for multi-language environments (#60231)
Merged via squash.

Prepared head SHA: 88e7c3c95b
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-04-22 20:26:44 -07:00
Peter Steinberger
576dbdeef7 build: enable new oxlint rules 2026-04-23 04:23:34 +01:00
Peter Steinberger
2908190ba2 fix(agents): recover streamed timings usage (#41056) (thanks @xaeon2026) 2026-04-23 04:23:27 +01:00
Peter Steinberger
137a3629cc fix: harden acpx openclaw bridge routing 2026-04-23 04:22:32 +01:00
alexlomt
0bcd390546 fix(acpx): avoid per-session MCP on openclaw bridge 2026-04-23 04:22:32 +01:00
Peter Steinberger
f79c6ab607 test: update bundled runtime mirror expectations 2026-04-23 04:22:20 +01:00
Peter Steinberger
d0d018bdad fix(qa): restore agentic parity tool runtime 2026-04-23 04:22:03 +01:00
Peter Steinberger
ca8a6e811c docs: note TTS transcript fix (#68869) (thanks @zqchris) 2026-04-23 04:22:03 +01:00
zqchris
0020a327b9 fix(agents): defuse unicode-whitespace MEDIA lines 2026-04-23 04:22:03 +01:00
zqchris
c165af97d7 fix(agents): defuse TTS transcript fence markers 2026-04-23 04:22:03 +01:00
Chris Zhang
7b51b7b26f fix(agents): preserve spoken text in tts tool result
The tts tool previously returned a fixed "Generated audio reply."
string in its content, so session transcripts lost what was actually
spoken. Across every channel, a voice-only reply left no text record
for future turns, forcing users to recover transcripts from the
provider's API. Echo the synthesized text back in the tool result
content (audio still delivered via details.media).

Sanitize the transcript before embedding so crafted utterances cannot
inject reply directives when tool output is rendered in verbose mode:
MEDIA: at line start and [[…]] markers are interrupted with a
zero-width word joiner (U+2060) that defuses parseReplyDirectives
without altering the visible text.
2026-04-23 04:22:03 +01:00
Peter Steinberger
f0cc29af9a test(build): align runtime mirror guard expectations 2026-04-23 04:18:55 +01:00
Peter Steinberger
ff260ce67b build: fix bundled plugin runtime mirror guard 2026-04-23 04:15:39 +01:00
Super Zheng
87c6aaff3e build: verify bundled plugin runtime mirrors in postpublish checks (#60112)
Merged via squash.

Prepared head SHA: 79bbb105a8
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-04-22 20:12:23 -07:00
Peter Steinberger
1e8564cb13 fix(auth-profiles): repair stale codex oauth profiles 2026-04-23 04:03:47 +01:00
Mason Huang
c545416498 docs(changelog): remove Token Plan from Tencent provider entry (#68460) (#70450) 2026-04-23 11:02:57 +08:00
Peter Steinberger
9660cb705b fix(memory): preserve KNN filter limits (#69680) (thanks @aalekh-sarvam) 2026-04-23 04:01:47 +01:00
aalekh-sarvam
7cd051d7f7 fix(memory): use sqlite-vec KNN for searchVector (190x speedup)
Replace full-table scan via vec_distance_cosine() + ORDER BY LIMIT with
sqlite-vec's native MATCH + k = ? KNN operator. Keep vec_distance_cosine()
in the SELECT so score = 1 - dist preserves the existing cosine [0,1]
semantics the downstream merge pipeline depends on.

Fixes #69666.

Benchmark on 10,827 chunks, 4096-dim embeddings:
- Before (full scan):  ~8490 ms/query
- After  (KNN + join): ~50 ms/query

No behavioral changes: returned ids and ordering are identical to the
previous query on all tested queries. The LIMIT ? binding is replaced by
k = ? which caps sqlite-vec's candidate set to the same count.
2026-04-23 04:01:47 +01:00
Peter Steinberger
06308e21f7 build: update dependencies 2026-04-23 04:00:17 +01:00
Peter Steinberger
1c91f3f09f fix: route btw provider streams by workspace (#70413) (thanks @suboss87) 2026-04-23 03:59:11 +01:00
Subash
bc3c8eee2c fix(agents): route /btw through the provider's stream fn so Ollama URLs build correctly 2026-04-23 03:59:11 +01:00
Peter Steinberger
da8621df0d fix(openai-completions): enable local streaming usage compat (#68711) (thanks @gaineyllc) 2026-04-23 03:57:04 +01:00
Peter Steinberger
d968749c4d ci: split discord telegram extension shards 2026-04-23 03:56:39 +01:00
Peter Steinberger
728e29a898 test(agents): cover openai-completions tool-call arg repair 2026-04-23 03:54:16 +01:00
Peter Steinberger
6b765f58d3 docs(changelog): clarify realtime stt entries 2026-04-23 03:53:14 +01:00
Peter Steinberger
84e0c2f0ea ci: rebalance slack extension shard 2026-04-23 03:49:43 +01:00
Peter Steinberger
90a34cc242 docs: credit openai-completions repair PR (#70294) (thanks @MonkeyLeeT) 2026-04-23 03:49:04 +01:00
Peter Steinberger
7503d4859f fix(plugin-sdk): fall back for provider auth runtime 2026-04-23 03:49:04 +01:00
Peter Steinberger
5e172b3888 fix(qa): preserve image parity plugin allowlist 2026-04-23 03:49:04 +01:00
Peter Steinberger
f78fc61768 fix(agents): pass embedded tool allowlist to pi sessions 2026-04-23 03:49:04 +01:00
Ted Li
2ba43f5d27 fix(agents): keep tool-call repair scoped by transport 2026-04-23 03:49:04 +01:00
Ted Li
49c7319ea5 fix(agents): repair malformed tool-call args on openai-completions 2026-04-23 03:49:04 +01:00
Peter Steinberger
e54d0634c5 fix: harden removed Codex auth choice guidance (#70390) (thanks @pashpashpash) 2026-04-23 03:45:01 +01:00
Peter Steinberger
84aa35e9b2 ci: split slow extension shard pairs 2026-04-23 03:43:55 +01:00
Peter Steinberger
35c9f96878 test: wait for gateway restart sentinel 2026-04-23 03:42:34 +01:00
Ayaan Zaidi
2a4514afca fix: preserve restart hooks during async prep (#70269) 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
ab32c53103 fix(gateway): preserve restart hooks across coalescing 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
46ce666b04 fix(gateway): keep restart emitting after ack prep failure 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
fe5f0cddb9 fix(gateway): bind restart continuation to emitted restart 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
f5173589a4 fix(gateway): harden restart acknowledgements 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
95ecb0526e docs(gateway): document restart acknowledgement default 2026-04-23 08:07:53 +05:30
Ayaan Zaidi
b982d9e669 fix(gateway): default restart acknowledgement continuations 2026-04-23 08:07:53 +05:30
Peter Steinberger
0e7bcf7588 feat(plugin-sdk): share realtime transcription websocket sessions 2026-04-23 03:35:32 +01:00
Peter Steinberger
86b160869d ci: rebalance extension test shards 2026-04-23 03:34:44 +01:00
Peter Steinberger
b09aed8271 fix: cap long SDK retry waits (#68474) (thanks @jetd1) 2026-04-23 03:32:35 +01:00
Peter Steinberger
41715b56af ci: rebalance agentic test shard 2026-04-23 03:28:21 +01:00
pashpashpash
c71f07ba43 Fail fast for removed Codex import auth choice 2026-04-22 19:27:52 -07:00
pashpashpash
788fd14118 Preserve removed Codex import auth choice 2026-04-22 19:27:52 -07:00
pashpashpash
103d7af458 Fix legacy update compat sidecars 2026-04-22 19:27:52 -07:00
pashpashpash
93a2143384 Remove stale Codex import auth choice 2026-04-22 19:27:52 -07:00
pashpashpash
6f6fa5c90b Remove Codex CLI auth import 2026-04-22 19:27:52 -07:00
Peter Steinberger
5a22d16bde ci: collapse built artifact test consumers 2026-04-23 03:24:48 +01:00
Peter Steinberger
aa27a9474f fix(outbound): centralize active delivery claims 2026-04-23 03:23:38 +01:00
Neerav Makwana
ca83f0fd7a fix(outbound): bail live delivery when a concurrent drain wins the claim
If a reconnect/startup drain observes the newly enqueued queue entry and
calls claimRecoveryEntry before the live delivery path reaches
tryClaimActiveDelivery, tryClaimActiveDelivery returns false. Previously
the live path still proceeded to deliverOutboundPayloadsCore and then
ack/fail, which would race the drain's own delivery and ack/fail for the
same entry id and produce duplicate outbound messages.

Treat a failed claim acquisition as "another in-process owner is already
handling this queue entry" and bail out with an empty result array, leaving
the queue entry in place for the drain to deliver and clean up. This closes
the narrow residual race called out by the Aisle security review on
openclaw/openclaw#70428.

Made-with: Cursor
2026-04-23 03:23:38 +01:00
Neerav Makwana
c94a8702c7 fix(outbound): hold active-delivery claim so reconnect drain skips live sends
Reconnect drain (drainPendingDeliveries) matches fresh pending entries by
design to preserve crash-replay, but the live delivery path in
deliverOutboundPayloads held no in-memory claim while the send was running.
A reconnect firing mid-send therefore re-drove the same queue entry and
produced duplicate outbound messages (e.g. WhatsApp cron sends going out
7-12x when the 30-minute inbound-silence watchdog fired during delivery).

Claim the queueId against the existing entriesInProgress set right after
enqueueDelivery and release it in the finally branch around ack/fail. Drain
already skips claimed ids via claimRecoveryEntry, so no drain-side change is
needed. The claim is process-local on purpose: a crashed owner leaves no
claim behind, so startup recovery still reclaims orphaned entries.

Fixes #70386.

Made-with: Cursor
2026-04-23 03:23:38 +01:00
Peter Steinberger
adda0dcf20 test: cover bundled plugin dependency activation 2026-04-23 03:17:06 +01:00
Peter Steinberger
90696bffff fix: defer bundled plugin runtime deps until enabled 2026-04-23 03:17:06 +01:00
Peter Steinberger
4479d4d437 ci: fold gateway watch into build artifacts 2026-04-23 03:15:56 +01:00
Peter Steinberger
688a6ef4fd ci: keep gateway watch skip-build artifact fresh 2026-04-23 03:11:51 +01:00
Peter Steinberger
bae057fd77 fix: accept Codex MCP approval elicitations (#68807) 2026-04-23 03:11:26 +01:00
Peter Steinberger
24f5198caf ci: trust restored gateway watch artifacts 2026-04-23 03:09:40 +01:00
4572 changed files with 266994 additions and 57184 deletions

View File

@@ -1,11 +1,6 @@
---
name: blacksmith-testbox
description: >
Validate code changes against real CI when local execution is not
enough. Use for CI-parity checks, secrets/services, migrations, or
builds/tests that cannot run reliably on the local machine. Do not
replace repo-documented local test/build loops just because this
skill exists.
description: Run Blacksmith Testbox for CI-parity checks, secrets, hosted services, migrations, or builds local cannot reproduce.
---
# Blacksmith Testbox

View File

@@ -1,6 +1,6 @@
---
name: openclaw-ghsa-maintainer
description: Maintainer workflow for OpenClaw GitHub Security Advisories (GHSA). Use when Codex needs to inspect, patch, validate, or publish a repo advisory, verify private-fork state, prepare advisory Markdown or JSON payloads safely, handle GHSA API-specific publish constraints, or confirm advisory publish success.
description: Inspect, patch, validate, publish, or confirm OpenClaw GHSA security advisories and private-fork state.
---
# OpenClaw GHSA Maintainer

View File

@@ -1,6 +1,6 @@
---
name: openclaw-parallels-smoke
description: End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.
description: Run, rerun, debug, or interpret OpenClaw Parallels install, onboarding, gateway smoke, and upgrade checks.
---
# OpenClaw Parallels Smoke
@@ -45,6 +45,9 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
## npm install then update
- Preferred entrypoint: `pnpm test:parallels:npm-update`
- For a macOS-only published release update check, use:
- `timeout --foreground 75m pnpm test:parallels:npm-update -- --platform macos --package-spec openclaw@<old-version> --update-target <target-version-or-tag> --json`
This keeps the same-guest `openclaw update --tag ...` coverage and uses the shared macOS current-user/sudo fallback without starting Windows/Linux lanes.
- Required coverage: every release/update regression run must include both lanes:
- fresh snapshot -> install requested package/baseline -> smoke
- same guest baseline -> run the guest's installed `openclaw update ...` command -> smoke again
@@ -75,6 +78,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
## macOS flow
- Preferred entrypoint: `pnpm test:parallels:macos`
- `parallels-macos-smoke.sh --mode fresh --target-package-spec openclaw@<version>` is an install smoke only. For published old-version -> new-version update coverage on macOS, prefer the npm-update wrapper with `--platform macos`; `parallels-macos-smoke.sh --mode upgrade --target-package-spec ...` installs the target package and does not exercise the baseline CLI's updater.
- Default upgrade coverage on macOS should now include: fresh snapshot -> site installer pinned to the latest stable tag -> `openclaw update --channel dev` on the guest. Treat this as part of the default Tahoe regression plan, not an optional side quest.
- `parallels-macos-smoke.sh --mode upgrade` should run that release-to-dev lane by default. Keep the older host-tgz upgrade path only when the caller explicitly passes `--target-package-spec`.
- Because the default upgrade lane no longer needs a host tgz, skip `npm pack` + host HTTP server startup for `--mode upgrade` unless `--target-package-spec` is set. Keep the pack/server path for `fresh` and `both`.
@@ -144,6 +148,7 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- `--discord-token-env`
- `--discord-guild-id`
- `--discord-channel-id`
- After a successful Discord smoke/roundtrip, shut down the guest VM before handoff (`prlctl stop "$VM_NAME"` or the concrete VM name). The macOS smoke harness should do this automatically after successful Discord proof; still stop the VM manually after ad-hoc Discord checks. Do not leave the Discord-configured guest running; it can keep reading/posting in `#maintainer` and spam Discord after the proof is complete.
- Keep the Discord token only in a host env var.
- Use installed `openclaw message send/read`, not `node openclaw.mjs message ...`.
- Set `channels.discord.guilds` as one JSON object, not dotted config paths with snowflakes.

View File

@@ -1,6 +1,6 @@
---
name: openclaw-pr-maintainer
description: Maintainer workflow for reviewing, triaging, preparing, closing, or landing OpenClaw pull requests and related issues. Use when Codex needs to validate bug-fix claims, search for related issues or PRs, apply or recommend close/reason labels, prepare GitHub comments safely, check review-thread follow-up, or perform maintainer-style PR decision making before merge or closure.
description: Review, triage, close, label, comment on, or land OpenClaw PRs/issues with maintainer evidence checks.
---
# OpenClaw PR Maintainer
@@ -68,6 +68,7 @@ gh search issues --repo openclaw/openclaw --match title,body --limit 50 \
- Keep commit messages concise and action-oriented.
- Group related changes; avoid bundling unrelated refactors.
- Use `.github/pull_request_template.md` for PR submissions and `.github/ISSUE_TEMPLATE/` for issues.
- Do not commit PR-only artifacts such as screenshots under `.github/pr-assets`; attach them to the PR/comment or use an external artifact store instead.
## Extra safety

View File

@@ -1,6 +1,6 @@
---
name: openclaw-qa-testing
description: Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
description: Run, watch, debug, extend, or explain OpenClaw qa-lab and qa-channel scenarios, artifacts, and live lanes.
---
# OpenClaw QA Testing
@@ -49,6 +49,66 @@ pnpm openclaw qa suite \
5. If the user wants to watch the live UI, find the current `openclaw-qa` listen port and report `http://127.0.0.1:<port>`.
6. If a scenario fails, fix the product or harness root cause, then rerun the full lane.
## QA credentials and 1Password
- Use `op` only inside `tmux` for QA secret lookup in this repo.
- Quick auth check inside tmux:
```bash
op account list
```
- Direct Telegram npm live test secrets currently live in 1Password item:
- vault: `OpenClaw`
- item: `Telegram E2E`
- That item is the first place to look for:
- `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`
- `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`
- `OPENCLAW_QA_PROVIDER_MODE`
- `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC`
- Convex QA secrets currently live in 1Password items:
- vault: `OpenClaw`
- item: `OPENCLAW_QA_CONVEX_SITE_URL`
- item: `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`
- item: `OPENCLAW_QA_CONVEX_SECRET_CI`
- Additional related notes/login items seen during QA credential work:
- vault: `Private`
- items: `OPENCLAW QA`, `Convex`, `Telegram`
- If a required value is missing from those notes:
- do not guess
- ask the maintainer/operator for the current value or the current 1Password item name
- for Telegram direct runs, `OPENCLAW_QA_TELEGRAM_GROUP_ID` may be stored separately from `Telegram E2E`
- for Convex runs, the leased Telegram credential should provide the Telegram group id and bot tokens together; do not require a separate `OPENCLAW_QA_TELEGRAM_GROUP_ID`
- for Convex runs, prefer `OpenClaw/OPENCLAW_QA_CONVEX_SITE_URL`; if that is stale or unclear, ask for the active pool URL before running
- Prefer direct Telegram envs for the npm Telegram Docker lane when available:
```bash
OPENCLAW_QA_TELEGRAM_GROUP_ID="..." \
OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN="..." \
OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN="..." \
OPENCLAW_QA_PROVIDER_MODE="mock-openai" \
OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC="openclaw@beta" \
pnpm test:docker:npm-telegram-live
```
- Prefer Convex mode when the goal is stable shared QA infra:
- round-robin credential leasing
- thinner wrapper for channel-specific setup
- CLI/admin flows around the pooled credentials
- Live npm Telegram Docker lane note:
- `scripts/e2e/npm-telegram-live-runner.ts` reads `OPENCLAW_NPM_TELEGRAM_PROVIDER_MODE`
- do not assume `OPENCLAW_QA_PROVIDER_MODE` is consumed by that wrapper
- if a 1Password note only gives `OPENCLAW_QA_PROVIDER_MODE`, map it explicitly to `OPENCLAW_NPM_TELEGRAM_PROVIDER_MODE` before running the Docker lane
- Verified live shape:
- Convex mode can pass the real Docker lane without direct Telegram env vars
- leased Telegram payload includes the group id coupled to the driver/SUT tokens
- a real run of `pnpm test:docker:npm-telegram-live` passed with:
- `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`
- `OPENCLAW_QA_CREDENTIAL_ROLE=maintainer`
- `OPENCLAW_QA_CONVEX_SITE_URL`
- `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`
- `OPENCLAW_NPM_TELEGRAM_PROVIDER_MODE=mock-openai`
## Character evals
Use `qa character-eval` for style/persona/vibe checks across multiple live models.

View File

@@ -1,6 +1,6 @@
---
name: openclaw-release-maintainer
description: Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
description: Prepare or verify OpenClaw stable/beta releases, changelogs, release notes, publish commands, and artifacts.
---
# OpenClaw Release Maintainer
@@ -70,6 +70,22 @@ Use this skill for release and publish-time workflow. Keep ordinary development
- Every stable OpenClaw release ships the npm package and macOS app together.
Beta releases normally ship npm/package artifacts first and skip mac app
build/sign/notarize unless the operator requests mac beta validation.
- Do not let the slower macOS signing/notary path block npm publication once
the npm preflight has passed. Keep mac validation/publish running in
parallel, publish npm from the successful npm preflight, then start published
npm install/update, Docker, and Parallels verification while mac artifacts
continue.
- Mac packaging may be built from a slight release-branch variation of the
tagged commit when the delta is mac packaging, signing, workflow, or
validation-only release machinery. If mac packaging needs release-branch-only
fixes after the stable npm package or GitHub tag is already published, do not
create a `vYYYY.M.D-N` correction tag just to change the workflow source.
Dispatch the private mac workflows for the original `tag=vYYYY.M.D` with
`source_ref=release/YYYY.M.D` and `public_release_branch=release/YYYY.M.D`;
provenance checks must prove the source SHA descends from the tag and
validation/preflight use the same source. Reserve `vYYYY.M.D-N` correction
tags for emergency hotfixes that must publish a new npm package/release
identity, not for ordinary mac-only packaging recovery.
- The production Sparkle feed lives at `https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml`, and the canonical published file is `appcast.xml` on `main` in the `openclaw` repo.
- That shared production Sparkle feed is stable-only. Beta mac releases may
upload assets to the GitHub prerelease, but they must not replace the shared
@@ -81,7 +97,16 @@ Use this skill for release and publish-time workflow. Keep ordinary development
## Build changelog-backed release notes
- Before release branching or tagging, rewrite the target `CHANGELOG.md`
section from commit history, not just from existing notes: scan commits since
the last reachable release tag, add missed user-facing changes, dedupe
overlapping entries, and sort each section from most to least interesting for
users.
- Changelog entries should be user-facing, not internal release-process notes.
- GitHub release and prerelease bodies must use the full matching
`CHANGELOG.md` version section, not highlights or an excerpt. When creating
or editing a release, extract from `## YYYY.M.D` through the line before the
next level-2 heading and use that complete block as the release notes.
- When cutting a mac release with a beta GitHub prerelease:
- tag `vYYYY.M.D-beta.N` from the release commit
- create a prerelease titled `openclaw YYYY.M.D-beta.N`
@@ -104,14 +129,33 @@ live`; keep it clearly beta and avoid implying stable promotion.
- Lead with user-visible capabilities, then important integrations, then
reliability/security/install fixes. Compress "lots of fixes" into one
readable bullet.
- Read the full changelog section before drafting. Do not lead with coverage,
CI, validation, or internal release mechanics unless the release is explicitly
about those. Peter prefers concrete user wins: features, integrations,
workflow improvements, and practical reliability fixes.
- Tone: high-signal, slightly cheeky, confident, not corporate. One joke is
enough. Avoid punching down, insulting users, or promising what was not
verified.
- Length: release tweets are always standard tweets under 280 characters. Trim
to 3-4 bullets and count the final text before posting.
- Links/media: include the GitHub release or changelog link at the end. Add a
short docs follow-up reply only when there is a standout feature that needs
setup instructions.
- Peter likes dry, compact taglines when they feel earned. Good example:
`Big release, tiny release notes... kidding.` Keep the joke short and let the
feature bullets carry the tweet; do not turn the punchline into a second
paragraph or a forced bit.
- Length: release tweets are always standard tweets under 280 characters, with
room for one URL. Trim to 3-4 bullets and count the final text before posting.
- Links/media: include the GitHub release or changelog link at the end of the
first release tweet.
- Thread follow-ups: if doing a thread, keep the first release tweet as the
compact launch post, then publish one focused feature explainer per reply.
Follow-up replies should not repeat "new in VERSION" or the version number
when the thread context already makes it obvious.
- Every follow-up tweet should include a docs URL for that specific feature.
Prefer a bare URL over `Docs: <url>` unless the label is needed for clarity.
Keep follow-ups concise: around 160-220 raw characters is usually the sweet
spot; under 280 is the hard cap. If a URL makes a tweet fail, trim prose
before dropping the URL.
Prefer explaining diagnostics, trajectory/export, provider setup, model
commands, or other setup-heavy features in follow-ups instead of overloading
the first release tweet.
- Hotfix/correction: be direct and accountable. State what slipped, what is
fixed, and the new version. Keep jokes out of incident-style posts.
@@ -201,9 +245,18 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- 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`.
- Release QA and Parallels validation for this train must use both
- 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 the long lanes and report the missing key.
`.profile`, 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
for it to pass before npm preflight/publish readiness. Use a SHA only when it
satisfies the workflow's secret-bearing trust gate: main ancestor or open PR
head. It runs the QA Lab mock parity gate plus live Matrix and live Telegram
lanes using the `qa-live-shared` environment; Telegram uses Convex CI
credential leases.
- Default release checks:
- `pnpm check`
- `pnpm check:test-types`
@@ -221,23 +274,42 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- all Parallels install/update tests:
`pnpm test:parallels:npm-update -- --json` plus any needed individual
rerun lanes from `openclaw-parallels-smoke`
- all QA release validation:
OpenAI live suite with `openai/gpt-5.4` in fast mode, Anthropic live suite
with `anthropic/claude-opus-4-6`, and the repo-backed character evals
- all QA release validation: dispatch GitHub Actions > `QA-Lab - All Lanes`
against the release tag and require success. This is the release gate for
live credentialed Matrix/Telegram channel coverage. Use a SHA only when it
satisfies the workflow trust gate. Run local OpenAI/Anthropic suites or
repo-backed character evals only when the operator asks for extra model
coverage or a failure needs local debugging.
- Post-published beta verification roster:
- `node --import tsx scripts/openclaw-npm-postpublish-verify.ts <beta-version>`
- install/update smoke against the published beta channel
- Docker install/update coverage that exercises the published beta package
- published npm Telegram proof: dispatch Actions > `NPM Telegram Beta E2E`
from `main` with `package_spec=openclaw@<beta-version>` and
`provider_mode=mock-openai`, approve `npm-release`, and require success.
This is the default button path for installed-package onboarding,
Telegram setup, and real Telegram E2E against the published npm package.
Use the local `pnpm test:docker:npm-telegram-live` lane with the matching
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC` and Convex CI env only as a fallback
or debugging path.
- Parallels published beta install/update coverage with both OpenAI and
Anthropic provider keys available
- Parallels install/update proof must keep plugin installs enabled unless the
operator explicitly scopes a harness-only isolation check; a lane that
disables bundled plugin installs is not valid plugin/dependency release
evidence.
- targeted QA reruns only for areas touched by fixes after the full pre-npm
roster, unless the operator requests the full QA roster again
roster, unless the operator requests the full QA roster again. If the fix
touches live channel QA, credential plumbing, Matrix, Telegram, or the QA
harness, rerun Actions > `QA-Lab - All Lanes`.
- Check all release-related build surfaces touched by the release, not only the npm package.
- For beta-style full e2e batteries, hard-cap top-level long lanes instead of letting them run indefinitely. Use host `timeout --foreground`/`gtimeout --foreground` caps such as:
- `45m` for `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke`
- `90m` for `pnpm test:docker:all`
- `60m` each for standalone Docker live lanes
- `180m` for the full QA live OpenAI + Anthropic roster
- `180m` for local full QA live OpenAI + Anthropic rosters when explicitly
requested; the default release channel QA gate is Actions >
`QA-Lab - All Lanes`
- Parallels caps from the `openclaw-parallels-smoke` skill
If a lane hits its cap, stop and inspect/fix the affected lane before continuing; do not continue to wait on the same process.
- Actual npm install/update phases are capped at 5 minutes. If `npm install -g`, installer package install, or `openclaw update` takes longer than 300s in release e2e, stop treating the run as healthy progress and debug the installer/updater or harness.
@@ -257,7 +329,14 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
public release assets so the updater feed cannot lag the published binaries.
- Serialize stable appcast-producing runs across tags so two releases do not
generate replacement `appcast.xml` files from the same stale seed.
- For stable releases, confirm the latest beta already passed the broader release workflows before cutting stable.
- For stable releases, rely primarily on the latest beta's broader release
workflow confidence. When promoting the matching non-beta build to npm
`latest`, prefer a light time-bounded verification pass: published npm
postpublish verify, Docker install/update smoke, macOS-only Parallels
install/update smoke, and required QA signal. Do not rerun the full
Docker/Parallels matrix unless the beta evidence is stale, the stable build
differs materially from beta, or the operator explicitly asks for full
retesting.
- If any required build, packaging step, or release workflow is red, do not say the release is ready.
## Use the right auth flow
@@ -267,6 +346,29 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`
workflow because `npm dist-tag` management needs `NPM_TOKEN`, while the
public npm release workflow stays OIDC-only.
- Prefer fixing the private workflow token path over any local 1Password
fallback. The desired setup is a granular npm token stored as the private
repo's `NPM_TOKEN` secret, scoped to the `openclaw` package with read/write
and 2FA bypass for automation.
- If the private dist-tag workflow cannot promote because `NPM_TOKEN` is absent
or stale, use the local tmux + 1Password fallback:
- Start or reuse a tmux session so interactive `npm login` and OTP prompts
are observable and recoverable.
- Hard rule: never run `op` directly in the main agent shell during release
work. Any 1Password CLI use must happen inside that tmux session so prompts
and alerts are contained and observable.
- Use the 1Password item `op://Private/Npmjs` for npm credentials and OTP.
Do not print passwords, tokens, or OTPs to the transcript; send them through
tmux buffers, env vars scoped to the tmux command, or `expect` with
`log_user 0`.
- Re-authenticate npm inside that tmux session with
`npm login --auth-type=legacy`, then confirm `npm whoami` reports
`steipete`.
- Promote with a fresh OTP:
`npm dist-tag add openclaw@YYYY.M.D latest --otp "$OTP"`.
- Verify with a cache-bypassed registry read, for example:
`npm view openclaw dist-tags --json --prefer-online --cache /tmp/openclaw-npm-cache-verify-$$`
and `npm view openclaw@latest version dist.tarball --json --prefer-online`.
- Direct stable publishes can also use that private dist-tag workflow to point
`beta` at the already-published `latest` version when the operator wants both
tags aligned immediately.
@@ -383,73 +485,82 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
6. Create `release/YYYY.M.D` from that post-changelog `main` commit.
7. Make every repo version location match the beta tag before creating it.
8. Commit release preparation changes on the release branch and push the branch.
9. Run the full pre-npm beta test roster from the release branch before any npm
preflight or publish.
9. Run the local build, Docker, and Parallels parts of the full pre-npm beta
test roster from the release branch before any npm preflight or publish.
10. For beta releases, skip mac app build/sign/notarize unless beta scope or a
release blocker specifically requires it. For stable releases, include the
mac app, signing, notarization, and appcast path.
11. Confirm the target npm version is not already published.
12. Create and push the git tag from the release branch.
13. Create or refresh the matching GitHub release.
14. Start `.github/workflows/openclaw-npm-release.yml` from the release branch
14. Dispatch Actions > `QA-Lab - All Lanes` against the release tag and wait
for the mock parity, live Matrix, and live Telegram credentialed-channel
lanes to pass.
15. Start `.github/workflows/openclaw-npm-release.yml` from the release branch
with `preflight_only=true`
and choose the intended `npm_dist_tag` (`beta` default; `latest` only for
an intentional direct stable publish). Wait for it to pass. Save that run id
because the real publish requires it to reuse the prepared npm tarball.
15. For stable releases, start `.github/workflows/macos-release.yml` in
16. For stable releases, start `.github/workflows/macos-release.yml` in
`openclaw/openclaw` and wait for the public validation-only run to pass.
16. For stable releases, start
17. For stable releases, start
`openclaw/releases-private/.github/workflows/openclaw-macos-validate.yml`
with the same tag and wait for the private mac validation lane to pass.
17. For stable releases, start
18. For stable releases, start
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml`
with `preflight_only=true` and wait for it to pass. Save that run id because
the real publish requires it to reuse the notarized mac artifacts.
18. If any preflight or validation run fails, fix the issue on a new commit,
19. If any preflight or validation run fails, fix the issue on a new commit,
delete the tag and matching GitHub release, recreate them from the fixed
commit, and rerun all relevant preflights from scratch before continuing.
Never reuse old preflight results after the commit changes. For pushed or
published beta tags, do not delete/recreate; increment to the next beta tag.
19. Start `.github/workflows/openclaw-npm-release.yml` from the same branch with
20. Start `.github/workflows/openclaw-npm-release.yml` from the same branch with
the same tag for the real publish, choose `npm_dist_tag` (`beta` default,
`latest` only when you intentionally want direct stable publish), keep it
the same as the preflight run, and pass the successful npm
`preflight_run_id`.
20. Wait for `npm-release` approval from `@openclaw/openclaw-release-managers`.
21. Run postpublish verification:
21. Wait for `npm-release` approval from `@openclaw/openclaw-release-managers`.
22. Run postpublish verification:
`node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>`.
22. Run the post-published beta verification roster. If any lane fails after
23. Run the post-published beta verification roster. If any lane fails after
the beta tag/package is pushed or published, fix, commit/push/pull,
increment to the next beta tag, and restart at the full pre-npm beta test
roster for the new beta. 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.
23. Announce the beta/stable release on Discord best-effort using Peter's bot
roster for the new beta. The roster includes the manual Actions >
`NPM Telegram Beta E2E` workflow against the exact published beta package.
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. If the operator requested beta only, stop after beta verification and the
25. If the operator requested beta only, stop after beta verification and the
announcement.
25. If the stable release was published to `beta`, start the private
26. If the stable release was published to `beta`, use the light stable
promotion roster when the matching beta already carried the full confidence
pass: published npm postpublish verify, Docker install/update smoke,
macOS-only Parallels install/update smoke, and required QA signal.
Then start the private
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`
workflow after beta validation passes to promote that stable version from
`beta` to `latest`, then verify `latest` now points at that version.
26. If the stable release was published directly to `latest` and `beta` should
workflow to promote that stable version from `beta` to `latest`, then
verify `latest` now points at that version.
27. If the stable release was published directly to `latest` and `beta` should
follow it, start that same private dist-tag workflow to point `beta` at the
stable version, then verify both `latest` and `beta` point at that version.
27. For stable releases, start
28. For stable releases, start
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml`
for the real publish with the successful private mac `preflight_run_id` and
wait for success.
28. Verify the successful real private mac run uploaded the `.zip`, `.dmg`,
29. Verify the successful real private mac run uploaded the `.zip`, `.dmg`,
and `.dSYM.zip` artifacts to the existing GitHub release in
`openclaw/openclaw`.
29. For stable releases, download `macos-appcast-<tag>` from the successful
30. For stable releases, download `macos-appcast-<tag>` from the successful
private mac run, update `appcast.xml` on `main`, and verify the feed. Merge
or cherry-pick release branch changes back to `main` after stable succeeds.
30. For beta releases, publish the mac assets only when intentionally requested;
31. For beta releases, publish the mac assets only when intentionally requested;
expect no shared production
`appcast.xml` artifact and do not update the shared production feed unless a
separate beta feed exists.
31. After publish, verify npm and the attached release artifacts.
32. After publish, verify npm and the attached release artifacts.
## GHSA advisory work

View File

@@ -1,6 +1,6 @@
---
name: openclaw-secret-scanning-maintainer
description: Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
description: Triage, redact, clean up, and resolve OpenClaw GitHub Secret Scanning alerts in issues or PRs.
---
# OpenClaw Secret Scanning Maintainer

View File

@@ -1,6 +1,6 @@
---
name: openclaw-test-heap-leaks
description: Investigate `pnpm test` memory growth, Vitest worker OOMs, and suspicious RSS increases in OpenClaw using the `scripts/test-parallel.mjs` heap snapshot tooling. Use when Codex needs to reproduce test-lane memory growth, collect repeated `.heapsnapshot` files, compare snapshots from the same worker PID, triage likely transformed-module retention versus likely runtime leaks, and fix or reduce the impact by patching cleanup logic or isolating hotspot tests.
description: Investigate OpenClaw pnpm test memory growth, Vitest OOMs, RSS spikes, and heap snapshot deltas.
---
# OpenClaw Test Heap Leaks

View File

@@ -1,6 +1,6 @@
---
name: openclaw-test-performance
description: Benchmark, diagnose, and optimize OpenClaw test performance without losing coverage. Use when Codex needs to reassess `pnpm test`, compare grouped Vitest reports, identify CPU/memory/import hotspots, fix slow tests or cold runtime paths, preserve behavior proofs, update the performance report, add AGENTS guardrails, and make scoped commits/pushes for OpenClaw test-speed work.
description: Benchmark, diagnose, and optimize OpenClaw test runtime, import hotspots, CPU/RSS, and slow coverage paths.
---
# OpenClaw Test Performance

View File

@@ -1,6 +1,6 @@
---
name: optimizetests
description: Optimize OpenClaw test runtime end to end. Use when the user asks for /optimizetests, slow-test review, import optimization, deduping tests, moving misplaced core coverage to extensions, or reducing CI/test wall time without adding shards or dropping coverage.
description: Optimize OpenClaw slow tests, imports, misplaced coverage, and CI wall time without dropping coverage.
---
# Optimize Tests

View File

@@ -1,6 +1,6 @@
---
name: parallels-discord-roundtrip
description: Run the macOS Parallels smoke harness with Discord end-to-end roundtrip verification, including guest send, host verification, host reply, and guest readback.
description: Run macOS Parallels smoke with Discord send, host verification, host reply, and guest readback proof.
---
# Parallels Discord Roundtrip
@@ -50,6 +50,7 @@ pnpm test:parallels:macos \
- Avoid `prlctl enter` / expect for long Discord setup scripts; it line-wraps/corrupts long commands. Use `prlctl exec --current-user /bin/sh -lc ...` for the Discord config phase.
- Full 3-OS sweeps: the shared build lock is safe in parallel, but snapshot restore is still a Parallels bottleneck. Prefer serialized Windows/Linux restore-heavy reruns if the host is already under load.
- Harness cleanup deletes the temporary Discord smoke messages at exit.
- After a successful Discord roundtrip, shut down the macOS guest before handoff (`prlctl stop "macOS Tahoe"`). The macOS smoke harness should do this automatically after successful Discord proof; still stop the VM manually after ad-hoc Discord checks. Do not leave the Discord-configured VM running; it can keep reading/posting in `#maintainer` and spam Discord after the proof is complete.
- Per-phase logs: `/tmp/openclaw-parallels-smoke.*`
- Machine summary: pass `--json`
- If roundtrip flakes, inspect `fresh.discord-roundtrip.log` and `discord-last-readback.json` in the run dir first.

View File

@@ -1,6 +1,6 @@
---
name: security-triage
description: Triage GitHub security advisories for OpenClaw with high-confidence close/keep decisions, exact tag and commit verification, trust-model checks, optional hardening notes, and a final reply ready to post and copy to clipboard.
description: Triage OpenClaw security advisories, drafts, and GHSA reports with shipped-tag and trust-model proof.
---
# Security Triage
@@ -45,6 +45,17 @@ For each advisory, decide:
- `keep open`
- `keep open but narrow`
Default to one advisory at a time when comments/closures are involved:
1. Review exactly one GHSA.
2. Print the GHSA URL first.
3. Summarize the decision and evidence for discussion.
4. Draft one maintainer-ready comment.
5. Copy only that one comment to the clipboard.
6. Stop and wait for Peter to post/discuss before moving to the next GHSA.
Do not batch multiple close comments unless Peter explicitly asks for a batch.
Check in this order:
1. Trust model
@@ -60,6 +71,11 @@ Check in this order:
4. Functional tradeoff
- If a hardening change would reduce intended user functionality, call that out before proposing it.
- Prefer fixes that preserve user workflows over deny-by-default regressions unless the boundary demands it.
5. Hardening follow-up
- Even when the GHSA should close, ask whether a narrow hardening change would reduce footguns without changing the documented trust boundary.
- Separate hardening from vulnerability status. Phrase it as "not required for GHSA closure, but worth considering".
- Bring up hardening only if it is concrete, low-risk, and preserves intended maintainer/operator workflows.
- If hardening would require a product/security model change, say that explicitly and do not imply it is a required fix for closure.
## Response Format
@@ -76,9 +92,22 @@ When preparing a maintainer-ready close reply:
Keep tone firm, specific, non-defensive.
## Discussion Mode
When Peter is manually posting GHSA comments, use this flow:
1. Show the URL.
2. Give a terse verdict (`close`, `keep open`, or `keep open but narrow`).
3. List the strongest evidence bullets.
4. State any optional hardening follow-up separately from the close reason.
5. Copy the proposed comment body with `pbcopy`.
6. End the reply after the one advisory. Do not continue to the next advisory until Peter says to continue.
If the GitHub API cannot post comments for private advisories, say so once and keep using clipboard/UI paste.
## Clipboard Step
After drafting the final post body, copy it:
After drafting the final post body for the current advisory, copy it:
```bash
pbcopy <<'EOF'
@@ -86,7 +115,7 @@ pbcopy <<'EOF'
EOF
```
Tell the user that the clipboard now contains the proposed response.
Tell the user that the clipboard now contains the proposed response for that advisory.
## Useful Commands

View File

@@ -1,6 +1,6 @@
---
name: tag-duplicate-prs-issues
description: Maintainer workflow for deciding whether an OpenClaw pull request or issue is a duplicate, gathering evidence with ghreplica and pr-search-cli, grouping related work in prtags, and syncing the duplicate grouping back to GitHub through prtags. Use when Codex needs to search for duplicate PRs or issues, create or reuse a duplicate group, enforce one-group-per-target discipline, save duplicate judgments in prtags, or prepare group state for comment sync.
description: Search duplicate OpenClaw PRs/issues, group related work in prtags, and sync duplicate state to GitHub.
---
# Tag Duplicate PRs and Issues

View File

@@ -8,6 +8,14 @@
.bun-cache
.bun
.artifacts
**/.artifacts
.local
**/.local
.pi
**/.pi
__openclaw_vitest__
**/__openclaw_vitest__
.tmp
**/.tmp
.DS_Store
@@ -38,6 +46,9 @@ docs/.generated
*.log
tmp
**/tmp
dist-runtime
**/dist-runtime
openclaw-path-alias-*
# build artifacts
dist

View File

@@ -37,6 +37,7 @@ runs:
check-latest: false
- name: Setup pnpm + cache store
id: pnpm-cache
uses: ./.github/actions/setup-pnpm-store-cache
with:
pnpm-version: ${{ inputs.pnpm-version }}
@@ -97,3 +98,11 @@ runs:
install_args+=("$LOCKFILE_FLAG")
fi
pnpm "${install_args[@]}" || pnpm "${install_args[@]}"
- name: Save pnpm store cache
if: inputs.install-deps == 'true' && steps.pnpm-cache.outputs.cache-enabled == 'true' && steps.pnpm-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
continue-on-error: true
with:
path: ${{ steps.pnpm-cache.outputs.store-path }}
key: ${{ steps.pnpm-cache.outputs.primary-key }}

View File

@@ -14,9 +14,25 @@ inputs:
required: false
default: "true"
use-actions-cache:
description: Whether to restore/save pnpm store with actions/cache.
description: Whether to restore pnpm store with actions/cache.
required: false
default: "true"
outputs:
cache-enabled:
description: Whether actions/cache restore was enabled.
value: ${{ steps.pnpm-cache-config.outputs.enabled }}
cache-hit:
description: Whether the pnpm store cache had an exact key hit.
value: ${{ steps.pnpm-cache-restore.outputs.cache-hit }}
cache-matched-key:
description: Cache key matched by restore, if any.
value: ${{ steps.pnpm-cache-restore.outputs.cache-matched-key }}
primary-key:
description: Primary pnpm store cache key.
value: ${{ steps.pnpm-cache-config.outputs.primary-key }}
store-path:
description: Resolved pnpm store path.
value: ${{ steps.pnpm-store.outputs.path }}
runs:
using: composite
steps:
@@ -46,18 +62,29 @@ runs:
shell: bash
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Restore pnpm store cache (exact key only)
if: inputs.use-actions-cache == 'true' && inputs.use-restore-keys != 'true'
uses: actions/cache@v5
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-pnpm-store-${{ inputs.cache-key-suffix }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Resolve pnpm store cache keys
id: pnpm-cache-config
shell: bash
env:
CACHE_KEY_SUFFIX: ${{ inputs.cache-key-suffix }}
LOCKFILE_HASH: ${{ hashFiles('pnpm-lock.yaml') }}
USE_ACTIONS_CACHE: ${{ inputs.use-actions-cache }}
USE_RESTORE_KEYS: ${{ inputs.use-restore-keys }}
run: |
set -euo pipefail
echo "enabled=$USE_ACTIONS_CACHE" >> "$GITHUB_OUTPUT"
echo "primary-key=${RUNNER_OS}-pnpm-store-${CACHE_KEY_SUFFIX}-${LOCKFILE_HASH}" >> "$GITHUB_OUTPUT"
if [ "$USE_RESTORE_KEYS" = "true" ]; then
echo "restore-keys=${RUNNER_OS}-pnpm-store-${CACHE_KEY_SUFFIX}-" >> "$GITHUB_OUTPUT"
else
echo "restore-keys=" >> "$GITHUB_OUTPUT"
fi
- name: Restore pnpm store cache (with fallback keys)
if: inputs.use-actions-cache == 'true' && inputs.use-restore-keys == 'true'
uses: actions/cache@v5
- name: Restore pnpm store cache
id: pnpm-cache-restore
if: inputs.use-actions-cache == 'true'
uses: actions/cache/restore@v5
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-pnpm-store-${{ inputs.cache-key-suffix }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-${{ inputs.cache-key-suffix }}-
key: ${{ steps.pnpm-cache-config.outputs.primary-key }}
restore-keys: ${{ steps.pnpm-cache-config.outputs.restore-keys }}

View File

@@ -12,6 +12,9 @@ paths-ignore:
- docs
- "**/node_modules"
- "**/coverage"
- "**/*.generated.ts"
- "**/*.bundle.js"
- "**/*-runtime.js"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.e2e.test.ts"

33
.github/codex/prompts/docs-agent.md vendored Normal file
View File

@@ -0,0 +1,33 @@
# OpenClaw Docs Agent
You are maintaining OpenClaw documentation after a main-branch commit.
Goal: inspect the code changes and existing documentation, then update existing docs only when they are stale, incomplete, or misleading.
Hard limits:
- Edit existing files only.
- Do not create new docs pages, images, assets, scripts, code files, or workflow files.
- Do not delete or rename files.
- Do not change production code, tests, package metadata, generated baselines, lockfiles, or CI config.
- Keep changes minimal and factual.
- Use "plugin/plugins" in user-facing docs/UI/changelog; `extensions/` is only the internal workspace layout.
- Do not add a changelog entry unless the docs update describes a user-facing behavior/API change from the triggering commit.
Allowed paths:
- `docs/**`
- `README.md`
- `CHANGELOG.md`
Required workflow:
1. Run `pnpm docs:list` if available and read relevant docs based on `read_when` hints.
2. Inspect the triggering event via `$GITHUB_EVENT_PATH`, then review `$DOCS_AGENT_BASE_SHA..$DOCS_AGENT_HEAD_SHA` and its changed files. If either env var is missing, fall back to the event payload.
3. Update stale existing documentation, if needed.
4. Run `pnpm check:docs` if dependencies are available.
5. Leave the worktree clean if no docs need changes.
If `pnpm docs:check-mdx` or `pnpm check:docs` reports MDX parse errors, fix only the syntax needed for the listed existing docs files. Preserve prose meaning, frontmatter, code fences, and links; do not broadly rewrite translated or source content while repairing parser failures.
When uncertain, prefer no edit and explain the uncertainty in the final message.

View File

@@ -0,0 +1,25 @@
# OpenClaw Docs MDX Repair Agent
You are repairing generated OpenClaw documentation after a fast MDX validation failure.
Goal: fix only the MDX syntax errors reported by the checker.
Hard limits:
- Edit only existing Markdown/MDX files under the locale path named by `LOCALE`.
- Do not edit source English docs unless `LOCALE=en`.
- Do not edit code, workflows, package metadata, generated sync metadata, translation memory, or assets.
- Do not add, delete, or rename files.
- Preserve the meaning of translated prose.
- Preserve frontmatter, `x-i18n.source_hash`, links, code fences, JSX component names, and existing page structure.
- Avoid broad formatting or retranslation.
Required workflow:
1. Read `.openclaw-sync/mdx/${LOCALE}.json` when it exists.
2. Inspect only the listed files and nearby lines.
3. Fix the minimal syntax issue, such as broken JSX attribute quoting, mismatched component closing tags, raw `<` text, raw HTML comments, or accidental top-level `import`/`export` text.
4. Run `node source/scripts/check-docs-mdx.mjs "docs/${LOCALE}" --json-out ".openclaw-sync/mdx/${LOCALE}.json"`.
5. Leave no changes outside `docs/${LOCALE}`.
When uncertain, prefer the smallest escaping fix: backticks for literal words, `&lt;` for literal `<`, double quotes around JSX attribute values, and balanced component tags.

View File

@@ -0,0 +1,44 @@
# OpenClaw Test Performance Agent
You are maintaining OpenClaw test performance after a trusted main-branch CI run.
Goal: inspect the full-suite test performance report, then make small, coverage-preserving improvements to slow tests when the fix is clear. If the baseline report shows failing tests and the fix is obvious, fix those too.
Inputs:
- Baseline grouped report: `.artifacts/test-perf/baseline-before.json`
- Per-config Vitest JSON reports: `.artifacts/test-perf/baseline-before/vitest-json/`
- Per-config logs: `.artifacts/test-perf/baseline-before/logs/`
Hard limits:
- Preserve test coverage and behavioral intent.
- Do not delete, skip, weaken, or narrow test cases to make the suite faster.
- Do not add `test.skip`, `it.skip`, `describe.skip`, `test.only`, `it.only`, or `describe.only`.
- Do not update snapshots, generated baselines, inventories, ignore files, lockfiles, package metadata, CI workflows, or release metadata.
- Do not add dependencies.
- Do not create, delete, or rename files.
- Do not do broad refactors or style-only rewrites.
- Keep changes minimal and focused on the slow or failing tests you can justify from the report.
- Prefer no edit when a performance improvement is speculative.
- If `.artifacts/test-perf/baseline-before.json` has `"failed": true`, do not make performance-only edits. First inspect the failed config logs. Edit only when the test failure has an obvious, coverage-preserving fix. If no obvious failure fix exists, leave the worktree clean.
Good fixes:
- Replace broad partial module mocks, especially `importOriginal()` mocks, with narrow injected dependencies or local runtime seams.
- Avoid importing heavy barrels in hot tests when a narrow module or helper covers the same behavior.
- Add or adjust a production lazy/injection seam only when that is the narrowest way to preserve coverage while removing expensive imports or fixing an obvious mock/import failure.
- Move expensive setup from per-test hooks to shared setup only when state isolation remains correct.
- Reuse existing fixtures/builders instead of recreating expensive work per case.
- Mock expensive runtime boundaries directly: filesystem crawls, package registries, provider SDKs, network/process launch, browser/runtime scanners.
- Keep one integration smoke per boundary and test pure helpers directly, but only when the same behavior remains covered.
Required workflow:
1. Run `pnpm docs:list` if available, then read `docs/reference/test.md` and `docs/help/testing.md` sections about test performance.
2. Inspect `.artifacts/test-perf/baseline-before.json`. If `failed` is true, inspect the failed config logs before looking at slow files.
3. Pick at most a few low-risk files. When baseline failed, pick only files needed for the obvious failure fix; otherwise focus on the slowest files/configs. Explain the coverage-preserving reason in comments only if the code would otherwise be unclear.
4. Run targeted tests for changed files where possible. Use `pnpm test <path>` and optionally `pnpm test:perf:imports <path>`.
5. Leave the worktree clean if no safe improvement exists.
When uncertain, make no edit and explain the uncertainty in the final message.

29
.github/labeler.yml vendored
View File

@@ -24,6 +24,16 @@
- any-glob-to-any-file:
- "extensions/googlechat/**"
- "docs/channels/googlechat.md"
"plugin: google-meet":
- changed-files:
- any-glob-to-any-file:
- "extensions/google-meet/**"
- "docs/plugins/google-meet.md"
"plugin: bonjour":
- changed-files:
- any-glob-to-any-file:
- "extensions/bonjour/**"
- "docs/gateway/bonjour.md"
"channel: imessage":
- changed-files:
- any-glob-to-any-file:
@@ -305,6 +315,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/lmstudio/**"
"extensions: litellm":
- changed-files:
- any-glob-to-any-file:
- "extensions/litellm/**"
- "docs/providers/litellm.md"
"extensions: openai":
- changed-files:
- any-glob-to-any-file:
@@ -341,6 +356,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/qianfan/**"
"extensions: senseaudio":
- changed-files:
- any-glob-to-any-file:
- "extensions/senseaudio/**"
- "docs/providers/senseaudio.md"
"extensions: synthetic":
- changed-files:
- any-glob-to-any-file:
@@ -357,6 +377,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/together/**"
"extensions: tts-local-cli":
- changed-files:
- any-glob-to-any-file:
- "extensions/tts-local-cli/**"
- "docs/tools/tts.md"
"extensions: venice":
- changed-files:
- any-glob-to-any-file:
@@ -377,3 +402,7 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/fal/**"
"extensions: gradium":
- changed-files:
- any-glob-to-any-file:
- "extensions/gradium/**"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -62,18 +62,18 @@ jobs:
git -C "$workdir" checkout --force --detach "$CHECKOUT_SHA" || return 1
test -f "$workdir/.github/actions/setup-node-env/action.yml" || return 1
echo "checkout attempt ${attempt}/2 succeeded"
echo "checkout attempt ${attempt}/5 succeeded"
}
for attempt in 1 2; do
for attempt in 1 2 3 4 5; do
if checkout_attempt "$attempt"; then
exit 0
fi
echo "checkout attempt ${attempt}/2 failed"
echo "checkout attempt ${attempt}/5 failed"
sleep $((attempt * 5))
done
echo "checkout failed after 2 attempts" >&2
echo "checkout failed after 5 attempts" >&2
exit 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ jobs:
matrix:
include:
- language: javascript-typescript
runs_on: blacksmith-16vcpu-ubuntu-2404
runs_on: blacksmith-32vcpu-ubuntu-2404
needs_node: true
needs_python: false
needs_java: false

View File

@@ -49,7 +49,7 @@ jobs:
run: |
set -euo pipefail
all_locales_json='["zh-CN","zh-TW","pt-BR","de","es","ja-JP","ko","fr","tr","uk","id","pl"]'
all_locales_json='["zh-CN","zh-TW","pt-BR","de","es","ja-JP","ko","fr","tr","uk","id","pl","th"]'
if [ "$EVENT_NAME" != "push" ]; then
echo "has_locales=true" >> "$GITHUB_OUTPUT"
@@ -137,7 +137,7 @@ 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: gpt-5.4
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_THINKING: low
LOCALE: ${{ matrix.locale }}
run: node --import tsx scripts/control-ui-i18n.ts sync --locale "${LOCALE}" --write

250
.github/workflows/docs-agent.yml vendored Normal file
View File

@@ -0,0 +1,250 @@
name: Docs Agent
on:
workflow_run: # zizmor: ignore[dangerous-triggers] main-only docs repair after trusted CI; job gates repository, event, branch, actor, conclusion, exact current main SHA, and hourly cadence before using write token
workflows:
- CI
types:
- completed
workflow_dispatch:
permissions:
actions: read
contents: write
concurrency:
group: docs-agent-main
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
update-docs:
if: >
github.repository == 'openclaw/openclaw' &&
github.actor != 'github-actions[bot]' &&
(github.event_name != 'workflow_run' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.actor.login != 'github-actions[bot]'))
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: main
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Gate trusted main activity and hourly cadence
id: gate
env:
EVENT_NAME: ${{ github.event_name }}
GH_TOKEN: ${{ github.token }}
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" != "workflow_run" ]; then
head_sha="$(git rev-parse HEAD)"
review_base="$(git rev-parse "${head_sha}^" 2>/dev/null || printf '%s' "$head_sha")"
{
echo "run_agent=true"
echo "base_sha=${head_sha}"
echo "review_base_sha=${review_base}"
echo "review_head_sha=${head_sha}"
} >> "$GITHUB_OUTPUT"
exit 0
fi
for attempt in 1 2 3 4 5; do
if git fetch --no-tags origin main; then
break
fi
if [ "$attempt" = "5" ]; then
echo "Failed to fetch main after retries." >&2
exit 1
fi
echo "Fetch attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done
remote_main="$(git rev-parse origin/main)"
if [ "$remote_main" != "$WORKFLOW_HEAD_SHA" ]; then
echo "CI run is superseded by ${remote_main}; skipping docs agent for ${WORKFLOW_HEAD_SHA}."
echo "run_agent=false" >> "$GITHUB_OUTPUT"
exit 0
fi
runs_json="$RUNNER_TEMP/docs-agent-runs.json"
gh api --method GET "repos/${GITHUB_REPOSITORY}/actions/workflows/docs-agent.yml/runs" \
-f branch=main \
-f event=workflow_run \
-f per_page=100 > "$runs_json"
one_hour_ago="$(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ)"
recent_runs="$(
jq -r \
--argjson current_run_id "$GITHUB_RUN_ID" \
--arg one_hour_ago "$one_hour_ago" \
'.workflow_runs[]
| select(.database_id != $current_run_id)
| select(.created_at >= $one_hour_ago)
| select(.status != "cancelled")
| select((.conclusion // "") != "skipped")
| [.database_id, .status, (.conclusion // ""), .created_at, .head_sha]
| @tsv' "$runs_json"
)"
if [ -n "$recent_runs" ]; then
echo "Docs agent already ran or is running within the last hour; skipping."
printf '%s\n' "$recent_runs"
echo "run_agent=false" >> "$GITHUB_OUTPUT"
exit 0
fi
review_base="$(
jq -r \
--argjson current_run_id "$GITHUB_RUN_ID" \
--arg remote_main "$remote_main" \
'.workflow_runs[]
| select(.database_id != $current_run_id)
| select(.status != "cancelled")
| select((.conclusion // "") != "skipped")
| .head_sha
| select(. != null and . != "")
| select(. != $remote_main)
' "$runs_json" | head -n 1
)"
if [ -z "$review_base" ] || ! git cat-file -e "${review_base}^{commit}" 2>/dev/null; then
review_base="$(git rev-parse "${remote_main}^" 2>/dev/null || printf '%s' "$remote_main")"
fi
{
echo "run_agent=true"
echo "base_sha=${remote_main}"
echo "review_base_sha=${review_base}"
echo "review_head_sha=${remote_main}"
} >> "$GITHUB_OUTPUT"
- name: Setup Node environment
if: steps.gate.outputs.run_agent == 'true'
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Ensure docs agent key exists
if: steps.gate.outputs.run_agent == 'true'
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
if [ -z "${OPENAI_API_KEY:-}" ]; then
echo "Missing OPENCLAW_DOCS_AGENT_OPENAI_API_KEY or OPENAI_API_KEY secret." >&2
exit 1
fi
- name: Run Codex docs agent
if: steps.gate.outputs.run_agent == 'true'
uses: openai/codex-action@v1
env:
DOCS_AGENT_BASE_SHA: ${{ steps.gate.outputs.review_base_sha }}
DOCS_AGENT_HEAD_SHA: ${{ steps.gate.outputs.review_head_sha }}
with:
openai-api-key: ${{ secrets.OPENCLAW_DOCS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
prompt-file: .github/codex/prompts/docs-agent.md
model: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
effort: medium
sandbox: workspace-write
safety-strategy: drop-sudo
codex-args: '["--full-auto"]'
- name: Enforce existing-docs-only patch
if: steps.gate.outputs.run_agent == 'true'
run: |
set -euo pipefail
untracked="$(git ls-files --others --exclude-standard)"
if [ -n "$untracked" ]; then
echo "Docs agent created untracked files; forbidden:"
printf '%s\n' "$untracked"
exit 1
fi
added_or_deleted="$(git diff --name-status --diff-filter=AD)"
if [ -n "$added_or_deleted" ]; then
echo "Docs agent added or deleted tracked files; forbidden:"
printf '%s\n' "$added_or_deleted"
exit 1
fi
bad_paths="$(
git diff --name-only | while IFS= read -r path; do
case "$path" in
docs/*|README.md|CHANGELOG.md) ;;
*) printf '%s\n' "$path" ;;
esac
done
)"
if [ -n "$bad_paths" ]; then
echo "Docs agent touched non-doc paths; forbidden:"
printf '%s\n' "$bad_paths"
exit 1
fi
- name: Restore Node 24 path
if: steps.gate.outputs.run_agent == 'true'
run: | # zizmor: ignore[github-env] NODE_BIN is set by the trusted local setup-node-env action in this same job
set -euo pipefail
export PATH="${NODE_BIN}:${PATH}"
echo "${NODE_BIN}" >> "$GITHUB_PATH"
node -v
corepack enable
pnpm -v
- name: Check docs
if: steps.gate.outputs.run_agent == 'true'
run: pnpm check:docs
- name: Commit docs updates
if: steps.gate.outputs.run_agent == 'true'
env:
BASE_SHA: ${{ steps.gate.outputs.base_sha }}
GITHUB_TOKEN: ${{ github.token }}
TARGET_BRANCH: main
run: |
set -euo pipefail
if git diff --quiet; then
echo "No docs changes."
exit 0
fi
git config user.name "openclaw-docs-agent[bot]"
git config user.email "openclaw-docs-agent[bot]@users.noreply.github.com"
git add docs README.md CHANGELOG.md
git commit --no-verify -m "docs: refresh documentation"
for attempt in 1 2 3 4 5; do
if ! git fetch --no-tags origin "${TARGET_BRANCH}"; then
echo "Fetch attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
continue
fi
if git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" HEAD:"${TARGET_BRANCH}"; then
exit 0
fi
remote_main="$(git rev-parse "origin/${TARGET_BRANCH}")"
if [ "$remote_main" != "$BASE_SHA" ]; then
echo "main advanced from ${BASE_SHA} to ${remote_main}; skipping stale docs update."
exit 0
fi
echo "Docs update attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done
echo "Failed to push docs updates after retries." >&2
exit 1

View File

@@ -32,9 +32,19 @@ jobs:
OPENCLAW_DOCS_SYNC_TOKEN: ${{ secrets.OPENCLAW_DOCS_SYNC_TOKEN }}
run: |
set -euo pipefail
git clone \
"https://x-access-token:${OPENCLAW_DOCS_SYNC_TOKEN}@github.com/openclaw/docs.git" \
publish
for attempt in 1 2 3 4 5; do
rm -rf publish
if git clone \
"https://x-access-token:${OPENCLAW_DOCS_SYNC_TOKEN}@github.com/openclaw/docs.git" \
publish; then
exit 0
fi
echo "Clone attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done
echo "Failed to clone publish repo after retries." >&2
exit 1
- name: Sync docs into publish repo
run: |
@@ -43,26 +53,56 @@ jobs:
--source-repo "$GITHUB_REPOSITORY" \
--source-sha "$GITHUB_SHA"
- name: Install docs MDX checker dependency
run: npm install --no-save --package-lock=false @mdx-js/mdx@3.1.1
- name: Check publish docs MDX
run: node "$GITHUB_WORKSPACE/publish/.openclaw-sync/check-docs-mdx.mjs" "$GITHUB_WORKSPACE/publish/docs"
- name: Commit publish repo sync
working-directory: publish
run: |
set -euo pipefail
remote_source_sha() {
git show refs/remotes/origin/main:.openclaw-sync/source.json 2>/dev/null \
| node -e 'const fs = require("node:fs"); try { const data = JSON.parse(fs.readFileSync(0, "utf8")); if (data.sha) process.stdout.write(data.sha); } catch {}' \
|| true
}
skip_stale_source() {
current_source_sha="$(remote_source_sha)"
if [ -z "$current_source_sha" ] || [ "$current_source_sha" = "$GITHUB_SHA" ]; then
return
fi
if git -C "$GITHUB_WORKSPACE" merge-base --is-ancestor "$GITHUB_SHA" "$current_source_sha"; then
echo "Skipping stale publish sync for $GITHUB_SHA; origin/main already mirrors $current_source_sha."
exit 0
fi
}
if git diff --quiet -- docs .openclaw-sync; then
echo "No publish-repo changes."
exit 0
fi
if git fetch origin main:refs/remotes/origin/main; then
skip_stale_source
fi
git config user.name "openclaw-docs-sync[bot]"
git config user.email "openclaw-docs-sync[bot]@users.noreply.github.com"
git add docs .openclaw-sync
git commit -m "chore(sync): mirror docs from $GITHUB_REPOSITORY@$GITHUB_SHA"
for attempt in 1 2 3 4 5; do
git fetch origin main
git rebase origin/main
if git push origin HEAD:main; then
exit 0
if git fetch origin main:refs/remotes/origin/main; then
skip_stale_source
if git rebase -X theirs origin/main && git push origin HEAD:main; then
exit 0
fi
fi
echo "Push attempt ${attempt} failed; retrying."
git rebase --abort >/dev/null 2>&1 || true
echo "Publish sync attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done

View File

@@ -31,7 +31,8 @@ jobs:
translate-tr-release \
translate-uk-release \
translate-id-release \
translate-pl-release
translate-pl-release \
translate-th-release
do
gh api repos/openclaw/docs/dispatches \
--method POST \

39
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Docs
on:
push:
branches: [main]
paths:
- "**/*.md"
- "docs/**"
permissions:
contents: read
concurrency:
group: ${{ format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
docs:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v6
with:
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: Check docs
run: pnpm check:docs

View File

@@ -0,0 +1,59 @@
name: Duplicate PRs After Merge
on:
workflow_dispatch:
inputs:
landed_pr:
description: "Merged PR number that supersedes the duplicates"
required: true
type: string
duplicate_prs:
description: "Comma or whitespace separated duplicate PR numbers to close"
required: true
type: string
apply:
description: "When true, label/comment/close; otherwise dry-run only"
required: true
type: boolean
default: false
permissions:
contents: read
issues: write
pull-requests: write
concurrency:
group: duplicate-after-merge-${{ github.event.inputs.landed_pr }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
GH_TOKEN: ${{ github.token }}
jobs:
close-duplicates:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Close confirmed duplicates
env:
APPLY: ${{ inputs.apply }}
DUPLICATE_PRS: ${{ inputs.duplicate_prs }}
LANDED_PR: ${{ inputs.landed_pr }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
args=(
--repo "$REPO"
--landed-pr "$LANDED_PR"
--duplicates "$DUPLICATE_PRS"
)
if [[ "$APPLY" == "true" ]]; then
args+=(--apply)
fi
node scripts/close-duplicate-prs-after-merge.mjs "${args[@]}"

View File

@@ -1,17 +1,32 @@
name: Install Smoke
on:
push:
branches: [main]
pull_request:
types: [opened, reopened, synchronize, ready_for_review, converted_to_draft]
schedule:
- cron: "17 3 * * *"
workflow_dispatch:
inputs:
run_bun_global_install_smoke:
description: Run the Bun global install image-provider smoke
required: false
default: false
type: boolean
workflow_call:
inputs:
ref:
description: Git ref to validate
required: false
type: string
run_bun_global_install_smoke:
description: Run the Bun global install image-provider smoke
required: false
default: true
type: boolean
permissions:
contents: read
concurrency:
group: ${{ github.event_name == 'pull_request' && format('{0}-{1}', github.workflow, github.event.pull_request.number) || format('{0}-{1}', github.workflow, github.ref) }}
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-manual-{1}', github.workflow, github.run_id) || format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: true
env:
@@ -19,65 +34,54 @@ env:
jobs:
preflight:
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
runs-on: ubuntu-24.04
outputs:
docs_only: ${{ steps.manifest.outputs.docs_only }}
run_install_smoke: ${{ steps.manifest.outputs.run_install_smoke }}
run_fast_install_smoke: ${{ steps.manifest.outputs.run_fast_install_smoke }}
run_full_install_smoke: ${{ steps.manifest.outputs.run_full_install_smoke }}
run_bun_global_install_smoke: ${{ steps.manifest.outputs.run_bun_global_install_smoke }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Ensure preflight base commit
uses: ./.github/actions/ensure-base-commit
with:
base-sha: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
fetch-ref: ${{ github.event_name == 'push' && github.ref_name || github.event.pull_request.base.ref }}
- name: Detect docs-only changes
id: docs_scope
uses: ./.github/actions/detect-docs-changes
- name: Detect changed smoke scope
id: changed_scope
if: steps.docs_scope.outputs.docs_only != 'true'
shell: bash
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "push" ]; then
BASE="${{ github.event.before }}"
else
BASE="${{ github.event.pull_request.base.sha }}"
fi
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD
- name: Build install-smoke CI manifest
id: manifest
env:
OPENCLAW_CI_DOCS_ONLY: ${{ steps.docs_scope.outputs.docs_only }}
OPENCLAW_CI_RUN_CHANGED_SMOKE: ${{ steps.changed_scope.outputs.run_changed_smoke || 'false' }}
OPENCLAW_CI_EVENT_NAME: ${{ github.event_name }}
OPENCLAW_CI_WORKFLOW_BUN_GLOBAL_INSTALL_SMOKE: ${{ inputs.run_bun_global_install_smoke || 'false' }}
run: |
docs_only="${OPENCLAW_CI_DOCS_ONLY:-false}"
run_changed_smoke="${OPENCLAW_CI_RUN_CHANGED_SMOKE:-false}"
run_install_smoke=false
if [ "$docs_only" != "true" ] && [ "$run_changed_smoke" = "true" ]; then
run_install_smoke=true
event_name="${OPENCLAW_CI_EVENT_NAME:-}"
workflow_bun_global_install_smoke="${OPENCLAW_CI_WORKFLOW_BUN_GLOBAL_INSTALL_SMOKE:-false}"
docs_only=false
run_fast_install_smoke=true
run_full_install_smoke=true
run_bun_global_install_smoke=false
run_install_smoke=true
if [ "$event_name" = "schedule" ]; then
run_bun_global_install_smoke=true
elif [ "$event_name" = "workflow_dispatch" ] || [ "$event_name" = "workflow_call" ]; then
if [ "$workflow_bun_global_install_smoke" = "true" ]; then
run_bun_global_install_smoke=true
fi
fi
{
echo "docs_only=$docs_only"
echo "run_install_smoke=$run_install_smoke"
echo "run_fast_install_smoke=$run_fast_install_smoke"
echo "run_full_install_smoke=$run_full_install_smoke"
echo "run_bun_global_install_smoke=$run_bun_global_install_smoke"
} >> "$GITHUB_OUTPUT"
install-smoke:
install-smoke-fast:
needs: [preflight]
if: needs.preflight.outputs.run_install_smoke == 'true'
if: needs.preflight.outputs.run_fast_install_smoke == 'true' && needs.preflight.outputs.run_full_install_smoke != 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
DOCKER_BUILD_SUMMARY: "false"
@@ -85,6 +89,102 @@ jobs:
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
# Blacksmith's builder owns the Docker layer cache; keep smoke builds off
# explicit gha cache directives so local tags still load cleanly.
- name: Build root Dockerfile smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
context: .
file: ./Dockerfile
build-args: |
OPENCLAW_DOCKER_APT_UPGRADE=0
OPENCLAW_EXTENSIONS=matrix
tags: |
openclaw-dockerfile-smoke:local
openclaw-ext-smoke:local
load: true
push: false
provenance: false
- name: Run root Dockerfile CLI smoke
run: |
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
- name: Run agents delete shared workspace Docker CLI smoke
env:
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh
- name: Run Docker gateway network e2e
env:
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_GATEWAY_NETWORK_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/gateway-network-docker.sh
- name: Smoke test Dockerfile with matrix extension build arg
run: |
docker run --rm --entrypoint sh openclaw-ext-smoke:local -lc '
which openclaw &&
openclaw --version &&
node -e "
const Module = require(\"node:module\");
const matrixPackage = require(\"/app/extensions/matrix/package.json\");
const requireFromMatrix = Module.createRequire(\"/app/extensions/matrix/package.json\");
const runtimeDeps = Object.keys(matrixPackage.dependencies ?? {});
if (runtimeDeps.length === 0) {
throw new Error(
\"matrix package has no declared runtime dependencies; smoke cannot validate install mirroring\",
);
}
for (const dep of runtimeDeps) {
requireFromMatrix.resolve(dep);
}
const { spawnSync } = require(\"node:child_process\");
const run = spawnSync(\"openclaw\", [\"plugins\", \"list\", \"--json\"], { encoding: \"utf8\" });
if (run.status !== 0) {
process.stderr.write(run.stderr || run.stdout || \"plugins list failed\\n\");
process.exit(run.status ?? 1);
}
const parsed = JSON.parse(run.stdout);
const matrix = (parsed.plugins || []).find((entry) => entry.id === \"matrix\");
if (!matrix) {
throw new Error(\"matrix plugin missing from bundled plugin list\");
}
const matrixDiag = (parsed.diagnostics || []).filter(
(diag) =>
typeof diag.source === \"string\" &&
diag.source.includes(\"/extensions/matrix\") &&
typeof diag.message === \"string\" &&
diag.message.includes(\"extension entry escapes package directory\"),
);
if (matrixDiag.length > 0) {
throw new Error(
\"unexpected matrix diagnostics: \" +
matrixDiag.map((diag) => diag.message).join(\"; \"),
);
}
"
'
install-smoke:
needs: [preflight]
if: needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
@@ -96,6 +196,8 @@ jobs:
OPENCLAW_QR_SMOKE_FORCE_INSTALL: "1"
run: bash scripts/e2e/qr-import-docker.sh
# Build once with the matrix extension and tag both smoke names. This
# keeps the build-arg coverage without a second Blacksmith build action.
- name: Build root Dockerfile smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
@@ -103,7 +205,10 @@ jobs:
file: ./Dockerfile
build-args: |
OPENCLAW_DOCKER_APT_UPGRADE=0
tags: openclaw-dockerfile-smoke:local
OPENCLAW_EXTENSIONS=matrix
tags: |
openclaw-dockerfile-smoke:local
openclaw-ext-smoke:local
load: true
push: false
provenance: false
@@ -112,28 +217,18 @@ jobs:
run: |
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
- name: Run agents delete shared workspace Docker CLI smoke
env:
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh
- name: Run Docker gateway network e2e
env:
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_GATEWAY_NETWORK_E2E_SKIP_BUILD: "1"
run: bash scripts/e2e/gateway-network-docker.sh
# This smoke validates that the build-arg path preinstalls the matrix
# runtime deps declared by the plugin and that matrix discovery stays
# healthy in the final runtime image.
- name: Build extension Dockerfile smoke image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
context: .
file: ./Dockerfile
build-args: |
OPENCLAW_DOCKER_APT_UPGRADE=0
OPENCLAW_EXTENSIONS=matrix
tags: openclaw-ext-smoke:local
load: true
push: false
provenance: false
- name: Smoke test Dockerfile with matrix extension build arg
run: |
docker run --rm --entrypoint sh openclaw-ext-smoke:local -lc '
@@ -190,7 +285,6 @@ jobs:
provenance: false
- name: Build installer non-root image
if: github.event_name != 'pull_request'
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
context: ./scripts/docker
@@ -200,12 +294,19 @@ jobs:
push: false
provenance: false
- name: Setup Node environment for local pack smoke
- name: Setup Node environment for installer smoke
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
install-bun: ${{ needs.preflight.outputs.run_bun_global_install_smoke }}
install-deps: "true"
- name: Run Bun global install image-provider smoke
if: needs.preflight.outputs.run_bun_global_install_smoke == 'true'
env:
OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD: "0"
run: bash scripts/e2e/bun-global-install-smoke.sh
- name: Run installer docker tests
env:
OPENCLAW_INSTALL_URL: https://openclaw.ai/install.sh
@@ -213,16 +314,18 @@ jobs:
OPENCLAW_NO_ONBOARD: "1"
OPENCLAW_INSTALL_SMOKE_SKIP_CLI: "1"
OPENCLAW_INSTALL_SMOKE_SKIP_IMAGE_BUILD: "1"
OPENCLAW_INSTALL_NONROOT_SKIP_IMAGE_BUILD: ${{ github.event_name == 'pull_request' && '0' || '1' }}
OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT: ${{ github.event_name == 'pull_request' && '1' || '0' }}
OPENCLAW_INSTALL_NONROOT_SKIP_IMAGE_BUILD: "1"
OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT: "0"
OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL: "1"
OPENCLAW_INSTALL_SMOKE_SKIP_PREVIOUS: "1"
OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE: latest
OPENCLAW_INSTALL_SMOKE_UPDATE_DIST_IMAGE: openclaw-dockerfile-smoke:local
OPENCLAW_INSTALL_SMOKE_UPDATE_SKIP_LOCAL_BUILD: "1"
run: bash scripts/test-install-sh-docker.sh
docker-e2e-fast:
needs: [preflight]
if: needs.preflight.outputs.run_install_smoke == 'true'
if: needs.preflight.outputs.run_fast_install_smoke == 'true' || needs.preflight.outputs.run_full_install_smoke == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 8
env:
@@ -231,6 +334,8 @@ jobs:
steps:
- name: Checkout CLI
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
@@ -244,4 +349,5 @@ jobs:
- name: Run fast bundled plugin Docker E2E
env:
OPENCLAW_BUNDLED_CHANNEL_DEPS_E2E_IMAGE: openclaw-bundled-channel-fast:local
run: timeout 120s pnpm test:docker:bundled-channel-deps:fast
OPENCLAW_BUNDLED_CHANNEL_DOCKER_RUN_TIMEOUT: 90s
run: timeout 240s pnpm test:docker:bundled-channel-deps:fast

View File

@@ -0,0 +1,210 @@
name: NPM Telegram Beta E2E
on:
workflow_dispatch:
inputs:
package_spec:
description: Published OpenClaw package spec to test
required: true
default: openclaw@beta
type: string
provider_mode:
description: QA provider mode
required: true
default: mock-openai
type: choice
options:
- mock-openai
- live-frontier
scenario:
description: Optional comma-separated Telegram scenario ids
required: false
type: string
permissions:
contents: read
concurrency:
group: npm-telegram-beta-e2e-${{ github.run_id }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
jobs:
validate_dispatch_ref:
name: Validate dispatch ref
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- name: Require main workflow ref
env:
WORKFLOW_REF: ${{ github.ref }}
run: |
set -euo pipefail
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]]; then
echo "NPM Telegram beta E2E must be dispatched from main so workflow logic stays controlled." >&2
exit 1
fi
approve_release_manager:
name: Approve npm Telegram beta E2E
needs: validate_dispatch_ref
runs-on: ubuntu-latest
environment: npm-release
steps:
- name: Record approval
env:
PACKAGE_SPEC: ${{ inputs.package_spec }}
run: echo "Approved npm Telegram beta E2E for ${PACKAGE_SPEC}"
prepare_docker_e2e_image:
name: Prepare Docker E2E image
needs: validate_dispatch_ref
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 90
permissions:
contents: read
packages: write
outputs:
image: ${{ steps.image.outputs.image }}
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
steps:
- name: Checkout main
uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
fetch-depth: 1
- name: Resolve Docker E2E image tag
id: image
shell: bash
env:
SELECTED_SHA: ${{ github.sha }}
run: |
set -euo pipefail
repository="${GITHUB_REPOSITORY,,}"
image="ghcr.io/${repository}-docker-e2e:${SELECTED_SHA}"
echo "image=$image" >> "$GITHUB_OUTPUT"
echo "Docker E2E image: \`$image\`" >> "$GITHUB_STEP_SUMMARY"
- name: Set up Blacksmith Docker Builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Build and push Docker E2E image
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
with:
context: .
file: ./scripts/e2e/Dockerfile
target: build
platforms: linux/amd64
tags: ${{ steps.image.outputs.image }}
provenance: false
push: true
run_npm_telegram_beta_e2e:
name: Run published npm Telegram E2E
needs: [approve_release_manager, prepare_docker_e2e_image]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
permissions:
contents: read
packages: read
steps:
- name: Checkout main
uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
fetch-depth: 1
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate inputs and secrets
env:
PACKAGE_SPEC: ${{ inputs.package_spec }}
PROVIDER_MODE: ${{ inputs.provider_mode }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
run: |
set -euo pipefail
if [[ ! "${PACKAGE_SPEC}" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then
echo "package_spec must be openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: ${PACKAGE_SPEC}" >&2
exit 1
fi
require_var() {
local key="$1"
if [[ -z "${!key:-}" ]]; then
echo "Missing required ${key}." >&2
exit 1
fi
}
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
if [[ "${PROVIDER_MODE}" == "live-frontier" ]]; then
require_var OPENAI_API_KEY
fi
- name: Run npm Telegram beta E2E
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_SKIP_DOCKER_BUILD: "1"
OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC: ${{ inputs.package_spec }}
OPENCLAW_NPM_TELEGRAM_PROVIDER_MODE: ${{ inputs.provider_mode }}
OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE: convex
OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE: ci
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
INPUT_SCENARIO: ${{ inputs.scenario }}
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/npm-telegram-beta-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
export OPENCLAW_NPM_TELEGRAM_OUTPUT_DIR="${output_dir}"
if [[ -n "${INPUT_SCENARIO// }" ]]; then
export OPENCLAW_NPM_TELEGRAM_SCENARIOS="${INPUT_SCENARIO}"
fi
pnpm test:docker:npm-telegram-live
- name: Upload npm Telegram E2E artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: npm-telegram-beta-e2e-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn

View File

@@ -432,24 +432,35 @@ jobs:
OPENCLAW_DISCORD_SMOKE_CHANNEL_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_CHANNEL_ID }}
OPENCLAW_RELEASE_CHECK_OS: ${{ matrix.os_id }}
OPENCLAW_RELEASE_CHECK_RUNNER: ${{ matrix.runner }}
CANDIDATE_TGZ: ${{ runner.temp }}/openclaw-cross-os-release-checks/candidate/${{ needs.prepare.outputs.candidate_file_name }}
CANDIDATE_VERSION: ${{ needs.prepare.outputs.candidate_version }}
SOURCE_SHA: ${{ needs.prepare.outputs.source_sha }}
BASELINE_SPEC: ${{ needs.prepare.outputs.baseline_spec }}
PREVIOUS_VERSION: ${{ inputs.previous_version }}
BASELINE_TGZ: ${{ runner.temp }}/openclaw-cross-os-release-checks/baseline/${{ needs.prepare.outputs.baseline_file_name }}
PROVIDER: ${{ inputs.provider }}
MODE: ${{ matrix.lane }}
SUITE: ${{ matrix.suite }}
REF: ${{ inputs.ref }}
OUTPUT_DIR: ${{ runner.temp }}/openclaw-cross-os-release-checks/${{ matrix.artifact_name }}-${{ matrix.suite }}
run: |
DISCORD_ARGS=()
if [[ -n "${OPENCLAW_DISCORD_SMOKE_BOT_TOKEN}" ]] && [[ -n "${OPENCLAW_DISCORD_SMOKE_GUILD_ID}" ]] && [[ -n "${OPENCLAW_DISCORD_SMOKE_CHANNEL_ID}" ]]; then
DISCORD_ARGS+=(--run-discord-roundtrip true)
fi
pnpm dlx "tsx@${TSX_VERSION}" workflow/scripts/openclaw-cross-os-release-checks.ts \
--candidate-tgz "$RUNNER_TEMP/openclaw-cross-os-release-checks/candidate/${{ needs.prepare.outputs.candidate_file_name }}" \
--candidate-version "${{ needs.prepare.outputs.candidate_version }}" \
--source-sha "${{ needs.prepare.outputs.source_sha }}" \
--baseline-spec "${{ needs.prepare.outputs.baseline_spec }}" \
--previous-version "${{ inputs.previous_version }}" \
--baseline-tgz "$RUNNER_TEMP/openclaw-cross-os-release-checks/baseline/${{ needs.prepare.outputs.baseline_file_name }}" \
--provider "${{ inputs.provider }}" \
--mode "${{ matrix.lane }}" \
--suite "${{ matrix.suite }}" \
--ref "${{ inputs.ref }}" \
--candidate-tgz "${CANDIDATE_TGZ}" \
--candidate-version "${CANDIDATE_VERSION}" \
--source-sha "${SOURCE_SHA}" \
--baseline-spec "${BASELINE_SPEC}" \
--previous-version "${PREVIOUS_VERSION}" \
--baseline-tgz "${BASELINE_TGZ}" \
--provider "${PROVIDER}" \
--mode "${MODE}" \
--suite "${SUITE}" \
--ref "${REF}" \
"${DISCORD_ARGS[@]}" \
--output-dir "$RUNNER_TEMP/openclaw-cross-os-release-checks/${{ matrix.artifact_name }}-${{ matrix.suite }}"
--output-dir "${OUTPUT_DIR}"
- name: Summarize release checks
if: always()

View File

@@ -28,6 +28,11 @@ on:
required: false
default: true
type: boolean
live_models_only:
description: Whether to run only the Docker live model matrix when live suites are enabled
required: false
default: false
type: boolean
workflow_call:
inputs:
ref:
@@ -54,6 +59,11 @@ on:
required: false
default: true
type: boolean
live_models_only:
description: Whether to run only the Docker live model matrix when live suites are enabled
required: false
default: false
type: boolean
secrets:
OPENAI_API_KEY:
required: false
@@ -141,9 +151,12 @@ on:
required: false
OPENCLAW_GEMINI_SETTINGS_JSON:
required: false
FIREWORKS_API_KEY:
required: false
permissions:
contents: read
packages: write
pull-requests: read
env:
@@ -153,7 +166,7 @@ env:
jobs:
validate_selected_ref:
runs-on: blacksmith-8vcpu-ubuntu-2404
runs-on: ubuntu-24.04
outputs:
selected_sha: ${{ steps.validate.outputs.selected_sha }}
trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
@@ -209,8 +222,8 @@ jobs:
validate_release_live_cache:
needs: validate_selected_ref
if: inputs.include_live_suites
runs-on: blacksmith-32vcpu-ubuntu-2404
if: inputs.include_live_suites && !inputs.live_models_only
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
@@ -275,7 +288,7 @@ jobs:
validate_special_e2e:
needs: validate_selected_ref
if: inputs.include_repo_e2e || inputs.include_live_suites
if: inputs.include_repo_e2e || (inputs.include_live_suites && !inputs.live_models_only)
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
@@ -349,8 +362,8 @@ jobs:
run: ${{ matrix.command }}
validate_docker_e2e:
needs: validate_selected_ref
if: inputs.include_release_path_suites || inputs.include_openwebui
needs: [validate_selected_ref, prepare_docker_e2e_image]
if: inputs.include_release_path_suites
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
@@ -362,55 +375,71 @@ jobs:
command: pnpm test:docker:onboard
timeout_minutes: 60
release_path: true
openwebui_only: false
- suite_id: docker-npm-onboard-channel-agent
label: Npm Onboard Channel Agent Docker E2E
command: pnpm test:docker:npm-onboard-channel-agent
timeout_minutes: 90
release_path: true
- suite_id: docker-gateway-network
label: Gateway Network Docker E2E
command: pnpm test:docker:gateway-network
timeout_minutes: 60
release_path: true
openwebui_only: false
- suite_id: docker-openai-web-search-minimal
label: OpenAI Web Search Minimal Docker E2E
command: pnpm test:docker:openai-web-search-minimal
timeout_minutes: 60
release_path: true
- suite_id: docker-mcp-channels
label: MCP Channels Docker E2E
command: pnpm test:docker:mcp-channels
timeout_minutes: 60
release_path: true
openwebui_only: false
- suite_id: docker-pi-bundle-mcp-tools
label: Pi Bundle MCP Tools Docker E2E
command: pnpm test:docker:pi-bundle-mcp-tools
timeout_minutes: 60
release_path: true
- suite_id: docker-cron-mcp-cleanup
label: Cron MCP Cleanup Docker E2E
command: pnpm test:docker:cron-mcp-cleanup
timeout_minutes: 60
release_path: true
- suite_id: docker-plugins
label: Plugins Docker E2E
command: pnpm test:docker:plugins
timeout_minutes: 75
release_path: true
openwebui_only: false
- suite_id: docker-plugin-update
label: Plugin Update Docker E2E
command: pnpm test:docker:plugin-update
timeout_minutes: 60
release_path: true
- suite_id: docker-config-reload
label: Config Reload Docker E2E
command: pnpm test:docker:config-reload
timeout_minutes: 60
release_path: true
- suite_id: docker-bundled-channel-deps
label: Bundled Channel Runtime Deps Docker E2E
command: pnpm test:docker:bundled-channel-deps
timeout_minutes: 75
release_path: true
openwebui_only: false
- suite_id: docker-doctor-switch
label: Doctor Install Switch Docker E2E
command: pnpm test:docker:doctor-switch
timeout_minutes: 60
release_path: true
openwebui_only: false
- suite_id: docker-qr
label: QR Import Docker E2E
command: pnpm test:docker:qr
timeout_minutes: 60
release_path: true
openwebui_only: false
- suite_id: docker-install-e2e
label: Installer Docker E2E
command: pnpm test:install:e2e
timeout_minutes: 120
release_path: true
openwebui_only: false
- suite_id: docker-openwebui
label: Open WebUI Docker E2E
command: pnpm test:docker:openwebui
timeout_minutes: 75
release_path: false
openwebui_only: true
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
@@ -455,6 +484,9 @@ jobs:
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
OPENCLAW_SKIP_DOCKER_BUILD: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
@@ -462,6 +494,13 @@ jobs:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Log in to GHCR for shared Docker E2E image
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
@@ -497,23 +536,229 @@ jobs:
exit 1
fi
;;
docker-openwebui)
[[ -n "${OPENAI_API_KEY:-}" ]] || {
echo "OPENAI_API_KEY is required for the Open WebUI Docker smoke." >&2
exit 1
}
;;
esac
- name: Run ${{ matrix.label }}
if: |
(inputs.include_release_path_suites && matrix.release_path) ||
(inputs.include_openwebui && matrix.openwebui_only)
run: ${{ matrix.command }}
validate_docker_openwebui:
needs: [validate_selected_ref, prepare_docker_e2e_image]
if: inputs.include_openwebui
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 75
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
OPENCLAW_SKIP_DOCKER_BUILD: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Log in to GHCR for shared Docker E2E image
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate Open WebUI credentials
shell: bash
run: |
set -euo pipefail
[[ -n "${OPENAI_API_KEY:-}" ]] || {
echo "OPENAI_API_KEY is required for the Open WebUI Docker smoke." >&2
exit 1
}
- name: Run Open WebUI Docker E2E
run: pnpm test:docker:openwebui
prepare_docker_e2e_image:
needs: validate_selected_ref
if: inputs.include_release_path_suites || inputs.include_openwebui
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 90
permissions:
contents: read
packages: write
outputs:
image: ${{ steps.image.outputs.image }}
env:
DOCKER_BUILD_SUMMARY: "false"
DOCKER_BUILD_RECORD_UPLOAD: "false"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Resolve shared Docker E2E image tag
id: image
shell: bash
env:
SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
run: |
set -euo pipefail
repository="${GITHUB_REPOSITORY,,}"
image="ghcr.io/${repository}-docker-e2e:${SELECTED_SHA}"
echo "image=$image" >> "$GITHUB_OUTPUT"
echo "Shared Docker E2E image: \`$image\`" >> "$GITHUB_STEP_SUMMARY"
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Setup Docker builder
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
- name: Build and push shared Docker E2E image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: ./scripts/e2e/Dockerfile
target: build
platforms: linux/amd64
cache-from: type=gha,scope=docker-e2e
cache-to: type=gha,mode=max,scope=docker-e2e
tags: ${{ steps.image.outputs.image }}
provenance: false
push: true
validate_live_models_docker:
name: Docker live models (${{ matrix.provider_label }})
needs: validate_selected_ref
if: inputs.include_live_suites
runs-on: ubuntu-24.04
timeout-minutes: 75
strategy:
fail-fast: false
matrix:
include:
- provider_label: Anthropic
providers: anthropic
- provider_label: Google
providers: google
- provider_label: MiniMax
providers: minimax
- provider_label: OpenAI
providers: openai
- provider_label: OpenCode
providers: opencode-go
- provider_label: OpenRouter
providers: openrouter
- provider_label: xAI
providers: xai
- provider_label: Z.ai
providers: zai
- provider_label: Fireworks
providers: fireworks
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
OPENCLAW_LIVE_PROVIDERS: ${{ matrix.providers }}
OPENCLAW_VITEST_MAX_WORKERS: "2"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Hydrate live auth/profile inputs
run: bash scripts/ci-hydrate-live-auth.sh
- name: Validate provider credential
shell: bash
run: |
set -euo pipefail
require_any() {
local label="$1"
shift
local key
for key in "$@"; do
if [[ -n "${!key:-}" ]]; then
return 0
fi
done
echo "Missing credential for ${label}: expected one of $*" >&2
exit 1
}
case "${{ matrix.providers }}" in
anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;;
google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;;
minimax) require_any MiniMax MINIMAX_API_KEY ;;
openai) require_any OpenAI OPENAI_API_KEY ;;
opencode-go) require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY ;;
openrouter) require_any OpenRouter OPENROUTER_API_KEY ;;
xai) require_any xAI XAI_API_KEY ;;
zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;;
fireworks) require_any Fireworks FIREWORKS_API_KEY ;;
*)
echo "Unhandled live model provider shard: ${{ matrix.providers }}" >&2
exit 1
;;
esac
- name: Run Docker live model sweep
run: pnpm test:docker:live-models
validate_live_provider_suites:
needs: validate_selected_ref
if: inputs.include_live_suites
if: inputs.include_live_suites && !inputs.live_models_only
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
@@ -525,11 +770,6 @@ jobs:
command: pnpm test:live
timeout_minutes: 180
profile_env_only: false
- suite_id: live-models-docker
label: Docker live models
command: pnpm test:docker:live-models
timeout_minutes: 120
profile_env_only: false
- suite_id: live-gateway-docker
label: Docker live gateway
command: pnpm test:docker:live-gateway
@@ -594,6 +834,7 @@ jobs:
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS: ""
OPENCLAW_LIVE_VYDRA_VIDEO: "1"
OPENCLAW_VITEST_MAX_WORKERS: "2"
@@ -623,7 +864,7 @@ 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=codex-cli/gpt-5.5" >> "$GITHUB_ENV"
# The CLI backend Docker lane should exercise the same staged
# Codex auth path Peter uses locally so MCP cron creation and
# multimodal probes stay covered in CI. Replace the staged

View File

@@ -43,7 +43,7 @@ jobs:
# so this public workflow can stay focused on OIDC publish only.
preflight_openclaw_npm:
if: ${{ inputs.preflight_only }}
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ubuntu-latest
permissions:
contents: read
steps:
@@ -252,7 +252,7 @@ jobs:
validate_publish_request:
if: ${{ !inputs.preflight_only }}
runs-on: blacksmith-32vcpu-ubuntu-2404
runs-on: ubuntu-latest
permissions:
contents: read
steps:

View File

@@ -32,6 +32,9 @@ concurrency:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
jobs:
resolve_target:
@@ -121,9 +124,18 @@ jobs:
echo "- Validated SHA: \`${RELEASE_SHA}\`"
echo "- Cross-OS provider: \`${RELEASE_PROVIDER}\`"
echo "- Cross-OS mode: \`${RELEASE_MODE}\`"
echo "- This run will execute cross-OS release validation plus the non-Parallels Docker/live/openwebui coverage from the CI migration plan."
echo "- This run will execute cross-OS release validation, install smoke, QA Lab parity, Matrix, and Telegram lanes, and the non-Parallels Docker/live/openwebui coverage from the CI migration plan."
} >> "$GITHUB_STEP_SUMMARY"
install_smoke_release_checks:
needs: [resolve_target]
permissions:
contents: read
uses: ./.github/workflows/install-smoke.yml
with:
ref: ${{ needs.resolve_target.outputs.ref }}
run_bun_global_install_smoke: true
cross_os_release_checks:
needs: [resolve_target]
permissions: read-all
@@ -144,6 +156,7 @@ jobs:
needs: [resolve_target]
permissions:
contents: read
packages: write
pull-requests: read
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
with:
@@ -196,3 +209,232 @@ jobs:
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
qa_lab_parity_release_checks:
name: Run QA Lab parity gate
needs: [resolve_target]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 30
permissions:
contents: read
env:
QA_PARITY_CONCURRENCY: "1"
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
OPENCLAW_LIVE_OPENAI_KEY: ""
OPENCLAW_LIVE_ANTHROPIC_KEY: ""
OPENCLAW_LIVE_GEMINI_KEY: ""
OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ""
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.ref }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Build private QA runtime
run: pnpm build
- name: Run OpenAI candidate lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model openai/gpt-5.4-alt \
--output-dir .artifacts/qa-e2e/gpt54
- name: Run Opus 4.6 lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model anthropic/claude-opus-4-6 \
--alt-model anthropic/claude-sonnet-4-6 \
--output-dir .artifacts/qa-e2e/opus46
- name: Generate parity report
run: |
pnpm openclaw qa parity-report \
--repo-root . \
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
--baseline-label anthropic/claude-opus-4-6 \
--output-dir .artifacts/qa-e2e/parity
- name: Upload parity artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-parity-${{ needs.resolve_target.outputs.sha }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
qa_live_matrix_release_checks:
name: Run QA Lab live Matrix lane
needs: [resolve_target]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
permissions:
contents: read
pull-requests: read
environment: qa-live-shared
env:
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.ref }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
echo "Missing required OPENAI_API_KEY." >&2
exit 1
fi
- name: Build private QA runtime
run: pnpm build
- name: Run Matrix live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/matrix-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa matrix \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--fast
- name: Upload Matrix QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-live-matrix-${{ needs.resolve_target.outputs.sha }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn
qa_live_telegram_release_checks:
name: Run QA Lab live Telegram lane
needs: [resolve_target]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
permissions:
contents: read
pull-requests: read
environment: qa-live-shared
env:
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.resolve_target.outputs.ref }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
run: |
set -euo pipefail
require_var() {
local key="$1"
if [[ -z "${!key:-}" ]]; then
echo "Missing required ${key}." >&2
exit 1
fi
}
require_var OPENAI_API_KEY
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
- name: Build private QA runtime
run: pnpm build
- name: Run Telegram live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/telegram-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa telegram \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci
- name: Upload Telegram QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: release-qa-live-telegram-${{ needs.resolve_target.outputs.sha }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn

View File

@@ -7,6 +7,7 @@ on:
permissions:
contents: read
packages: write
pull-requests: read
concurrency:
@@ -20,12 +21,13 @@ jobs:
live_and_openwebui_checks:
permissions:
contents: read
packages: write
pull-requests: read
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
with:
ref: ${{ github.sha }}
include_repo_e2e: true
include_release_path_suites: false
include_release_path_suites: true
include_openwebui: true
include_live_suites: true
secrets:
@@ -72,3 +74,4 @@ jobs:
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}

View File

@@ -13,6 +13,7 @@ on:
- "src/gateway/**"
- "src/media/**"
- ".github/workflows/parity-gate.yml"
workflow_dispatch:
permissions:
contents: read
@@ -23,7 +24,7 @@ concurrency:
jobs:
parity-gate:
name: Run the GPT-5.4 / Opus 4.6 parity gate against the qa-lab mock
name: Run the OpenAI / Opus 4.6 parity gate against the qa-lab mock
if: ${{ github.event.pull_request.draft != true }}
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 30
@@ -41,6 +42,7 @@ jobs:
# followthrough gate that expects a fast post-approval read within a 30s
# agent.wait timeout.
QA_PARITY_CONCURRENCY: "1"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
@@ -74,13 +76,13 @@ jobs:
# The approval-turn sentinel still runs inside the full parity pack below.
# Keep the exact mock read-plan contract in deterministic unit tests instead
# of paying for a separate full-runtime preflight that has been flaky in CI.
- name: Run GPT-5.4 lane
- name: Run OpenAI candidate lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model openai/gpt-5.4 \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model openai/gpt-5.4-alt \
--output-dir .artifacts/qa-e2e/gpt54
@@ -100,7 +102,7 @@ jobs:
--repo-root . \
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
--candidate-label openai/gpt-5.4 \
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
--baseline-label anthropic/claude-opus-4-6 \
--output-dir .artifacts/qa-e2e/parity

View File

@@ -0,0 +1,445 @@
name: QA-Lab - All Lanes
on:
schedule:
- cron: "41 4 * * *"
workflow_dispatch:
inputs:
ref:
description: Ref, tag, or SHA to run
required: true
default: main
type: string
scenario:
description: Optional comma-separated Telegram scenario ids
required: false
type: string
discord_scenario:
description: Optional comma-separated Discord scenario ids
required: false
type: string
permissions:
contents: read
pull-requests: read
concurrency:
group: qa-lab-all-lanes-${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
PNPM_VERSION: "10.33.0"
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
jobs:
authorize_actor:
name: Authorize workflow actor
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- name: Require maintainer-level repository access
uses: actions/github-script@v8
with:
script: |
if (context.eventName === "schedule") {
core.info("Scheduled default-branch QA run; actor permission check is only required for manual dispatch.");
return;
}
const allowed = new Set(["admin", "maintain", "write"]);
const { owner, repo } = context.repo;
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner,
repo,
username: context.actor,
});
const permission = data.permission;
core.info(`Actor ${context.actor} permission: ${permission}`);
if (!allowed.has(permission)) {
core.setFailed(
`Workflow requires write/maintain/admin access. Actor "${context.actor}" has "${permission}".`,
);
}
validate_selected_ref:
name: Validate selected ref
needs: authorize_actor
runs-on: blacksmith-8vcpu-ubuntu-2404
outputs:
selected_sha: ${{ steps.validate.outputs.selected_sha }}
trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
fetch-depth: 0
- name: Validate selected ref
id: validate
env:
GH_TOKEN: ${{ github.token }}
INPUT_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
shell: bash
run: |
set -euo pipefail
selected_sha="$(git rev-parse HEAD)"
trusted_reason=""
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
if git merge-base --is-ancestor "$selected_sha" refs/remotes/origin/main; then
trusted_reason="main-ancestor"
elif git tag --points-at "$selected_sha" | grep -Eq '^v'; then
trusted_reason="release-tag"
elif [[ "$INPUT_REF" =~ ^release/[0-9]{4}\.[0-9]+\.[0-9]+$ ]]; then
git fetch --no-tags origin "+refs/heads/${INPUT_REF}:refs/remotes/origin/${INPUT_REF}"
release_branch_sha="$(git rev-parse "refs/remotes/origin/${INPUT_REF}")"
if [[ "$selected_sha" == "$release_branch_sha" ]]; then
trusted_reason="release-branch-head"
fi
else
pr_head_count="$(
gh api \
-H "Accept: application/vnd.github+json" \
"repos/${GITHUB_REPOSITORY}/commits/${selected_sha}/pulls" \
--jq '[.[] | select(.state == "open" and .head.repo.full_name == "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${selected_sha}"'")] | length'
)"
if [[ "$pr_head_count" != "0" ]]; then
trusted_reason="open-pr-head"
fi
fi
if [[ -z "$trusted_reason" ]]; then
echo "Ref '${INPUT_REF}' resolved to $selected_sha, which is not trusted for this secret-bearing QA run." >&2
echo "Allowed refs must be on main, point to a release tag, match a release branch head, or match an open PR head in ${GITHUB_REPOSITORY}." >&2
exit 1
fi
echo "selected_sha=$selected_sha" >> "$GITHUB_OUTPUT"
echo "trusted_reason=$trusted_reason" >> "$GITHUB_OUTPUT"
{
echo "Validated ref: \`${INPUT_REF}\`"
echo "Resolved SHA: \`$selected_sha\`"
echo "Trust reason: \`$trusted_reason\`"
} >> "$GITHUB_STEP_SUMMARY"
run_mock_parity:
name: Run QA Lab parity gate
needs: [validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 30
env:
QA_PARITY_CONCURRENCY: "1"
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
OPENCLAW_LIVE_OPENAI_KEY: ""
OPENCLAW_LIVE_ANTHROPIC_KEY: ""
OPENCLAW_LIVE_GEMINI_KEY: ""
OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ""
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Build private QA runtime
run: pnpm build
- name: Run OpenAI candidate lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model openai/gpt-5.4-alt \
--output-dir .artifacts/qa-e2e/gpt54
- name: Run Opus 4.6 lane
run: |
pnpm openclaw qa suite \
--provider-mode mock-openai \
--parity-pack agentic \
--concurrency "${QA_PARITY_CONCURRENCY}" \
--model anthropic/claude-opus-4-6 \
--alt-model anthropic/claude-sonnet-4-6 \
--output-dir .artifacts/qa-e2e/opus46
- name: Generate parity report
run: |
pnpm openclaw qa parity-report \
--repo-root . \
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
--baseline-label anthropic/claude-opus-4-6 \
--output-dir .artifacts/qa-e2e/parity
- name: Upload parity artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-parity-${{ github.run_id }}-${{ github.run_attempt }}
path: .artifacts/qa-e2e/
retention-days: 14
if-no-files-found: warn
run_live_matrix:
name: Run Matrix live QA lane
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
echo "Missing required OPENAI_API_KEY." >&2
exit 1
fi
- name: Build private QA runtime
run: pnpm build
- name: Run Matrix live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/matrix-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa matrix \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--fast
- name: Upload Matrix QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-live-matrix-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn
run_live_telegram:
name: Run Telegram live QA lane with Convex leases
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
run: |
set -euo pipefail
require_var() {
local key="$1"
if [[ -z "${!key:-}" ]]; then
echo "Missing required ${key}." >&2
exit 1
fi
}
require_var OPENAI_API_KEY
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
- name: Build private QA runtime
run: pnpm build
- name: Run Telegram live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.scenario || '' }}
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/telegram-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
scenario_args=()
if [[ -n "${INPUT_SCENARIO// }" ]]; then
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
for raw in "${raw_scenarios[@]}"; do
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
if [[ -n "${scenario}" ]]; then
scenario_args+=(--scenario "${scenario}")
fi
done
fi
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa telegram \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
--fast \
--credential-source convex \
--credential-role ci \
"${scenario_args[@]}"
- name: Upload Telegram QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-live-telegram-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn
run_live_discord:
name: Run Discord live QA lane with Convex leases
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
run: |
set -euo pipefail
require_var() {
local key="$1"
if [[ -z "${!key:-}" ]]; then
echo "Missing required ${key}." >&2
exit 1
fi
}
require_var OPENAI_API_KEY
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
- name: Build private QA runtime
run: pnpm build
- name: Run Discord live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_DISCORD_CAPTURE_CONTENT: "1"
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.discord_scenario || '' }}
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/discord-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
scenario_args=()
if [[ -n "${INPUT_SCENARIO// }" ]]; then
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
for raw in "${raw_scenarios[@]}"; do
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
if [[ -n "${scenario}" ]]; then
scenario_args+=(--scenario "${scenario}")
fi
done
fi
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa discord \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model openai/gpt-5.4 \
--alt-model openai/gpt-5.4 \
--fast \
--credential-source convex \
--credential-role ci \
"${scenario_args[@]}"
- name: Upload Discord QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-live-discord-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn

View File

@@ -0,0 +1,278 @@
name: Test Performance Agent
on:
workflow_run: # zizmor: ignore[dangerous-triggers] main-only test optimization after trusted CI; job gates repository, event, branch, actor, conclusion, current main SHA, and daily cadence before using write token
workflows:
- CI
types:
- completed
workflow_dispatch:
permissions:
actions: read
contents: write
concurrency:
group: test-performance-agent-main
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
TEST_PERF_BEFORE: .artifacts/test-perf/baseline-before.json
TEST_PERF_AFTER: .artifacts/test-perf/after-agent.json
TEST_PERF_COMPARE: .artifacts/test-perf/agent-compare.json
jobs:
optimize-tests:
if: >
github.repository == 'openclaw/openclaw' &&
(github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.head_branch == 'main' &&
!endsWith(github.event.workflow_run.actor.login, '[bot]')))
runs-on: ubuntu-24.04
timeout-minutes: 240
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: main
fetch-depth: 0
persist-credentials: false
submodules: false
- name: Gate trusted main activity and daily cadence
id: gate
env:
EVENT_NAME: ${{ github.event_name }}
GH_TOKEN: ${{ github.token }}
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" != "workflow_run" ]; then
echo "run_agent=true" >> "$GITHUB_OUTPUT"
echo "base_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
exit 0
fi
for attempt in 1 2 3 4 5; do
if git fetch --no-tags origin main; then
break
fi
if [ "$attempt" = "5" ]; then
echo "Failed to fetch main after retries." >&2
exit 1
fi
echo "Fetch attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done
remote_main="$(git rev-parse origin/main)"
if [ "$remote_main" != "$WORKFLOW_HEAD_SHA" ]; then
echo "CI run is superseded by ${remote_main}; skipping test performance agent for ${WORKFLOW_HEAD_SHA}."
echo "run_agent=false" >> "$GITHUB_OUTPUT"
exit 0
fi
day_start="$(date -u +%Y-%m-%dT00:00:00Z)"
runs_json="$RUNNER_TEMP/test-performance-agent-runs.json"
gh api --method GET "repos/${GITHUB_REPOSITORY}/actions/workflows/test-performance-agent.yml/runs" \
-f branch=main \
-f event=workflow_run \
-f per_page=50 > "$runs_json"
prior_runs="$(
jq -r \
--argjson current_run_id "$GITHUB_RUN_ID" \
--arg day_start "$day_start" \
'.workflow_runs[]
| select(.database_id != $current_run_id)
| select(.created_at >= $day_start)
| select(.status != "cancelled")
| select((.conclusion // "") != "skipped")
| [.database_id, .status, (.conclusion // ""), .created_at, .head_sha]
| @tsv' "$runs_json"
)"
if [ -n "$prior_runs" ]; then
echo "Test performance agent already ran or is running today; skipping."
printf '%s\n' "$prior_runs"
echo "run_agent=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "run_agent=true" >> "$GITHUB_OUTPUT"
echo "base_sha=${remote_main}" >> "$GITHUB_OUTPUT"
- name: Setup Node environment
if: steps.gate.outputs.run_agent == 'true'
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Ensure test performance agent key exists
if: steps.gate.outputs.run_agent == 'true'
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_TEST_PERF_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
if [ -z "${OPENAI_API_KEY:-}" ]; then
echo "Missing OPENCLAW_TEST_PERF_AGENT_OPENAI_API_KEY or OPENAI_API_KEY secret." >&2
exit 1
fi
- name: Build baseline full-suite performance report
if: steps.gate.outputs.run_agent == 'true'
run: pnpm test:perf:groups --full-suite --allow-failures --output "$TEST_PERF_BEFORE" --limit 20 --top-files 40
- name: Run Codex test performance agent
if: steps.gate.outputs.run_agent == 'true'
uses: openai/codex-action@v1
with:
openai-api-key: ${{ secrets.OPENCLAW_TEST_PERF_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
prompt-file: .github/codex/prompts/test-performance-agent.md
model: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
effort: high
sandbox: workspace-write
safety-strategy: drop-sudo
codex-args: '["--full-auto"]'
- name: Enforce focused test performance patch
if: steps.gate.outputs.run_agent == 'true'
id: patch
run: |
set -euo pipefail
untracked="$(git ls-files --others --exclude-standard)"
if [ -n "$untracked" ]; then
echo "Test performance agent created untracked files; forbidden:"
printf '%s\n' "$untracked"
exit 1
fi
added_deleted_or_renamed="$(git diff --name-status --diff-filter=ADR)"
if [ -n "$added_deleted_or_renamed" ]; then
echo "Test performance agent added, deleted, or renamed tracked files; forbidden:"
printf '%s\n' "$added_deleted_or_renamed"
exit 1
fi
bad_paths="$(
git diff --name-only | while IFS= read -r path; do
case "$path" in
apps/*|extensions/*|packages/*|scripts/*|src/*|Swabble/*|test/*|ui/*) ;;
*) printf '%s\n' "$path" ;;
esac
done
)"
if [ -n "$bad_paths" ]; then
echo "Test performance agent touched forbidden paths:"
printf '%s\n' "$bad_paths"
exit 1
fi
if git diff --quiet; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Restore Node 24 path
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
run: | # zizmor: ignore[github-env] NODE_BIN is set by the trusted local setup-node-env action in this same job
set -euo pipefail
export PATH="${NODE_BIN}:${PATH}"
echo "${NODE_BIN}" >> "$GITHUB_PATH"
node -v
corepack enable
pnpm -v
- name: Run full-suite performance report after agent changes
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
run: pnpm test:perf:groups --full-suite --output "$TEST_PERF_AFTER" --limit 20 --top-files 40
- name: Compare test performance reports
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
run: pnpm test:perf:groups:compare "$TEST_PERF_BEFORE" "$TEST_PERF_AFTER" --output "$TEST_PERF_COMPARE" --limit 20 --top-files 40
- name: Enforce coverage-preserving test count
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
run: |
set -euo pipefail
node <<'NODE'
const fs = require("node:fs");
const before = JSON.parse(fs.readFileSync(process.env.TEST_PERF_BEFORE, "utf8"));
const after = JSON.parse(fs.readFileSync(process.env.TEST_PERF_AFTER, "utf8"));
if (before.failed) {
console.log("Baseline had failing configs; skipping total test-count comparison against partial report.");
process.exit(0);
}
const beforeTests = before.totals?.testCount ?? 0;
const afterTests = after.totals?.testCount ?? 0;
if (afterTests < beforeTests) {
console.error(`Test count decreased from ${beforeTests} to ${afterTests}; refusing coverage-reducing patch.`);
process.exit(1);
}
console.log(`Test count preserved: ${beforeTests} -> ${afterTests}.`);
NODE
- name: Check changed lanes
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
run: pnpm check:changed
- name: Commit test performance updates
if: steps.gate.outputs.run_agent == 'true' && steps.patch.outputs.has_changes == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
TARGET_BRANCH: main
run: |
set -euo pipefail
if git diff --quiet; then
echo "No test performance changes."
exit 0
fi
git config user.name "openclaw-test-performance-agent[bot]"
git config user.email "openclaw-test-performance-agent[bot]@users.noreply.github.com"
git add apps extensions packages scripts src Swabble test ui
git commit --no-verify -m "test: optimize slow tests"
for attempt in 1 2 3 4 5; do
if ! git fetch --no-tags origin "${TARGET_BRANCH}"; then
echo "Fetch attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
continue
fi
if git push "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" HEAD:"${TARGET_BRANCH}"; then
exit 0
fi
remote_main="$(git rev-parse "origin/${TARGET_BRANCH}")"
if [ "$remote_main" != "$(git rev-parse HEAD^)" ]; then
echo "main advanced; rebasing test performance update onto ${remote_main}."
if ! git rebase "origin/${TARGET_BRANCH}"; then
echo "Test performance update no longer applies cleanly; skipping stale update."
git rebase --abort || true
exit 0
fi
pnpm check:changed
fi
echo "Test performance update attempt ${attempt} failed; retrying."
sleep $((attempt * 2))
done
echo "Failed to push test performance updates after retries." >&2
exit 1
- name: Upload test performance artifacts
if: steps.gate.outputs.run_agent == 'true' && always()
uses: actions/upload-artifact@v7
with:
name: test-performance-agent-${{ github.run_id }}
path: .artifacts/test-perf/
if-no-files-found: ignore
retention-days: 14

10
.gitignore vendored
View File

@@ -128,15 +128,14 @@ dist/protocol.schema.json
# Synthing
**/.stfolder/
.dev-state
docs/superpowers/plans/2026-03-10-collapsed-side-nav.md
docs/superpowers/specs/2026-03-10-collapsed-side-nav-design.md
docs/superpowers
.superpowers/
.gitignore
test/config-form.analyze.telegram.test.ts
ui/src/ui/theme-variants.browser.test.ts
ui/src/ui/__screenshots__
ui/src/ui/views/__screenshots__
ui/.vitest-attachments
docs/superpowers
# Generated docs baseline artifacts (locally generated, only hashes tracked)
docs/.generated/*.json
@@ -147,8 +146,13 @@ changelog/fragments/
# Local scratch workspace
.tmp/
.vmux*
.artifacts/
test/fixtures/openclaw-vitest-unit-report.json
analysis/
.artifacts/qa-e2e/
extensions/qa-lab/web/dist/
# Generated bundled plugin runtime dependency manifests
extensions/**/.openclaw-runtime-deps.json
extensions/**/.openclaw-runtime-deps-stamp.json

View File

@@ -39,7 +39,12 @@
"details",
"summary",
"p",
"div",
"strong",
"span",
"iframe",
"h2",
"h3",
"picture",
"source",
"Tooltip",

View File

@@ -11,24 +11,53 @@
"eslint-plugin-unicorn/prefer-array-find": "error",
"eslint/no-array-constructor": "error",
"eslint/no-await-in-loop": "off",
"eslint/no-constructor-return": "error",
"eslint/no-div-regex": "error",
"eslint/no-extra-label": "error",
"eslint/no-empty-pattern": "error",
"eslint/no-lone-blocks": "error",
"eslint/no-multi-str": "error",
"eslint/no-new": "error",
"eslint/no-object-constructor": "error",
"eslint/no-proto": "error",
"eslint/no-regex-spaces": "error",
"eslint/no-return-assign": "error",
"eslint/no-sequences": "error",
"eslint/no-self-compare": "error",
"eslint/no-shadow": "off",
"eslint/no-var": "error",
"eslint/no-useless-call": "error",
"eslint/no-useless-computed-key": "error",
"eslint/no-useless-concat": "error",
"eslint/no-useless-constructor": "error",
"eslint/no-warning-comments": "error",
"eslint/no-unmodified-loop-condition": "error",
"eslint/no-new-wrappers": "error",
"eslint/no-else-return": "error",
"eslint/no-case-declarations": "error",
"eslint/prefer-exponentiation-operator": "error",
"eslint/prefer-numeric-literals": "error",
"eslint/radix": "error",
"eslint/unicode-bom": "error",
"eslint/yoda": "error",
"import/no-absolute-path": "error",
"import/no-empty-named-blocks": "error",
"import/no-self-import": "error",
"node/no-exports-assign": "error",
"eslint-plugin-unicorn/prefer-set-size": "error",
"oxc/no-accumulating-spread": "error",
"oxc/no-async-endpoint-handlers": "error",
"oxc/no-map-spread": "error",
"promise/no-new-statics": "error",
"typescript/adjacent-overload-signatures": "error",
"typescript/ban-tslint-comment": "error",
"typescript/consistent-return": "error",
"typescript/no-empty-object-type": ["error", { "allowInterfaces": "with-single-extends" }],
"typescript/no-explicit-any": "error",
"typescript/no-extraneous-class": "error",
"typescript/no-meaningless-void-operator": "error",
"typescript/no-non-null-asserted-nullish-coalescing": "error",
"typescript/no-unnecessary-qualifier": "error",
"typescript/no-unnecessary-type-assertion": "error",
"typescript/no-unnecessary-type-arguments": "error",
"typescript/no-unnecessary-type-constraint": "error",
@@ -36,15 +65,52 @@
"typescript/no-unnecessary-type-parameters": "error",
"typescript/no-unsafe-type-assertion": "off",
"typescript/no-useless-default-assignment": "error",
"typescript/switch-exhaustiveness-check": [
"error",
{ "considerDefaultExhaustiveForUnions": true }
],
"typescript/prefer-return-this-type": "error",
"typescript/prefer-find": "error",
"typescript/prefer-function-type": "error",
"typescript/prefer-includes": "error",
"typescript/prefer-reduce-type-parameter": "error",
"typescript/prefer-ts-expect-error": "error",
"unicorn/consistent-date-clone": "error",
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-console-spaces": "error",
"unicorn/no-length-as-slice-end": "error",
"unicorn/no-instanceof-array": "error",
"unicorn/no-negation-in-equality-check": "error",
"unicorn/no-new-buffer": "error",
"unicorn/no-typeof-undefined": "error",
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-useless-error-capture-stack-trace": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-number-properties": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-optional-catch-binding": "error",
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-set-size": "error",
"unicorn/require-post-message-target-origin": "error"
"unicorn/prefer-string-slice": "error",
"unicorn/require-array-join-separator": "error",
"unicorn/require-number-to-fixed-digits-argument": "error",
"unicorn/require-post-message-target-origin": "error",
"unicorn/throw-new-error": "error",
"vitest/no-import-node-test": "error",
"vitest/consistent-vitest-vi": "error",
"vitest/prefer-called-once": "error",
"vitest/prefer-called-times": "error",
"vitest/prefer-expect-type-of": "error"
},
"ignorePatterns": [
"assets/",

276
AGENTS.md
View File

@@ -1,201 +1,167 @@
# AGENTS.MD
Telegraph style. Root rules only. Read scoped `AGENTS.md` before touching a subtree.
Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
## Start
- Repo: `https://github.com/openclaw/openclaw`
- Replies: repo-root file refs only, e.g. `extensions/telegram/src/index.ts:80`. No absolute paths, no `~/`.
- CODEOWNERS: maintenance/refactors/tests are ok. For larger behavior, product, security, or ownership-sensitive changes, get a listed owner request/review first.
- First pass: run docs list (`pnpm docs:list`; ignore if unavailable), then read only relevant docs/guides.
- Missing deps: run `pnpm install`, rerun once, then report first actionable error.
- Use "plugin/plugins" in docs/UI/changelog. `extensions/` remains internal workspace layout.
- Add channel/plugin/app/doc surface: update `.github/labeler.yml` and matching GitHub labels.
- New `AGENTS.md`: add sibling `CLAUDE.md` symlink to it.
- Replies: repo-root refs only: `extensions/telegram/src/index.ts:80`. No absolute paths, no `~/`.
- Run docs list first: `pnpm docs:list` if available; read relevant docs only.
- High-confidence answers only when fixing/triaging: verify source, tests, shipped/current behavior, and dependency contracts before deciding.
- Dependency-backed behavior: read upstream dependency docs/source/types first. Do not assume APIs, defaults, errors, timing, or runtime behavior.
- Missing deps: `pnpm install`, retry once, then report first actionable error.
- CODEOWNERS: maint/refactor/tests ok. Larger behavior/product/security/ownership: owner ask/review.
- Wording: product/docs/UI/changelog say "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.
## Repo Map
## Map
- Core TS: `src/`, `ui/`, `packages/`
- Bundled plugins: `extensions/`
- Plugin SDK/public contract: `src/plugin-sdk/*`
- Core channel internals: `src/channels/*`
- Plugin loader/registry/contracts: `src/plugins/*`
- Gateway protocol: `src/gateway/protocol/*`
- Docs: `docs/`
- Apps: `apps/`, `Swabble/`
- Installers served from `openclaw.ai`: sibling `../openclaw.ai`
Scoped guides:
- `extensions/AGENTS.md`: bundled plugin rules
- `src/plugin-sdk/AGENTS.md`: public SDK rules
- `src/channels/AGENTS.md`: channel core rules
- `src/plugins/AGENTS.md`: plugin loader/registry rules
- `src/gateway/AGENTS.md`, `src/gateway/protocol/AGENTS.md`: gateway/protocol rules
- `src/agents/AGENTS.md`: agent import/test perf rules
- `test/helpers/AGENTS.md`, `test/helpers/channels/AGENTS.md`: shared test helpers
- `docs/AGENTS.md`, `ui/AGENTS.md`, `scripts/AGENTS.md`: docs/UI/scripts
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `src/gateway/protocol/*`; docs/apps: `docs/`, `apps/`, `Swabble/`.
- Installers: sibling `../openclaw.ai`.
- Scoped guides exist in: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,gateway/protocol,agents}/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
## Architecture
- Core must stay extension-agnostic. No core special cases for bundled plugin/provider/channel ids when manifest/registry/capability contracts can express it.
- Extensions cross into core only via `openclaw/plugin-sdk/*`, manifest metadata, injected runtime helpers, and documented local barrels (`api.ts`, `runtime-api.ts`).
- Extension production code must not import core `src/**`, `src/plugin-sdk-internal/**`, another extension's `src/**`, or relative paths outside its package.
- Core code/tests must not deep-import plugin internals (`extensions/*/src/**`, `onboard.js`). Use plugin `api.ts` / public SDK facade / generic contract.
- Extension-owned behavior stays in the extension: legacy repair, detection, onboarding, auth/provider defaults, provider tools/settings.
- Legacy config repair: prefer doctor/fix paths over startup/load-time core migrations.
- If a core test asserts extension-specific behavior, move it to the owning extension or a generic contract test.
- Core stays extension-agnostic. No bundled ids in core when manifest/registry/capability contracts work.
- Extensions cross into core only via `openclaw/plugin-sdk/*`, manifest metadata, injected runtime helpers, documented barrels (`api.ts`, `runtime-api.ts`).
- Extension prod code: no core `src/**`, `src/plugin-sdk-internal/**`, other extension `src/**`, or relative outside package.
- Core/tests: no deep plugin internals (`extensions/*/src/**`, `onboard.js`). Use `api.ts`, SDK facade, generic contracts.
- Extension-owned behavior stays extension-owned: repair, detection, onboarding, auth/provider defaults, provider tools/settings.
- Legacy config repair: doctor/fix paths, not startup/load-time core migrations.
- Core test asserting extension-specific behavior: move to owner extension or generic contract test.
- New seams: backwards-compatible, documented, versioned. Third-party plugins exist.
- Channels: `src/channels/**` is implementation. Plugin authors get SDK seams, not channel internals.
- Providers: core owns generic inference loop; provider plugins own provider-specific auth/catalog/runtime hooks.
- Gateway protocol changes are contract changes: additive first; incompatible needs versioning/docs/client follow-through.
- Config contract: keep exported types, schema/help, generated metadata, baselines, docs aligned. Retired public keys stay retired; compatibility belongs in raw migration/doctor paths.
- Plugin architecture direction: manifest-first control plane; targeted runtime loaders; no hidden paths around declared contracts; broad mutable registries are transitional.
- Prompt-cache rule: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
- Channels: `src/channels/**` is implementation; plugin authors get SDK seams.
- Providers: core owns generic loop; provider plugins own auth/catalog/runtime hooks.
- 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.
- Direction: manifest-first control plane; targeted runtime loaders; no hidden contract bypasses; broad mutable registries transitional.
- Prompt cache: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
## Commands
- Runtime: Node 22+. Keep Node and Bun paths working.
- Install: `pnpm install` (Bun supported; keep lockfiles/patches aligned if touched).
- Dev CLI: `pnpm openclaw ...` or `pnpm dev`.
- Build: `pnpm build`
- Smart local gate: `pnpm check:changed` (scoped typecheck/lint/guards + relevant tests)
- Explain smart gate: `pnpm changed:lanes --json`
- Pre-commit view: `pnpm check:changed --staged`
- Normal full prod sweep: `pnpm check` (prod typecheck/lint/guards, no tests)
- Full tests: `pnpm test`
- Changed tests only: `pnpm test:changed`
- Local serial loop: `pnpm test:serial`
- Extension tests: `pnpm test:extensions` or `pnpm test extensions` = all extension shards; `pnpm test extensions/<id>` = one extension lane. Heavy channels/OpenAI have dedicated shards.
- Shard timing artifact: `.artifacts/vitest-shard-timings.json`; auto-used for balanced shard ordering. Disable with `OPENCLAW_TEST_PROJECTS_TIMINGS=0`.
- Targeted tests: `pnpm test <path-or-filter> [vitest args...]`; do not call raw `vitest`.
- Coverage: `pnpm test:coverage`
- Format check/fix: `pnpm format:check` / `pnpm format`
- Typecheck:
- `pnpm tsgo`: fastest core prod graph
- `pnpm tsgo:prod`: core + extensions prod graphs; used by `pnpm check`
- `pnpm check:test-types` / `pnpm tsgo:test`: all test graphs
- `pnpm tsgo:all`: all prod + test project refs
- Debug slices exist; do not present as normal user flow.
- Profile: `pnpm tsgo:profile [core-test|extensions-test|--all]`
- Type policy: use `tsgo`; do not add `tsc --noEmit`, `typecheck`, or `check:types` lanes. `tsc` only for declaration/package-boundary emit gaps.
- Lint:
- `pnpm lint`: core/extensions/scripts shards
- `pnpm lint:core`, `pnpm lint:extensions`, `pnpm lint:scripts`
- `pnpm lint:apps`: Swift/app surface, separate from TS lint
- `pnpm lint:all`: legacy comparison lane
- Local heavy-check behavior: `OPENCLAW_LOCAL_CHECK=1` default; `OPENCLAW_LOCAL_CHECK_MODE=throttled|full`; `OPENCLAW_LOCAL_CHECK=0` for CI/shared runs.
- Local validation is local-first. Do not default to Blacksmith/Testbox for routine OpenClaw iteration; it burns warm caches and startup time. Use repo `pnpm` lanes first, then reach for remote CI/Testbox only for parity-only failures, secrets/services, or when explicitly requested.
- Runtime: Node 22+. Keep Node + Bun paths working.
- Install: `pnpm install` (keep Bun lock/patches aligned if touched).
- CLI: `pnpm openclaw ...` or `pnpm dev`; build: `pnpm build`.
- Smart gate: `pnpm check:changed`; explain `pnpm changed:lanes --json`; staged preview `pnpm check:changed --staged`.
- Sparse worktrees: `pnpm check:changed` is sparse-safe and may skip sparse-missing typecheck projects; do not expand sparse checkout just to satisfy changed-gate tsgo. Direct `pnpm tsgo*` remains strict; use a fuller worktree when you need direct typecheck proof.
- Prod sweep: `pnpm check`; tests: `pnpm test`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`.
- Extension tests: `pnpm test:extensions`, `pnpm test extensions`, `pnpm test extensions/<id>`.
- Targeted tests: `pnpm test <path-or-filter> [vitest args...]`; never raw `vitest`.
- Typecheck: `tsgo` lanes only (`pnpm tsgo*`, `pnpm check:test-types`); do not add `tsc --noEmit`, `typecheck`, `check:types`.
- Format/lint: `pnpm format:check`/`pnpm format`; `pnpm lint*` lanes.
- Heavy checks: `OPENCLAW_LOCAL_CHECK=1`, mode `OPENCLAW_LOCAL_CHECK_MODE=throttled|full`; CI/shared use `OPENCLAW_LOCAL_CHECK=0`.
- Local first. Use repo `pnpm` lanes before Blacksmith/Testbox. Remote only for parity-only failures, secrets/services, or explicit ask.
## GitHub / CI
- Triage: list first, hydrate few. Use bounded `gh --json --jq`; avoid repeated full comment scans.
- Search/dedupe: prefer `gh search issues 'repo:openclaw/openclaw is:open <terms>' --json number,title,state,updatedAt --limit 20`.
- PR shortlist: `gh pr list ...`; then `gh pr view <n> --json number,title,body,closingIssuesReferences,files,statusCheckRollup,reviewDecision`.
- After landing PR: search duplicate open issues/PRs. Before closing: comment why + canonical link.
- GH comments with markdown backticks, `$`, or shell snippets: avoid inline double-quoted `--body`; use single quotes or `--body-file`.
- PR execution artifacts/screenshots: attach them to the PR, comment, or an external artifact store. Do not add `.github/pr-assets` or other PR-only assets to the repo.
- PR review answer must explicitly cover: what bug/behavior we are trying to fix; PR/issue URL(s) and affected endpoint/surface; whether this is the best possible fix, with high-certainty evidence from code, tests, CI, and shipped/current behavior.
- CI polling: exact SHA, needed fields only. Example: `gh api repos/<owner>/<repo>/actions/runs/<id> --jq '{status,conclusion,head_sha,updated_at,name,path}'`.
- Post-land wait: minimal. Exact landed SHA only. If superseded on `main`, same-branch `cancel-in-progress` cancellations are expected; stop once local touched-surface proof exists. Never wait for newer unrelated `main` unless asked.
- Wait matrix:
- never: `Auto response`, `Labeler`, `Docs Sync Publish Repo`, `Docs Agent`, `Test Performance Agent`, `Stale`.
- conditional: `CI` exact SHA only; `Docs` only docs task/no local docs proof; `Workflow Sanity` only workflow/composite/CI-policy edits; `Plugin NPM Release` only plugin package/release metadata.
- release/manual only: `Docker Release`, `OpenClaw NPM Release`, `macOS Release`, `OpenClaw Release Checks`, `Cross-OS Release Checks`, `NPM Telegram Beta E2E`.
- explicit/surface only: `QA-Lab - All Lanes`, `Scheduled Live And E2E`, `Install Smoke`, `CodeQL`, `Sandbox Common Smoke`, `Parity gate`, `Blacksmith Testbox`, `Control UI Locale Refresh`.
- `/landpr`: do not idle on `auto-response` or `check-docs`. Treat docs as local proof unless `check-docs` already failed with actionable relevant error.
- Poll 30-60s. Fetch jobs/logs/artifacts only after failure/completion or concrete need.
## Gates
- Pre-commit hook: staged format/lint, then `pnpm check:changed --staged`; docs/markdown-only skips changed-scope check; `FAST_COMMIT=1` skips changed-scope check only.
- Pre-commit hook: staged formatting only. Validation explicit.
- Changed lanes:
- core prod => core prod typecheck + core tests
- core tests => core test typecheck/tests only
- extension prod => extension prod typecheck + extension tests
- extension tests => extension test typecheck/tests only
- public SDK/plugin contract => extension prod/test validation too
- unknown root/config => all lanes
- Local loop: prefer `pnpm check:changed`; use `pnpm test:changed` for tests only; use `pnpm check` for full prod TS/lint sweep without tests.
- Landing on `main`: verify touched surface near landing; default bar is `pnpm check` + `pnpm test` when feasible.
- Hard build gate: run/pass `pnpm build` before push if build output, packaging, lazy/module boundaries, or published surfaces can change.
- Do not land related failing format/lint/type/build/tests. If failures are unrelated on latest `origin/main`, say so and give scoped proof.
- CI architecture gate: `check-additional`; local equivalent `pnpm check:architecture`.
- Config docs drift: `pnpm config:docs:gen/check`
- Plugin SDK API drift: `pnpm plugin-sdk:api:gen/check`
- Generated docs baselines: tracked `docs/.generated/*.sha256`; full JSON ignored.
- core prod: core prod typecheck + core tests
- core tests: core test typecheck/tests
- extension prod: extension prod typecheck + extension tests
- extension tests: extension test typecheck/tests
- public SDK/plugin contract: extension prod/test too
- unknown root/config: all lanes
- Before handoff/push: `pnpm check:changed`. Tests-only: `pnpm test:changed`. Full prod sweep: `pnpm check`.
- Landing on `main`: verify touched surface near landing. Default feasible bar: `pnpm check` + `pnpm test`.
- Hard build gate: `pnpm build` before push if build output, packaging, lazy/module boundaries, or published surfaces can change.
- Do not land related failing format/lint/type/build/tests. If unrelated on latest `origin/main`, say so with scoped proof.
- Generated/API drift: `pnpm check:architecture`, `pnpm config:docs:gen/check`, `pnpm plugin-sdk:api:gen/check`. Track `docs/.generated/*.sha256`; full JSON ignored.
## Code Style
## Code
- TypeScript ESM. Strict types. Avoid `any`; prefer real types/`unknown`/narrow adapters.
- No `@ts-nocheck`. No lint suppressions unless intentional and explained.
- TS ESM, strict. Avoid `any`; prefer real types, `unknown`, narrow adapters.
- No `@ts-nocheck`. Lint suppressions only intentional + explained.
- External boundaries: prefer `zod` or existing schema helpers.
- Runtime branching: prefer discriminated unions / closed codes over freeform strings.
- Avoid magic sentinels like `?? 0`, empty object/string when semantics change.
- Dynamic import: do not mix static and dynamic import for same module in prod path. Use dedicated `*.runtime.ts` lazy boundary. After lazy-boundary edits, run `pnpm build` and check `[INEFFECTIVE_DYNAMIC_IMPORT]`.
- Cycles: keep `pnpm check:import-cycles` and architecture/madge cycle checks green.
- Classes: no prototype mixins/mutations. Use explicit inheritance/composition. Tests prefer per-instance stubs.
- Comments: brief only for non-obvious logic.
- File size: split around ~700 LOC when it improves clarity/testability.
- Product naming: **OpenClaw** product/docs; `openclaw` CLI/package/path/config.
- Written English: American spelling.
- Runtime branching: discriminated unions/closed codes over freeform strings.
- Avoid semantic sentinels: `?? 0`, empty object/string, etc.
- Dynamic import: no static+dynamic import for same prod module. Use `*.runtime.ts` lazy boundary. After edits: `pnpm build`; check `[INEFFECTIVE_DYNAMIC_IMPORT]`.
- Cycles: keep `pnpm check:import-cycles` + architecture/madge green.
- Classes: no prototype mixins/mutations. Prefer inheritance/composition. Tests prefer per-instance stubs.
- Comments: brief, only non-obvious logic.
- Split files around ~700 LOC when clarity/testability improves.
- Naming: **OpenClaw** product/docs; `openclaw` CLI/package/path/config.
- English: American spelling.
## Tests
- Vitest. Tests colocated `*.test.ts`; e2e `*.e2e.test.ts`.
- Example models in tests: `sonnet-4.6`, `gpt-5.4`.
- Clean up timers/env/globals/mocks/sockets/temp dirs/module state; `--isolate=false` must stay safe.
- Hot tests: avoid per-test `vi.resetModules()` + fresh heavy imports; prefer static or `beforeAll` imports and reset state directly.
- Measure first: `pnpm test:perf:imports <file>` for import drag; `pnpm test:perf:hotspots --limit N` for suite targets.
- Keep tests at seam depth: unit-test pure helpers/contracts; one integration smoke per boundary, not per branch.
- Mock expensive runtime seams directly: scanners, manifests, package registries, filesystem crawls, provider SDKs, network/process launch.
- Prefer injected deps over module mocks; if mocking modules, mock narrow local `*.runtime.ts` seams, not broad barrels.
- Share fixtures/builders; do not recreate temp dirs, package manifests, or plugin workspaces in every case unless state isolation needs it.
- Delete duplicate assertions when another test owns the boundary; assert only the behavior that can regress here.
- Avoid broad `importOriginal()` / broad `openclaw/plugin-sdk/*` partial mocks in hot tests. Add narrow local `*.runtime.ts` seam and mock it.
- Use existing deps/callback/runtime injection seams before module mocks.
- Import-dominated test time is a boundary smell; shrink import surface before adding cases.
- Replacing slow integration coverage: extract production composition into a named helper and test that helper.
- Do not modify baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
- Do not set test workers above 16. For memory pressure: `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`.
- Live: `OPENCLAW_LIVE_TEST=1 pnpm test:live`; full logs `OPENCLAW_LIVE_TEST_QUIET=0`.
- Full testing guide: `docs/help/testing.md`.
- Vitest. Colocated `*.test.ts`; e2e `*.e2e.test.ts`; example models `sonnet-4.6`, `gpt-5.4`.
- Clean timers/env/globals/mocks/sockets/temp dirs/module state; `--isolate=false` safe.
- Hot tests: avoid per-test `vi.resetModules()` + heavy imports. Measure with `pnpm test:perf:imports <file>` / `pnpm test:perf:hotspots --limit N`.
- Seam depth: pure helper/contract unit tests; one integration smoke per boundary.
- Mock expensive seams directly: scanners, manifests, registries, fs crawls, provider SDKs, network/process launch.
- Prefer injection; if module mocking, mock narrow local `*.runtime.ts`, not broad barrels or `openclaw/plugin-sdk/*`.
- Share fixtures/builders; delete duplicate assertions; assert behavior that can regress here.
- Do not edit baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
- Test workers max 16. Memory pressure: `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`.
- Live: `OPENCLAW_LIVE_TEST=1 pnpm test:live`; verbose `OPENCLAW_LIVE_TEST_QUIET=0`.
- Guide: `docs/help/testing.md`.
## Docs / Changelog
- Update docs when behavior/API changes. Use docs list/read_when hints.
- Docs links: see `docs/AGENTS.md`.
- Changelog: user-facing only. Pure test/internal changes usually no entry.
- Changelog placement: append to active version `### Changes`/`### Fixes`; at most one contributor mention, prefer `Thanks @user`.
- Docs change with behavior/API. Use docs list/read_when hints; docs links per `docs/AGENTS.md`.
- Changelog user-facing only; pure test/internal usually no entry.
- Changelog placement: active version `### Changes`/`### Fixes`; every added entry must include at least one `Thanks @author` attribution, using credited GitHub username(s).
## Git
- Use `scripts/committer "<msg>" <file...>`; stage only intended files.
- Commits: conventional-ish, concise/action-oriented. Group related changes.
- No manual stash/autostash unless explicitly requested. No branch/worktree changes unless requested.
- No merge commits on `main`; rebase on latest `origin/main` before push.
- User says "commit": commit your changes only. "commit all": commit everything in grouped chunks. "push": may `git pull --rebase` first.
- Do not delete/rename unexpected files; ask if it blocks. Otherwise ignore unrelated WIP.
- If bulk PR close/reopen affects >5 PRs, ask with exact count/scope.
- PR/issue workflows: use `$openclaw-pr-maintainer`.
- `/landpr`: use `~/.codex/prompts/landpr.md`.
- Commit via `scripts/committer "<msg>" <file...>`; stage intended files only. It formats staged files; still run gates.
- Commits: conventional-ish, concise, grouped.
- No manual stash/autostash unless explicit. No branch/worktree changes unless requested.
- `main`: no merge commits; rebase on latest `origin/main` before push.
- User says `commit`: your changes only. `commit all`: all changes in grouped chunks. `push`: may `git pull --rebase` first.
- Do not delete/rename unexpected files; ask if blocking, else ignore.
- Bulk PR close/reopen >5: ask with count/scope.
- PR/issue workflows: `$openclaw-pr-maintainer`. `/landpr`: `~/.codex/prompts/landpr.md`.
## Security / Release
- Never commit real phone numbers, videos, credentials, live config.
- Secrets: channel/provider credentials under `~/.openclaw/credentials/`; model auth profiles under `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
- Secrets: channel/provider creds in `~/.openclaw/credentials/`; model auth profiles in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
- Env keys: check `~/.profile`.
- Dependency patches/overrides/vendor changes require explicit approval. `pnpm.patchedDependencies` must use exact versions.
- Carbon pins owner-only: do not change `@buape/carbon` versions unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
- Releases/publish/version bumps require explicit approval.
- Release docs: `docs/reference/RELEASING.md`; use `$openclaw-release-maintainer`.
- GHSA/advisories: use `$openclaw-ghsa-maintainer`.
- Beta tag/version must match, e.g. `vYYYY.M.D-beta.N` => npm `YYYY.M.D-beta.N --tag beta`.
- Dependency patches/overrides/vendor changes need explicit approval. `pnpm.patchedDependencies` 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. Release docs: `docs/reference/RELEASING.md`; use `$openclaw-release-maintainer`.
- GHSA/advisories: `$openclaw-ghsa-maintainer`.
- Beta tag/version match: `vYYYY.M.D-beta.N` -> npm `YYYY.M.D-beta.N --tag beta`.
## Apps / Platform
- Before simulator/emulator testing, check connected real iOS/Android devices first.
- Before simulator/emulator testing, check real iOS/Android devices.
- "restart iOS/Android apps" = rebuild/reinstall/relaunch, not kill/launch.
- SwiftUI: prefer Observation (`@Observable`, `@Bindable`) over new `ObservableObject`.
- mac gateway: use app or `openclaw gateway restart/status --deep`; avoid ad-hoc tmux gateway sessions. Rebuild mac app locally, not over SSH.
- mac logs: `./scripts/clawlog.sh`.
- Version bump touches: `package.json`, `apps/android/app/build.gradle.kts`, `apps/ios/version.json` then `pnpm ios:version:sync`, `apps/macos/.../Info.plist`, `docs/install/updating.md`. Appcast only for Sparkle release.
- iOS Team ID: `security find-identity -p codesigning -v`; fallback `defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers`.
- Mobile LAN pairing: plaintext `ws://` is loopback-only by default. Trusted private-network `ws://` needs `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`; Tailscale/public use `wss://` or a tunnel.
- SwiftUI: Observation (`@Observable`, `@Bindable`) over new `ObservableObject`.
- Mac gateway: use app or `openclaw gateway restart/status --deep`; no ad-hoc tmux gateway. Logs: `./scripts/clawlog.sh`.
- Version bump touches: `package.json`, `apps/android/app/build.gradle.kts`, `apps/ios/version.json` + `pnpm ios:version:sync`, macOS `Info.plist`, `docs/install/updating.md`. Appcast only for Sparkle release.
- Mobile LAN pairing: plaintext `ws://` loopback-only. Private-network `ws://` needs `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`; Tailscale/public use `wss://` or tunnel.
- A2UI hash `src/canvas-host/a2ui/.bundle.hash`: generated; ignore unless running `pnpm canvas:a2ui:bundle`; commit separately.
## External Ops
- Remote install docs: `docs/install/exe-dev.md`, `docs/install/fly.md`, `docs/install/hetzner.md`.
- Parallels smoke: `$openclaw-parallels-smoke`; Discord roundtrip: `parallels-discord-roundtrip`.
## Misc Footguns
## Ops / Footguns
- Remote install docs: `docs/install/{exe-dev,fly,hetzner}.md`. Parallels smoke: `$openclaw-parallels-smoke`; Discord roundtrip: `parallels-discord-roundtrip`.
- Rebrand/migration/config warnings: run `openclaw doctor`.
- Never edit `node_modules`.
- Local-only `.agents` ignores: use `.git/info/exclude`, not repo `.gitignore`.
- CLI progress: use `src/cli/progress.ts`; status tables: `src/terminal/table.ts`.
- Local-only `.agents` ignores: `.git/info/exclude`, not repo `.gitignore`.
- CLI progress: `src/cli/progress.ts`; status tables: `src/terminal/table.ts`.
- Connection/provider additions: update all UI surfaces + docs + status/config forms.
- Provider-facing tool schemas: prefer flat string enum helpers over `Type.Union([Type.Literal(...)])`; some providers reject generated `anyOf`. Do not treat this as a repo-wide protocol/schema ban.
- External messaging surfaces: no token-delta channel messages. Follow `docs/concepts/streaming.md`; preview/block streaming uses message edits/chunks and must preserve final/fallback delivery.
- Provider tool schemas: prefer flat string enum helpers over `Type.Union([Type.Literal(...)])`; some providers reject `anyOf`. Not a repo-wide protocol/schema ban.
- External messaging: no token-delta channel messages. Follow `docs/concepts/streaming.md`; preview/block streaming uses edits/chunks and preserves final/fallback delivery.

File diff suppressed because it is too large Load Diff

View File

@@ -29,9 +29,9 @@ ARG OPENCLAW_NODE_BOOKWORM_SLIM_DIGEST="sha256:e8e2e91b1378f83c5b2dd15f0247f3411
FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS ext-deps
ARG OPENCLAW_EXTENSIONS
ARG OPENCLAW_BUNDLED_PLUGIN_DIR
COPY ${OPENCLAW_BUNDLED_PLUGIN_DIR} /tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}
# Copy package.json for opted-in extensions so pnpm resolves their deps.
RUN mkdir -p /out && \
RUN --mount=type=bind,source=${OPENCLAW_BUNDLED_PLUGIN_DIR},target=/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR},readonly \
mkdir -p /out && \
for ext in $OPENCLAW_EXTENSIONS; do \
if [ -f "/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}/$ext/package.json" ]; then \
mkdir -p "/out/$ext" && \

View File

@@ -96,7 +96,7 @@ Model note: while many providers and models are supported, prefer a current flag
## Install (recommended)
Runtime: **Node 24 (recommended) or Node 22.16+**.
Runtime: **Node 24 (recommended) or Node 22.14+**.
```bash
npm install -g openclaw@latest
@@ -109,7 +109,7 @@ OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service) so i
## Quick start (TL;DR)
Runtime: **Node 24 (recommended) or Node 22.16+**.
Runtime: **Node 24 (recommended) or Node 22.14+**.
Full beginner guide (auth, pairing, channels): [Getting started](https://docs.openclaw.ai/start/getting-started)
@@ -119,7 +119,7 @@ openclaw onboard --install-daemon
openclaw gateway --port 18789 --verbose
# Send a message
openclaw message send --to +1234567890 --message "Hello from OpenClaw"
openclaw message send --target +1234567890 --message "Hello from OpenClaw"
# Talk to the assistant (optionally deliver back to any connected channel: WhatsApp/Telegram/Slack/Discord/Google Chat/Signal/iMessage/BlueBubbles/IRC/Microsoft Teams/Matrix/Feishu/LINE/Mattermost/Nextcloud Talk/Nostr/Synology Chat/Tlon/Twitch/Zalo/Zalo Personal/WeChat/QQ/WebChat)
openclaw agent --message "Ship checklist" --thinking high

View File

@@ -288,7 +288,7 @@ OpenClaw's web interface (Gateway Control UI + HTTP endpoints) is intended for *
### Node.js Version
OpenClaw requires **Node.js 22.12.0 or later** (LTS). This version includes important security patches:
OpenClaw requires **Node.js 22.14.0 or later** (LTS). This version includes important security patches:
- CVE-2025-59466: async_hooks DoS vulnerability
- CVE-2026-21636: Permission model bypass vulnerability
@@ -296,7 +296,7 @@ OpenClaw requires **Node.js 22.12.0 or later** (LTS). This version includes impo
Verify your Node.js version:
```bash
node --version # Should be v22.12.0 or later
node --version # Should be v22.14.0 or later
```
### Docker Security

View File

@@ -53,12 +53,24 @@ We prioritize secure defaults, but also expose clear knobs for trusted high-powe
OpenClaw has an extensive plugin API.
Core stays lean; optional capability should usually ship as plugins.
We are generally slimming down core while expanding what plugins can do.
If a useful feature cannot be built as a plugin yet, we welcome PRs and design discussions that extend the plugin API instead of adding one-off core behavior.
There are two broad plugin styles:
- Code plugins run OpenClaw plugin code and are appropriate for deeper runtime extension.
- Bundle-style plugins package stable external surfaces such as skills, MCP servers, and related configuration.
Prefer bundle-style plugins when they can express the capability.
They have a smaller, more stable interface and better security boundaries.
Use code plugins when the capability needs runtime hooks, providers, channels, tools, or other in-process extension points.
Preferred plugin path is npm package distribution plus local extension loading for development.
If you build a plugin, host and maintain it in your own repository.
The bar for adding optional plugins to core is intentionally high.
Plugin docs: [`docs/tools/plugin.md`](docs/tools/plugin.md)
Community plugin listing + PR bar: https://docs.openclaw.ai/plugins/community
Plugin discovery, official publisher status, provenance, and security review live in [ClawHub](https://clawhub.ai/).
OpenClaw docs should document core extension points; plugin promotion belongs in ClawHub, preferably under vetted org publishers for official plugins.
Memory is a special plugin slot where only one memory plugin can be active at a time.
Today we ship multiple memory options; over time we plan to converge on one recommended default path.
@@ -66,21 +78,16 @@ Today we ship multiple memory options; over time we plan to converge on one reco
### Skills
We still ship some bundled skills for baseline UX.
New skills should be published to ClawHub first (`clawhub.ai`), not added to core by default.
Core skill additions should be rare and require a strong product or security reason.
New skills should be published through [ClawHub](https://clawhub.ai/) first, not added to core by default.
Official or bundled promotion should require a clear product, security, or maintainer-ownership reason.
### MCP Support
OpenClaw supports MCP through `mcporter`: https://github.com/steipete/mcporter
OpenClaw supports MCP as both a server and a runtime integration surface.
MCP details live in [`docs/cli/mcp.md`](docs/cli/mcp.md).
This keeps MCP integration flexible and decoupled from core runtime:
- add or change MCP servers without restarting the gateway
- keep core tool/context surface lean
- reduce MCP churn impact on core stability and security
For now, we prefer this bridge model over building first-class MCP runtime into core.
If there is an MCP server or feature `mcporter` does not support yet, please open an issue there.
The project goal is pragmatic MCP support without duplicating existing agent,
tool, ACPX, plugin, or ClawHub paths.
### Setup
@@ -98,11 +105,11 @@ It is widely known, fast to iterate in, and easy to read, modify, and extend.
## What We Will Not Merge (For Now)
- New core skills when they can live on ClawHub
- New core skills when they can live on [ClawHub](https://clawhub.ai/)
- Full-doc translation sets for all docs (deferred; we plan AI-generated translations later)
- Commercial service integrations that do not clearly fit the model-provider category
- Wrapper channels around already supported channels without a clear capability or security gap
- First-class MCP runtime in core when `mcporter` already provides the integration path
- MCP work that duplicates existing MCP, ACPX, plugin, or ClawHub paths without a clear product or security gap
- Agent-hierarchy frameworks (manager-of-managers / nested planner trees) as a default architecture
- Heavy orchestration layers that duplicate existing agent and tool infrastructure

View File

@@ -2,6 +2,207 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.4.22</title>
<pubDate>Thu, 23 Apr 2026 15:18:00 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026042290</sparkle:version>
<sparkle:shortVersionString>2026.4.22</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.22</h2>
<h3>Changes</h3>
<ul>
<li>Providers/xAI: add image generation, text-to-speech, and speech-to-text support, including <code>grok-imagine-image</code> / <code>grok-imagine-image-pro</code>, reference-image edits, six live xAI voices, MP3/WAV/PCM/G.711 TTS formats, <code>grok-stt</code> audio transcription, and xAI realtime transcription for Voice Call streaming. (#68694) Thanks @KateWilkins.</li>
<li>Providers/STT: add Voice Call streaming transcription for Deepgram, ElevenLabs, and Mistral, alongside the existing OpenAI and xAI realtime STT paths; ElevenLabs also gains Scribe v2 batch audio transcription for inbound media.</li>
<li>TUI: add local embedded mode for running terminal chats without a Gateway while keeping plugin approval gates enforced. (#66767) Thanks @fuller-stack-dev.</li>
<li>Onboarding: auto-install missing provider and channel plugins during setup so first-run configuration can complete without manual plugin recovery.</li>
<li>OpenAI/Responses: use OpenAI's native <code>web_search</code> tool automatically for direct OpenAI Responses models when web search is enabled and no managed search provider is pinned; explicit providers such as Brave keep the managed <code>web_search</code> tool.</li>
<li>Models/commands: add <code>/models add <provider> <modelId></code> so you can register a model from chat and use it without restarting the gateway; keep <code>/models</code> as a simple provider browser while adding clearer add guidance and copy-friendly command examples. (#70211) Thanks @Takhoffman.</li>
<li>WhatsApp: add configurable native reply quoting with replyToMode for WhatsApp conversations. Thanks @mcaxtr.</li>
<li>WhatsApp/groups+direct: forward per-group and per-direct <code>systemPrompt</code> config into inbound context <code>GroupSystemPrompt</code> so configured per-chat behavioral instructions are injected on every turn. Supports <code>"*"</code> wildcard fallback and account-scoped overrides under <code>channels.whatsapp.accounts.<id>.{groups,direct}</code>; account maps fully replace root maps (no deep merge), matching the existing <code>requireMention</code> pattern. Closes #7011. (#59553) Thanks @Bluetegu.</li>
<li>Agents/sessions: add mailbox-style <code>sessions_list</code> filters for label, agent, and search plus visibility-scoped derived title and last-message previews. (#69839) Thanks @dangoZhang.</li>
<li>Control UI/settings+chat: add a browser-local personal identity for the operator (name plus local-safe avatar), route user identity rendering through the shared chat/avatar path used by assistant and agent surfaces, and tighten Quick Settings, agent fallback chips, and narrow-screen chat layouts so personalization no longer wastes space or clips controls. (#70362) Thanks @BunsDev.</li>
<li>Gateway/diagnostics: enable payload-free stability recording by default and add a support-ready diagnostics export with sanitized logs, status, health, config, and stability snapshots for bug reports. (#70324) Thanks @gumadeiras.</li>
<li>Providers/Tencent: add the bundled Tencent Cloud provider plugin with TokenHub onboarding, docs, <code>hy3-preview</code> model catalog entries, and tiered Hy3 pricing metadata. (#68460) Thanks @JuniperSling.</li>
<li>Providers/Amazon Bedrock Mantle: add Claude Opus 4.7 through Mantle's Anthropic Messages route with provider-owned bearer-auth streaming, so the model is actually callable without treating AWS bearer tokens like Anthropic API keys. Thanks @wirjo.</li>
<li>Providers/GPT-5: move the GPT-5 prompt overlay into the shared provider runtime so compatible GPT-5 models receive the same behavior and heartbeat guidance through OpenAI, OpenRouter, OpenCode, Codex, and other GPT providers; add <code>agents.defaults.promptOverlays.gpt5.personality</code> as the global friendly-style toggle while keeping the OpenAI plugin setting as a fallback.</li>
<li>Providers/OpenAI Codex: remove the Codex CLI auth import path from onboarding and provider discovery so OpenClaw no longer copies <code>~/.codex</code> OAuth material into agent auth stores; use browser login or device pairing instead. (#70390) Thanks @pashpashpash.</li>
<li>CLI/Claude: default <code>claude-cli</code> runs to warm stdio sessions, including custom configs that omit transport fields, and resume from the stored Claude session after Gateway restarts or idle exits. (#69679) Thanks @obviyus.</li>
<li>Pi/models: update the bundled pi packages to <code>0.68.1</code> and let the OpenCode Go catalog come from pi instead of plugin-maintained model aliases, adding the refreshed <code>opencode-go/kimi-k2.6</code>, Qwen, GLM, MiMo, and MiniMax entries.</li>
<li>Tokenjuice: add bundled native OpenClaw support for tokenjuice as an opt-in plugin that compacts noisy <code>exec</code> and <code>bash</code> tool results in Pi embedded runs. (#69946) Thanks @vincentkoc.</li>
<li>ACPX: add an explicit <code>openClawToolsMcpBridge</code> option that injects a core OpenClaw MCP server for selected built-in tools, starting with <code>cron</code>.</li>
<li>CLI/doctor plugins: lazy-load doctor plugin paths and prefer installed plugin <code>dist/*</code> runtime entries over source-adjacent JavaScript fallbacks, reducing the measured <code>doctor --non-interactive</code> runtime by about 74% while keeping cold doctor startup on built plugin artifacts. (#69840) Thanks @gumadeiras.</li>
<li>CLI/debugging: add an opt-in temporary debug timing helper for local CLI performance investigations, with readable stderr output, JSONL capture, and docs for removing probes before landing fixes. (#70469) Thanks @shakkernerd.</li>
<li>Docs/i18n: add Thai translation support for the docs site.</li>
<li>Providers/OpenAI-compatible: mark known local backends such as vLLM, SGLang, llama.cpp, LM Studio, LocalAI, Jan, TabbyAPI, and text-generation-webui as streaming-usage compatible, so their token accounting no longer degrades to unknown/stale totals. (#68711) Thanks @gaineyllc.</li>
<li>Providers/OpenAI-compatible: recover streamed token usage from llama.cpp-style <code>timings.prompt_n</code> / <code>timings.predicted_n</code> metadata and sanitize usage counts before accumulation, fixing unknown or stale totals when compatible servers do not emit an OpenAI-shaped <code>usage</code> object. (#41056) Thanks @xaeon2026.</li>
<li>Plugins/startup: prefer native Jiti loading for built bundled plugin dist modules on supported runtimes, cutting measured bundled plugin load time by 82-90% while keeping source TypeScript on the transform path. (#69925) Thanks @aauren.</li>
<li>Plugin SDK/STT: share realtime transcription WebSocket transport and multipart batch transcription form helpers across bundled STT providers, reducing provider plugin boilerplate while preserving proxy capture, reconnects, audio queueing, close flushing, upload filename normalization, and ready handshakes.</li>
<li>Plugin SDK/Pi embedded runs: add a bundled-plugin embedded extension factory seam so native plugins can extend Pi embedded runs with async runtime hooks such as <code>tool_result</code> handling instead of falling back to the older synchronous persistence path. (#69946) Thanks @vincentkoc.</li>
<li>Codex harness/hooks: route native Codex app-server turns through <code>before_prompt_build</code> and emit <code>before_compaction</code> / <code>after_compaction</code> for native compaction items so prompt and compaction hooks stop drifting from Pi. Thanks @vincentkoc.</li>
<li>Codex harness/plugins: add a bundled-plugin Codex app-server extension seam for async <code>tool_result</code> middleware, fire <code>after_tool_call</code> for Codex tool runs, and route mirrored Codex transcript writes through <code>before_message_write</code> so tool integrations stop diverging from Pi. Thanks @vincentkoc.</li>
<li>Codex harness/hooks: fire <code>llm_input</code>, <code>llm_output</code>, and <code>agent_end</code> for native Codex app-server turns so lifecycle hooks stop drifting from Pi. Thanks @vincentkoc.</li>
<li>QA/Telegram: record per-scenario reply RTT in the live Telegram QA report and summary, starting with the canary response. (#70550) Thanks @obviyus.</li>
<li>Status: add an explicit <code>Runner:</code> field to <code>/status</code> so sessions now report whether they are running on embedded Pi, a CLI-backed provider, or an ACP harness agent/backend such as <code>codex (acp/acpx)</code> or <code>gemini (acp/acpx)</code>. (#70595)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Thinking defaults/status: raise the implicit default thinking level for reasoning-capable models from legacy <code>off</code>/<code>low</code> fallback behavior to a safe provider-supported <code>medium</code> equivalent when no explicit config default is set, preserve configured-model reasoning metadata when runtime catalog loading is empty, and make <code>/status</code> report the same resolved default as runtime.</li>
<li>Gateway/model pricing: fetch OpenRouter and LiteLLM pricing asynchronously at startup and extend catalog fetch timeouts to 30 seconds, reducing noisy timeout warnings during slow upstream responses.</li>
<li>Agents/sessions: keep daily reset and idle-maintenance bookkeeping from bumping session activity or pruning freshly active routes, so active conversations no longer look newer or disappear for maintenance-only updates.</li>
<li>Plugins/install: add newly installed plugin ids to an existing <code>plugins.allow</code> list before enabling them, so allowlisted configs load installed plugins after restart.</li>
<li>Status: show <code>Fast</code> in <code>/status</code> when fast mode is enabled, including config/default-derived fast mode, and omit it when disabled.</li>
<li>OpenAI/image generation: detect Azure OpenAI-style image endpoints, use Azure <code>api-key</code> auth plus deployment-scoped image URLs, honor <code>AZURE_OPENAI_API_VERSION</code>, and document the Azure setup path so image generation and edits work against Azure-hosted OpenAI resources. (#70570) Thanks @zhanggpcsu.</li>
<li>Telegram/forum topics: cache recovered forum metadata with bounded expiry so supergroup updates no longer need repeated <code>getChat</code> lookups before topic routing.</li>
<li>Onboarding/WeCom: show the official WeCom channel plugin with its native Enterprise WeChat display name and blurb in the external channel catalog.</li>
<li>Models/auth: merge provider-owned default-model additions from <code>openclaw models auth login</code> instead of replacing <code>agents.defaults.models</code>, so re-authenticating an OAuth provider such as OpenAI Codex no longer wipes other providers' aliases and per-model params. Migrations that must rename keys (Anthropic -> Claude CLI) opt in with <code>replaceDefaultModels</code>. Fixes #69414. (#70435) Thanks @neeravmakwana.</li>
<li>Media understanding/audio: prefer configured or key-backed STT providers before auto-detected local Whisper CLIs, so installed local transcription tools no longer shadow API providers such as Groq/OpenAI in <code>tools.media.audio</code> auto mode. Fixes #68727.</li>
<li>Providers/OpenAI: lock the auth picker wording for OpenAI API key, Codex browser login, and Codex device pairing so the setup choices no longer imply a mixed Codex/API-key auth path. (#67848) Thanks @tmlxrd.</li>
<li>Agents/BTW: route <code>/btw</code> side questions through provider stream registration with the session workspace, so Ollama provider URL construction and workspace-scoped hooks apply correctly. Fixes #68336. (#70413) Thanks @suboss87.</li>
<li>Agents/sessions: make session transcript write locks non-reentrant by default, so same-process transcript writers contend unless a helper explicitly opts into nested lock ownership.</li>
<li>ACPX/probe: expose an optional <code>probeAgent</code> plugin config field so the embedded ACP runtime health probe can target a configured agent (for example <code>opencode</code> or <code>claude</code>) instead of hardcoding <code>codex</code>, and stop marking the entire ACP runtime backend unavailable when the default probe agent is simply not installed or not authenticated. (#68409) Thanks @lyfuci.</li>
<li>Memory search: use sqlite-vec KNN for vector recall while preserving full post-filter result limits in multi-model indexes. Fixes #69666. (#69680) Thanks @aalekh-sarvam.</li>
<li>Providers/OpenAI Codex: stop stale per-agent <code>openai-codex:default</code> OAuth profiles from shadowing a newer main-agent identity-scoped profile, and let <code>openclaw doctor</code> offer the matching cleanup. (#70393) Thanks @pashpashpash.</li>
<li>ACPX: route OpenClaw ACP bridge commands through the MCP-free runtime path even when the command is wrapped with <code>env</code>, has bridge flags, or is resumed from persisted session state, so documented <code>acpx openclaw</code> setups no longer fail on per-session MCP injection. (#68741) Thanks @alexlomt.</li>
<li>Codex harness: route Codex-tagged MCP tool approval elicitations through OpenClaw plugin approvals, including current empty-schema app-server requests, while leaving generic user-input prompts fail-closed. (#68807) Thanks @kesslerio.</li>
<li>WhatsApp/outbound: hold an in-memory active-delivery claim while a live outbound send is in flight, so a concurrent reconnect drain no longer re-drives the same pending queue entry and duplicates cron sends 7-12x after the 30-minute inbound-silence watchdog fires mid-delivery. Crash-replay of fresh queue entries left behind by a dead process is preserved because the claim is intentionally process-local. Fixes #70386. (#70428) Thanks @neeravmakwana.</li>
<li>Matrix/commands: keep Matrix DM allowlist state out of room control-command authorization, so trusted DM senders do not accidentally gain room-command access.</li>
<li>Providers/SDK retry: cap long <code>Retry-After</code> sleeps in Stainless-based Anthropic/OpenAI model SDKs so 60s+ retry windows surface immediately for OpenClaw failover instead of blocking the run. (#68474) Thanks @jetd1.</li>
<li>Agents/TTS: preserve spoken text in TTS tool results while defusing reply directives in transcript content, so future turns remember voice replies without treating spoken <code>MEDIA:</code> or voice tags as delivery metadata. (#68869) Thanks @zqchris.</li>
<li>Providers/OpenAI: harden Voice Call realtime transcription against OpenAI Realtime session-update drift, forward language and prompt hints, and add live coverage for realtime STT.</li>
<li>Agents/Pi embedded runs: suppress the "⚠️ Agent couldn't generate a response" warning when the assistant already delivered user-visible content through a messaging tool and the turn ended cleanly (<code>stopReason=stop</code>). Real failure modes (tool errors, provider <code>stopReason=error</code>, interrupted tool use) still surface the existing "verify before retrying" warning. Fixes #70396. (#70425) Thanks @neeravmakwana.</li>
<li>Gateway/Linux: wrap gateway-managed supervisor, PTY, MCP stdio, and browser child processes in a tiny <code>/bin/sh</code> shim that raises the child's own <code>oom_score_adj</code> on Linux, so under cgroup memory pressure the kernel prefers transient workers over the long-lived gateway. Opt out with <code>OPENCLAW_CHILD_OOM_SCORE_ADJ=0</code>. Fixes #70404. (#70419) Thanks @neeravmakwana.</li>
<li>Providers/Moonshot: stop strict-sanitizing Kimi's native tool_call IDs (shaped like <code>functions.<name>:<index></code>) on the OpenAI-compatible transport, so multi-turn agentic flows through Kimi K2.6 no longer break after 2-3 tool-calling rounds when the serving layer fails to match mangled IDs against the original tool definitions. Adds a <code>sanitizeToolCallIds</code> opt-out to the shared <code>openai-compatible</code> replay family helper and wires Moonshot to it. Fixes #62319. (#70030) Thanks @LeoDu0314.</li>
<li>Dependencies/security: override transitive <code>uuid</code> to <code>14.0.0</code>, clearing the runtime advisory across dependencies.</li>
<li>Codex harness: ignore dynamic tool descriptions when deciding whether to reuse a native app-server thread while still fingerprinting tool schemas, so channel-specific copy changes no longer reset otherwise compatible Codex conversations. (#69976) Thanks @chen-zhang-cs-code.</li>
<li>Codex harness: expose the Codex app-server model catalog in <code>models list/status</code>, avoid startup hangs from app-server discovery timeouts, and accept current Codex turn-completion notifications so Docker live gateway turns finish reliably.</li>
<li>Codex harness: drop invalid legacy app-server <code>serviceTier</code> values such as <code>"priority"</code> before native thread and turn requests, while keeping supported Codex tiers limited to <code>"fast"</code> and <code>"flex"</code>. Fixes #64815.</li>
<li>Codex harness: show bounded, sanitized permission target samples in app-server approval prompts, so native permission requests keep their specific hosts, roots, and paths visible without leaking home usernames or URL credentials. (#70340) Thanks @Lucenx9.</li>
<li>Docs/Codex harness: narrow native compaction docs to the current start/completion signals, without promising a readable summary or kept-entry audit list yet. (#69612) Thanks @91wan.</li>
<li>Providers/Amazon Bedrock: use known context-window metadata for discovered models while keeping the unknown-model fallback conservative, so compaction and overflow handling improve for newer Bedrock models without overstating unlisted model limits. Thanks @wirjo.</li>
<li>Providers/Amazon Bedrock Mantle: refresh IAM-backed bearer tokens at runtime instead of baking discovery-time tokens into provider config, so long-lived Mantle sessions keep working after the initial token ages out. Thanks @wirjo.</li>
<li>Config/includes: write through single-file top-level includes for isolated OpenClaw-owned mutations, so <code>plugins install</code> and <code>plugins update</code> update an included <code>plugins.json5</code> file instead of flattening modular <code>$include</code> configs. Fixes #41050 and #66048.</li>
<li>Config/reload: plan gateway reloads from source-authored config instead of runtime-materialized snapshots, so plugin update writes no longer trigger false restarts from derived provider/plugin config paths. Fixes #68732.</li>
<li>Plugins/update: skip npm plugin reinstall/config rewrites when the installed version and recorded artifact identity already match the registry target, let bare npm package names resolve back to tracked install records, and point already-installed <code>plugins install</code> attempts at <code>plugins update</code> / <code>--force</code> instead of a hook-pack fallback. Fixes #46955, #67957, and #68073.</li>
<li>Agents/MCP: keep <code>mcp.servers</code> and bundle MCP tools available in Pi embedded <code>coding</code> and <code>messaging</code> sessions while preserving <code>minimal</code> profile and <code>tools.deny: ["bundle-mcp"]</code> opt-out behavior. Fixes #68875 and #68818.</li>
<li>Plugins/startup: tolerate transient bundled-channel catalog/metadata drift while auto-enabling configured plugins, so CLI and gateway startup no longer crash when a channel id is known but its display metadata is unavailable.</li>
<li>CLI/Claude: report CLI-backed reply runs as streaming while Claude/Codex CLI turns are still in flight, so WebChat keeps visible response state until the backend finishes. Fixes #70125.</li>
<li>Slack/streaming: fall back to normal Slack replies for Slack Connect streams rejected before the SDK flushes its local buffer, so short replies no longer disappear or report success before Slack acknowledges delivery. Fixes #70295. (#70370) Thanks @mvanhorn.</li>
<li>Codex harness: rotate the shared app-server websocket client when the configured bearer token changes, so auth-token refreshes reconnect with the new <code>Authorization</code> header instead of reusing a stale socket. (#70328) Thanks @Lucenx9.</li>
<li>Channels/sandbox: derive runtime policy keys for external direct messages that share the main conversation, so sandbox/tool policy no longer treats channel-originated DMs as local main-session runs.</li>
<li>Config/models: merge provider-scoped model allowlist updates and protect model/provider map writes from accidental full replacement, adding <code>config set --merge</code> for additive updates and <code>--replace</code> for intentional clobbers. Fixes #65920, #68392, and #68653.</li>
<li>Agents/Pi auth: preserve AWS SDK-authenticated Bedrock runs for IMDS and task-role setups, clear stale refresh timers on sentinel fallback, and log unexpected runtime-auth prep failures instead of silently leaving the provider unauthenticated. Thanks @wirjo.</li>
<li>Config/gateway: restore last-known-good config on critical clobber signatures such as missing metadata, missing <code>gateway.mode</code>, or sharp size drops, preventing gateway crash loops when a valid backup exists. Fixes #70336.</li>
<li>Config/gateway: recover configs accidentally prefixed with non-JSON output during gateway startup or <code>openclaw doctor --fix</code>, preserving the clobbered file as a backup while leaving normal config reads read-only.</li>
<li>Agents/GitHub Copilot: normalize connection-bound Responses item IDs in the Copilot provider wrapper so replayed histories no longer fail after the upstream connection changes. (#69362) Thanks @Menci.</li>
<li>Pi embedded runs: pass real built-in tools into Pi session creation and then narrow active tool names after custom tool registration, so the runner and compaction paths compile cleanly and keep OpenClaw-managed custom tool allowlists without feeding string arrays into <code>createAgentSession</code>. Thanks @vincentkoc.</li>
<li>Agents/OpenAI websocket: route native OpenAI websocket metadata and session-header decisions through the shared endpoint classifier so local mocks and custom <code>models.providers.openai.baseUrl</code> endpoints stay out of the native OpenAI path consistently across embedded-runner and websocket transport code. Thanks @vincentkoc.</li>
<li>Cron/MCP: retire bundled MCP runtimes through one shared cleanup path for isolated cron run ends, persistent cron session rollover, and direct cron <code>deleteAfterRun</code> fallback cleanup. Fixes #69145, #68623, and #68827.</li>
<li>MCP/gateway: tear down stdio MCP process trees on transport close and dispose bundled MCP runtimes during session delete/reset, preventing orphaned wrapper/server processes from accumulating. Fixes #68809 and #69465.</li>
<li>Agents/MCP: retire bundled MCP runtimes after completed one-shot subagent cleanup and nested <code>sessions_send</code> steps, while keeping persistent subagent sessions warm.</li>
<li>Config: render validation warnings with real line breaks instead of a literal <code>\n</code> sequence in CLI/audit output. Fixes #70140.</li>
<li>Cron/doctor: repair malformed persisted cron job IDs through <code>openclaw doctor</code>, including legacy <code>jobId</code>, non-string <code>id</code>, and missing <code>id</code> rows, so <code>cron list</code> no longer needs display-layer coercion for corrupt store data. Fixes #70128.</li>
<li>Discord: normalize prefixed channel targets only at the thread-binding API boundary, so <code>sessions_spawn({ runtime: "acp", thread: true })</code> can create child threads from Discord channels without breaking current-channel ACP bindings. (#68034) Thanks @Zetarcos.</li>
<li>Discord: harden inbound thread metadata handling against partial Carbon channel getters, so non-command thread messages and queued jobs no longer crash when <code>name</code>, <code>parentId</code>, <code>parent</code>, or <code>ownerId</code> requires fetched raw data.</li>
<li>Discord: let <code>message</code> tool reactions resolve <code>user:<id></code> DM targets and preserve <code>channels.discord.guilds.<guild>.channels.<channel>.requireMention: false</code> during reply-stage activation fallback. Fixes #70165 and #69441.</li>
<li>Plugins/startup: pre-normalize and cache Jiti alias maps before creating plugin loaders, so module-scoped loader filenames do not reintroduce per-plugin alias-normalization startup cost. Fixes #70186.</li>
<li>ACP/Codex: run the bundled Codex ACP harness with an isolated <code>CODEX_HOME</code> and avoid writing incomplete ChatGPT auth bridge files, so Codex ACP sessions no longer clobber the user's real Codex CLI auth. Fixes #70234. Thanks @Lonobers88.</li>
<li>Gateway/client: keep long-running RPCs such as ACP <code>agent.wait</code> calls in charge of their own timeout instead of closing the websocket on a missed app-level tick while work is still pending.</li>
<li>Telegram/webhooks: lower the grammY webhook callback timeout to 5s so Telegram gets an early 200 response instead of retrying long-running updates as read timeouts. (#70146) Thanks @friday-james.</li>
<li>Telegram/polling: rebuild the polling HTTP transport after <code>getUpdates</code> 409 conflicts, so retries use a fresh TCP connection instead of looping on a Telegram-terminated keep-alive socket. (#69873) Thanks @hclsys.</li>
<li>Media delivery: strip persisted base64 audio payloads from webchat history, resolve stored <code>media://inbound/*</code> attachments before local-root checks, suppress duplicate Telegram voice/audio sends when TTS emits the same media twice, and support custom image-model IDs that already include their provider prefix.</li>
<li>Slack/files: resolve <code>downloadFile</code> bot tokens from the runtime config when callers provide <code>cfg</code> without an explicit token or prebuilt client, preserving cfg-only file downloads outside the action runtime path. (#70160) Thanks @martingarramon.</li>
<li>Slack/HTTP: dispatch registered Request URL webhooks through the same handler registry used by Slack monitor setup, so HTTP-mode Slack events no longer 404 after successful route registration. (#70275) Thanks @FroeMic.</li>
<li>Slack/runtime bindings: route focused Slack thread replies through their bound ACP session instead of preparing replies against the default agent shell. Fixes #67739. Thanks @Frankla20.</li>
<li>CLI/Claude: keep stored Claude CLI sessions through OAuth refresh-token rotation by keying auth epochs on stable account identity instead of mutable OAuth token material. (#70452) Thanks @obviyus.</li>
<li>CLI/Claude: verify stored Claude CLI session ids have a readable project transcript before resuming, clearing phantom bindings with <code>reason=transcript-missing</code> instead of silently starting fresh under <code>--resume</code>. Fixes #70177.</li>
<li>CLI sessions: persist CLI session clearing through the atomic session-store merge path, so expired Claude/Codex CLI bindings are actually removed before retrying without the stale session id. (#70298) Thanks @HFConsultant.</li>
<li>ACP/sessions_spawn: honor explicit <code>model</code> overrides for ACP child sessions instead of silently falling back to the target agent default model. (#70210) Thanks @felix-miao.</li>
<li>Diffs/viewer: re-read remote viewer access policy from live runtime config on each request, so toggling <code>plugins.entries.diffs.config.security.allowRemoteViewer</code> closes proxied viewer access immediately instead of waiting for a restart. Thanks @vincentkoc.</li>
<li>Diffs/tooling: re-read <code>viewerBaseUrl</code>, presentation defaults, and viewer access policy from live runtime config, and fail closed when the live <code>diffs</code> plugin entry disappears instead of reviving startup viewer settings. Thanks @vincentkoc.</li>
<li>Memory/LanceDB: stop resurrecting removed live <code>memory-lancedb</code> hook config from startup snapshots, so deleting or disabling the plugin entry shuts off auto-recall and auto-capture without a restart. Thanks @vincentkoc.</li>
<li>Memory/LanceDB: keep auto-recall and auto-capture hooks wired when those settings start disabled, so turning them on in live config starts recall and capture without waiting for a restart. Thanks @vincentkoc.</li>
<li>Skill Workshop: keep the tool plus <code>before_prompt_build</code> / <code>agent_end</code> hooks wired while the plugin is disabled at startup, so turning the plugin back on in live config starts guidance and capture without waiting for a restart. Thanks @vincentkoc.</li>
<li>Active Memory: stop reviving removed live <code>active-memory</code> config from startup snapshots, so removing the plugin entry turns the hook off immediately instead of waiting for a restart. Thanks @vincentkoc.</li>
<li>GitHub Copilot: re-read plugin discovery config from the live runtime snapshot, so toggling <code>plugins.entries.github-copilot.config.discovery.enabled</code> takes effect without a restart. Thanks @vincentkoc.</li>
<li>Ollama: re-read plugin discovery config from the live runtime snapshot, so toggling <code>plugins.entries.ollama.config.discovery.enabled</code> takes effect without a restart. Thanks @vincentkoc.</li>
<li>OpenAI: re-read the plugin prompt-overlay personality from live runtime config, so GPT-5 system prompt contributions update without a restart when <code>plugins.entries.openai.config.personality</code> changes. Thanks @vincentkoc.</li>
<li>Amazon Bedrock: re-read live discovery and guardrail plugin config, so toggling <code>plugins.entries.amazon-bedrock.config.discovery</code> or <code>plugins.entries.amazon-bedrock.config.guardrail</code> takes effect without a restart. Thanks @vincentkoc.</li>
<li>Codex: re-read the plugin discovery config from the live runtime snapshot, so toggling <code>plugins.entries.codex.config.discovery</code> takes effect without a restart. Thanks @vincentkoc.</li>
<li>Agents/subagents: drop bare <code>NO_REPLY</code> from the parent turn when the session still has pending spawned children, so direct-conversation surfaces such as Telegram DMs no longer rewrite the sentinel into visible fallback chatter while waiting for the child completion event. (#69942) Thanks @neeravmakwana.</li>
<li>Plugins/install: keep bundled plugin dependencies off npm install while repairing them when plugins activate from a packaged install, including Feishu/Lark, Browser, and direct bundled channel setup-entry loads.</li>
<li>CLI/channels: skip and cache bundled channel plugin, setup, and secrets load failures during read-only discovery, so one broken unused bundled channel cannot crash <code>openclaw status</code> or bootstrap secret scans.</li>
<li>Memory/LanceDB: retry initialization after a failed LanceDB load and report unsupported Intel macOS native runtime clearly instead of caching the failure or repeatedly attempting an install that cannot work.</li>
<li>CLI/Claude: hash only static extra system prompt parts when deciding whether to reuse a CLI session, so per-message inbound metadata no longer resets Claude CLI conversations on every turn. (#70122) Thanks @zijunl.</li>
<li>Hooks/Slack: standardize shared message hook routing fields (<code>threadId</code> / <code>replyToId</code>) and stop Slack outbound delivery from re-running <code>message_sending</code> inside the channel adapter, so plugins like thread-ownership make one outbound routing decision per reply. Thanks @vincentkoc.</li>
<li>Auto-reply/media: share one run-scoped reply media context between streamed block delivery and final payload filtering, so a local <code>MEDIA:</code> attachment is staged once and duplicate media sends are suppressed reliably. (#68111) Thanks @ayeshakhalid192007-dev.</li>
<li>Plugins/gateway hooks: expose startup config, workspace dir, and a live cron getter on the typed <code>gateway_start</code> hook, and move memory-core managed dreaming off the internal <code>gateway:startup</code> bridge so cron reconciliation stays on the public plugin hook path. Thanks @vincentkoc.</li>
<li>Plugins/config: read plugin trust decisions from the source config snapshot when a resolved runtime snapshot is active, so <code>plugins.allow</code> remains enforced and <code>doctor</code>/gateway startup no longer warn that the allowlist is empty when it is configured. Fixes #70161. Also fixes #70141.</li>
<li>Agents/openai-completions: enable malformed streamed tool-call argument repair for self-hosted OpenAI-compatible backends such as Kimi/SGLang, so fragmented tool-call arguments no longer reach tools as empty or unusable objects. Fixes #69672. (#70294) Thanks @MonkeyLeeT.</li>
<li>Gateway/restart: preserve group and channel chat context when resuming an agent turn after a Gateway restart, so continuation replies keep the same prompt, routing, and tool-status behavior as the original conversation.</li>
<li>Gateway/pairing: shared-secret loopback CLI clients now silently auto-approve <code>metadata-upgrade</code> pairing (platform / device family refresh) instead of being disconnected with <code>1008 pairing required</code>. This matches the scope-upgrade and role-upgrade behavior added in #69431 and unblocks non-interactive CLI automation when a paired-device record has a stale platform string (e.g. device key replicated across hosts, install migrated between OSes, or platform-string format changed between OpenClaw versions). Browser / Control-UI clients keep the existing approval-required flow for metadata changes.</li>
<li>Gateway/pairing: treat any forwarded-header evidence (<code>Forwarded</code>, <code>X-Forwarded-*</code>, or <code>X-Real-IP</code>) as proxied WebSocket traffic before pairing locality checks, so reverse-proxy topologies cannot use the loopback shared-secret helper auto-pairing path.</li>
<li>Agents/OpenAI: treat exact <code>NO_REPLY</code> assistant output as a deliberate silent reply in embedded runs, so GPT-5.4 turns with signed reasoning plus a silent final no longer surface a false incomplete-turn error.</li>
<li>Auto-reply/streaming: preserve streamed reply directives through chunk boundaries and phase-aware <code>final_answer</code> delivery, so split <code>MEDIA:<path></code> lines, voice tags, and reply targets reach channel delivery instead of leaking as text or being dropped. (#70243) Thanks @zqchris.</li>
<li>Anthropic/Claude Opus 4.7: normalize Opus 4.7 and <code>claude-cli</code> Opus 4.7 variants to a 1M context window in resolved runtime metadata and active-agent status/context reporting, so they no longer inherit the stale 200k fallback. Thanks @BunsDev.</li>
<li>Gateway/pairing webchat: render <code>/pair qr</code> replies as structured media instead of raw markdown text, preserve inline reply threading and silent-control handling on media replies, avoid persisting sensitive QR images into transcript history, and keep local webchat media embedding behind internal-only trust markers. (#70047) Thanks @BunsDev.</li>
<li>Codex harness: default app-server runs to unchained local execution, so OpenAI heartbeats can use network and shell tools without stalling behind native Codex approvals or the workspace-write sandbox.</li>
<li>Codex harness: fail closed for unknown native app-server approval methods instead of routing unsupported future approval shapes through OpenClaw approval grants. (#70356) Thanks @Lucenx9.</li>
<li>Codex harness: apply the GPT-5 behavior and heartbeat prompt overlay to native Codex app-server runs, so <code>codex/gpt-5.x</code> sessions get the same follow-through, tool-use, and proactive heartbeat guidance as OpenAI GPT-5 runs.</li>
<li>Codex harness: add an explicit Guardian mode for Codex app-server approvals, plus a Docker live probe for approved and ask-back Guardian decisions, while keeping default app-server runs unchained for unattended local heartbeats. The legacy <code>OPENCLAW_CODEX_APP_SERVER_GUARDIAN</code> shortcut is removed; use plugin config <code>appServer.mode: "guardian"</code> or <code>OPENCLAW_CODEX_APP_SERVER_MODE=guardian</code>. Thanks @pashpashpash.</li>
<li>OpenAI/Responses: keep embedded OpenAI Responses runs on HTTP when <code>models.providers.openai.baseUrl</code> points at a local mock or other non-public endpoint, so mocked/custom endpoints no longer drift onto the hardcoded public websocket transport. (#69815) Thanks @vincentkoc.</li>
<li>Channels/config: require resolved runtime config on channel send/action/client helpers and block runtime helper <code>loadConfig()</code> calls, so SecretRefs are resolved at startup/boundaries instead of being re-read during sends.</li>
<li>Discord: pass resolved runtime config through guild and moderation action helpers, so thread-originated Discord commands can run channel, member, role, and guild actions without falling back to runtime config reads. (#70215) Thanks @szponeczek.</li>
<li>CLI/channels: preserve bundled setup promotion metadata when a loaded partial channel plugin omits it, so adding a non-default account still moves legacy single-account fields such as Telegram <code>streaming</code> into <code>accounts.default</code>.</li>
<li>Telegram: keep the sent-message ownership cache isolated per configured session store, so own-message reaction filtering remains correct with custom <code>session.store</code> paths.</li>
<li>Security/update: fail closed when exact pinned npm plugin or hook-pack updates detect integrity drift, and expose aborted plugin drift details in <code>openclaw update --json</code>.</li>
<li>Ollama: forward OpenClaw thinking control to native <code>/api/chat</code> requests as top-level <code>think</code>, so <code>/think off</code> and <code>openclaw agent --thinking off</code> suppress thinking on models such as qwen3 instead of idling until the watchdog fires. Fixes #69902. (#69967) Thanks @WZH8898.</li>
<li>Memory-core/dreaming: suppress the startup-only managed dreaming cron unavailable warning when the cron service is still attaching, while preserving the runtime warning if cron genuinely remains unavailable. Fixes #69939. (#69941) Thanks @Sanjays2402.</li>
<li>Mattermost: suppress reasoning-only payloads even when they arrive as blockquoted <code>> Reasoning:</code> text, preventing <code>/reasoning on</code> from leaking thinking into channel posts. (#69927) Thanks @lawrence3699.</li>
<li>Discord: read <code>channel.parentId</code> through a safe accessor in the slash-command, reaction, and model-picker paths so partial <code>GuildThreadChannel</code> prototype getters no longer throw <code>Cannot access rawData on partial Channel</code> when commands like <code>/new</code> run from inside a thread. Fixes #69861. (#69908) Thanks @neeravmakwana.</li>
<li>Discord: use safe channel name and parent accessors across voice command authorization, so <code>/vc</code> commands from partial Discord thread channels no longer crash on Carbon rawData getters. (#70199) Thanks @hanamizuki.</li>
<li>Discord: make auto-thread parent transcript inheritance opt-in via <code>channels.discord.thread.inheritParent</code>, keeping newly created Discord thread sessions isolated by default while preserving explicit inheritance for configured accounts. Fixes #69907. (#69986) Thanks @Blahdude.</li>
<li>Browser/Chrome MCP: reset cached existing-session control sessions when a <code>navigate_page</code> call times out, so one stuck navigation no longer poisons the browser profile until a gateway restart. (#69733) Thanks @ayeshakhalid192007-dev.</li>
<li>Browser/Chrome MCP: propagate click timeouts and abort signals to existing-session actions so a stuck click fails fast and reconnects instead of poisoning the browser tool until gateway restart. (#63524) Thanks @dongseok0.</li>
<li>Amazon Bedrock/prompt caching: resolve opaque application inference profile targets before injecting Bedrock cache points, require every routed target to support explicit cache points, and retry transient profile lookups instead of caching a false negative for the rest of the process. (#69953) Thanks @anirudhmarc and @vincentkoc.</li>
<li>Gateway/channel health: base stale-socket recovery on provider-proven transport activity instead of inbound app-event freshness, preventing quiet Slack, Discord, Telegram, Matrix, and local-style channels from being restarted solely because no user traffic arrived. (#69833) Thanks @bek91.</li>
<li>OpenCode Go: canonicalize stale bundled <code>opencode-go</code> base URLs from <code>/go</code> or <code>/go/v1</code> to <code>/zen/go</code> or <code>/zen/go/v1</code>, so older generated model metadata stops hitting the 404 HTML endpoint. (#69898)</li>
<li>CLI/channels: honor <code>channels.<id>.enabled=false</code> as a hard read-only presence opt-out, so env vars, manifest env vars, or stale persisted auth state no longer make disabled channel plugins appear in status, doctor, or setup-only discovery.</li>
<li>Channels/preview streaming: centralize draft-preview finalization so Slack, Discord, Mattermost, and Matrix no longer flush temporary preview messages for media/error finals, and preserve first-reply threading for normal fallback delivery.</li>
<li>Discord: keep slash command follow-up chunks ephemeral when the command is configured for ephemeral replies, so long <code>/status</code> output no longer leaks fallback model or runtime details into the public channel. (#69869) thanks @gumadeiras.</li>
<li>Gateway/session history: re-check current auth and <code>chat.history</code> scope before later SSE keepalives and transcript updates, so active session-history streams close before delivering post-revocation events.</li>
<li>Plugins/discovery: reject package plugin source entries that escape the package directory before explicit runtime entries or inferred built JavaScript peers can be used. (#69868) thanks @gumadeiras.</li>
<li>CLI/channels: resolve channel presence through a shared policy that keeps ambient env vars and stale persisted auth from surfacing disabled bundled plugins in status, doctor, security audit, and cron delivery validation unless the channel or plugin is effectively enabled or explicitly configured. (#69862) Thanks @gumadeiras.</li>
<li>Doctor/plugins: hydrate legacy partial interactive handler state before plugin reload clears dedupe caches, so <code>openclaw doctor</code> and post-update doctor runs no longer crash with <code>Cannot read properties of undefined (reading 'clear')</code>. (#70135) Thanks @ngutman.</li>
<li>Control UI/config: preserve intentionally empty raw config snapshots when clearing pending updates so reset restores the original bytes instead of synthesizing JSON for blank config files. (#68178) Thanks @BunsDev.</li>
<li>memory-core/dreaming: surface a <code>Dreaming status: blocked</code> line in <code>openclaw memory status</code> when dreaming is enabled but the heartbeat that drives the managed cron is not firing for the default agent, and add a Troubleshooting section to the dreaming docs covering the two common causes (per-agent <code>heartbeat</code> blocks excluding <code>main</code>, and <code>heartbeat.every</code> set to <code>0</code>/empty/invalid), so the silent failure described in #69843 becomes legible on the status surface.</li>
<li>Cron/run-log: report generic <code>message</code> tool sends under the resolved delivery channel when they match the cron target, while preserving account-specific mismatch checks for delivery traces. (#69940) Thanks @davehappyminion.</li>
<li>Doctor/channels: merge configured-channel doctor hooks across read-only, loaded, setup, and runtime plugin discovery so partial adapters no longer hide runtime-only compatibility repair or allowlist warnings, preserve disabled-channel opt-outs, and ignore malformed hook values before they can mask valid fallbacks. (#69919) Thanks @gumadeiras.</li>
<li>Models/CLI: show bundled provider-owned static catalog rows in <code>models list --all</code> before auth is configured, including Kimi K2.6 rows for Moonshot, OpenRouter, and Vercel AI Gateway, while keeping local-only and workspace plugin catalog paths isolated. (#69909) Thanks @shakkernerd.</li>
<li>Models/CLI: clarify that <code>models list --provider</code> expects provider ids and reject display labels before loading model discovery. (#70504) Thanks @shakkernerd.</li>
<li>Configure: skip generic CLI startup bootstrap for <code>openclaw configure</code> and bound hint-only gateway probes so the onboarding TUI reaches its first prompt faster when the Gateway is unavailable. (#69984) Thanks @obviyus.</li>
<li>Agents/harness: surface selected plugin harness failures directly instead of replaying the same turn through embedded PI, preventing misleading secondary PI auth errors and avoiding duplicate side effects.</li>
<li>OpenAI Codex: add a ChatGPT device-code auth option beside browser OAuth, so headless or callback-hostile setups can sign in without relying on the localhost browser callback. (#69557) Thanks @vincentkoc.</li>
<li>CLI sessions: keep provider-owned CLI sessions through implicit daily expiry while preserving explicit reset behavior, and retain Claude CLI binding metadata across gateway agent requests. (#70106) Thanks @obviyus.</li>
<li>fix(config): accept truncateAfterCompaction (#68395). Thanks @MonkeyLeeT</li>
<li>CLI/Claude: keep Claude CLI session bindings stable across OAuth access-token refreshes, so gateway restarts continue the same Claude conversation instead of minting a fresh one. (#70132) Thanks @obviyus.</li>
<li>QQBot: add <code>INTERACTION</code> intent (<code>1 << 26</code>) to the gateway constants and include it in the <code>FULL_INTENTS</code> mask so interaction events are received. (#70143) Thanks @cxyhhhhh.</li>
<li>Gateway/restart: preserve one-shot continuation instructions across gateway restarts so agents can resume and reply back to the original chat after reboot. (#63406) Thanks @VACInc.</li>
<li>Gateway/restart: write restart sentinel files atomically so interrupted writes cannot leave a truncated sentinel behind. (#70225) Thanks @obviyus.</li>
<li>Pairing: remove stale pending requests for a device when that paired device is deleted, so an old repair approval cannot recreate the removed device from leftover state.</li>
<li>Security/dotenv: block workspace <code>.env</code> overrides for Matrix, Mattermost, IRC, and Synology endpoint settings so cloned workspaces cannot redirect bundled connector traffic through local endpoint config. (#70240) Thanks @drobison00.</li>
<li>Telegram: require the same <code>/models</code> authorization for group model-picker callbacks, so unauthorized participants can no longer browse or change the session model through inline buttons. (#70235) Thanks @drobison00.</li>
<li>Agents/Pi: keep the filtered tool-name allowlist active for embedded OpenAI/OpenAI Codex GPT-5 runs and compaction sessions, so bundled and client tools still execute after the Pi <code>0.68.1</code> session-tool allowlist change instead of stopping at plan-only replies with no tool call. (#70281) Thanks @jalehman.</li>
<li>Agents/Pi: honor explicit <code>strict-agentic</code> execution contracts for incomplete-turn retry guards across providers, so manually opted-in local or compatible models get the same retry behavior without relying on OpenAI model inference. (#66750) Thanks @ziomancer.</li>
<li>OpenShell/sandbox: pin verified file reads to an already-opened descriptor, walk the ancestor chain for symlinked parents on platforms without fd-path readlink, and re-check file identity so parent symlink swaps cannot redirect in-sandbox reads to host files outside the allowed mount root. (#69798) Thanks @drobison00.</li>
<li>Gateway/Control UI: require authenticated Control UI read access before serving <code>/__openclaw/control-ui-config.json</code> when <code>gateway.auth</code> is enabled, so unauthenticated callers can no longer read bootstrap metadata. (#70247) Thanks @drobison00.</li>
<li>Gateway/restart: default session-scoped restart sentinels to a one-shot agent continuation, so chat-initiated Gateway restarts acknowledge successful boot automatically. (#70269) Thanks @obviyus.</li>
<li>Build/npm publish: fail postpublish verification when root <code>dist/*</code> files import bundled plugin runtime dependencies without mirroring them in the root package manifest, so Slack-style plugin deps cannot silently ship on the wrong module-resolution path again. (#60112) 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.4.22/OpenClaw-2026.4.22.zip" length="47883836" type="application/octet-stream" sparkle:edSignature="kzJ2j2sWX4H+ZIc4dXEFORYr9tk3w1txpjCJ38cdSFz6yWHU0M6Sx9zN0DB7JGIpv1QC+D+jFbWBkl4SJqW2AA=="/>
</item>
<item>
<title>2026.4.20</title>
<pubDate>Tue, 21 Apr 2026 19:53:52 +0000</pubDate>
@@ -230,91 +431,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.4.15/OpenClaw-2026.4.15.zip" length="47501638" type="application/octet-stream" sparkle:edSignature="JUG3cicpJqCQDvp7VYoN6qBuN4Kn4s0+QQFjlMR69OZlwViLdiStPIHa+1vpuoR4miYhJc9knSDVCFzSfQuYCQ=="/>
</item>
<item>
<title>2026.4.14</title>
<pubDate>Tue, 14 Apr 2026 14:08:09 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026041490</sparkle:version>
<sparkle:shortVersionString>2026.4.14</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.14</h2>
<h3>Changes</h3>
<ul>
<li>OpenAI Codex/models: add forward-compat support for <code>gpt-5.4-pro</code>, including Codex pricing/limits and list/status visibility before the upstream catalog catches up. (#66453) Thanks @jepson-liu.</li>
<li>Telegram/forum topics: surface human topic names in agent context, prompt metadata, and plugin hook metadata by learning names from Telegram forum service messages. (#65973) Thanks @ptahdunbar.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Agents/Ollama: forward the configured embedded-run timeout into the global undici stream timeout tuning so slow local Ollama runs no longer inherit the default stream cutoff instead of the operator-set run timeout. (#63175) Thanks @mindcraftreader and @vincentkoc.</li>
<li>Models/Codex: include <code>apiKey</code> in the codex provider catalog output so the Pi ModelRegistry validator no longer rejects the entry and silently drops all custom models from every provider in <code>models.json</code>. (#66180) Thanks @hoyyeva.</li>
<li>Tools/image+pdf: normalize configured provider/model refs before media-tool registry lookup so image and PDF tool runs stop rejecting valid Ollama vision models as unknown just because the tool path skipped the usual model-ref normalization step. (#59943) Thanks @yqli2420 and @vincentkoc.</li>
<li>Slack/interactions: apply the configured global <code>allowFrom</code> owner allowlist to channel block-action and modal interactive events, require an expected sender id for cross-verification, and reject ambiguous channel types so interactive triggers can no longer bypass the documented allowlist intent in channels without a <code>users</code> list. Open-by-default behavior is preserved when no allowlists are configured. (#66028) Thanks @eleqtrizit.</li>
<li>Media-understanding/attachments: fail closed when a local attachment path cannot be canonically resolved via <code>realpath</code>, so a <code>realpath</code> error can no longer downgrade the canonical-roots allowlist check to a non-canonical comparison; attachments that also have a URL still fall back to the network fetch path. (#66022) Thanks @eleqtrizit.</li>
<li>Agents/gateway-tool: reject <code>config.patch</code> and <code>config.apply</code> calls from the model-facing gateway tool when they would newly enable any flag enumerated by <code>openclaw security audit</code> (for example <code>dangerouslyDisableDeviceAuth</code>, <code>allowInsecureAuth</code>, <code>dangerouslyAllowHostHeaderOriginFallback</code>, <code>hooks.gmail.allowUnsafeExternalContent</code>, <code>tools.exec.applyPatch.workspaceOnly: false</code>); already-enabled flags pass through unchanged so non-dangerous edits in the same patch still apply, and direct authenticated operator RPC behavior is unchanged. (#62006) Thanks @eleqtrizit.</li>
<li>Google image generation: strip a trailing <code>/openai</code> suffix from configured Google base URLs only when calling the native Gemini image API so Gemini image requests stop 404ing without breaking explicit OpenAI-compatible Google endpoints. (#66445) Thanks @dapzthelegend.</li>
<li>Telegram/forum topics: persist learned topic names to the Telegram session sidecar store so agent context can keep using human topic names after a restart instead of relearning from future service metadata. (#66107) Thanks @obviyus.</li>
<li>Doctor/systemd: keep <code>openclaw doctor --repair</code> and service reinstall from re-embedding dotenv-backed secrets in user systemd units, while preserving newer inline overrides over stale state-dir <code>.env</code> values. (#66249) Thanks @tmimmanuel.</li>
<li>Ollama/OpenAI-compat: send <code>stream_options.include_usage</code> for Ollama streaming completions so local Ollama runs report real usage instead of falling back to bogus prompt-token counts that trigger premature compaction. (#64568) Thanks @xchunzhao and @vincentkoc.</li>
<li>Doctor/plugins: cache external <code>preferOver</code> catalog lookups within each plugin auto-enable pass so large <code>agents.list</code> configs no longer peg CPU and repeatedly reread plugin catalogs during doctor/plugins resolution. (#66246) Thanks @yfge.</li>
<li>GitHub Copilot/thinking: allow <code>github-copilot/gpt-5.4</code> to use <code>xhigh</code> reasoning so Copilot GPT-5.4 matches the rest of the GPT-5.4 family. (#50168) Thanks @jakepresent and @vincentkoc.</li>
<li>Memory/embeddings: preserve non-OpenAI provider prefixes when normalizing OpenAI-compatible embedding model refs so proxy-backed memory providers stop failing with <code>Unknown memory embedding provider</code>. (#66452) Thanks @jlapenna.</li>
<li>Agents/local models: clarify low-context preflight hints for self-hosted models, point config-backed caps at the relevant OpenClaw setting, and stop suggesting larger models when <code>agents.defaults.contextTokens</code> is the real limit. (#66236) Thanks @ImLukeF.</li>
<li>Browser/SSRF: restore hostname navigation under the default browser SSRF policy while keeping explicit strict mode reachable from config, and keep managed loopback CDP <code>/json/new</code> fallback requests on the local CDP control policy so browser follow-up fixes stop regressing normal navigation or self-blocking local CDP control. (#66386) Thanks @obviyus.</li>
<li>Models/Codex: canonicalize the legacy <code>openai-codex/gpt-5.4-codex</code> runtime alias to <code>openai-codex/gpt-5.4</code> while still honoring alias-specific and canonical per-model overrides. (#43060) Thanks @Sapientropic and @vincentkoc.</li>
<li>Browser/SSRF: preserve explicit strict browser navigation mode for legacy <code>browser.ssrfPolicy.allowPrivateNetwork: false</code> configs by normalizing the legacy alias to the canonical strict marker instead of silently widening those installs to the default non-strict hostname-navigation path.</li>
<li>Onboarding/custom providers: use <code>max_tokens=16</code> for OpenAI-compatible verification probes so stricter custom endpoints stop rejecting onboarding checks that only need a tiny completion. (#66450) Thanks @WuKongAI-CMU.</li>
<li>Agents/subagents: emit the subagent registry lazy-runtime stub on the stable dist path that both source and bundled runtime imports resolve, so the follow-up dist fix no longer still fails with <code>ERR_MODULE_NOT_FOUND</code> at runtime. (#66420) Thanks @obviyus.</li>
<li>Media-understanding/proxy env: auto-upgrade provider HTTP helper requests to trusted env-proxy mode only when <code>HTTP_PROXY</code>/<code>HTTPS_PROXY</code> is active and the target is not bypassed by <code>NO_PROXY</code>, so remote media-understanding and transcription requests stop failing local DNS pre-resolution in proxy-only environments without widening SSRF bypasses. (#52162) Thanks @mjamiv and @vincentkoc.</li>
<li>Telegram/media downloads: let Telegram media fetches trust an operator-configured explicit proxy for target DNS resolution after hostname-policy checks, so proxy-backed installs stop failing <code>could not download media</code> on Bot API file downloads after the DNS-pinning regression. (#66245) Thanks @dawei41468 and @vincentkoc.</li>
<li>Browser: keep loopback CDP readiness checks reachable under strict SSRF defaults so OpenClaw can reconnect to locally started managed Chrome. (#66354) Thanks @hxy91819.</li>
<li>Agents/context engine: compact engine-owned sessions from the first tool-loop delta and preserve ingest fallback when <code>afterTurn</code> is absent, so long-running tool loops can stay bounded without dropping engine state. (#63555) Thanks @Bikkies.</li>
<li>OpenAI Codex/auth: keep malformed Codex CLI auth-file diagnostics on the debug logger instead of stdout so interactive command output stays clean while auth read failures remain traceable. (#66451) Thanks @SimbaKingjoe.</li>
<li>Discord/native commands: return the real status card for native <code>/status</code> interactions instead of falling through to the synthetic <code>✅ Done.</code> ack when the generic dispatcher produces no visible reply. (#54629) Thanks @tkozzer and @vincentkoc.</li>
<li>Hooks/Ollama: let LLM-backed session-memory slug generation honor an explicit <code>agents.defaults.timeoutSeconds</code> override instead of always aborting after 15 seconds, so slow local Ollama runs stop silently dropping back to generic filenames. (#66237) Thanks @dmak and @vincentkoc.</li>
<li>Media/transcription: remap <code>.aac</code> filenames to <code>.m4a</code> for OpenAI-compatible audio uploads so AAC voice notes stop failing MIME-sensitive transcription endpoints. (#66446) Thanks @ben-z.</li>
<li>UI/chat: replace marked.js with markdown-it so maliciously crafted markdown can no longer freeze the Control UI via ReDoS. (#46707) Thanks @zhangfnf.</li>
<li>Auto-reply/send policy: keep <code>sendPolicy: "deny"</code> from blocking inbound message processing, so the agent still runs its turn while all outbound delivery is suppressed for observer-style setups. (#65461, #53328) Thanks @omarshahine.</li>
<li>BlueBubbles: lazy-refresh the Private API server-info cache on send when reply threading or message effects are requested but status is unknown, so sends no longer silently degrade to plain messages when the 10-minute cache expires. (#65447, #43764) Thanks @omarshahine.</li>
<li>Heartbeat/security: force owner downgrade for untrusted <code>hook:wake</code> system events [AI-assisted]. (#66031) Thanks @pgondhi987.</li>
<li>Browser/security: enforce SSRF policy on snapshot, screenshot, and tab routes [AI]. (#66040) Thanks @pgondhi987.</li>
<li>Microsoft Teams/security: enforce sender allowlist checks on SSO signin invokes [AI]. (#66033) Thanks @pgondhi987.</li>
<li>Config/security: redact <code>sourceConfig</code> and <code>runtimeConfig</code> alias fields in <code>redactConfigSnapshot</code> [AI]. (#66030) Thanks @pgondhi987.</li>
<li>Agents/context engines: run opt-in turn maintenance as idle-aware background work so the next foreground turn no longer waits on proactive maintenance. (#65233) Thanks @100yenadmin.</li>
<li>Plugins/status: report the registered context-engine IDs in <code>plugins inspect</code> instead of the owning plugin ID, so non-matching engine IDs and multi-engine plugins are classified correctly. (#58766) Thanks @zhuisDEV.</li>
<li>Context engines: reject resolved plugin engines whose reported <code>info.id</code> does not match their registered slot id, so malformed engines fail fast before id-based runtime branches can misbehave. (#63222) Thanks @fuller-stack-dev.</li>
<li>WhatsApp: patch installed Baileys media encryption writes during OpenClaw postinstall so the default npm/install.sh delivery path waits for encrypted media files to finish flushing before readback, avoiding transient <code>ENOENT</code> crashes on image sends. (#65896) Thanks @frankekn.</li>
<li>Gateway/update: unify service entrypoint resolution around the canonical bundled gateway entrypoint so update, reinstall, and doctor repair stop drifting between stale <code>dist/entry.js</code> and current <code>dist/index.js</code> paths. (#65984) Thanks @mbelinky.</li>
<li>Heartbeat/Telegram topics: keep isolated heartbeat replies on the bound forum topic when <code>target=last</code>, instead of dropping them into the group root chat. (#66035) Thanks @mbelinky.</li>
<li>Browser/CDP: let managed local Chrome readiness, status probes, and managed loopback CDP control bypass browser SSRF policy for their own loopback control plane, so OpenClaw no longer misclassifies a healthy child browser as "not reachable after start". (#65695, #66043) Thanks @mbelinky.</li>
<li>Gateway/sessions: stop heartbeat, cron-event, and exec-event turns from overwriting shared-session routing and origin metadata, preventing synthetic <code>heartbeat</code> targets from poisoning later cron or user delivery. (#66073, #63733, #35300) Thanks @mbelinky.</li>
<li>Browser/CDP: let local attach-only <code>manual-cdp</code> profiles reuse the local loopback CDP control plane under strict default policy and remote-class probe timeouts, so tabs/snapshot stop falsely reporting a live local browser session as not running. (#65611, #66080) Thanks @mbelinky.</li>
<li>Cron/scheduler: stop inventing short retries when cron next-run calculation returns no valid future slot, and keep a maintenance wake armed so enabled unscheduled jobs recover without entering a refire loop. (#66019, #66083) Thanks @mbelinky.</li>
<li>Cron/scheduler: preserve the active error-backoff floor when maintenance repair recomputes a missing cron next-run, so recurring errored jobs do not resume early after a transient next-run resolution failure. (#66019, #66083, #66113) Thanks @mbelinky.</li>
<li>Outbound/delivery-queue: persist the originating outbound <code>session</code> context on queued delivery entries and replay it during recovery, so write-ahead-queued sends keep their original outbound media policy context after restart instead of evaluating against a missing session. (#66025) Thanks @eleqtrizit.</li>
<li>Memory/Ollama: restore the built-in <code>ollama</code> embedding adapter in memory-core so explicit <code>memorySearch.provider: "ollama"</code> works again, and include endpoint-aware cache keys so different Ollama hosts do not reuse each other's embeddings. (#63429, #66078, #66163) Thanks @nnish16 and @vincentkoc.</li>
<li>Auto-reply/queue: split collect-mode followup drains into contiguous groups by per-message authorization context (sender id, owner status, exec/bash-elevated overrides), so queued items from different senders or exec configs no longer execute under the last queued run's owner-only and exec-approval context. (#66024) Thanks @eleqtrizit.</li>
<li>Dreaming/memory-core: require a live queued Dreaming cron event before the heartbeat hook runs the sweep, so managed Dreaming no longer replays on later heartbeats after the scheduled run was already consumed. (#66139) Thanks @mbelinky.</li>
<li>Control UI/Dreaming: stop Imported Insights and Memory Palace from calling optional <code>memory-wiki</code> gateway methods when the plugin is off, and refresh config before wiki reloads so the Dreaming tab stops showing misleading unknown-method failures. (#66140) Thanks @mbelinky.</li>
<li>Agents/tools: only mark streamed unknown-tool retries as counted when a streamed message actually classifies an unavailable tool, and keep incomplete streamed tool names from resetting the retry streak before the final assistant message arrives. (#66145) Thanks @dutifulbob.</li>
<li>Memory/active-memory: move recalled memory onto the hidden untrusted prompt-prefix path instead of system prompt injection, label the visible Active Memory status line fields, and include the resolved recall provider/model in gateway debug logs so trace/debug output matches what the model actually saw. (#66144) Thanks @Takhoffman.</li>
<li>Memory/QMD: stop treating legacy lowercase <code>memory.md</code> as a second default root collection, so QMD recall no longer searches phantom <code>memory-alt-*</code> collections and builtin/QMD root-memory fallback stays aligned. (#66141) Thanks @mbelinky.</li>
<li>Agents/subagents: ship <code>dist/agents/subagent-registry.runtime.js</code> in npm builds so <code>runtime: "subagent"</code> runs stop stalling in <code>queued</code> after the registry import fails. (#66189) Thanks @yqli2420 and @vincentkoc.</li>
<li>Agents/OpenAI: map <code>minimal</code> thinking to OpenAI's supported <code>low</code> reasoning effort for GPT-5.4 requests, so embedded runs stop failing request validation. Thanks @steipete.</li>
<li>Voice-call/media-stream: resolve the source IP from trusted forwarding headers for per-IP pending-connection limits when <code>webhookSecurity.trustForwardingHeaders</code> and <code>trustedProxyIPs</code> are configured, and reserve <code>maxConnections</code> capacity for in-flight WebSocket upgrades so concurrent handshakes can no longer momentarily exceed the operator-set cap. (#66027) Thanks @eleqtrizit.</li>
<li>Feishu/allowlist: canonicalize allowlist entries by explicit <code>user</code>/<code>chat</code> kind, strip repeated <code>feishu:</code>/<code>lark:</code> provider prefixes, and stop folding opaque Feishu IDs to lowercase, so allowlist matching no longer crosses user/chat namespaces or widens to case-insensitive ID matches the operator did not intend. (#66021) Thanks @eleqtrizit.</li>
<li>Telegram/status commands: let read-only status slash commands bypass busy topic turns, while keeping <code>/export-session</code> on the normal lane so it cannot interleave with an in-flight session mutation. (#66226) Thanks @VACInc and @vincentkoc.</li>
<li>TTS/reply media: persist OpenClaw temp voice outputs into managed outbound media and allow them through reply-media normalization, so voice-note replies stop silently dropping. (#63511) Thanks @jetd1.</li>
<li>Agents/tools: treat Windows drive-letter paths (<code>C:\\...</code>) as absolute when resolving sandbox and read-tool paths so workspace root is not prepended under POSIX path rules. (#54039) Thanks @ly85206559 and @vincentkoc.</li>
<li>Agents/OpenAI: recover embedded GPT-style runs when reasoning-only or empty turns need bounded continuation, with replay-safe retry gating and incomplete-turn fallback when no visible answer arrives. (#66167) thanks @jalehman</li>
<li>Outbound/relay-status: suppress internal relay-status placeholder payloads (<code>No channel reply.</code>, <code>Replied in-thread.</code>, <code>Replied in #...</code>, wiki-update status variants ending in <code>No channel reply.</code>) before channel delivery so internal housekeeping text does not leak to users.</li>
<li>Slack/doctor: add a dedicated doctor-contract sidecar so config warmup paths such as <code>openclaw cron</code> no longer fall back to Slack's broader contract surface, which could trigger Slack-related config-read crashes on affected setups. (#63192) Thanks @shhtheonlyperson.</li>
<li>Hooks/session-memory: pass the resolved agent workspace into gateway <code>/new</code> and <code>/reset</code> session-memory hooks so reset snapshots stay scoped to the right agent workspace instead of leaking into the default workspace. (#64735) Thanks @suboss87 and @vincentkoc.</li>
<li>CLI/approvals: raise the default <code>openclaw approvals get</code> gateway timeout and report config-load timeouts explicitly, so slow hosts stop showing a misleading <code>Config unavailable.</code> note when the approvals snapshot succeeds but the follow-up config RPC needs more time. (#66239) Thanks @neeravmakwana.</li>
<li>Media/store: honor configured agent media limits when saving generated media and persisting outbound reply media, so the store no longer hard-stops those flows at 5 MB before the configured limit applies. (#66229) Thanks @neeravmakwana and @vincentkoc.</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.14/OpenClaw-2026.4.14.zip" length="47490719" type="application/octet-stream" sparkle:edSignature="KW4gq3qjhKPSQebRVL/mSgttTOhLVKtnWz7pNCZt29oEZ96yU14OnxxSsmtNHmDi4m7G7gfVOfndp80XKFQlCw=="/>
</item>
</channel>
</rss>
</rss>

View File

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

View File

@@ -34,7 +34,7 @@ fun parseAssistantLaunchIntent(intent: Intent?): AssistantLaunchRequest? {
AssistantLaunchRequest(
source = "app_action",
prompt = prompt,
autoSend = prompt != null,
autoSend = false,
)
}

View File

@@ -63,8 +63,6 @@ internal fun isPrivateLanGatewayHost(
}
if (host.isEmpty()) return false
if (isLoopbackGatewayHost(host, allowEmulatorBridgeAlias = allowEmulatorBridgeAlias)) return true
if (host.endsWith(".local")) return true
if (!host.contains('.') && !host.contains(':')) return true
parseIpv4Address(host)?.let { ipv4 ->
val first = ipv4[0].toInt() and 0xff

View File

@@ -7,7 +7,7 @@ import ai.openclaw.app.gateway.GatewayClientInfo
import ai.openclaw.app.gateway.GatewayConnectOptions
import ai.openclaw.app.gateway.GatewayEndpoint
import ai.openclaw.app.gateway.GatewayTlsParams
import ai.openclaw.app.gateway.isPrivateLanGatewayHost
import ai.openclaw.app.gateway.isLoopbackGatewayHost
import ai.openclaw.app.LocationMode
import ai.openclaw.app.VoiceWakeMode
@@ -34,7 +34,7 @@ class ConnectionManager(
val stableId = endpoint.stableId
val stored = storedFingerprint?.trim().takeIf { !it.isNullOrEmpty() }
val isManual = stableId.startsWith("manual|")
val cleartextAllowedHost = isPrivateLanGatewayHost(endpoint.host)
val cleartextAllowedHost = isLoopbackGatewayHost(endpoint.host)
if (isManual) {
if (!manualTlsEnabled && cleartextAllowedHost) return null

View File

@@ -1,6 +1,6 @@
package ai.openclaw.app.ui
import ai.openclaw.app.gateway.isPrivateLanGatewayHost
import ai.openclaw.app.gateway.isLoopbackGatewayHost
import java.util.Base64
import java.util.Locale
import java.net.URI
@@ -56,9 +56,9 @@ internal data class GatewayScannedSetupCodeResult(
private val gatewaySetupJson = Json { ignoreUnknownKeys = true }
private const val remoteGatewaySecurityRule =
"Tailscale and public mobile nodes require wss:// or Tailscale Serve. ws:// is allowed for private LAN, localhost, and the Android emulator."
"Tailscale and public mobile nodes require wss:// or Tailscale Serve. ws:// is allowed only for localhost and the Android emulator."
private const val remoteGatewaySecurityFix =
"Use a private LAN host/address, or enable Tailscale Serve / expose a wss:// gateway URL."
"Use localhost/the Android emulator, or enable Tailscale Serve / expose a wss:// gateway URL."
internal fun resolveGatewayConnectConfig(
useSetupCode: Boolean,
@@ -143,7 +143,7 @@ internal fun parseGatewayEndpoint(rawInput: String): GatewayEndpointConfig? {
"wss", "https" -> true
else -> true
}
if (!tls && !isPrivateLanGatewayHost(host)) {
if (!tls && !isLoopbackGatewayHost(host)) {
return GatewayEndpointParseResult(error = GatewayEndpointValidationError.INSECURE_REMOTE_URL)
}
val defaultPort =

View File

@@ -49,7 +49,7 @@ internal fun buildGatewayDiagnosticsReport(
Please:
- pick one route only: same machine, same LAN, Tailscale, or public URL
- classify this as pairing/auth, TLS trust, wrong advertised route, wrong address/port, or gateway down
- remember: Tailscale/public mobile routes require wss:// or Tailscale Serve; private LAN ws:// is still allowed
- remember: Tailscale/public mobile routes require wss:// or Tailscale Serve; ws:// is loopback-only
- quote the exact app status/error below
- tell me whether `openclaw devices list` should show a pending pairing request
- if more signal is needed, ask for `openclaw qr --json`, `openclaw devices list`, and `openclaw nodes status`

View File

@@ -4,7 +4,6 @@ import android.content.Intent
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@@ -33,7 +32,7 @@ class AssistantLaunchTest {
requireNotNull(parsed)
assertEquals("app_action", parsed.source)
assertEquals("summarize my unread texts", parsed.prompt)
assertTrue(parsed.autoSend)
assertFalse(parsed.autoSend)
}
@Test

View File

@@ -108,7 +108,7 @@ class ConnectionManagerTest {
}
@Test
fun resolveTlsParamsForEndpoint_manualPrivateLanCanStayCleartextWhenToggleIsOff() {
fun resolveTlsParamsForEndpoint_manualPrivateLanForcesTlsWhenToggleIsOff() {
val endpoint = GatewayEndpoint.manual(host = "192.168.1.20", port = 18789)
val params =
@@ -118,7 +118,9 @@ class ConnectionManagerTest {
manualTlsEnabled = false,
)
assertNull(params)
assertEquals(true, params?.required)
assertNull(params?.expectedFingerprint)
assertEquals(false, params?.allowTOFU)
}
@Test
@@ -146,7 +148,7 @@ class ConnectionManagerTest {
}
@Test
fun resolveTlsParamsForEndpoint_discoveryPrivateLanWithoutHintsCanStayCleartext() {
fun resolveTlsParamsForEndpoint_discoveryPrivateLanWithoutHintsStillRequiresTls() {
val endpoint =
GatewayEndpoint(
stableId = "_openclaw-gw._tcp.|local.|Test",
@@ -164,7 +166,9 @@ class ConnectionManagerTest {
manualTlsEnabled = false,
)
assertNull(params)
assertEquals(true, params?.required)
assertNull(params?.expectedFingerprint)
assertEquals(false, params?.allowTOFU)
}
@Test
@@ -240,9 +244,9 @@ class ConnectionManagerTest {
}
@Test
fun isPrivateLanGatewayHost_acceptsLanHostsButRejectsTailnetHosts() {
fun isPrivateLanGatewayHost_acceptsLanIpsButRejectsMdnsAndTailnetHosts() {
assertTrue(isPrivateLanGatewayHost("192.168.1.20"))
assertTrue(isPrivateLanGatewayHost("gateway.local"))
assertFalse(isPrivateLanGatewayHost("gateway.local"))
assertFalse(isPrivateLanGatewayHost("100.64.0.9"))
assertFalse(isPrivateLanGatewayHost("gateway.tailnet.ts.net"))
}

View File

@@ -99,33 +99,16 @@ class GatewayConfigResolverTest {
}
@Test
fun parseGatewayEndpointAllowsPrivateLanCleartextWsUrls() {
fun parseGatewayEndpointRejectsPrivateLanCleartextWsUrls() {
val parsed = parseGatewayEndpoint("ws://192.168.1.20:18789")
assertEquals(
GatewayEndpointConfig(
host = "192.168.1.20",
port = 18789,
tls = false,
displayUrl = "http://192.168.1.20:18789",
),
parsed,
)
assertNull(parsed)
}
@Test
fun parseGatewayEndpointAllowsMdnsCleartextWsUrls() {
fun parseGatewayEndpointRejectsMdnsCleartextWsUrls() {
val parsed = parseGatewayEndpoint("ws://gateway.local:18789")
assertEquals(
GatewayEndpointConfig(
host = "gateway.local",
port = 18789,
tls = false,
displayUrl = "http://gateway.local:18789",
),
parsed,
)
assertNull(parsed)
}
@Test
@@ -163,13 +146,9 @@ class GatewayConfigResolverTest {
}
@Test
fun parseGatewayEndpointAllowsLinkLocalIpv6ZoneCleartextWsUrls() {
fun parseGatewayEndpointRejectsLinkLocalIpv6ZoneCleartextWsUrls() {
val parsed = parseGatewayEndpoint("ws://[fe80::1%25eth0]")
assertEquals("fe80::1%25eth0", parsed?.host)
assertEquals(18789, parsed?.port)
assertEquals(false, parsed?.tls)
assertEquals("http://[fe80::1%25eth0]:18789", parsed?.displayUrl)
assertNull(parsed)
}
@Test
@@ -290,19 +269,10 @@ class GatewayConfigResolverTest {
}
@Test
fun parseGatewayEndpointResultAcceptsLanCleartextGateway() {
fun parseGatewayEndpointResultFlagsInsecureLanCleartextGateway() {
val parsed = parseGatewayEndpointResult("ws://192.168.1.20:18789")
assertEquals(
GatewayEndpointConfig(
host = "192.168.1.20",
port = 18789,
tls = false,
displayUrl = "http://192.168.1.20:18789",
),
parsed.config,
)
assertNull(parsed.error)
assertNull(parsed.config)
assertEquals(GatewayEndpointValidationError.INSECURE_REMOTE_URL, parsed.error)
}
@Test
@@ -443,7 +413,7 @@ class GatewayConfigResolverTest {
}
@Test
fun resolveGatewayConnectConfigAllowsPrivateLanManualCleartextEndpoint() {
fun resolveGatewayConnectConfigRejectsPrivateLanManualCleartextEndpoint() {
val resolved =
resolveGatewayConnectConfig(
useSetupCode = false,
@@ -459,9 +429,7 @@ class GatewayConfigResolverTest {
fallbackPassword = "",
)
assertEquals("192.168.31.100", resolved?.host)
assertEquals(18789, resolved?.port)
assertEquals(false, resolved?.tls)
assertNull(resolved)
}
@Test

View File

@@ -1,5 +1,13 @@
# OpenClaw iOS Changelog
## 2026.4.25 - 2026-04-25
Maintenance update for the current OpenClaw development release.
## 2026.4.23 - 2026-04-23
Maintenance update for the current OpenClaw development release.
## 2026.4.22 - 2026-04-22
Maintenance update for the current OpenClaw development release.

View File

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

View File

@@ -1,3 +1,3 @@
{
"version": "2026.4.22"
"version": "2026.4.25"
}

View File

@@ -1,6 +1,24 @@
import Foundation
import OpenClawProtocol
func whatsappLoginWaitRequestTimeoutMs(
startedAt: Date,
timeoutMs: Int,
didRunFinalWait: inout Bool,
now: Date = Date()) -> Int?
{
let elapsedMs = Int(now.timeIntervalSince(startedAt) * 1000)
let remainingMs = max(timeoutMs - elapsedMs, 0)
if remainingMs > 0 {
return remainingMs
}
if didRunFinalWait {
return nil
}
didRunFinalWait = true
return 1
}
extension ChannelsStore {
func start() {
guard !self.isPreview else { return }
@@ -77,18 +95,28 @@ extension ChannelsStore {
guard !self.whatsappBusy else { return }
self.whatsappBusy = true
defer { self.whatsappBusy = false }
let startedAt = Date()
var didRunFinalWait = false
do {
let params: [String: AnyCodable] = [
"timeoutMs": AnyCodable(timeoutMs),
]
let result: WhatsAppLoginWaitResult = try await GatewayConnection.shared.requestDecoded(
method: .webLoginWait,
params: params,
timeoutMs: Double(timeoutMs) + 5000)
self.whatsappLoginMessage = result.message
self.whatsappLoginConnected = result.connected
if result.connected {
self.whatsappLoginQrDataUrl = nil
while let remainingMs = whatsappLoginWaitRequestTimeoutMs(
startedAt: startedAt,
timeoutMs: timeoutMs,
didRunFinalWait: &didRunFinalWait)
{
var params: [String: AnyCodable] = [
"timeoutMs": AnyCodable(remainingMs),
]
if let currentQrDataUrl = self.whatsappLoginQrDataUrl {
params["currentQrDataUrl"] = AnyCodable(currentQrDataUrl)
}
let result: WhatsAppLoginWaitResult = try await GatewayConnection.shared.requestDecoded(
method: .webLoginWait,
params: params,
timeoutMs: Double(remainingMs) + 5000)
self.applyWhatsAppLoginWaitResult(result)
if result.connected || result.qrDataUrl == nil || didRunFinalWait {
break
}
}
} catch {
self.whatsappLoginMessage = error.localizedDescription
@@ -151,9 +179,10 @@ private struct WhatsAppLoginStartResult: Codable {
let connected: Bool?
}
private struct WhatsAppLoginWaitResult: Codable {
struct WhatsAppLoginWaitResult: Codable {
let connected: Bool
let message: String
let qrDataUrl: String?
}
private struct ChannelLogoutResult: Codable {

View File

@@ -290,6 +290,16 @@ final class ChannelsStore {
return self.snapshot?.channelOrder ?? []
}
func applyWhatsAppLoginWaitResult(_ result: WhatsAppLoginWaitResult) {
self.whatsappLoginMessage = result.message
self.whatsappLoginConnected = result.connected
if let qrDataUrl = result.qrDataUrl {
self.whatsappLoginQrDataUrl = qrDataUrl
} else if result.connected {
self.whatsappLoginQrDataUrl = nil
}
}
init(isPreview: Bool = ProcessInfo.processInfo.isPreview) {
self.isPreview = isPreview
}

View File

@@ -9,8 +9,14 @@ enum ExecAllowlistMatcher {
for entry in entries {
switch ExecApprovalHelpers.validateAllowlistPattern(entry.pattern) {
case let .valid(pattern):
let target = resolvedPath ?? rawExecutable
if self.matches(pattern: pattern, target: target) { return entry }
if ExecApprovalHelpers.patternHasPathSelector(pattern) {
let target = resolvedPath ?? rawExecutable
if self.matches(pattern: pattern, target: target) { return entry }
} else if pattern != "*",
!ExecApprovalHelpers.patternHasPathSelector(rawExecutable),
self.matchesExecutableBasename(pattern: pattern, resolution: resolution) {
return entry
}
case .invalid:
continue
}
@@ -34,6 +40,20 @@ enum ExecAllowlistMatcher {
return matches
}
private static func matchesExecutableBasename(
pattern: String,
resolution: ExecCommandResolution) -> Bool
{
var candidates = Set<String>()
if !resolution.executableName.isEmpty {
candidates.insert(resolution.executableName)
}
if let resolvedPath = resolution.resolvedPath, !resolvedPath.isEmpty {
candidates.insert(URL(fileURLWithPath: resolvedPath).lastPathComponent)
}
return candidates.contains { self.matches(pattern: pattern, target: $0) }
}
private static func matches(pattern: String, target: String) -> Bool {
let trimmed = pattern.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return false }

View File

@@ -616,6 +616,17 @@ enum ExecApprovalsStore {
let trimmedResolved = entry.lastResolvedPath?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let normalizedResolved = trimmedResolved.isEmpty ? nil : trimmedResolved
if !ExecApprovalHelpers.patternHasPathSelector(trimmedPattern),
!trimmedResolved.isEmpty,
case let .valid(migratedPattern) = ExecApprovalHelpers.validateAllowlistPattern(trimmedResolved) {
return ExecAllowlistEntry(
id: entry.id,
pattern: migratedPattern,
lastUsedAt: entry.lastUsedAt,
lastUsedCommand: entry.lastUsedCommand,
lastResolvedPath: normalizedResolved)
}
switch ExecApprovalHelpers.validateAllowlistPattern(trimmedPattern) {
case let .valid(pattern):
return ExecAllowlistEntry(
@@ -724,11 +735,10 @@ enum ExecApprovalHelpers {
static func validateAllowlistPattern(_ pattern: String?) -> ExecAllowlistPatternValidation {
let trimmed = pattern?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
guard !trimmed.isEmpty else { return .invalid(.empty) }
guard self.containsPathComponent(trimmed) else { return .invalid(.missingPathComponent) }
return .valid(trimmed)
}
static func isPathPattern(_ pattern: String?) -> Bool {
static func isValidAllowlistPattern(_ pattern: String?) -> Bool {
switch self.validateAllowlistPattern(pattern) {
case .valid:
true
@@ -737,6 +747,11 @@ enum ExecApprovalHelpers {
}
}
static func isPathPattern(_ pattern: String?) -> Bool {
let trimmed = pattern?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
return self.patternHasPathSelector(trimmed)
}
static func parseDecision(_ raw: String?) -> ExecApprovalDecision? {
let trimmed = raw?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
guard !trimmed.isEmpty else { return nil }
@@ -759,7 +774,7 @@ enum ExecApprovalHelpers {
return pattern.isEmpty ? nil : pattern
}
private static func containsPathComponent(_ pattern: String) -> Bool {
static func patternHasPathSelector(_ pattern: String) -> Bool {
pattern.contains("/") || pattern.contains("~") || pattern.contains("\\")
}
}

View File

@@ -70,6 +70,7 @@ actor GatewayConnection {
case wizardStatus = "wizard.status"
case talkConfig = "talk.config"
case talkMode = "talk.mode"
case talkSpeak = "talk.speak"
case webLoginStart = "web.login.start"
case webLoginWait = "web.login.wait"
case channelsLogout = "channels.logout"

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.4.22</string>
<string>2026.4.25</string>
<key>CFBundleVersion</key>
<string>2026042200</string>
<string>2026042500</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -105,7 +105,7 @@ struct SystemRunSettingsView: View {
.foregroundStyle(.secondary)
} else {
HStack(spacing: 8) {
TextField("Add allowlist path pattern (case-insensitive globs)", text: self.$newPattern)
TextField("Add command name or path glob", text: self.$newPattern)
.textFieldStyle(.roundedBorder)
Button("Add") {
if self.model.addEntry(self.newPattern) == nil {
@@ -113,10 +113,10 @@ struct SystemRunSettingsView: View {
}
}
.buttonStyle(.bordered)
.disabled(!self.model.isPathPattern(self.newPattern))
.disabled(!self.model.isValidPattern(self.newPattern))
}
Text("Path patterns only. Basename entries like \"echo\" are ignored.")
Text("Bare names match PATH-resolved commands. Use a path glob for a specific binary.")
.font(.footnote)
.foregroundStyle(.secondary)
if let validationMessage = self.model.allowlistValidationMessage {
@@ -424,8 +424,8 @@ final class ExecApprovalsSettingsModel {
self.entries.first(where: { $0.id == id })
}
func isPathPattern(_ pattern: String) -> Bool {
ExecApprovalHelpers.isPathPattern(pattern)
func isValidPattern(_ pattern: String) -> Bool {
ExecApprovalHelpers.isValidAllowlistPattern(pattern)
}
func refreshSkillBins(force: Bool = false) async {

View File

@@ -2,6 +2,7 @@ import AVFoundation
import Foundation
import OpenClawChatUI
import OpenClawKit
import OpenClawProtocol
import OSLog
import Speech
@@ -475,7 +476,16 @@ actor TalkModeRuntime {
self.ttsLogger
.error(
"talk TTS failed: \(error.localizedDescription, privacy: .public); " +
"falling back to system voice")
"retrying gateway talk.speak")
do {
try await self.playGatewayTalkSpeak(input: input)
return
} catch {
self.ttsLogger
.error(
"talk gateway TTS failed: \(error.localizedDescription, privacy: .public); " +
"falling back to system voice")
}
do {
try await self.playSystemVoice(input: input)
} catch {
@@ -720,6 +730,42 @@ actor TalkModeRuntime {
return await self.playMP3(stream: stream)
}
private func playGatewayTalkSpeak(input: TalkPlaybackInput) async throws {
let params = Self.makeTalkSpeakParams(
text: input.cleanedText,
voiceId: input.voiceId,
modelId: self.currentModelId ?? self.defaultModelId,
outputFormat: self.defaultOutputFormat,
directive: input.directive)
let result: TalkSpeakResult = try await GatewayConnection.shared.requestDecoded(
method: .talkSpeak,
params: params,
timeoutMs: max(30000, input.synthTimeoutSeconds * 1000 + 5000))
guard let audioData = Data(base64Encoded: result.audiobase64), !audioData.isEmpty else {
throw NSError(domain: "TalkSpeak", code: 1, userInfo: [
NSLocalizedDescriptionKey: "gateway talk.speak returned empty audio",
])
}
_ = await self.stopPCM()
_ = await self.stopMP3()
if self.interruptOnSpeech {
guard await self.prepareForPlayback(generation: input.generation) else { return }
}
await MainActor.run { TalkModeController.shared.updatePhase(.speaking) }
self.phase = .speaking
let playback = await self.playTalkAudio(data: audioData)
self.ttsLogger
.info(
"talk gateway audio provider=\(result.provider, privacy: .public) " +
"format=\(result.outputformat ?? "unknown", privacy: .public) " +
"finished=\(playback.finished, privacy: .public)")
if !playback.finished, playback.interruptedAt == nil {
throw NSError(domain: "TalkSpeak", code: 2, userInfo: [
NSLocalizedDescriptionKey: "gateway talk.speak audio playback failed",
])
}
}
private func playSystemVoice(input: TalkPlaybackInput) async throws {
self.ttsLogger.info("talk system voice start chars=\(input.cleanedText.count, privacy: .public)")
if self.interruptOnSpeech {
@@ -847,6 +893,54 @@ actor TalkModeRuntime {
}
extension TalkModeRuntime {
static func makeTalkSpeakParams(
text: String,
voiceId: String?,
modelId: String?,
outputFormat: String?,
directive: TalkDirective?) -> [String: AnyCodable]
{
var params: [String: AnyCodable] = ["text": AnyCodable(text)]
func addString(_ key: String, _ value: String?) {
let trimmed = value?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
guard !trimmed.isEmpty else { return }
params[key] = AnyCodable(trimmed)
}
addString("voiceId", voiceId)
addString("modelId", directive?.modelId ?? modelId)
addString("outputFormat", directive?.outputFormat ?? outputFormat)
if let speed = directive?.speed {
params["speed"] = AnyCodable(speed)
}
if let rateWPM = directive?.rateWPM {
params["rateWpm"] = AnyCodable(rateWPM)
}
if let stability = directive?.stability {
params["stability"] = AnyCodable(stability)
}
if let similarity = directive?.similarity {
params["similarity"] = AnyCodable(similarity)
}
if let style = directive?.style {
params["style"] = AnyCodable(style)
}
if let speakerBoost = directive?.speakerBoost {
params["speakerBoost"] = AnyCodable(speakerBoost)
}
if let seed = directive?.seed {
params["seed"] = AnyCodable(seed)
}
addString("normalize", directive?.normalize)
addString("language", directive?.language)
if let latencyTier = directive?.latencyTier {
params["latencyTier"] = AnyCodable(latencyTier)
}
return params
}
// MARK: - Audio playback (MainActor helpers)
@MainActor

View File

@@ -464,6 +464,7 @@ public struct SendParams: Codable, Sendable {
public let channel: String?
public let accountid: String?
public let agentid: String?
public let replytoid: String?
public let threadid: String?
public let sessionkey: String?
public let idempotencykey: String
@@ -477,6 +478,7 @@ public struct SendParams: Codable, Sendable {
channel: String?,
accountid: String?,
agentid: String?,
replytoid: String?,
threadid: String?,
sessionkey: String?,
idempotencykey: String)
@@ -489,6 +491,7 @@ public struct SendParams: Codable, Sendable {
self.channel = channel
self.accountid = accountid
self.agentid = agentid
self.replytoid = replytoid
self.threadid = threadid
self.sessionkey = sessionkey
self.idempotencykey = idempotencykey
@@ -503,6 +506,7 @@ public struct SendParams: Codable, Sendable {
case channel
case accountid = "accountId"
case agentid = "agentId"
case replytoid = "replyToId"
case threadid = "threadId"
case sessionkey = "sessionKey"
case idempotencykey = "idempotencyKey"
@@ -719,17 +723,26 @@ public struct AgentIdentityResult: Codable, Sendable {
public let agentid: String
public let name: String?
public let avatar: String?
public let avatarsource: String?
public let avatarstatus: String?
public let avatarreason: String?
public let emoji: String?
public init(
agentid: String,
name: String?,
avatar: String?,
avatarsource: String?,
avatarstatus: String?,
avatarreason: String?,
emoji: String?)
{
self.agentid = agentid
self.name = name
self.avatar = avatar
self.avatarsource = avatarsource
self.avatarstatus = avatarstatus
self.avatarreason = avatarreason
self.emoji = emoji
}
@@ -737,6 +750,9 @@ public struct AgentIdentityResult: Codable, Sendable {
case agentid = "agentId"
case name
case avatar
case avatarsource = "avatarSource"
case avatarstatus = "avatarStatus"
case avatarreason = "avatarReason"
case emoji
}
}
@@ -2321,6 +2337,62 @@ public struct TalkConfigResult: Codable, Sendable {
}
}
public struct TalkRealtimeSessionParams: Codable, Sendable {
public let sessionkey: String?
public let provider: String?
public let model: String?
public let voice: String?
public init(
sessionkey: String?,
provider: String?,
model: String?,
voice: String?)
{
self.sessionkey = sessionkey
self.provider = provider
self.model = model
self.voice = voice
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case provider
case model
case voice
}
}
public struct TalkRealtimeSessionResult: Codable, Sendable {
public let provider: String
public let clientsecret: String
public let model: String?
public let voice: String?
public let expiresat: Double?
public init(
provider: String,
clientsecret: String,
model: String?,
voice: String?,
expiresat: Double?)
{
self.provider = provider
self.clientsecret = clientsecret
self.model = model
self.voice = voice
self.expiresat = expiresat
}
private enum CodingKeys: String, CodingKey {
case provider
case clientsecret = "clientSecret"
case model
case voice
case expiresat = "expiresAt"
}
}
public struct TalkSpeakParams: Codable, Sendable {
public let text: String
public let voiceid: String?
@@ -2550,18 +2622,22 @@ public struct WebLoginStartParams: Codable, Sendable {
public struct WebLoginWaitParams: Codable, Sendable {
public let timeoutms: Int?
public let accountid: String?
public let currentqrdataurl: String?
public init(
timeoutms: Int?,
accountid: String?)
accountid: String?,
currentqrdataurl: String?)
{
self.timeoutms = timeoutms
self.accountid = accountid
self.currentqrdataurl = currentqrdataurl
}
private enum CodingKeys: String, CodingKey {
case timeoutms = "timeoutMs"
case accountid = "accountId"
case currentqrdataurl = "currentQrDataUrl"
}
}

View File

@@ -156,4 +156,63 @@ struct ChannelsSettingsSmokeTests {
let view = ChannelsSettings(store: store)
_ = view.body
}
@Test func `whatsapp login wait result keeps latest qr until connected`() {
let store = makeChannelsStore(channels: [:])
store.whatsappLoginQrDataUrl = "data:image/png;base64,initial"
store.applyWhatsAppLoginWaitResult(
WhatsAppLoginWaitResult(
connected: false,
message: "QR refreshed. Scan the latest code in WhatsApp → Linked Devices.",
qrDataUrl: "data:image/png;base64,rotated"))
#expect(store.whatsappLoginQrDataUrl == "data:image/png;base64,rotated")
#expect(store.whatsappLoginConnected == false)
store.applyWhatsAppLoginWaitResult(
WhatsAppLoginWaitResult(
connected: false,
message: "Still waiting for the QR scan. Let me know when youve scanned it.",
qrDataUrl: nil))
#expect(store.whatsappLoginQrDataUrl == "data:image/png;base64,rotated")
store.applyWhatsAppLoginWaitResult(
WhatsAppLoginWaitResult(
connected: true,
message: "✅ Linked! WhatsApp is ready.",
qrDataUrl: nil))
#expect(store.whatsappLoginQrDataUrl == nil)
#expect(store.whatsappLoginConnected == true)
}
@Test func `whatsapp login wait budget allows one final poll`() {
let startedAt = Date(timeIntervalSince1970: 1_700_000_000)
var didRunFinalWait = false
#expect(
whatsappLoginWaitRequestTimeoutMs(
startedAt: startedAt,
timeoutMs: 1_000,
didRunFinalWait: &didRunFinalWait,
now: Date(timeInterval: 0.25, since: startedAt)) == 750)
#expect(didRunFinalWait == false)
#expect(
whatsappLoginWaitRequestTimeoutMs(
startedAt: startedAt,
timeoutMs: 1_000,
didRunFinalWait: &didRunFinalWait,
now: Date(timeInterval: 1.25, since: startedAt)) == 1)
#expect(didRunFinalWait == true)
#expect(
whatsappLoginWaitRequestTimeoutMs(
startedAt: startedAt,
timeoutMs: 1_000,
didRunFinalWait: &didRunFinalWait,
now: Date(timeInterval: 1.5, since: startedAt)) == nil)
}
}

View File

@@ -66,22 +66,34 @@ struct ExecAllowlistTests {
#expect(match?.pattern == entry.pattern)
}
@Test func `match ignores basename pattern`() {
@Test func `match accepts basename pattern for PATH resolved executable`() {
let entry = ExecAllowlistEntry(pattern: "rg")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match == nil)
#expect(match?.pattern == entry.pattern)
}
@Test func `match ignores basename for relative executable`() {
@Test func `match accepts basename glob for PATH resolved executable`() {
let entry = ExecAllowlistEntry(pattern: "r?")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match?.pattern == entry.pattern)
}
@Test func `match ignores basename for path selected executable`() {
let entry = ExecAllowlistEntry(pattern: "echo")
let resolution = ExecCommandResolution(
let relativeResolution = ExecCommandResolution(
rawExecutable: "./echo",
resolvedPath: "/tmp/oc-basename/echo",
executableName: "echo",
cwd: "/tmp/oc-basename")
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match == nil)
let absoluteResolution = ExecCommandResolution(
rawExecutable: "/tmp/oc-basename/echo",
resolvedPath: "/tmp/oc-basename/echo",
executableName: "echo",
cwd: "/tmp/oc-basename")
#expect(ExecAllowlistMatcher.match(entries: [entry], resolution: relativeResolution) == nil)
#expect(ExecAllowlistMatcher.match(entries: [entry], resolution: absoluteResolution) == nil)
}
@Test func `match is case insensitive`() {

View File

@@ -33,18 +33,13 @@ struct ExecApprovalHelpersTests {
#expect(ExecApprovalHelpers.isPathPattern("/usr/bin/rg"))
#expect(ExecApprovalHelpers.isPathPattern(" ~/bin/rg "))
#expect(!ExecApprovalHelpers.isPathPattern("rg"))
#expect(ExecApprovalHelpers.isValidAllowlistPattern("rg"))
if case let .invalid(reason) = ExecApprovalHelpers.validateAllowlistPattern(" ") {
#expect(reason == .empty)
} else {
Issue.record("Expected empty pattern rejection")
}
if case let .invalid(reason) = ExecApprovalHelpers.validateAllowlistPattern("echo") {
#expect(reason == .missingPathComponent)
} else {
Issue.record("Expected basename pattern rejection")
}
}
@Test func `requires ask matches policy`() {

View File

@@ -31,7 +31,7 @@ struct ExecApprovalsStoreRefactorTests {
}
@Test
func `update allowlist reports rejected basename pattern`() async throws {
func `update allowlist accepts basename pattern`() async throws {
try await self.withTempStateDir { _ in
let rejected = ExecApprovalsStore.updateAllowlist(
agentId: "main",
@@ -39,12 +39,10 @@ struct ExecApprovalsStoreRefactorTests {
ExecAllowlistEntry(pattern: "echo"),
ExecAllowlistEntry(pattern: "/bin/echo"),
])
#expect(rejected.count == 1)
#expect(rejected.first?.reason == .missingPathComponent)
#expect(rejected.first?.pattern == "echo")
#expect(rejected.isEmpty)
let resolved = ExecApprovalsStore.resolve(agentId: "main")
#expect(resolved.allowlist.map(\.pattern) == ["/bin/echo"])
#expect(resolved.allowlist.map(\.pattern) == ["echo", "/bin/echo"])
}
}

View File

@@ -1,3 +1,4 @@
import OpenClawKit
import Speech
import Testing
@testable import OpenClaw
@@ -16,23 +17,19 @@ struct TalkModeRuntimeSpeechTests {
let elevenLabsPlan = TalkModeRuntime.playbackPlan(
provider: "elevenlabs",
apiKey: "key",
voiceId: "voice"
)
voiceId: "voice")
let missingKeyPlan = TalkModeRuntime.playbackPlan(
provider: "elevenlabs",
apiKey: nil,
voiceId: "voice"
)
voiceId: "voice")
let missingVoicePlan = TalkModeRuntime.playbackPlan(
provider: "elevenlabs",
apiKey: "key",
voiceId: nil
)
voiceId: nil)
let blankKeyPlan = TalkModeRuntime.playbackPlan(
provider: "elevenlabs",
apiKey: "",
voiceId: "voice"
)
voiceId: "voice")
let mlxPlan = TalkModeRuntime.playbackPlan(provider: "mlx", apiKey: nil, voiceId: nil)
let systemPlan = TalkModeRuntime.playbackPlan(provider: "system", apiKey: nil, voiceId: nil)
@@ -43,4 +40,40 @@ struct TalkModeRuntimeSpeechTests {
#expect(mlxPlan == .mlxThenSystemVoice)
#expect(systemPlan == .systemVoiceOnly)
}
@Test func `talk speak params carry resolved voice and directive overrides`() {
let params = TalkModeRuntime.makeTalkSpeakParams(
text: "hello",
voiceId: "voice-123",
modelId: "eleven_v3",
outputFormat: "mp3_44100_128",
directive: TalkDirective(
modelId: "eleven_turbo_v2_5",
speed: 1.1,
rateWPM: 180,
stability: 0.4,
similarity: 0.7,
style: 0.2,
speakerBoost: true,
seed: 42,
normalize: "auto",
language: "en",
outputFormat: "mp3_44100_128",
latencyTier: 3))
#expect(params["text"]?.value as? String == "hello")
#expect(params["voiceId"]?.value as? String == "voice-123")
#expect(params["modelId"]?.value as? String == "eleven_turbo_v2_5")
#expect(params["outputFormat"]?.value as? String == "mp3_44100_128")
#expect(params["speed"]?.value as? Double == 1.1)
#expect(params["rateWpm"]?.value as? Int == 180)
#expect(params["stability"]?.value as? Double == 0.4)
#expect(params["similarity"]?.value as? Double == 0.7)
#expect(params["style"]?.value as? Double == 0.2)
#expect(params["speakerBoost"]?.value as? Bool == true)
#expect(params["seed"]?.value as? Int == 42)
#expect(params["normalize"]?.value as? String == "auto")
#expect(params["language"]?.value as? String == "en")
#expect(params["latencyTier"]?.value as? Int == 3)
}
}

View File

@@ -464,6 +464,7 @@ public struct SendParams: Codable, Sendable {
public let channel: String?
public let accountid: String?
public let agentid: String?
public let replytoid: String?
public let threadid: String?
public let sessionkey: String?
public let idempotencykey: String
@@ -477,6 +478,7 @@ public struct SendParams: Codable, Sendable {
channel: String?,
accountid: String?,
agentid: String?,
replytoid: String?,
threadid: String?,
sessionkey: String?,
idempotencykey: String)
@@ -489,6 +491,7 @@ public struct SendParams: Codable, Sendable {
self.channel = channel
self.accountid = accountid
self.agentid = agentid
self.replytoid = replytoid
self.threadid = threadid
self.sessionkey = sessionkey
self.idempotencykey = idempotencykey
@@ -503,6 +506,7 @@ public struct SendParams: Codable, Sendable {
case channel
case accountid = "accountId"
case agentid = "agentId"
case replytoid = "replyToId"
case threadid = "threadId"
case sessionkey = "sessionKey"
case idempotencykey = "idempotencyKey"
@@ -719,17 +723,26 @@ public struct AgentIdentityResult: Codable, Sendable {
public let agentid: String
public let name: String?
public let avatar: String?
public let avatarsource: String?
public let avatarstatus: String?
public let avatarreason: String?
public let emoji: String?
public init(
agentid: String,
name: String?,
avatar: String?,
avatarsource: String?,
avatarstatus: String?,
avatarreason: String?,
emoji: String?)
{
self.agentid = agentid
self.name = name
self.avatar = avatar
self.avatarsource = avatarsource
self.avatarstatus = avatarstatus
self.avatarreason = avatarreason
self.emoji = emoji
}
@@ -737,6 +750,9 @@ public struct AgentIdentityResult: Codable, Sendable {
case agentid = "agentId"
case name
case avatar
case avatarsource = "avatarSource"
case avatarstatus = "avatarStatus"
case avatarreason = "avatarReason"
case emoji
}
}
@@ -2321,6 +2337,62 @@ public struct TalkConfigResult: Codable, Sendable {
}
}
public struct TalkRealtimeSessionParams: Codable, Sendable {
public let sessionkey: String?
public let provider: String?
public let model: String?
public let voice: String?
public init(
sessionkey: String?,
provider: String?,
model: String?,
voice: String?)
{
self.sessionkey = sessionkey
self.provider = provider
self.model = model
self.voice = voice
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case provider
case model
case voice
}
}
public struct TalkRealtimeSessionResult: Codable, Sendable {
public let provider: String
public let clientsecret: String
public let model: String?
public let voice: String?
public let expiresat: Double?
public init(
provider: String,
clientsecret: String,
model: String?,
voice: String?,
expiresat: Double?)
{
self.provider = provider
self.clientsecret = clientsecret
self.model = model
self.voice = voice
self.expiresat = expiresat
}
private enum CodingKeys: String, CodingKey {
case provider
case clientsecret = "clientSecret"
case model
case voice
case expiresat = "expiresAt"
}
}
public struct TalkSpeakParams: Codable, Sendable {
public let text: String
public let voiceid: String?
@@ -2550,18 +2622,22 @@ public struct WebLoginStartParams: Codable, Sendable {
public struct WebLoginWaitParams: Codable, Sendable {
public let timeoutms: Int?
public let accountid: String?
public let currentqrdataurl: String?
public init(
timeoutms: Int?,
accountid: String?)
accountid: String?,
currentqrdataurl: String?)
{
self.timeoutms = timeoutms
self.accountid = accountid
self.currentqrdataurl = currentqrdataurl
}
private enum CodingKeys: String, CodingKey {
case timeoutms = "timeoutMs"
case accountid = "accountId"
case currentqrdataurl = "currentQrDataUrl"
}
}

View File

@@ -1,4 +1,4 @@
b05357fa162ba1f1d4ed192671b758d3905602678ff61148568840c6544d6222 config-baseline.json
a4e167f169db58d71c385a31fa2b980772f9fee963e70dd9553f63536cae5aed config-baseline.core.json
35d132fe176bd2bf9f0e46b29de91baba63ec4db3317cc5b294a982b46d16ba9 config-baseline.channel.json
3703c5345288adb9eee8cda3b592147cf4fed25a7782bed21ca83c88c3ca1cc0 config-baseline.plugin.json
c8d24c55df89a76f44cd6ab5fdb7c28b0b3a8adadcd2c94a1d81263512075c0f config-baseline.json
97c37380e03c167ee710adb0ee297573146e78434635780226b744841628370b config-baseline.core.json
7cd9c908f066c143eab2a201efbc9640f483ab28bba92ddeca1d18cc2b528bc3 config-baseline.channel.json
7825b56a5b3fcdbe2e09ef8fe5d9f12ac3598435afebe20413051e45b0d1968e config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
2b7093a57992029cc70126d33544e02eed6c3076a3a6b4ffa6aef7664da0f33d plugin-sdk-api-baseline.json
ea6a2f2326565517b6c42a4d334f615163fb434dbad5e0b8d134c92767714256 plugin-sdk-api-baseline.jsonl
f813474b1623f06e1465daacd56db970e8e92ab1be122faee0fa2a1dc2d4fc43 plugin-sdk-api-baseline.json
b3ea88c0c9b4cf6d9a46f0d34149063303853e78ef9708224608e4da79b23190 plugin-sdk-api-baseline.jsonl

View File

@@ -0,0 +1,78 @@
[
{
"source": "ACP",
"target": "ACP"
},
{
"source": "Active Memory",
"target": "Active Memory"
},
{
"source": "ClawHub",
"target": "ClawHub"
},
{
"source": "CLI",
"target": "CLI"
},
{
"source": "Compaction",
"target": "Compaction"
},
{
"source": "Cron",
"target": "Cron"
},
{
"source": "Dreaming",
"target": "Dreaming"
},
{
"source": "Gateway",
"target": "Gateway"
},
{
"source": "Heartbeat",
"target": "Heartbeat"
},
{
"source": "Mintlify",
"target": "Mintlify"
},
{
"source": "Node",
"target": "Node"
},
{
"source": "OpenClaw",
"target": "OpenClaw"
},
{
"source": "Pi",
"target": "Pi"
},
{
"source": "Plugin",
"target": "Plugin"
},
{
"source": "Skills",
"target": "Skills"
},
{
"source": "Tailscale",
"target": "Tailscale"
},
{
"source": "TaskFlow",
"target": "TaskFlow"
},
{
"source": "TUI",
"target": "TUI"
},
{
"source": "Webhook",
"target": "Webhook"
}
]

View File

@@ -3,6 +3,18 @@
"source": "OpenClaw",
"target": "OpenClaw"
},
{
"source": "OpenAI",
"target": "OpenAI"
},
{
"source": "OpenAI provider",
"target": "OpenAI provider"
},
{
"source": "Status",
"target": "Status"
},
{
"source": "Gateway",
"target": "Gateway 网关"
@@ -11,6 +23,30 @@
"source": "Pi",
"target": "Pi"
},
{
"source": "Agent runtimes",
"target": "Agent Runtimes"
},
{
"source": "Agent Runtimes",
"target": "Agent Runtimes"
},
{
"source": "Codex harness",
"target": "Codex harness"
},
{
"source": "Agent harness plugins",
"target": "Agent harness plugins"
},
{
"source": "Agent loop",
"target": "Agent loop"
},
{
"source": "Models",
"target": "Models"
},
{
"source": "Skills",
"target": "Skills"
@@ -75,6 +111,10 @@
"source": "BytePlus (International)",
"target": "BytePlus国际版"
},
{
"source": "Amazon Bedrock Mantle",
"target": "Amazon Bedrock Mantle"
},
{
"source": "Anthropic (API + Claude CLI)",
"target": "AnthropicAPI + Claude CLI"
@@ -319,14 +359,26 @@
"source": "env var",
"target": "环境变量"
},
{
"source": "Google Meet Plugin",
"target": "Google Meet 插件"
},
{
"source": "Plugin SDK",
"target": "插件 SDK"
},
{
"source": "Building plugins",
"target": "构建插件"
},
{
"source": "Plugin SDK Overview",
"target": "插件 SDK 概览"
},
{
"source": "Plugin SDK overview",
"target": "插件 SDK 概览"
},
{
"source": "SDK Overview",
"target": "SDK 概览"
@@ -335,6 +387,22 @@
"source": "Plugin Entry Points",
"target": "插件入口点"
},
{
"source": "Plugin entry points",
"target": "插件入口点"
},
{
"source": "Plugin hooks",
"target": "插件钩子"
},
{
"source": "Internal hooks",
"target": "内部钩子"
},
{
"source": "Plugin architecture internals",
"target": "插件架构内部机制"
},
{
"source": "Entry Points",
"target": "入口点"
@@ -379,6 +447,26 @@
"source": "Testing",
"target": "测试"
},
{
"source": "Async Exec Duplicate Completion Investigation",
"target": "Async Exec Duplicate Completion Investigation"
},
{
"source": "QA Refactor",
"target": "QA 重构"
},
{
"source": "Rich Output Protocol",
"target": "富输出协议"
},
{
"source": "Tencent Cloud (TokenHub)",
"target": "腾讯云TokenHub"
},
{
"source": "Codex Harness Context Engine Port",
"target": "Codex Harness Context Engine Port"
},
{
"source": "/gateway/configuration#strict-validation",
"target": "/gateway/configuration#strict-validation"

View File

@@ -5,8 +5,8 @@ This directory owns docs authoring, Mintlify link rules, and docs i18n policy.
## Mintlify Rules
- Docs are hosted on Mintlify (`https://docs.openclaw.ai`).
- Internal doc links in `docs/**/*.md` must stay root-relative with no `.md` or `.mdx` suffix (example: `[Config](/configuration)`).
- Section cross-references should use anchors on root-relative paths (example: `[Hooks](/configuration#hooks)`).
- Internal doc links in `docs/**/*.md` must stay root-relative with no `.md` or `.mdx` suffix (example: `[Config](/gateway/configuration)`).
- Section cross-references should use anchors on root-relative paths (example: `[Hooks](/gateway/configuration-reference#hooks)`).
- Doc headings should avoid em dashes and apostrophes because Mintlify anchor generation is brittle there.
- README and other GitHub-rendered docs should keep absolute docs URLs so links work outside Mintlify.
- Docs content must stay generic: no personal device names, hostnames, or local paths; use placeholders like `user@gateway-host`.

View File

@@ -1,13 +1,11 @@
---
title: "Auth Credential Semantics"
summary: "Canonical credential eligibility and resolution semantics for auth profiles"
title: "Auth credential semantics"
read_when:
- Working on auth profile resolution or credential routing
- Debugging model auth failures or profile order
---
# Auth Credential Semantics
This document defines the canonical credential eligibility and resolution semantics used across:
- `resolveAuthProfileOrder`
@@ -78,3 +76,8 @@ For script compatibility, probe errors keep this first line unchanged:
`Auth profile credentials are missing or expired.`
Human-friendly detail and stable reason codes may be added on subsequent lines.
## Related
- [Secrets management](/gateway/secrets)
- [Auth storage](/concepts/oauth)

View File

@@ -1,8 +1,11 @@
---
summary: "Redirect to /gateway/authentication"
title: "Auth Monitoring"
title: "Auth monitoring"
---
# Auth Monitoring
This page moved to [Authentication](/gateway/authentication). See [Authentication](/gateway/authentication) for auth monitoring documentation.
## Related
- [Automation troubleshooting](/automation/troubleshooting)
- [Hooks](/automation/hooks)

View File

@@ -3,6 +3,10 @@ summary: "Redirect to Task Flow"
title: "ClawFlow"
---
# ClawFlow
ClawFlow was renamed to [Task Flow](/automation/taskflow). See [Task Flow](/automation/taskflow) for the current documentation.
## Related
- [Task flow](/automation/taskflow)
- [Standing orders](/automation/standing-orders)
- [Hooks](/automation/hooks)

View File

@@ -4,11 +4,9 @@ read_when:
- Scheduling background jobs or wakeups
- Wiring external triggers (webhooks, Gmail) into OpenClaw
- Deciding between heartbeat and cron for scheduled tasks
title: "Scheduled Tasks"
title: "Scheduled tasks"
---
# Scheduled Tasks (Cron)
Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at the right time, and can deliver output back to a chat channel or webhook endpoint.
## Quick start
@@ -88,12 +86,21 @@ This fires ~56 times per month instead of 01 times per month. OpenClaw use
**Main session** jobs enqueue a system event and optionally wake the heartbeat (`--wake now` or `--wake next-heartbeat`). **Isolated** jobs run a dedicated agent turn with a fresh session. **Custom sessions** (`session:xxx`) persist context across runs, enabling workflows like daily standups that build on previous summaries.
For isolated jobs, “fresh session” means a new transcript/session id for each run. OpenClaw may carry safe preferences such as thinking/fast/verbose settings, labels, and explicit user-selected model/auth overrides, but it does not inherit ambient conversation context from an older cron row: channel/group routing, send or queue policy, elevation, origin, or ACP runtime binding. Use `current` or `session:<id>` when a recurring job should deliberately build on the same conversation context.
For isolated jobs, runtime teardown now includes best-effort browser cleanup for that cron session. Cleanup failures are ignored so the actual cron result still wins.
Isolated cron runs also dispose any bundled MCP runtime instances created for the job through the shared runtime-cleanup path. This matches how main-session and custom-session MCP clients are torn down, so isolated cron jobs do not leak stdio child processes or long-lived MCP connections across runs.
When isolated cron runs orchestrate subagents, delivery also prefers the final
descendant output over stale parent interim text. If descendants are still
running, OpenClaw suppresses that partial parent update instead of announcing it.
For text-only Discord announce targets, OpenClaw sends the canonical final
assistant text once instead of replaying both streamed/intermediate text payloads
and the final answer. Media and structured Discord payloads are still delivered
as separate payloads so attachments and components are not dropped.
### Payload options for isolated jobs
- `--message`: prompt text (required for isolated)
@@ -111,7 +118,7 @@ Model-selection precedence for isolated jobs is:
1. Gmail hook model override (when the run came from Gmail and that override is allowed)
2. Per-job payload `model`
3. Stored cron session model override
3. User-selected stored cron session model override
4. Agent/default model selection
Fast mode follows the resolved live selection too. If the selected model config
@@ -119,10 +126,11 @@ has `params.fastMode`, isolated cron uses that by default. A stored session
`fastMode` override still wins over config in either direction.
If an isolated run hits a live model-switch handoff, cron retries with the
switched provider/model and persists that live selection before retrying. When
the switch also carries a new auth profile, cron persists that auth profile
override too. Retries are bounded: after the initial attempt plus 2 switch
retries, cron aborts instead of looping forever.
switched provider/model and persists that live selection for the active run
before retrying. When the switch also carries a new auth profile, cron persists
that auth profile override for the active run too. Retries are bounded: after
the initial attempt plus 2 switch retries, cron aborts instead of looping
forever.
## Delivery and output
@@ -233,7 +241,7 @@ Run an isolated agent turn:
curl -X POST http://127.0.0.1:18789/hooks/agent \
-H 'Authorization: Bearer SECRET' \
-H 'Content-Type: application/json' \
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.4-mini"}'
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.4"}'
```
Fields: `message` (required), `name`, `agentId`, `wakeMode`, `deliver`, `channel`, `to`, `model`, `thinking`, `timeoutSeconds`.

View File

@@ -1,8 +1,11 @@
---
summary: "Redirect to /automation"
title: "Cron vs Heartbeat"
title: "Cron vs heartbeat"
---
# Cron vs Heartbeat
This page moved to [Automation & Tasks](/automation). See [Automation & Tasks](/automation) for the decision guide comparing cron and heartbeat.
## Related
- [Scheduled tasks](/automation/cron-jobs)
- [Background tasks](/automation/tasks)

View File

@@ -3,6 +3,9 @@ summary: "Redirect to /automation/cron-jobs"
title: "Gmail PubSub"
---
# Gmail PubSub
This page moved to [Scheduled Tasks](/automation/cron-jobs#gmail-pubsub-integration). See [Scheduled Tasks](/automation/cron-jobs#gmail-pubsub-integration) for Gmail PubSub documentation.
## Related
- [Webhook](/automation/webhook)
- [Automation troubleshooting](/automation/troubleshooting)

View File

@@ -6,8 +6,6 @@ read_when:
title: "Hooks"
---
# Hooks
Hooks are small scripts that run when something happens inside the Gateway. They can be discovered from directories and inspected with `openclaw hooks`. The Gateway loads internal hooks only after you enable hooks or configure at least one hook entry, hook pack, legacy handler, or extra hook directory.
There are two kinds of hooks in OpenClaw:
@@ -108,7 +106,7 @@ const handler = async (event) => {
export default handler;
```
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push to send to user), and `context` (event-specific data).
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push to send to user), and `context` (event-specific data). Agent and tool plugin hook contexts can also include `trace`, a read-only W3C-compatible diagnostic trace context that plugins may pass into structured logs for OTEL correlation.
### Event context highlights
@@ -207,9 +205,12 @@ Runs `BOOT.md` from the active workspace when the gateway starts.
## Plugin hooks
Plugins can register hooks through the Plugin SDK for deeper integration: intercepting tool calls, modifying prompts, controlling message flow, and more. The Plugin SDK exposes 28 hooks covering model resolution, agent lifecycle, message flow, tool execution, subagent coordination, and gateway lifecycle.
Plugins can register typed hooks through the Plugin SDK for deeper integration:
intercepting tool calls, modifying prompts, controlling message flow, and more.
Use plugin hooks when you need `before_tool_call`, `before_agent_reply`,
`before_install`, or other in-process lifecycle hooks.
For the complete plugin hook reference including `before_tool_call`, `before_agent_reply`, `before_install`, and all other plugin hooks, see [Plugin Architecture](/plugins/architecture#provider-runtime-hooks).
For the complete plugin hook reference, see [Plugin hooks](/plugins/hooks).
## Configuration
@@ -317,5 +318,5 @@ Check for missing binaries (PATH), environment variables, config values, or OS c
- [CLI Reference: hooks](/cli/hooks)
- [Webhooks](/automation/cron-jobs#webhooks)
- [Plugin Architecture](/plugins/architecture#provider-runtime-hooks) — full plugin hook reference
- [Plugin hooks](/plugins/hooks) — in-process plugin lifecycle hooks
- [Configuration](/gateway/configuration-reference#hooks)

View File

@@ -4,11 +4,9 @@ read_when:
- Deciding how to automate work with OpenClaw
- Choosing between heartbeat, cron, hooks, and standing orders
- Looking for the right automation entry point
title: "Automation & Tasks"
title: "Automation & tasks"
---
# Automation & Tasks
OpenClaw runs work in the background through tasks, scheduled jobs, event hooks, and standing instructions. This page helps you choose the right mechanism and understand how they fit together.
## Quick decision guide
@@ -42,7 +40,7 @@ flowchart TD
| Audit what ran and when | Background Tasks | `openclaw tasks list` and `openclaw tasks audit` |
| Multi-step research then summarize | Task Flow | Durable orchestration with revision tracking |
| Run a script on session reset | Hooks | Event-driven, fires on lifecycle events |
| Execute code on every tool call | Hooks | Hooks can filter by event type |
| Execute code on every tool call | Plugin hooks | In-process hooks can intercept tool calls |
| Always check compliance before replying | Standing Orders | Injected into every session automatically |
### Scheduled Tasks (Cron) vs Heartbeat
@@ -85,7 +83,11 @@ See [Standing Orders](/automation/standing-orders).
### Hooks
Hooks are event-driven scripts triggered by agent lifecycle events (`/new`, `/reset`, `/stop`), session compaction, gateway startup, message flow, and tool calls. Hooks are automatically discovered from directories and can be managed with `openclaw hooks`.
Internal hooks are event-driven scripts triggered by agent lifecycle events
(`/new`, `/reset`, `/stop`), session compaction, gateway startup, and message
flow. They are automatically discovered from directories and can be managed
with `openclaw hooks`. For in-process tool-call interception, use
[Plugin hooks](/plugins/hooks).
See [Hooks](/automation/hooks).
@@ -99,7 +101,7 @@ See [Heartbeat](/gateway/heartbeat).
- **Cron** handles precise schedules (daily reports, weekly reviews) and one-shot reminders. All cron executions create task records.
- **Heartbeat** handles routine monitoring (inbox, calendar, notifications) in one batched turn every 30 minutes.
- **Hooks** react to specific events (tool calls, session resets, compaction) with custom scripts.
- **Hooks** react to specific events (session resets, compaction, message flow) with custom scripts. Plugin hooks cover tool calls.
- **Standing orders** give the agent persistent context and authority boundaries.
- **Task Flow** coordinates multi-step flows above individual tasks.
- **Tasks** automatically track all detached work so you can inspect and audit it.
@@ -110,6 +112,7 @@ See [Heartbeat](/gateway/heartbeat).
- [Background Tasks](/automation/tasks) — task ledger for all detached work
- [Task Flow](/automation/taskflow) — durable multi-step flow orchestration
- [Hooks](/automation/hooks) — event-driven lifecycle scripts
- [Plugin hooks](/plugins/hooks) — in-process tool, prompt, message, and lifecycle hooks
- [Standing Orders](/automation/standing-orders) — persistent agent instructions
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
- [Configuration Reference](/gateway/configuration-reference) — all config keys

View File

@@ -1,8 +1,12 @@
---
summary: "Redirect to /tools/message"
summary: "Redirect to /cli/message"
title: "Polls"
---
# Polls
This page moved to [Message tool](/cli/message). See [Message tool](/cli/message) for poll documentation.
## Related
- [Webhook](/automation/webhook)
- [Scheduled tasks](/automation/cron-jobs)
- [Background tasks](/automation/tasks)

View File

@@ -4,11 +4,9 @@ read_when:
- Setting up autonomous agent workflows that run without per-task prompting
- Defining what the agent can do independently vs. what needs human approval
- Structuring multi-program agents with clear boundaries and escalation rules
title: "Standing Orders"
title: "Standing orders"
---
# Standing Orders
Standing orders grant your agent **permanent operating authority** for defined programs. Instead of giving individual task instructions each time, you define programs with clear scope, triggers, and escalation rules — and the agent executes autonomously within those boundaries.
This is the difference between telling your assistant "send the weekly report" every Friday vs. granting standing authority: "You own the weekly report. Compile it every Friday, send it, and only escalate if something looks wrong."
@@ -29,7 +27,7 @@ This is the difference between telling your assistant "send the weekly report" e
- You only get involved for exceptions and approvals
- The agent fills idle time productively
## How They Work
## How they work
Standing orders are defined in your [agent workspace](/concepts/agent-workspace) files. The recommended approach is to include them directly in `AGENTS.md` (which is auto-injected every session) so the agent always has them in context. For larger configurations, you can also place them in a dedicated file like `standing-orders.md` and reference it from `AGENTS.md`.
@@ -200,8 +198,6 @@ This pattern prevents the most common agent failure mode: acknowledging a task w
For agents managing multiple concerns, organize standing orders as separate programs with clear boundaries:
```markdown
# Standing Orders
## Program 1: [Domain A] (Weekly)
...

View File

@@ -4,11 +4,9 @@ read_when:
- You want to understand how Task Flow relates to background tasks
- You encounter Task Flow or openclaw tasks flow in release notes or docs
- You want to inspect or manage durable flow state
title: "Task Flow"
title: "Task flow"
---
# Task Flow
Task Flow is the flow orchestration substrate that sits above [background tasks](/automation/tasks). It manages durable multi-step flows with their own state, revision tracking, and sync semantics while individual tasks remain the unit of detached work.
## When to use Task Flow
@@ -22,6 +20,78 @@ Use Task Flow when work spans multiple sequential or branching steps and you nee
| Observe externally created tasks | Task Flow (mirrored) |
| One-shot reminder | Cron job |
## Reliable scheduled workflow pattern
For recurring workflows such as market intelligence briefings, treat the schedule, orchestration, and reliability checks as separate layers:
1. Use [Scheduled Tasks](/automation/cron-jobs) for timing.
2. Use a persistent cron session when the workflow should build on prior context.
3. Use [Lobster](/tools/lobster) for deterministic steps, approval gates, and resume tokens.
4. Use Task Flow to track the multi-step run across child tasks, waits, retries, and gateway restarts.
Example cron shape:
```bash
openclaw cron add \
--name "Market intelligence brief" \
--cron "0 7 * * 1-5" \
--tz "America/New_York" \
--session session:market-intel \
--message "Run the market-intel Lobster workflow. Verify source freshness before summarizing." \
--announce \
--channel slack \
--to "channel:C1234567890"
```
Use `session:<id>` instead of `isolated` when the recurring workflow needs deliberate history, previous run summaries, or standing context. Use `isolated` when each run should start fresh and all required state is explicit in the workflow.
Inside the workflow, put reliability checks before the LLM summary step:
```yaml
name: market-intel-brief
steps:
- id: preflight
command: market-intel check --json
- id: collect
command: market-intel collect --json
stdin: $preflight.json
- id: summarize
command: market-intel summarize --json
stdin: $collect.json
- id: approve
command: market-intel deliver --preview
stdin: $summarize.json
approval: required
- id: deliver
command: market-intel deliver --execute
stdin: $summarize.json
condition: $approve.approved
```
Recommended preflight checks:
- Browser availability and profile choice, for example `openclaw` for managed state or `user` when a signed-in Chrome session is required. See [Browser](/tools/browser).
- API credentials and quota for each source.
- Network reachability for required endpoints.
- Required tools enabled for the agent, such as `lobster`, `browser`, and `llm-task`.
- Failure destination configured for cron so preflight failures are visible. See [Scheduled Tasks](/automation/cron-jobs#delivery-and-output).
Recommended data provenance fields for every collected item:
```json
{
"sourceUrl": "https://example.com/report",
"retrievedAt": "2026-04-24T12:00:00Z",
"asOf": "2026-04-24",
"title": "Example report",
"content": "..."
}
```
Have the workflow reject or mark stale items before summarization. The LLM step should receive only structured JSON and should be asked to preserve `sourceUrl`, `retrievedAt`, and `asOf` in its output. Use [LLM Task](/tools/llm-task) when you need a schema-validated model step inside the workflow.
For reusable team or community workflows, package the CLI, `.lobster` files, and any setup notes as a skill or plugin and publish it through [ClawHub](/tools/clawhub). Keep workflow-specific guardrails in that package unless the plugin API is missing a needed generic capability.
## Sync modes
### Managed mode
@@ -77,6 +147,6 @@ Flows coordinate tasks, not replace them. A single flow may drive multiple backg
## Related
- [Background Tasks](/automation/tasks) — the detached work ledger that flows coordinate
- [CLI: tasks](/cli/index#tasks) — CLI command reference for `openclaw tasks flow`
- [CLI: tasks](/cli/tasks) — CLI command reference for `openclaw tasks flow`
- [Automation Overview](/automation) — all automation mechanisms at a glance
- [Cron Jobs](/automation/cron-jobs) — scheduled jobs that may feed into flows

View File

@@ -4,11 +4,9 @@ read_when:
- Inspecting background work in progress or recently completed
- Debugging delivery failures for detached agent runs
- Understanding how background runs relate to sessions, cron, and heartbeat
title: "Background Tasks"
title: "Background tasks"
---
# Background Tasks
> **Looking for scheduling?** See [Automation & Tasks](/automation) for choosing the right mechanism. This page covers **tracking** background work, not scheduling it.
Background tasks track work that runs **outside your main conversation session**:
@@ -325,4 +323,4 @@ A task's `runId` links to the agent run doing the work. Agent lifecycle events (
- [Task Flow](/automation/taskflow) — flow orchestration above tasks
- [Scheduled Tasks](/automation/cron-jobs) — scheduling background work
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
- [CLI: Tasks](/cli/index#tasks) — CLI command reference
- [CLI: Tasks](/cli/tasks) — CLI command reference

View File

@@ -1,8 +1,12 @@
---
summary: "Redirect to /automation/cron-jobs"
title: "Automation Troubleshooting"
title: "Automation troubleshooting"
---
# Automation Troubleshooting
This page moved to [Scheduled Tasks](/automation/cron-jobs#troubleshooting). See [Scheduled Tasks](/automation/cron-jobs#troubleshooting) for troubleshooting documentation.
## Related
- [Hooks](/automation/hooks)
- [Background tasks](/automation/tasks)
- [Gateway troubleshooting](/gateway/troubleshooting)

View File

@@ -3,6 +3,10 @@ summary: "Redirect to /automation/cron-jobs"
title: "Webhooks"
---
# Webhooks
This page moved to [Scheduled Tasks](/automation/cron-jobs#webhooks). See [Scheduled Tasks](/automation/cron-jobs#webhooks) for webhook documentation.
## Related
- [Poll](/automation/poll)
- [Gmail PubSub](/automation/gmail-pubsub)
- [Hooks](/automation/hooks)

View File

@@ -3,7 +3,7 @@ summary: "Brave Search API setup for web_search"
read_when:
- You want to use Brave Search for web_search
- You need a BRAVE_API_KEY or plan details
title: "Brave Search (legacy path)"
title: "Brave search (legacy path)"
---
# Brave Search API
@@ -101,3 +101,7 @@ await web_search({
- Results are cached for 15 minutes by default (configurable via `cacheTtlMinutes`).
See [Web tools](/tools/web) for the full web_search configuration.
## Related
- [Brave search](/tools/brave-search)

View File

@@ -7,8 +7,6 @@ read_when:
title: "BlueBubbles"
---
# BlueBubbles (macOS REST)
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **Recommended for iMessage integration** due to its richer API and easier setup compared to the legacy imsg channel.
## Bundled plugin
@@ -393,6 +391,8 @@ Use full IDs for durable automations and storage:
See [Configuration](/gateway/configuration) for template variables.
<a id="coalescing-split-send-dms-command--url-in-one-composition"></a>
## Coalescing split-send DMs (command + URL in one composition)
When a user types a command and a URL together in iMessage — e.g. `Dump https://example.com/article` — Apple splits the send into **two separate webhook deliveries**:

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