Skip to content

Commit 49a5c3b

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents bfc90b2 + 0105816 commit 49a5c3b

88 files changed

Lines changed: 2230 additions & 479 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: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Docs: https://docs.openclaw.ai
66

77
### Changes
88

9-
- Memory/Active Memory: add a new optional Active Memory plugin that gives OpenClaw a dedicated memory sub-agent right before the main reply, so ongoing chats can automatically pull in relevant preferences, context, and past details without making users remember to manually say "remember this" or "search memory" first. Includes configurable message/recent/full context modes, live `/verbose` inspection, advanced prompt/thinking overrides for tuning, and opt-in transcript persistence for debugging. (#63286)
9+
- Memory/Active Memory: add a new optional Active Memory plugin that gives OpenClaw a dedicated memory sub-agent right before the main reply, so ongoing chats can automatically pull in relevant preferences, context, and past details without making users remember to manually say "remember this" or "search memory" first. Includes configurable message/recent/full context modes, live `/verbose` inspection, advanced prompt/thinking overrides for tuning, and opt-in transcript persistence for debugging. Docs: https://docs.openclaw.ai/concepts/active-memory. (#63286) Thanks @Takhoffman.
1010
- macOS/Talk: add an experimental local MLX speech provider for Talk Mode, with explicit provider selection, local utterance playback, interruption handling, and system-voice fallback. (#63539) Thanks @ImLukeF.
1111
- CLI/exec policy: add a local `openclaw exec-policy` command with `show`, `preset`, and `set` subcommands for synchronizing requested `tools.exec.*` config with the local exec approvals file, plus follow-up hardening for node-host rejection, rollback safety, and sync conflict detection. (#64050)
1212
- Gateway: add a `commands.list` RPC so remote gateway clients can discover runtime-native, text, skill, and plugin commands with surface-aware naming and serialized argument metadata. (#62656) Thanks @samzong.
@@ -69,6 +69,18 @@ Docs: https://docs.openclaw.ai
6969
- UI/compaction: keep the compaction indicator in a retry-pending state until the run actually finishes, so the UI does not show `Context compacted` before compaction actually finishes. (#55132) Thanks @mpz4life.
7070
- Cron/tool schemas: keep cron tool schemas strict-model-friendly while still preserving `failureAlert=false`, nullable `agentId`/`sessionKey`, and flattened add/update recovery for the newly exposed cron job fields. (#55043) Thanks @brunolorente.
7171
- Git metadata: read commit ids from packed refs as well as loose refs so version and status metadata stay accurate after repository maintenance. (#63943)
72+
- Gateway: keep `commands.list` skill entries categorized under tools and include provider-aware plugin `nativeName` metadata even when `scope=text`, so remote clients can group skills correctly and map text-surface plugin commands back to native aliases.
73+
- TUI: reset footer activity to idle when switching sessions so a stale streaming indicator cannot persist after the selection changes. (#63988) Thanks @neeravmakwana.
74+
- iMessage: treat `sender === chat_identifier` as self-chat only when `destination_caller_id` is present and matches the sender, fixing DM outbound rows that omit destination from being run through self-chat echo handling. (#63980) Thanks @neeravmakwana.
75+
- Cron/Telegram: collapse isolated announce delivery to the final assistant-visible text only for Telegram targets, while preserving existing multi-message direct delivery semantics for other channels. (#63228) Thanks @welfo-beo.
76+
- Gateway/thread routing: preserve Slack, Telegram, and Mattermost thread-child delivery targets so bound subagent completion messages land in the originating thread instead of top-level channels. (#54840) Thanks @yzzymt.
77+
- ACP/stream relay: pass parent delivery context to ACP stream relay system events so `streamTo="parent"` updates route to the correct thread or topic instead of falling back to the main DM. (#57056) Thanks @pingren.
78+
- Agents/sessions: preserve announce `threadId` when `sessions.list` fallback rehydrates agent-to-agent announce targets so final announce messages stay in the originating thread/topic. (#63506) Thanks @SnowSky1.
79+
- iMessage/self-chat: remember ambiguous `sender === chat_identifier` outbound rows with missing `destination_caller_id` in self-chat dedupe state so the later reflected inbound copy still drops instead of re-entering inbound handling when the echo cache misses. Thanks @neeravmakwana.
80+
- Claude CLI: stop marking spawned Claude Code runs as host-managed so they keep using normal CLI subscription behavior. (#64023) Thanks @Alex-Alaniz.
81+
- Agents/failover: classify OpenRouter `404 No endpoints found for <model>` responses as `model_not_found` so fallback chains continue past retired OpenRouter candidates. (#61472) Thanks @MonkeyLeeT.
82+
- Browser/plugin SDK: route browser auth, profile, host-inspection, and doctor readiness helpers through browser plugin public facades so core compatibility helpers stop carrying duplicate runtime implementations. (#63957) Thanks @joshavant.
83+
- Agents/failover: allow cooldown probes for `timeout` (including network outage classifications) so the primary model can recover after failover without a gateway restart. (#63996) Thanks @neeravmakwana.
7284

7385
## 2026.4.9
7486

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
0a75b57f5dbb0bb1488eacb47111ee22ff42dd3747bfe07bb69c9445d5e55c3e config-baseline.json
2-
ff15bb8b4231fc80174249ae89bcb61439d7adda5ee6be95e4d304680253a59f config-baseline.core.json
3-
7f42b22b46c487d64aaac46001ba9d9096cf7bf0b1c263a54d39946303ff5018 config-baseline.channel.json
4-
483d4f3c1d516719870ad6f2aba6779b9950f85471ee77b9994a077a7574a892 config-baseline.plugin.json
1+
a962c1d7ddffa15f2333854f77b03da4f6db07fada16f288377ee1daf50afc08 config-baseline.json
2+
3c8455d44a63d495ad295d2c9d76fed7a190b80344dabaa0e78ba433bf2d253b config-baseline.core.json
3+
df55c673a1cdbebc4fe68baaaf9d0d4289313be5034be92f0d510726a086b1d6 config-baseline.channel.json
4+
3f6fccab66a9abe7e1dd412fb01b13b944ed24edbe09df55ada3323acc7f76fe config-baseline.plugin.json

docs/docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@
10741074
"concepts/memory-qmd",
10751075
"concepts/memory-honcho",
10761076
"concepts/memory-search",
1077+
"concepts/active-memory",
10771078
"concepts/dreaming"
10781079
]
10791080
},

extensions/anthropic/cli-backend.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
CLAUDE_CLI_BACKEND_ID,
88
CLAUDE_CLI_DEFAULT_MODEL_REF,
99
CLAUDE_CLI_CLEAR_ENV,
10-
CLAUDE_CLI_HOST_MANAGED_ENV,
1110
CLAUDE_CLI_MODEL_ALIASES,
1211
CLAUDE_CLI_SESSION_ID_FIELDS,
1312
normalizeClaudeBackendConfig,
@@ -63,7 +62,6 @@ export function buildAnthropicCliBackend(): CliBackendPlugin {
6362
systemPromptArg: "--append-system-prompt",
6463
systemPromptMode: "append",
6564
systemPromptWhen: "first",
66-
env: { ...CLAUDE_CLI_HOST_MANAGED_ENV },
6765
clearEnv: [...CLAUDE_CLI_CLEAR_ENV],
6866
reliability: {
6967
watchdog: {

extensions/anthropic/cli-shared.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest";
22
import { buildAnthropicCliBackend } from "./cli-backend.js";
33
import {
44
CLAUDE_CLI_CLEAR_ENV,
5-
CLAUDE_CLI_HOST_MANAGED_ENV,
65
normalizeClaudeBackendConfig,
76
normalizeClaudePermissionArgs,
87
normalizeClaudeSettingSourcesArgs,
@@ -132,10 +131,10 @@ describe("normalizeClaudeBackendConfig", () => {
132131
expect(normalized?.resumeArgs).toContain("user");
133132
});
134133

135-
it("marks claude cli as host-managed, restricts setting sources, and clears inherited env overrides", () => {
134+
it("leaves claude cli subscription-managed, restricts setting sources, and clears inherited env overrides", () => {
136135
const backend = buildAnthropicCliBackend();
137136

138-
expect(backend.config.env).toEqual(CLAUDE_CLI_HOST_MANAGED_ENV);
137+
expect(backend.config.env).toBeUndefined();
139138
expect(backend.config.args).toContain("--setting-sources");
140139
expect(backend.config.args).toContain("user");
141140
expect(backend.config.resumeArgs).toContain("--setting-sources");

extensions/anthropic/cli-shared.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ export const CLAUDE_CLI_SESSION_ID_FIELDS = [
4040
"conversationId",
4141
] as const;
4242

43-
export const CLAUDE_CLI_HOST_MANAGED_ENV = {
44-
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: "1",
45-
} as const;
46-
4743
// Claude Code honors provider-routing, auth, and config-root env before
4844
// consulting its local login state, so inherited shell overrides must not
4945
// steer OpenClaw-managed Claude CLI runs toward a different provider,

extensions/discord/src/approval-handler.runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import type {
2525
ExecApprovalDecision,
2626
} from "openclaw/plugin-sdk/infra-runtime";
2727
import { logDebug, logError, normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
28-
import { shouldHandleDiscordApprovalRequest } from "./approval-native.js";
28+
import { shouldHandleDiscordApprovalRequest } from "./approval-shared.js";
2929
import { isDiscordExecApprovalClientEnabled } from "./exec-approvals.js";
3030
import { createDiscordClient, stripUndefinedFields } from "./send.shared.js";
3131
import { DiscordUiContainer } from "./ui.js";

extensions/discord/src/approval-native.ts

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
11
import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
22
import type { ChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime";
33
import { resolveApprovalRequestSessionConversation } from "openclaw/plugin-sdk/approval-native-runtime";
4-
import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
5-
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
4+
import type { DiscordExecApprovalConfig } from "openclaw/plugin-sdk/config-runtime";
65
import {
76
normalizeLowercaseStringOrEmpty,
87
normalizeOptionalString,
98
} from "openclaw/plugin-sdk/text-runtime";
9+
export { shouldHandleDiscordApprovalRequest } from "./approval-shared.js";
1010
import { listDiscordAccountIds, resolveDiscordAccount } from "./accounts.js";
1111
import {
1212
createChannelApproverDmTargetResolver,
1313
createChannelNativeOriginTargetResolver,
1414
createApproverRestrictedNativeApprovalCapability,
1515
splitChannelApprovalCapability,
16-
doesApprovalRequestMatchChannelAccount,
17-
isChannelExecApprovalClientEnabledFromConfig,
18-
matchesApprovalRequestFilters,
1916
} from "./approval-runtime.js";
17+
import { shouldHandleDiscordApprovalRequest } from "./approval-shared.js";
2018
import {
2119
getDiscordExecApprovalApprovers,
2220
isDiscordExecApprovalApprover,
2321
isDiscordExecApprovalClientEnabled,
2422
} from "./exec-approvals.js";
2523

26-
type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
27-
2824
// Legacy export kept for monitor test/support surfaces; native routing now uses
2925
// the shared session-conversation fallback helper instead.
3026
export function extractDiscordChannelId(sessionKey?: string | null): string | null {
@@ -80,45 +76,6 @@ function normalizeDiscordThreadId(value?: string | number | null): string | unde
8076
return /^\d+$/.test(normalized) ? normalized : undefined;
8177
}
8278

83-
export function shouldHandleDiscordApprovalRequest(params: {
84-
cfg: OpenClawConfig;
85-
accountId?: string | null;
86-
request: ApprovalRequest;
87-
configOverride?: DiscordExecApprovalConfig | null;
88-
}): boolean {
89-
const config =
90-
params.configOverride ??
91-
resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId }).config.execApprovals;
92-
const approvers = getDiscordExecApprovalApprovers({
93-
cfg: params.cfg,
94-
accountId: params.accountId,
95-
configOverride: params.configOverride,
96-
});
97-
if (
98-
!doesApprovalRequestMatchChannelAccount({
99-
cfg: params.cfg,
100-
request: params.request,
101-
channel: "discord",
102-
accountId: params.accountId,
103-
})
104-
) {
105-
return false;
106-
}
107-
if (
108-
!isChannelExecApprovalClientEnabledFromConfig({
109-
enabled: config?.enabled,
110-
approverCount: approvers.length,
111-
})
112-
) {
113-
return false;
114-
}
115-
return matchesApprovalRequestFilters({
116-
request: params.request.request,
117-
agentFilter: config?.agentFilter,
118-
sessionFilter: config?.sessionFilter,
119-
});
120-
}
121-
12279
function createDiscordOriginTargetResolver(configOverride?: DiscordExecApprovalConfig | null) {
12380
return createChannelNativeOriginTargetResolver({
12481
channel: "discord",
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { doesApprovalRequestMatchChannelAccount } from "openclaw/plugin-sdk/approval-native-runtime";
2+
import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
3+
import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime";
4+
import { resolveDiscordAccount } from "./accounts.js";
5+
import {
6+
isChannelExecApprovalClientEnabledFromConfig,
7+
matchesApprovalRequestFilters,
8+
} from "./approval-runtime.js";
9+
import { getDiscordExecApprovalApprovers } from "./exec-approvals.js";
10+
11+
type ApprovalRequest = ExecApprovalRequest | PluginApprovalRequest;
12+
13+
export function shouldHandleDiscordApprovalRequest(params: {
14+
cfg: OpenClawConfig;
15+
accountId?: string | null;
16+
request: ApprovalRequest;
17+
configOverride?: DiscordExecApprovalConfig | null;
18+
}): boolean {
19+
const config =
20+
params.configOverride ??
21+
resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId }).config.execApprovals;
22+
const approvers = getDiscordExecApprovalApprovers({
23+
cfg: params.cfg,
24+
accountId: params.accountId,
25+
configOverride: params.configOverride,
26+
});
27+
if (
28+
!doesApprovalRequestMatchChannelAccount({
29+
cfg: params.cfg,
30+
request: params.request,
31+
channel: "discord",
32+
accountId: params.accountId,
33+
})
34+
) {
35+
return false;
36+
}
37+
if (
38+
!isChannelExecApprovalClientEnabledFromConfig({
39+
enabled: config?.enabled,
40+
approverCount: approvers.length,
41+
})
42+
) {
43+
return false;
44+
}
45+
return matchesApprovalRequestFilters({
46+
request: params.request.request,
47+
agentFilter: config?.agentFilter,
48+
sessionFilter: config?.sessionFilter,
49+
});
50+
}

extensions/imessage/src/monitor/inbound-processing.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ describe("resolveIMessageInboundDecision echo detection", () => {
119119
resolveDecision({
120120
message: {
121121
id: 9641,
122+
sender: "+15555550123",
123+
chat_identifier: "+15555550123",
124+
destination_caller_id: "+15555550123",
122125
text: "Do you want to report this issue?",
123126
created_at: createdAt,
124127
is_from_me: true,
@@ -127,12 +130,14 @@ describe("resolveIMessageInboundDecision echo detection", () => {
127130
bodyText: "Do you want to report this issue?",
128131
selfChatCache,
129132
}),
130-
).toEqual({ kind: "drop", reason: "from me" });
133+
).toMatchObject({ kind: "dispatch" });
131134

132135
expect(
133136
resolveDecision({
134137
message: {
135138
id: 9642,
139+
sender: "+15555550123",
140+
chat_identifier: "+15555550123",
136141
text: "Do you want to report this issue?",
137142
created_at: createdAt,
138143
},
@@ -252,6 +257,9 @@ describe("resolveIMessageInboundDecision echo detection", () => {
252257
resolveDecision({
253258
message: {
254259
id: 9801,
260+
sender: "+15555550123",
261+
chat_identifier: "+15555550123",
262+
destination_caller_id: "+15555550123",
255263
text: bodyText,
256264
created_at: createdAt,
257265
is_from_me: true,
@@ -265,6 +273,8 @@ describe("resolveIMessageInboundDecision echo detection", () => {
265273
resolveDecision({
266274
message: {
267275
id: 9802,
276+
sender: "+15555550123",
277+
chat_identifier: "+15555550123",
268278
text: bodyText,
269279
created_at: createdAt,
270280
},

0 commit comments

Comments
 (0)