Skip to content

Commit 47560da

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents 9768eb4 + a35ac86 commit 47560da

331 files changed

Lines changed: 17658 additions & 2437 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/openclaw-parallels-smoke/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
4545
## macOS flow
4646

4747
- Preferred entrypoint: `pnpm test:parallels:macos`
48+
- 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.
49+
- If that release-to-dev lane fails with `reason=preflight-no-good-commit` and repeated `sh: pnpm: command not found` tails from `preflight build`, treat it as an updater regression first. The fix belongs in the git/dev updater bootstrap path, not in Parallels retry logic.
4850
- Default to the snapshot closest to `macOS 26.3.1 latest`.
4951
- On Peter's Tahoe VM, `fresh-latest-march-2026` can hang in `prlctl snapshot-switch`; if restore times out there, rerun with `--snapshot-hint 'macOS 26.3.1 latest'` before blaming auth or the harness.
5052
- `parallels-macos-smoke.sh` now retries `snapshot-switch` once after force-stopping a stuck running/suspended guest. If Tahoe still times out after that recovery path, then treat it as a real Parallels/host issue and rerun manually.

.github/labeler.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@
6464
- any-glob-to-any-file:
6565
- "extensions/qqbot/**"
6666
- "docs/channels/qqbot.md"
67+
"channel: qa-channel":
68+
- changed-files:
69+
- any-glob-to-any-file:
70+
- "extensions/qa-channel/**"
71+
- "docs/channels/qa-channel.md"
72+
"extensions: qa-lab":
73+
- changed-files:
74+
- any-glob-to-any-file:
75+
- "extensions/qa-lab/**"
76+
- "docs/concepts/qa-e2e-automation.md"
77+
- "docs/channels/qa-channel.md"
6778
"channel: signal":
6879
- changed-files:
6980
- any-glob-to-any-file:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,5 @@ changelog/fragments/
148148
.artifacts/
149149
test/fixtures/openclaw-vitest-unit-report.json
150150
analysis/
151+
.artifacts/qa-e2e/
152+
extensions/qa-lab/web/dist/

CHANGELOG.md

Lines changed: 49 additions & 33 deletions
Large diffs are not rendered by default.

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ RUN pnpm build:docker
9797
# Force pnpm for UI build (Bun may fail on ARM/Synology architectures)
9898
ENV OPENCLAW_PREFER_PNPM=1
9999
RUN pnpm ui:build
100+
RUN pnpm qa:lab:build
100101

101102
# Prune dev dependencies and strip build-only metadata before copying
102103
# runtime assets into the final image.
@@ -156,6 +157,7 @@ COPY --from=runtime-assets --chown=node:node /app/openclaw.mjs .
156157
COPY --from=runtime-assets --chown=node:node /app/${OPENCLAW_BUNDLED_PLUGIN_DIR} ./${OPENCLAW_BUNDLED_PLUGIN_DIR}
157158
COPY --from=runtime-assets --chown=node:node /app/skills ./skills
158159
COPY --from=runtime-assets --chown=node:node /app/docs ./docs
160+
COPY --from=runtime-assets --chown=node:node /app/qa ./qa
159161

160162
# In npm-installed Docker images, prefer the copied source extension tree for
161163
# bundled discovery so package metadata that points at source entries stays valid.

SECURITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ When patching a GHSA via `gh api`, include `X-GitHub-Api-Version: 2022-11-28` (o
9797
OpenClaw does **not** model one gateway as a multi-tenant, adversarial user boundary.
9898

9999
- Authenticated Gateway callers are treated as trusted operators for that gateway instance.
100+
- Direct localhost/loopback Control UI and Gateway WebSocket sessions authenticated with the shared gateway secret (`token` / `password`) are in that same trusted-operator bucket. Local auto-paired device sessions on that path are expected to retain full localhost operator capability; they do not create a separate `operator.write` vs `operator.admin` security boundary.
100101
- The HTTP compatibility endpoints (`POST /v1/chat/completions`, `POST /v1/responses`) and direct tool endpoint (`POST /tools/invoke`) are in that same trusted-operator bucket. Passing Gateway bearer auth there is equivalent to operator access for that gateway; they do not implement a narrower `operator.write` vs `operator.admin` trust split.
101102
- Concretely, on the OpenAI-compatible HTTP surface:
102103
- shared-secret bearer auth (`token` / `password`) authenticates possession of the gateway operator secret

docs/channels/matrix.md

Lines changed: 157 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ This is a practical baseline config with DM pairing, room allowlist, and E2EE en
178178

179179
Matrix reply streaming is opt-in.
180180

181-
Set `channels.matrix.streaming` to `"partial"` when you want OpenClaw to send a single draft reply,
182-
edit that draft in place while the model is generating text, and then finalize it when the reply is
183-
done:
181+
Set `channels.matrix.streaming` to `"partial"` when you want OpenClaw to send a single live preview
182+
reply, edit that preview in place while the model is generating text, and then finalize it when the
183+
reply is done:
184184

185185
```json5
186186
{
@@ -193,15 +193,164 @@ done:
193193
```
194194

195195
- `streaming: "off"` is the default. OpenClaw waits for the final reply and sends it once.
196-
- `streaming: "partial"` creates one editable preview message for the current assistant block instead of sending multiple partial messages.
197-
- `blockStreaming: true` enables separate Matrix progress messages. With `streaming: "partial"`, Matrix keeps the live draft for the current block and preserves completed blocks as separate messages.
198-
- When `streaming: "partial"` and `blockStreaming` is off, Matrix only edits the live draft and sends the completed reply once that block or turn finishes.
196+
- `streaming: "partial"` creates one editable preview message for the current assistant block using normal Matrix text messages. This preserves Matrix's legacy preview-first notification behavior, so stock clients may notify on the first streamed preview text instead of the finished block.
197+
- `streaming: "quiet"` creates one editable quiet preview notice for the current assistant block. Use this only when you also configure recipient push rules for finalized preview edits.
198+
- `blockStreaming: true` enables separate Matrix progress messages. With preview streaming enabled, Matrix keeps the live draft for the current block and preserves completed blocks as separate messages.
199+
- When preview streaming is on and `blockStreaming` is off, Matrix edits the live draft in place and finalizes that same event when the block or turn finishes.
199200
- If the preview no longer fits in one Matrix event, OpenClaw stops preview streaming and falls back to normal final delivery.
200201
- Media replies still send attachments normally. If a stale preview can no longer be reused safely, OpenClaw redacts it before sending the final media reply.
201202
- Preview edits cost extra Matrix API calls. Leave streaming off if you want the most conservative rate-limit behavior.
202203

203204
`blockStreaming` does not enable draft previews by itself.
204-
Use `streaming: "partial"` for preview edits; then add `blockStreaming: true` only if you also want completed assistant blocks to remain visible as separate progress messages.
205+
Use `streaming: "partial"` or `streaming: "quiet"` for preview edits; then add `blockStreaming: true` only if you also want completed assistant blocks to remain visible as separate progress messages.
206+
207+
If you need stock Matrix notifications without custom push rules, use `streaming: "partial"` for preview-first behavior or leave `streaming` off for final-only delivery. With `streaming: "off"`:
208+
209+
- `blockStreaming: true` sends each finished block as a normal notifying Matrix message.
210+
- `blockStreaming: false` sends only the final completed reply as a normal notifying Matrix message.
211+
212+
### Self-hosted push rules for quiet finalized previews
213+
214+
If you run your own Matrix infrastructure and want quiet previews to notify only when a block or
215+
final reply is done, set `streaming: "quiet"` and add a per-user push rule for finalized preview edits.
216+
217+
This is usually a recipient-user setup, not a homeserver-global config change:
218+
219+
Quick map before you start:
220+
221+
- recipient user = the person who should receive the notification
222+
- bot user = the OpenClaw Matrix account that sends the reply
223+
- use the recipient user's access token for the API calls below
224+
- match `sender` in the push rule against the bot user's full MXID
225+
226+
1. Configure OpenClaw to use quiet previews:
227+
228+
```json5
229+
{
230+
channels: {
231+
matrix: {
232+
streaming: "quiet",
233+
},
234+
},
235+
}
236+
```
237+
238+
2. Make sure the recipient account already receives normal Matrix push notifications. Quiet preview
239+
rules only work if that user already has working pushers/devices.
240+
241+
3. Get the recipient user's access token.
242+
- Use the receiving user's token, not the bot's token.
243+
- Reusing an existing client session token is usually easiest.
244+
- If you need to mint a fresh token, you can log in through the standard Matrix Client-Server API:
245+
246+
```bash
247+
curl -sS -X POST \
248+
"https://matrix.example.org/_matrix/client/v3/login" \
249+
-H "Content-Type: application/json" \
250+
--data '{
251+
"type": "m.login.password",
252+
"identifier": {
253+
"type": "m.id.user",
254+
"user": "@alice:example.org"
255+
},
256+
"password": "REDACTED"
257+
}'
258+
```
259+
260+
4. Verify the recipient account already has pushers:
261+
262+
```bash
263+
curl -sS \
264+
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
265+
"https://matrix.example.org/_matrix/client/v3/pushers"
266+
```
267+
268+
If this returns no active pushers/devices, fix normal Matrix notifications first before adding the
269+
OpenClaw rule below.
270+
271+
OpenClaw marks finalized text-only preview edits with:
272+
273+
```json
274+
{
275+
"com.openclaw.finalized_preview": true
276+
}
277+
```
278+
279+
5. Create an override push rule for each recipient account which should receive these notifications:
280+
281+
```bash
282+
curl -sS -X PUT \
283+
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview" \
284+
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
285+
-H "Content-Type: application/json" \
286+
--data '{
287+
"conditions": [
288+
{ "kind": "event_match", "key": "type", "pattern": "m.room.message" },
289+
{
290+
"kind": "event_property_is",
291+
"key": "content.m\\.relates_to.rel_type",
292+
"value": "m.replace"
293+
},
294+
{
295+
"kind": "event_property_is",
296+
"key": "content.com\\.openclaw\\.finalized_preview",
297+
"value": true
298+
},
299+
{ "kind": "event_match", "key": "sender", "pattern": "@bot:example.org" }
300+
],
301+
"actions": [
302+
"notify",
303+
{ "set_tweak": "sound", "value": "default" },
304+
{ "set_tweak": "highlight", "value": false }
305+
]
306+
}'
307+
```
308+
309+
Replace these values before you run the command:
310+
311+
- `https://matrix.example.org`: your homeserver base URL
312+
- `$USER_ACCESS_TOKEN`: the receiving user's access token
313+
- `@bot:example.org`: your OpenClaw Matrix bot MXID, not the receiving user's MXID
314+
315+
The rule is evaluated against the event sender:
316+
317+
- authenticate with the receiving user's token
318+
- match `sender` against the OpenClaw bot MXID
319+
320+
6. Verify the rule exists:
321+
322+
```bash
323+
curl -sS \
324+
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
325+
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview"
326+
```
327+
328+
7. Test a streamed reply. In quiet mode, the room should show a quiet draft preview and the final
329+
in-place edit should notify once the block or turn finishes.
330+
331+
Notes:
332+
333+
- Create the rule with the receiving user's access token, not the bot's.
334+
- New user-defined `override` rules are inserted ahead of default suppress rules, so no extra ordering parameter is needed.
335+
- This only affects text-only preview edits that OpenClaw can safely finalize in place. Media fallbacks and stale-preview fallbacks still use normal Matrix delivery.
336+
- If `GET /_matrix/client/v3/pushers` shows no pushers, the user does not yet have working Matrix push delivery for this account/device.
337+
338+
#### Synapse
339+
340+
For Synapse, the setup above is usually enough by itself:
341+
342+
- No special `homeserver.yaml` change is required for finalized OpenClaw preview notifications.
343+
- If your Synapse deployment already sends normal Matrix push notifications, the user token + `pushrules` call above is the main setup step.
344+
- If you run Synapse behind a reverse proxy or workers, make sure `/_matrix/client/.../pushrules/` reaches Synapse correctly.
345+
- If you run Synapse workers, make sure pushers are healthy. Push delivery is handled by the main process or `synapse.app.pusher` / configured pusher workers.
346+
347+
#### Tuwunel
348+
349+
For Tuwunel, use the same setup flow and push-rule API call shown above:
350+
351+
- No Tuwunel-specific config is required for the finalized preview marker itself.
352+
- If normal Matrix notifications already work for that user, the user token + `pushrules` call above is the main setup step.
353+
- If notifications seem to disappear while the user is active on another device, check whether `suppress_push_when_active` is enabled. Tuwunel added this option in Tuwunel 1.4.2 on September 12, 2025, and it can intentionally suppress pushes to other devices while one device is active.
205354

206355
## Encryption and verification
207356

@@ -833,7 +982,7 @@ Live directory lookup uses the logged-in Matrix account:
833982
- `historyLimit`: max room messages to include as group history context. Falls back to `messages.groupChat.historyLimit`. Set `0` to disable.
834983
- `replyToMode`: `off`, `first`, or `all`.
835984
- `markdown`: optional Markdown rendering configuration for outbound Matrix text.
836-
- `streaming`: `off` (default), `partial`, `true`, or `false`. `partial` and `true` enable single-message draft previews with edit-in-place updates.
985+
- `streaming`: `off` (default), `partial`, `quiet`, `true`, or `false`. `partial` and `true` enable preview-first draft updates with normal Matrix text messages. `quiet` uses non-notifying preview notices for self-hosted push-rule setups.
837986
- `blockStreaming`: `true` enables separate progress messages for completed assistant blocks while draft preview streaming is active.
838987
- `threadReplies`: `off`, `inbound`, or `always`.
839988
- `threadBindings`: per-channel overrides for thread-bound session routing and lifecycle.

docs/channels/qa-channel.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
title: "QA Channel"
3+
summary: "Synthetic Slack-class channel plugin for deterministic OpenClaw QA scenarios"
4+
read_when:
5+
- You are wiring the synthetic QA transport into a local or CI test run
6+
- You need the bundled qa-channel config surface
7+
- You are iterating on end-to-end QA automation
8+
---
9+
10+
# QA Channel
11+
12+
`qa-channel` is a bundled synthetic message transport for automated OpenClaw QA.
13+
14+
It is not a production channel. It exists to exercise the same channel plugin
15+
boundary used by real transports while keeping state deterministic and fully
16+
inspectable.
17+
18+
## What it does today
19+
20+
- Slack-class target grammar:
21+
- `dm:<user>`
22+
- `channel:<room>`
23+
- `thread:<room>/<thread>`
24+
- HTTP-backed synthetic bus for:
25+
- inbound message injection
26+
- outbound transcript capture
27+
- thread creation
28+
- reactions
29+
- edits
30+
- deletes
31+
- search and read actions
32+
- Bundled host-side self-check runner that writes a Markdown report
33+
34+
## Config
35+
36+
```json
37+
{
38+
"channels": {
39+
"qa-channel": {
40+
"baseUrl": "http://127.0.0.1:43123",
41+
"botUserId": "openclaw",
42+
"botDisplayName": "OpenClaw QA",
43+
"allowFrom": ["*"],
44+
"pollTimeoutMs": 1000
45+
}
46+
}
47+
}
48+
```
49+
50+
Supported account keys:
51+
52+
- `baseUrl`
53+
- `botUserId`
54+
- `botDisplayName`
55+
- `pollTimeoutMs`
56+
- `allowFrom`
57+
- `defaultTo`
58+
- `actions.messages`
59+
- `actions.reactions`
60+
- `actions.search`
61+
- `actions.threads`
62+
63+
## Runner
64+
65+
Current vertical slice:
66+
67+
```bash
68+
pnpm qa:e2e
69+
```
70+
71+
This now routes through the bundled `qa-lab` extension. It starts the in-repo
72+
QA bus, boots the bundled `qa-channel` runtime slice, runs a deterministic
73+
self-check, and writes a Markdown report under `.artifacts/qa-e2e/`.
74+
75+
Private debugger UI:
76+
77+
```bash
78+
pnpm qa:lab:build
79+
pnpm openclaw qa ui
80+
```
81+
82+
Full repo-backed QA suite:
83+
84+
```bash
85+
pnpm openclaw qa suite
86+
```
87+
88+
That launches the private QA debugger at a local URL, separate from the
89+
shipped Control UI bundle.
90+
91+
## Scope
92+
93+
Current scope is intentionally narrow:
94+
95+
- bus + plugin transport
96+
- threaded routing grammar
97+
- channel-owned message actions
98+
- Markdown reporting
99+
100+
Follow-up work will add:
101+
102+
- Dockerized OpenClaw orchestration
103+
- provider/model matrix execution
104+
- richer scenario discovery
105+
- OpenClaw-native orchestration later

docs/cli/memory.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,14 @@ Full options:
9393
## Dreaming (experimental)
9494

9595
Dreaming is the background memory consolidation system with three cooperative
96-
phases: **light** (organize into daily note), **deep** (promote into
97-
`MEMORY.md`), and **REM** (reflect and find patterns in the daily note).
96+
phases: **light** (organize into `DREAMS.md` in inline mode), **deep**
97+
(promote into `MEMORY.md`), and **REM** (reflect and find patterns in
98+
`DREAMS.md` in inline mode).
9899

99100
- Enable with `plugins.entries.memory-core.config.dreaming.enabled: true`.
100101
- Toggle from chat with `/dreaming on|off` or `/dreaming enable|disable light|deep|rem`.
101102
- Each phase runs on its own cron schedule, managed automatically by `memory-core`.
102-
- Only the deep phase writes to `MEMORY.md`. Light and REM write to the daily note only.
103+
- Only the deep phase writes durable memory to `MEMORY.md`. With default inline storage, Light and REM write to `DREAMS.md`.
103104
- Ranking uses weighted signals: recall frequency, retrieval relevance, query diversity, temporal recency, cross-day consolidation, and derived concept richness.
104105
- Promotion re-reads the live daily note before writing to `MEMORY.md`, so edited or deleted short-term snippets do not get promoted from stale recall-store snapshots.
105106
- Scheduled and manual `memory promote` runs share the same deep phase defaults unless you pass CLI threshold overrides.

0 commit comments

Comments
 (0)