Skip to content

Commit b2689f6

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents 7a2613b + fd2c883 commit b2689f6

363 files changed

Lines changed: 9401 additions & 3179 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/blacksmith-testbox/SKILL.md

Lines changed: 92 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
---
22
name: blacksmith-testbox
33
description: >
4-
Validate code changes against real CI. Use for all tests, builds,
5-
migrations, and any command that depends on secrets or services.
6-
Use when testing, validating, checking, verifying, or before any
7-
commit or push.
4+
Validate code changes against real CI when local execution is not
5+
enough. Use for CI-parity checks, secrets/services, migrations, or
6+
builds/tests that cannot run reliably on the local machine. Do not
7+
replace repo-documented local test/build loops just because this
8+
skill exists.
89
---
910

1011
# Blacksmith Testbox
1112

13+
## Scope
14+
15+
Use Testbox when you need remote CI parity, injected secrets, hosted services,
16+
or an OS/runtime image that your local machine cannot provide cheaply.
17+
18+
Do not default to Testbox for every local test/build loop. If the repo has
19+
documented local commands for normal iteration, use those first so you keep
20+
warm caches, local build state, and fast feedback.
21+
22+
Testbox is the expensive path. Reach for it deliberately.
23+
1224
## Install the CLI
1325

1426
If `blacksmith` is not installed, install it:
@@ -55,10 +67,41 @@ Optional flags:
5567

5668
- `--dashboard-url <url>` — Override dashboard URL (e.g. for staging)
5769

70+
## Decide first: local or Testbox
71+
72+
Before warming anything up, check the repo's own instructions.
73+
74+
Prefer local commands when:
75+
76+
- the repo documents a supported local test/build workflow
77+
- you are iterating on unit tests, lint, typecheck, formatting, or other
78+
local-only validation
79+
- the value comes from warm local caches and fast repeat runs
80+
- the command does not need remote secrets, hosted services, or CI-only images
81+
82+
Prefer Testbox when:
83+
84+
- the repo explicitly requires CI-parity or remote validation
85+
- the command needs secrets, service containers, or provisioned infra
86+
- you are reproducing CI-only failures
87+
- you need the exact workflow image/job environment from GitHub Actions
88+
89+
For OpenClaw specifically, normal local iteration should stay local:
90+
91+
- `pnpm check:changed`
92+
- `pnpm test:changed`
93+
- `pnpm test <path-or-filter>`
94+
- `pnpm test:serial`
95+
- `pnpm build`
96+
97+
Only use Testbox in OpenClaw when the user explicitly wants CI-parity or the
98+
check truly depends on remote secrets/services that the local repo loop cannot
99+
provide.
100+
58101
## Setup: Warmup before coding
59102

60-
Before writing any code, warm up a testbox. This returns an ID instantly
61-
and boots the CI environment in the background while you work:
103+
If you decided Testbox is actually warranted, warm one up early. This returns
104+
an ID instantly and boots the CI environment in the background while you work:
62105

63106
blacksmith testbox warmup ci-check-testbox.yml
64107
# → tbx_01jkz5b3t9...
@@ -177,39 +220,62 @@ to the remote testbox before executing your command:
177220
testbox. The sync model keeps the remote in lockstep with your local managed
178221
file set.
179222

180-
## CRITICAL: Never run tests locally
223+
## CRITICAL: Do not ban local tests
224+
225+
Do not assume local validation is forbidden. Many repos intentionally invest in
226+
fast, warm local loops, and forcing every run through Testbox destroys that
227+
advantage.
181228

182-
Your local machine does not have the secrets, services, or environment
183-
parity needed to validate changes reliably. Every test run, migration,
184-
build, or integration check MUST go through Testbox.
229+
Use Testbox for the checks that actually need it: remote parity, secrets,
230+
services, CI-only runners, or reproducibility against the workflow image.
231+
232+
If the repo says local tests/builds are the normal path, follow the repo.
185233

186234
## When to use
187235

188-
ALWAYS use Testbox when:
236+
Use Testbox when:
189237

190-
- Running any test (unit, integration, e2e)
191-
- Running database migrations
192-
- Building the project to check for compile errors
193-
- Running any command that depends on secrets or environment variables
194-
- Validating changes before committing
238+
- running database migrations or destructive environment checks
239+
- running commands that depend on secrets or environment variables not present locally
240+
- reproducing CI-only failures or validating against the workflow image
241+
- validating behavior that needs provisioned services or remote runners
242+
- doing a final parity check before commit/push when the repo or user wants that
195243

196-
The ONLY exception is trivial checks with zero external dependencies
197-
(e.g., running a linter or formatter locally).
244+
Trim that list based on repo guidance. If the repo documents supported local
245+
tests/builds, prefer local for routine iteration and keep Testbox for the
246+
checks that need parity or remote state.
198247

199248
## Workflow
200249

201-
1. Warm up immediately when you receive a coding task:
250+
1. Decide whether the repo's local loop is the right default.
251+
2. Only if Testbox is warranted, warm up early:
202252
`blacksmith testbox warmup ci-check-testbox.yml` → save the ID
203-
2. Write code while the testbox boots in the background.
204-
3. Run tests (the CLI auto-waits if the testbox isn't ready yet):
253+
3. Write code while the testbox boots in the background.
254+
4. Run the remote command when needed:
205255
`blacksmith testbox run --id <ID> "npm test"`
206-
4. If tests fail, fix code and re-run (fast — same warm testbox, only
207-
changed files are synced).
208-
5. If you changed dependency manifests (package.json, etc.), prepend
256+
5. If tests fail, fix code and re-run against the same warm box.
257+
6. If you changed dependency manifests (package.json, etc.), prepend
209258
the install command: `blacksmith testbox run --id <ID> "npm install && npm test"`
210-
6. If you need artifacts (coverage reports, build outputs, etc.), download them:
259+
7. If you need artifacts (coverage reports, build outputs, etc.), download them:
211260
`blacksmith testbox download --id <ID> coverage/ ./coverage/`
212-
7. Once green, commit and push.
261+
8. Once green, commit and push.
262+
263+
## OpenClaw full test suite
264+
265+
For OpenClaw, use the repo package manager and the measured stable full-suite
266+
profile below. It keeps six Vitest project shards active while limiting each
267+
shard to one worker to avoid worker OOMs on Testbox:
268+
269+
blacksmith testbox run --id <ID> "env NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test"
270+
271+
Observed full-suite time on Blacksmith Testbox is about 3-4 minutes:
272+
273+
- 173-180s on a warmed box
274+
- 219s on a fresh 32-vCPU box
275+
276+
When validating before commit/push, run `pnpm check:changed` first when
277+
appropriate, then the full suite with the profile above if broad confidence is
278+
needed.
213279

214280
## Examples
215281

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ OPENCLAW_GATEWAY_TOKEN=
5454
# Optional additional providers
5555
# ZAI_API_KEY=...
5656
# AI_GATEWAY_API_KEY=...
57+
# TOKENHUB_API_KEY=...
58+
# LKEAP_API_KEY=...
5759
# MINIMAX_API_KEY=...
5860
# SYNTHETIC_API_KEY=...
5961

.github/actions/setup-node-env/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ inputs:
1414
pnpm-version:
1515
description: pnpm version for corepack.
1616
required: false
17-
default: "10.32.1"
17+
default: "10.33.0"
1818
install-bun:
1919
description: Whether to install Bun alongside Node.
2020
required: false

.github/actions/setup-pnpm-store-cache/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ inputs:
44
pnpm-version:
55
description: pnpm version to activate via corepack.
66
required: false
7-
default: "10.32.1"
7+
default: "10.33.0"
88
cache-key-suffix:
99
description: Suffix appended to the cache key.
1010
required: false

.github/labeler.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@
269269
- changed-files:
270270
- any-glob-to-any-file:
271271
- "extensions/deepseek/**"
272+
"extensions: tencent":
273+
- changed-files:
274+
- any-glob-to-any-file:
275+
- "extensions/tencent/**"
272276
"extensions: stepfun":
273277
- changed-files:
274278
- any-glob-to-any-file:

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ Docs: https://docs.openclaw.ai
1010
- CLI/doctor plugins: lazy-load doctor plugin paths and prefer installed plugin `dist/*` runtime entries over source-adjacent JavaScript fallbacks, reducing the measured `doctor --non-interactive` runtime by about 74% while keeping cold doctor startup on built plugin artifacts. (#69840) Thanks @gumadeiras.
1111
- WhatsApp/groups+direct: forward per-group and per-direct `systemPrompt` config into inbound context `GroupSystemPrompt` so configured per-chat behavioral instructions are injected on every turn. Supports `"*"` wildcard fallback and account-scoped overrides under `channels.whatsapp.accounts.<id>.{groups,direct}`; account maps fully replace root maps (no deep merge), matching the existing `requireMention` pattern. Closes #7011. (#59553) Thanks @Bluetegu.
1212
- 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.
13+
- Providers/Tencent: add the bundled Tencent Cloud provider plugin with TokenHub and Token Plan onboarding, docs, `hy3-preview` model catalog entries, and tiered Hy3 pricing metadata. (#68460) Thanks @JuniperSling.
14+
- TUI: add local embedded mode for running terminal chats without a Gateway while keeping plugin approval gates enforced. (#66767) Thanks @fuller-stack-dev.
1315

1416
### Fixes
1517

18+
- Channels/config: require resolved runtime config on channel send/action/client helpers and block runtime helper `loadConfig()` calls, so SecretRefs are resolved at startup/boundaries instead of being re-read during sends.
19+
- 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 `streaming` into `accounts.default`.
20+
- Telegram: keep the sent-message ownership cache isolated per configured session store, so own-message reaction filtering remains correct with custom `session.store` paths.
21+
- Ollama: forward OpenClaw thinking control to native `/api/chat` requests as top-level `think`, so `/think off` and `openclaw agent --thinking off` suppress thinking on models such as qwen3 instead of idling until the watchdog fires. Fixes #69902. (#69967) Thanks @WZH8898.
1622
- 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.
1723
- Mattermost: suppress reasoning-only payloads even when they arrive as blockquoted `> Reasoning:` text, preventing `/reasoning on` from leaking thinking into channel posts. (#69927) Thanks @lawrence3699.
1824
- Discord: read `channel.parentId` through a safe accessor in the slash-command, reaction, and model-picker paths so partial `GuildThreadChannel` prototype getters no longer throw `Cannot access rawData on partial Channel` when commands like `/new` run from inside a thread. Fixes #69861. (#69908) Thanks @neeravmakwana.
@@ -29,6 +35,8 @@ Docs: https://docs.openclaw.ai
2935
- Cron/run-log: report generic `message` 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.
3036
- 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.
3137
- Models/CLI: show bundled provider-owned static catalog rows in `models list --all` 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.
38+
- Configure: skip generic CLI startup bootstrap for `openclaw configure` and bound hint-only gateway probes so the onboarding TUI reaches its first prompt faster when the Gateway is unavailable. (#69984) Thanks @obviyus.
39+
- 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.
3240

3341
## 2026.4.21
3442

@@ -59,6 +67,7 @@ Docs: https://docs.openclaw.ai
5967
- Synology Chat: validate outbound webhook `file_url` values against the shared SSRF policy before forwarding to the NAS, rejecting malformed URLs, non-`http(s)` schemes, and private/blocked network targets so the NAS cannot be used as a confused deputy to fetch internal addresses. (#69784) Thanks @eleqtrizit.
6068
- LINE: validate outbound media URLs against the shared public-network guard before handing them to LINE, preserving arbitrary public HTTPS media while rejecting loopback, link-local, and private-network targets.
6169
- Gateway/Control UI: require gateway auth on the Control UI avatar route (`GET /avatar/<agentId>` and `?meta=1` metadata) when auth is configured, matching the sibling assistant-media route, and propagate the existing gateway token through the UI avatar fetch (bearer header + authenticated blob URL) so authenticated dashboards still load local avatars. (#69775)
70+
- Google Chat/auth: replace the Google auth `gaxios` shim with a scoped SSRF-guarded transport, validate service-account auth endpoints against trusted Google URLs, and let the plugin own its staged `gaxios` auth runtime instead of patching process-wide globals or the root CLI startup path. Thanks @vincentkoc.
6271
- Exec/allowlist: reject POSIX parameter expansion forms such as `$VAR`, `$?`, `$$`, `$1`, and `$@` inside unquoted heredocs during shell approval analysis, so these heredocs no longer pass allowlist review as plain text. (#69795) Thanks @drobison00.
6372
- Gateway/MCP loopback: derive owner-only tool visibility from distinct authenticated owner vs non-owner loopback bearers instead of the caller-controlled owner header, so non-owner MCP child processes cannot recover owner access by spoofing request metadata. (#69796)
6473
- GitHub Copilot: update the default Opus model from `claude-opus-4.6` to `claude-opus-4.7` after GitHub removed Copilot support for 4.6. (#69818) Thanks @shakkernerd.
@@ -68,6 +77,7 @@ Docs: https://docs.openclaw.ai
6877
- Usage/providers: keep plugin-owned usage auth enabled when manifest-declared provider auth env vars such as `MINIMAX_CODE_PLAN_KEY` are present, so `/usage` can resolve MiniMax billing credentials through the provider plugin.
6978
- Tlon/uploads: route both hosted Memex upload targets and custom-S3 presigned upload URLs through the shared SSRF guard so blocked private or loopback destinations fail before upload, while public upload URLs continue through the existing hosted upload flow. (#69794) Thanks @drobison00.
7079
- Channels/thread routing: keep outbound replies in existing Slack, Mattermost, Matrix, Telegram, Discord, and QA-channel thread sessions by sharing the Plugin SDK thread-aware route builder across bundled plugins.
80+
- Agents/replay: normalize restored assistant text content before provider replay and prompt submission, so legacy or repaired sessions no longer crash on `assistantMsg.content.flatMap`. (#69850) Thanks @fuller-stack-dev.
7181

7282
## 2026.4.20
7383

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Welcome to the lobster tank! 🦞
66

77
- **GitHub:** https://github.com/openclaw/openclaw
88
- **Vision:** [`VISION.md`](VISION.md)
9-
- **Discord:** https://discord.gg/qkhbAGHRBT
9+
- **Discord:** https://discord.gg/clawd
1010
- **X/Twitter:** [@steipete](https://x.com/steipete) / [@openclaw](https://x.com/openclaw)
1111

1212
## Maintainers

apps/android/app/build.gradle.kts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,13 @@ ktlint {
182182
}
183183

184184
dependencies {
185-
val composeBom = platform("androidx.compose:compose-bom:2026.02.00")
185+
val composeBom = platform("androidx.compose:compose-bom:2026.03.01")
186186
implementation(composeBom)
187187
androidTestImplementation(composeBom)
188188

189189
implementation("androidx.core:core-ktx:1.17.0")
190190
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0")
191-
implementation("androidx.activity:activity-compose:1.12.2")
191+
implementation("androidx.activity:activity-compose:1.13.0")
192192
implementation("androidx.webkit:webkit:1.15.0")
193193

194194
implementation("androidx.compose.ui:ui")
@@ -204,17 +204,17 @@ dependencies {
204204
implementation("com.google.android.material:material:1.13.0")
205205

206206
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")
207-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0")
207+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0")
208208

209209
implementation("androidx.security:security-crypto:1.1.0")
210210
implementation("androidx.exifinterface:exifinterface:1.4.2")
211211
implementation("com.squareup.okhttp3:okhttp:5.3.2")
212-
implementation("org.bouncycastle:bcprov-jdk18on:1.83")
213-
implementation("org.commonmark:commonmark:0.27.1")
214-
implementation("org.commonmark:commonmark-ext-autolink:0.27.1")
215-
implementation("org.commonmark:commonmark-ext-gfm-strikethrough:0.27.1")
216-
implementation("org.commonmark:commonmark-ext-gfm-tables:0.27.1")
217-
implementation("org.commonmark:commonmark-ext-task-list-items:0.27.1")
212+
implementation("org.bouncycastle:bcprov-jdk18on:1.84")
213+
implementation("org.commonmark:commonmark:0.28.0")
214+
implementation("org.commonmark:commonmark-ext-autolink:0.28.0")
215+
implementation("org.commonmark:commonmark-ext-gfm-strikethrough:0.28.0")
216+
implementation("org.commonmark:commonmark-ext-gfm-tables:0.28.0")
217+
implementation("org.commonmark:commonmark-ext-task-list-items:0.28.0")
218218

219219
// CameraX (for node.invoke camera.* parity)
220220
implementation("androidx.camera:camera-core:1.5.2")
@@ -228,11 +228,11 @@ dependencies {
228228

229229
testImplementation("junit:junit:4.13.2")
230230
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
231-
testImplementation("io.kotest:kotest-runner-junit5-jvm:6.1.3")
232-
testImplementation("io.kotest:kotest-assertions-core-jvm:6.1.3")
231+
testImplementation("io.kotest:kotest-runner-junit5-jvm:6.1.11")
232+
testImplementation("io.kotest:kotest-assertions-core-jvm:6.1.11")
233233
testImplementation("com.squareup.okhttp3:mockwebserver:5.3.2")
234234
testImplementation("org.robolectric:robolectric:4.16.1")
235-
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:6.0.2")
235+
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:6.0.3")
236236
}
237237

238238
tasks.withType<Test>().configureEach {

apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ class ChatController(
403403

404404
val ts = payload["ts"].asLongOrNull() ?: System.currentTimeMillis()
405405
if (phase == "start") {
406-
val args = data?.get("args").asObjectOrNull()
406+
val args = data.get("args").asObjectOrNull()
407407
pendingToolCallsById[toolCallId] =
408408
ChatPendingToolCall(
409409
toolCallId = toolCallId,

apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayDiscovery.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ class GatewayDiscovery(
468468
for (r in records) {
469469
val strings: List<String> =
470470
try {
471-
r.strings.mapNotNull { it as? String }
471+
r.strings
472472
} catch (_: Throwable) {
473473
emptyList()
474474
}

0 commit comments

Comments
 (0)