Skip to content

Commit 0c38f07

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents 6ad3eea + 5b268a0 commit 0c38f07

21 files changed

Lines changed: 1230 additions & 32 deletions

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,24 @@ Docs: https://docs.openclaw.ai
3333
- Gateway/tailscale: start Tailscale exposure and the gateway update check before awaiting channel and plugin sidecar startup so remote operators are not locked out when startup sidecars stall.
3434
- QQBot/streaming: make block streaming configurable per QQ bot account via `streaming.mode` (`"partial"` | `"off"`, default `"partial"`) instead of hardcoding it off, so responses can be delivered incrementally. (#63746)
3535
- Dreaming/gateway: require `operator.admin` for persistent `/dreaming on|off` changes and treat missing gateway client scopes as unprivileged instead of silently allowing config writes. (#63872) Thanks @mbelinky.
36+
- Matrix/multi-account: keep room-level `account` scoping, inherited room overrides, and implicit account selection consistent across top-level default auth, named accounts, and cached-credential env setups. (#58449) thanks @Daanvdplas and @gumadeiras.
37+
- Gateway/pairing: prefer explicit QR bootstrap auth over earlier Tailscale auth classification so iOS `/pair qr` silent bootstrap pairing does not fall through to `pairing required`. (#59232) Thanks @ngutman.
38+
- Config/Discord: coerce safe integer numeric Discord IDs to strings during config validation, keep unsafe or precision-losing numeric snowflakes rejected, and align `openclaw doctor` repair guidance with the same fail-closed behavior. (#45125) Thanks @moliendocode.
39+
- Gateway/sessions: scope bare `sessions.create` aliases like `main` to the requested agent while preserving the canonical `global` and `unknown` sentinel keys. (#58207) thanks @jalehman.
40+
- `/context detail` now compares the tracked prompt estimate with cached context usage and surfaces untracked provider/runtime overhead when present. (#28391) thanks @ImLukeF.
41+
- Gateway/session reset: emit the typed `before_reset` hook for gateway `/new` and `/reset`, preserving reset-hook behavior even when the previous transcript has already been archived. (#53872) thanks @VACInc
42+
- Plugins/commands: pass the active host `sessionKey` into plugin command contexts, and include `sessionId` when it is already available from the active session entry, so bundled and third-party commands can resolve the current conversation reliably. (#59044) Thanks @jalehman.
43+
- Agents/auth: honor `models.providers.*.authHeader` for pi embedded runner model requests by injecting `Authorization: Bearer <apiKey>` when requested. (#54390) Thanks @lndyzwdxhs.
44+
- 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.
45+
- 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.
46+
- BlueBubbles/config: accept `enrichGroupParticipantsFromContacts` in the core strict config schema so gateways no longer fail validation or startup when the BlueBubbles plugin writes that field. (#56889) Thanks @zqchris.
47+
- Agents/failover: classify AbortError and stream-abort messages as timeout so Ollama NDJSON stream aborts stop showing `reason=unknown` in model fallback logs. (#58324) Thanks @yelog
48+
- Exec approvals: route Slack, Discord, and Telegram approvals through the shared channel approval-capability path so native approval auth, delivery, and `/approve` handling stay aligned across channels while preserving Telegram session-key agent filtering. (#58634) thanks @gumadeiras
49+
- Matrix/runtime: resolve the verification/bootstrap runtime from a distinct packaged Matrix entry so global npm installs stop failing on crypto bootstrap with missing-module or recursive runtime alias errors. (#59249) Thanks @gumadeiras.
50+
- Matrix/streaming: preserve ordered block flushes before tool, message, and agent boundaries, add explicit `channels.matrix.blockStreaming` opt-in so Matrix `streaming: "off"` stays final-only by default, and move MiniMax plain-text final handling into the MiniMax provider runtime instead of the shared core heuristic. (#59266) thanks @gumadeiras
51+
- Gateway/agents: fix stale run-context TTL cleanup so the new maintenance sweep compiles and resets orphaned run sequence state correctly. (#52731) thanks @artwalker
52+
- Memory/lancedb: accept `dreaming` config when `memory-lancedb` owns the memory slot so Dreaming surfaces can read slot-owner settings without schema rejection. (#63874) Thanks @mbelinky.
53+
- Heartbeats/sessions: remove stale accumulated isolated heartbeat session keys when the next tick converges them back to the canonical sibling, so repaired sessions stop showing orphaned `:heartbeat:heartbeat` variants in session listings. (#59606) Thanks @rogerdigital.
3654

3755
## 2026.4.9
3856

@@ -80,6 +98,7 @@ Docs: https://docs.openclaw.ai
8098
- Plugins/contracts: keep test-only helpers out of production contract barrels, load shared contract harnesses through bundled test surfaces, and harden guardrails so indirect re-exports and canonical `*.test.ts` files stay blocked. (#63311) Thanks @altaywtf.
8199
- Control UI/models: preserve provider-qualified refs for OpenRouter catalog models whose ids already contain slashes so picker selections submit allowlist-compatible model refs instead of dropping the `openrouter/` prefix. (#63416) Thanks @sallyom.
82100
- Plugin SDK/command auth: split command status builders onto the lightweight `openclaw/plugin-sdk/command-status` subpath while preserving deprecated `command-auth` compatibility exports, so auth-only plugin imports no longer pull status/context warmup into CLI onboarding paths. (#63174) Thanks @hxy91819.
101+
- Wizard/plugin config: coerce integer-typed plugin config fields from interactive text input so integer schema values persist as numbers instead of failing validation. (#63346) Thanks @jalehman.
83102

84103
## 2026.4.8
85104

apps/macos/Sources/OpenClawProtocol/GatewayModels.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,19 +2837,22 @@ public struct ModelChoice: Codable, Sendable {
28372837
public let id: String
28382838
public let name: String
28392839
public let provider: String
2840+
public let alias: String?
28402841
public let contextwindow: Int?
28412842
public let reasoning: Bool?
28422843

28432844
public init(
28442845
id: String,
28452846
name: String,
28462847
provider: String,
2848+
alias: String?,
28472849
contextwindow: Int?,
28482850
reasoning: Bool?)
28492851
{
28502852
self.id = id
28512853
self.name = name
28522854
self.provider = provider
2855+
self.alias = alias
28532856
self.contextwindow = contextwindow
28542857
self.reasoning = reasoning
28552858
}
@@ -2858,6 +2861,7 @@ public struct ModelChoice: Codable, Sendable {
28582861
case id
28592862
case name
28602863
case provider
2864+
case alias
28612865
case contextwindow = "contextWindow"
28622866
case reasoning
28632867
}

apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,19 +2837,22 @@ public struct ModelChoice: Codable, Sendable {
28372837
public let id: String
28382838
public let name: String
28392839
public let provider: String
2840+
public let alias: String?
28402841
public let contextwindow: Int?
28412842
public let reasoning: Bool?
28422843

28432844
public init(
28442845
id: String,
28452846
name: String,
28462847
provider: String,
2848+
alias: String?,
28472849
contextwindow: Int?,
28482850
reasoning: Bool?)
28492851
{
28502852
self.id = id
28512853
self.name = name
28522854
self.provider = provider
2855+
self.alias = alias
28532856
self.contextwindow = contextwindow
28542857
self.reasoning = reasoning
28552858
}
@@ -2858,6 +2861,7 @@ public struct ModelChoice: Codable, Sendable {
28582861
case id
28592862
case name
28602863
case provider
2864+
case alias
28612865
case contextwindow = "contextWindow"
28622866
case reasoning
28632867
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import fs from "node:fs";
2+
import { describe, expect, it } from "vitest";
3+
import { validateJsonSchemaValue } from "../../src/plugins/schema-validator.js";
4+
import { memoryConfigSchema } from "./config.js";
5+
6+
const manifest = JSON.parse(
7+
fs.readFileSync(new URL("./openclaw.plugin.json", import.meta.url), "utf-8"),
8+
) as { configSchema: Record<string, unknown> };
9+
10+
describe("memory-lancedb config", () => {
11+
it("accepts dreaming in the manifest schema and preserves it in runtime parsing", () => {
12+
const manifestResult = validateJsonSchemaValue({
13+
schema: manifest.configSchema,
14+
cacheKey: "memory-lancedb.manifest.dreaming",
15+
value: {
16+
embedding: {
17+
apiKey: "sk-test",
18+
},
19+
dreaming: {
20+
enabled: true,
21+
},
22+
},
23+
});
24+
25+
const parsed = memoryConfigSchema.parse({
26+
embedding: {
27+
apiKey: "sk-test",
28+
},
29+
dreaming: {
30+
enabled: true,
31+
},
32+
});
33+
34+
expect(manifestResult.ok).toBe(true);
35+
expect(parsed.dreaming).toEqual({
36+
enabled: true,
37+
});
38+
});
39+
40+
it("still rejects unrelated unknown top-level config keys", () => {
41+
expect(() => {
42+
memoryConfigSchema.parse({
43+
embedding: {
44+
apiKey: "sk-test",
45+
},
46+
dreaming: {
47+
enabled: true,
48+
},
49+
unexpected: true,
50+
});
51+
}).toThrow("memory config has unknown keys: unexpected");
52+
});
53+
54+
it("rejects non-object dreaming values in runtime parsing", () => {
55+
expect(() => {
56+
memoryConfigSchema.parse({
57+
embedding: {
58+
apiKey: "sk-test",
59+
},
60+
dreaming: true,
61+
});
62+
}).toThrow("dreaming config must be an object");
63+
});
64+
});

extensions/memory-lancedb/config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type MemoryConfig = {
1010
baseUrl?: string;
1111
dimensions?: number;
1212
};
13+
dreaming?: Record<string, unknown>;
1314
dbPath?: string;
1415
autoCapture?: boolean;
1516
autoRecall?: boolean;
@@ -97,7 +98,7 @@ export const memoryConfigSchema = {
9798
const cfg = value as Record<string, unknown>;
9899
assertAllowedKeys(
99100
cfg,
100-
["embedding", "dbPath", "autoCapture", "autoRecall", "captureMaxChars"],
101+
["embedding", "dreaming", "dbPath", "autoCapture", "autoRecall", "captureMaxChars"],
101102
"memory config",
102103
);
103104

@@ -118,6 +119,15 @@ export const memoryConfigSchema = {
118119
throw new Error("captureMaxChars must be between 100 and 10000");
119120
}
120121

122+
const dreaming =
123+
typeof cfg.dreaming === "undefined"
124+
? undefined
125+
: cfg.dreaming && typeof cfg.dreaming === "object" && !Array.isArray(cfg.dreaming)
126+
? (cfg.dreaming as Record<string, unknown>)
127+
: (() => {
128+
throw new Error("dreaming config must be an object");
129+
})();
130+
121131
return {
122132
embedding: {
123133
provider: "openai",
@@ -127,6 +137,7 @@ export const memoryConfigSchema = {
127137
typeof embedding.baseUrl === "string" ? resolveEnvVars(embedding.baseUrl) : undefined,
128138
dimensions: typeof embedding.dimensions === "number" ? embedding.dimensions : undefined,
129139
},
140+
dreaming,
130141
dbPath: typeof cfg.dbPath === "string" ? cfg.dbPath : DEFAULT_DB_PATH,
131142
autoCapture: cfg.autoCapture === true,
132143
autoRecall: cfg.autoRecall !== false,

extensions/memory-lancedb/openclaw.plugin.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
"label": "Auto-Recall",
3939
"help": "Automatically inject relevant memories into context"
4040
},
41+
"dreaming": {
42+
"label": "Dreaming",
43+
"help": "Optional dreaming config consumed when this plugin owns the memory slot"
44+
},
4145
"captureMaxChars": {
4246
"label": "Capture Max Chars",
4347
"help": "Maximum message length eligible for auto-capture",
@@ -77,6 +81,9 @@
7781
"autoRecall": {
7882
"type": "boolean"
7983
},
84+
"dreaming": {
85+
"type": "object"
86+
},
8087
"captureMaxChars": {
8188
"type": "number",
8289
"minimum": 100,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@
14311431
"@anthropic-ai/sdk": "0.81.0",
14321432
"hono": "4.12.12",
14331433
"@hono/node-server": "1.19.13",
1434-
"axios": "1.13.6",
1434+
"axios": "1.15.0",
14351435
"defu": "6.1.5",
14361436
"fast-xml-parser": "5.5.7",
14371437
"request": "npm:@cypress/request@3.0.10",

pnpm-lock.yaml

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ minimumReleaseAgeExclude:
1919
- "@typescript/native-preview*"
2020
- "@oxlint/*"
2121
- "@oxfmt/*"
22+
- "axios@1.15.0"
2223
- "sqlite-vec"
2324
- "sqlite-vec-*"
2425

src/agents/pi-tools.read.workspace-root-guard.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ import path from "node:path";
22
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
33
import type { AnyAgentTool } from "./pi-tools.types.js";
44

5+
type AssertSandboxPath = typeof import("./sandbox-paths.js").assertSandboxPath;
6+
57
const mocks = vi.hoisted(() => ({
6-
assertSandboxPath: vi.fn(async () => ({ resolved: "/tmp/root", relative: "" })),
8+
assertSandboxPath: vi.fn<AssertSandboxPath>(async () => ({
9+
resolved: "/tmp/root",
10+
relative: "",
11+
})),
712
}));
813

914
vi.mock("./sandbox-paths.js", () => ({
@@ -31,11 +36,19 @@ let wrapToolWorkspaceRootGuardWithOptions: typeof import("./pi-tools.read.js").w
3136

3237
describe("wrapToolWorkspaceRootGuardWithOptions", () => {
3338
const root = "/tmp/root";
39+
const assertSandboxPathImpl: AssertSandboxPath = async ({ filePath }) => ({
40+
resolved:
41+
filePath.startsWith("file://") || path.isAbsolute(filePath)
42+
? filePath
43+
: path.resolve(root, filePath),
44+
relative: "",
45+
});
3446

3547
beforeAll(loadModule);
3648

3749
beforeEach(() => {
38-
mocks.assertSandboxPath.mockClear();
50+
mocks.assertSandboxPath.mockReset();
51+
mocks.assertSandboxPath.mockImplementation(assertSandboxPathImpl);
3952
});
4053

4154
it("maps container workspace paths to host workspace root", async () => {

0 commit comments

Comments
 (0)