Skip to content

Commit 78039b9

Browse files
Auto-merge upstream openclaw/openclaw
2 parents 7ca51bb + 7fb58af commit 78039b9

369 files changed

Lines changed: 19571 additions & 2578 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.

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@ Docs: https://docs.openclaw.ai
3030
- Telegram/native commands: clean up metadata-driven progress placeholders when replies fall back, edits fail, or local exec approval prompts are suppressed. (#59300) Thanks @jalehman.
3131
- Media/request overrides: resolve shared and capability-filtered media request SecretRefs correctly and expose media transport override fields to schema-driven config consumers. (#59848) Thanks @vincentkoc.
3232
- Providers/request overrides: stop advertising unsupported proxy and TLS transport settings on `models.providers.*.request`, and fail closed if unvalidated config tries to route LLM model-provider traffic through dead transport fields. (#59682) Thanks @vincentkoc.
33+
- Discord/mentions: treat `@everyone` and `@here` as valid mention-gate triggers in guild preflight so mention-required bots still respond to those broadcasts. (#60343) Thanks @geekhuashan.
3334
- Matrix: allow secret-storage recreation during automatic repair bootstrap so clients that lose their recovery key can recover and persist new cross-signing keys. (#59846) Thanks @al3mart.
3435
- Matrix/crypto persistence: capture and write the IndexedDB snapshot while holding the snapshot file lock so concurrent gateway and CLI persists cannot overwrite newer crypto state. (#59851) Thanks @al3mart.
3536
- Ollama/auth: prefer real cloud auth over local marker during model auth resolution so cloud-backed Ollama auth does not get shadowed by stale local-only markers.
3637
- Plugins/Kimi Coding: parse tagged Kimi tool-call text into structured tool calls on the provider stream path so tools execute instead of echoing raw markup. (#60051) Thanks @obviyus.
3738
- Channels/passive hooks: emit passive message hooks for mention-skipped Telegram and Signal group messages when `ingest` is enabled, including wildcard/default fallback and per-group override handling. (#60018) Thanks @obviyus.
3839
- Plugins/manifest registry: stop warning when an explicit manifest `id` intentionally differs from the discovery hint. (#59185) Thanks @samzong.
3940
- WhatsApp/streaming: honor `channels.whatsapp.blockStreaming` again for inbound auto-replies so progressive block replies can be enabled explicitly instead of being forced to final-only delivery. Thanks @mcaxtr.
41+
- Auth/failover: shorten `auth_permanent` lockouts, add dedicated config knobs for permanent-auth backoff, and downgrade ambiguous auth-ish upstream incidents to retryable auth failures so providers recover automatically after transient outages. (#60404) Thanks @extrasmall0.
42+
- Providers/GitHub Copilot: route Claude models through Anthropic Messages with Copilot-compatible headers and Anthropic prompt-cache markers instead of forcing the OpenAI Responses transport.
4043
- Plugins/runtime: reuse compatible active registries for `web_search` and `web_fetch` provider snapshot resolution so repeated runtime reads do not re-import the same bundled plugin set on each agent message. Related #48380.
4144
- Infra/tailscale: ignore `OPENCLAW_TEST_TAILSCALE_BINARY` outside explicit test environments and block it from workspace `.env`, so test-only binary overrides cannot be injected through trusted repository state. (#58468) Thanks @eleqtrizit.
4245
- Plugins/OpenAI: enable reference-image edits for `gpt-image-1` by routing edit calls to `/images/edits` with multipart image uploads, and update image-generation capability/docs metadata accordingly. Thanks @steipete.
@@ -77,7 +80,11 @@ Docs: https://docs.openclaw.ai
7780
- Discord/ack reactions: keep automatic ACK reaction auth on the active hydrated Discord account so SecretRef-backed and non-default-account reactions stop falling back to stale default config resolution. (#60081) Thanks @FunJim.
7881
- Telegram/model switching: render non-default `/model` callback confirmations with HTML formatting so Telegram shows the selected model in bold instead of raw `**...**` markers. (#60042) Thanks @GitZhangChi.
7982
- Plugins/update: allow `openclaw plugins update` to use `--dangerously-force-unsafe-install` for built-in dangerous-code false positives during plugin updates. (#60066) Thanks @huntharo.
83+
- Gateway/auth: disconnect shared-auth websocket sessions only for effective auth rotations on restart-capable config writes, and keep `config.set` auth edits from dropping still-valid live sessions. (#60387) Thanks @mappel-nv.
8084
- Control UI/chat: keep the Stop button visible during tool-only execution so abortable runs do not fall back to Send while tools are still running. (#54528) thanks @chziyue.
85+
- Discord/voice: make READY auto-join fire-and-forget while keeping the shorter initial voice-connect timeout separate from the longer playback-start wait. (#60345) Thanks @geekhuashan.
86+
- Agents/skills: add inherited `agents.defaults.skills` allowlists, make per-agent `agents.list[].skills` replace defaults instead of merging, and scope embedded, session, sandbox, and cron skill snapshots through the effective runtime agent. (#59992) Thanks @gumadeiras.
87+
- Matrix/Telegram exec approvals: recover stored same-channel account bindings even when session reply state drifted to another channel, so foreign-channel approvals route to the bound account instead of fanning out or being rejected as ambiguous. (#60417) thanks @gumadeiras.
8188

8289
## 2026.4.2
8390

apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import ai.openclaw.app.gateway.GatewayConnectOptions
88
import ai.openclaw.app.gateway.GatewayEndpoint
99
import ai.openclaw.app.gateway.GatewayTlsParams
1010
import ai.openclaw.app.gateway.isLoopbackGatewayHost
11-
import ai.openclaw.app.gateway.isPrivateLanGatewayHost
1211
import ai.openclaw.app.LocationMode
1312
import ai.openclaw.app.VoiceWakeMode
1413

@@ -35,7 +34,7 @@ class ConnectionManager(
3534
val stableId = endpoint.stableId
3635
val stored = storedFingerprint?.trim().takeIf { !it.isNullOrEmpty() }
3736
val isManual = stableId.startsWith("manual|")
38-
val cleartextAllowedHost = isPrivateLanGatewayHost(endpoint.host)
37+
val cleartextAllowedHost = isLoopbackGatewayHost(endpoint.host)
3938

4039
if (isManual) {
4140
if (!manualTlsEnabled && cleartextAllowedHost) return null

apps/android/app/src/main/java/ai/openclaw/app/ui/GatewayConfigResolver.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ai.openclaw.app.ui
22

3-
import ai.openclaw.app.gateway.isPrivateLanGatewayHost
3+
import ai.openclaw.app.gateway.isLoopbackGatewayHost
44
import java.util.Base64
55
import java.util.Locale
66
import java.net.URI
@@ -56,7 +56,7 @@ internal data class GatewayScannedSetupCodeResult(
5656

5757
private val gatewaySetupJson = Json { ignoreUnknownKeys = true }
5858
private const val remoteGatewaySecurityRule =
59-
"Tailscale and public mobile nodes require wss:// or Tailscale Serve. ws:// is allowed for private LAN, localhost, and the Android emulator."
59+
"Non-loopback mobile nodes require wss:// or Tailscale Serve. ws:// is allowed only for localhost and the Android emulator."
6060
private const val remoteGatewaySecurityFix =
6161
"Use a private LAN host/address, or enable Tailscale Serve / expose a wss:// gateway URL."
6262

@@ -143,7 +143,7 @@ internal fun parseGatewayEndpoint(rawInput: String): GatewayEndpointConfig? {
143143
"wss", "https" -> true
144144
else -> true
145145
}
146-
if (!tls && !isPrivateLanGatewayHost(host)) {
146+
if (!tls && !isLoopbackGatewayHost(host)) {
147147
return GatewayEndpointParseResult(error = GatewayEndpointValidationError.INSECURE_REMOTE_URL)
148148
}
149149
val defaultPort =

apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class ConnectionManagerTest {
108108
}
109109

110110
@Test
111-
fun resolveTlsParamsForEndpoint_manualPrivateLanCanStayCleartextWhenToggleIsOff() {
111+
fun resolveTlsParamsForEndpoint_manualPrivateLanRequiresTlsWhenToggleIsOff() {
112112
val endpoint = GatewayEndpoint.manual(host = "192.168.1.20", port = 18789)
113113

114114
val params =
@@ -118,7 +118,9 @@ class ConnectionManagerTest {
118118
manualTlsEnabled = false,
119119
)
120120

121-
assertNull(params)
121+
assertEquals(true, params?.required)
122+
assertNull(params?.expectedFingerprint)
123+
assertEquals(false, params?.allowTOFU)
122124
}
123125

124126
@Test
@@ -146,7 +148,7 @@ class ConnectionManagerTest {
146148
}
147149

148150
@Test
149-
fun resolveTlsParamsForEndpoint_discoveryPrivateLanWithoutHintsCanStayCleartext() {
151+
fun resolveTlsParamsForEndpoint_discoveryPrivateLanWithoutHintsRequiresTls() {
150152
val endpoint =
151153
GatewayEndpoint(
152154
stableId = "_openclaw-gw._tcp.|local.|Test",
@@ -164,7 +166,9 @@ class ConnectionManagerTest {
164166
manualTlsEnabled = false,
165167
)
166168

167-
assertNull(params)
169+
assertEquals(true, params?.required)
170+
assertNull(params?.expectedFingerprint)
171+
assertEquals(false, params?.allowTOFU)
168172
}
169173

170174
@Test

apps/android/app/src/test/java/ai/openclaw/app/ui/GatewayConfigResolverTest.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,14 @@ class GatewayConfigResolverTest {
289289
assertEquals(GatewayEndpointValidationError.INSECURE_REMOTE_URL, parsed.error)
290290
}
291291

292+
@Test
293+
fun parseGatewayEndpointResultFlagsInsecureLanCleartextGateway() {
294+
val parsed = parseGatewayEndpointResult("ws://192.168.1.20:18789")
295+
296+
assertNull(parsed.config)
297+
assertEquals(GatewayEndpointValidationError.INSECURE_REMOTE_URL, parsed.error)
298+
}
299+
292300
@Test
293301
fun decodeGatewaySetupCodeParsesBootstrapToken() {
294302
val setupCode =

docs/.generated/config-baseline.core.json

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3983,6 +3983,30 @@
39833983
"tags": [],
39843984
"hasChildren": false
39853985
},
3986+
{
3987+
"path": "agents.defaults.skills",
3988+
"kind": "core",
3989+
"type": "array",
3990+
"required": false,
3991+
"deprecated": false,
3992+
"sensitive": false,
3993+
"tags": [
3994+
"advanced"
3995+
],
3996+
"label": "Skills",
3997+
"help": "Optional default skill allowlist inherited by agents that omit agents.list[].skills. Omit for unrestricted skills, set [] to give inheriting agents no skills, and remember explicit agents.list[].skills replaces this default instead of merging with it.",
3998+
"hasChildren": true
3999+
},
4000+
{
4001+
"path": "agents.defaults.skills.*",
4002+
"kind": "core",
4003+
"type": "string",
4004+
"required": false,
4005+
"deprecated": false,
4006+
"sensitive": false,
4007+
"tags": [],
4008+
"hasChildren": false
4009+
},
39864010
{
39874011
"path": "agents.defaults.skipBootstrap",
39884012
"kind": "core",
@@ -6460,7 +6484,7 @@
64606484
"advanced"
64616485
],
64626486
"label": "Agent Skill Filter",
6463-
"help": "Optional allowlist of skills for this agent (omit = all skills; empty = no skills).",
6487+
"help": "Optional allowlist of skills for this agent. If omitted, the agent inherits agents.defaults.skills when set; otherwise skills stay unrestricted. Set [] for no skills. An explicit list fully replaces inherited defaults instead of merging with them.",
64646488
"hasChildren": true
64656489
},
64666490
{
@@ -7816,6 +7840,38 @@
78167840
"help": "Cooldown/backoff controls for temporary profile suppression after billing-related failures and retry windows. Use these to prevent rapid re-selection of profiles that are still blocked.",
78177841
"hasChildren": true
78187842
},
7843+
{
7844+
"path": "auth.cooldowns.authPermanentBackoffMinutes",
7845+
"kind": "core",
7846+
"type": "number",
7847+
"required": false,
7848+
"deprecated": false,
7849+
"sensitive": false,
7850+
"tags": [
7851+
"access",
7852+
"auth",
7853+
"reliability"
7854+
],
7855+
"label": "Auth-Permanent Backoff (minutes)",
7856+
"help": "Base backoff (minutes) for high-confidence auth_permanent failures (default: 10). Keep this shorter than billing so providers recover automatically after transient upstream auth incidents.",
7857+
"hasChildren": false
7858+
},
7859+
{
7860+
"path": "auth.cooldowns.authPermanentMaxMinutes",
7861+
"kind": "core",
7862+
"type": "number",
7863+
"required": false,
7864+
"deprecated": false,
7865+
"sensitive": false,
7866+
"tags": [
7867+
"access",
7868+
"auth",
7869+
"performance"
7870+
],
7871+
"label": "Auth-Permanent Backoff Cap (minutes)",
7872+
"help": "Cap (minutes) for auth_permanent backoff (default: 60).",
7873+
"hasChildren": false
7874+
},
78197875
{
78207876
"path": "auth.cooldowns.billingBackoffHours",
78217877
"kind": "core",

docs/.generated/config-baseline.json

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3982,6 +3982,30 @@
39823982
"tags": [],
39833983
"hasChildren": false
39843984
},
3985+
{
3986+
"path": "agents.defaults.skills",
3987+
"kind": "core",
3988+
"type": "array",
3989+
"required": false,
3990+
"deprecated": false,
3991+
"sensitive": false,
3992+
"tags": [
3993+
"advanced"
3994+
],
3995+
"label": "Skills",
3996+
"help": "Optional default skill allowlist inherited by agents that omit agents.list[].skills. Omit for unrestricted skills, set [] to give inheriting agents no skills, and remember explicit agents.list[].skills replaces this default instead of merging with it.",
3997+
"hasChildren": true
3998+
},
3999+
{
4000+
"path": "agents.defaults.skills.*",
4001+
"kind": "core",
4002+
"type": "string",
4003+
"required": false,
4004+
"deprecated": false,
4005+
"sensitive": false,
4006+
"tags": [],
4007+
"hasChildren": false
4008+
},
39854009
{
39864010
"path": "agents.defaults.skipBootstrap",
39874011
"kind": "core",
@@ -6459,7 +6483,7 @@
64596483
"advanced"
64606484
],
64616485
"label": "Agent Skill Filter",
6462-
"help": "Optional allowlist of skills for this agent (omit = all skills; empty = no skills).",
6486+
"help": "Optional allowlist of skills for this agent. If omitted, the agent inherits agents.defaults.skills when set; otherwise skills stay unrestricted. Set [] for no skills. An explicit list fully replaces inherited defaults instead of merging with them.",
64636487
"hasChildren": true
64646488
},
64656489
{
@@ -7815,6 +7839,38 @@
78157839
"help": "Cooldown/backoff controls for temporary profile suppression after billing-related failures and retry windows. Use these to prevent rapid re-selection of profiles that are still blocked.",
78167840
"hasChildren": true
78177841
},
7842+
{
7843+
"path": "auth.cooldowns.authPermanentBackoffMinutes",
7844+
"kind": "core",
7845+
"type": "number",
7846+
"required": false,
7847+
"deprecated": false,
7848+
"sensitive": false,
7849+
"tags": [
7850+
"access",
7851+
"auth",
7852+
"reliability"
7853+
],
7854+
"label": "Auth-Permanent Backoff (minutes)",
7855+
"help": "Base backoff (minutes) for high-confidence auth_permanent failures (default: 10). Keep this shorter than billing so providers recover automatically after transient upstream auth incidents.",
7856+
"hasChildren": false
7857+
},
7858+
{
7859+
"path": "auth.cooldowns.authPermanentMaxMinutes",
7860+
"kind": "core",
7861+
"type": "number",
7862+
"required": false,
7863+
"deprecated": false,
7864+
"sensitive": false,
7865+
"tags": [
7866+
"access",
7867+
"auth",
7868+
"performance"
7869+
],
7870+
"label": "Auth-Permanent Backoff Cap (minutes)",
7871+
"help": "Cap (minutes) for auth_permanent backoff (default: 60).",
7872+
"hasChildren": false
7873+
},
78187874
{
78197875
"path": "auth.cooldowns.billingBackoffHours",
78207876
"kind": "core",

0 commit comments

Comments
 (0)