diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ace1ee966..1b239a57e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,67 +2,22 @@ Docs: https://docs.openclaw.ai -## 2026.2.9 +## 2026.2.6-4 ### Added -- Commands: add `commands.allowFrom` config for separate command authorization, allowing operators to restrict slash commands to specific users while keeping chat open to others. (#12430) Thanks @thewilloftheshadow. -- iOS: alpha node app + setup-code onboarding. (#11756) Thanks @mbelinky. -- Channels: comprehensive BlueBubbles and channel cleanup. (#11093) Thanks @tyler6204. -- Plugins: device pairing + phone control plugins (Telegram `/pair`, iOS/Android node controls). (#11755) Thanks @mbelinky. -- Tools: add Grok (xAI) as a `web_search` provider. (#12419) Thanks @tmchow. -- Gateway: add agent management RPC methods for the web UI (`agents.create`, `agents.update`, `agents.delete`). (#11045) Thanks @advaitpaliwal. -- Web UI: show a Compaction divider in chat history. (#11341) Thanks @Takhoffman. -- Agents: include runtime shell in agent envelopes. (#1835) Thanks @Takhoffman. -- Agents: auto-select `zai/glm-4.6v` for image understanding when ZAI is primary provider. (#10267) Thanks @liuy. -- Paths: add `OPENCLAW_HOME` for overriding the home directory used by internal path resolution. (#12091) Thanks @sebslight. +- Gateway: add `agents.create`, `agents.update`, `agents.delete` RPC methods for web UI agent management. (#11045) Thanks @advaitpaliwal. ### Fixes -- Discord: add exec approval cleanup option to delete DMs after approval/denial/timeout. (#13205) Thanks @thewilloftheshadow. -- Sessions: prune stale entries, cap session store size, rotate large stores, accept duration/size thresholds, default to warn-only maintenance, and prune cron run sessions after retention windows. (#13083) Thanks @skyfallsin, @Glucksberg, @gumadeiras. -- CI: Implement pipeline and workflow order. Thanks @quotentiroler. -- WhatsApp: preserve original filenames for inbound documents. (#12691) Thanks @akramcodez. -- Telegram: harden quote parsing; preserve quote context; avoid QUOTE_TEXT_INVALID; avoid nested reply quote misclassification. (#12156) Thanks @rybnikov. -- Telegram: recover proactive sends when stale topic thread IDs are used by retrying without `message_thread_id`. (#11620) -- Discord: auto-create forum/media thread posts on send, with chunked follow-up replies and media handling for forum sends. (#12380) Thanks @magendary, @thewilloftheshadow. -- Discord: cap gateway reconnect attempts to avoid infinite retry loops. (#12230) Thanks @Yida-Dev. -- Telegram: render markdown spoilers with `` HTML tags. (#11543) Thanks @ezhikkk. -- Telegram: truncate command registration to 100 entries to avoid `BOT_COMMANDS_TOO_MUCH` failures on startup. (#12356) Thanks @arosstale. -- Telegram: match DM `allowFrom` against sender user id (fallback to chat id) and clarify pairing logs. (#12779) Thanks @liuxiaopai-ai. -- Onboarding: QuickStart now auto-installs shell completion (prompt only in Manual). -- Auth: strip embedded line breaks from pasted API keys and tokens before storing/resolving credentials. -- Web UI: make chat refresh smoothly scroll to the latest messages and suppress new-messages badge flash during manual refresh. -- Tools/web_search: include provider-specific settings in the web search cache key, and pass `inlineCitations` for Grok. (#12419) Thanks @tmchow. -- Tools/web_search: fix Grok response parsing for xAI Responses API output blocks. (#13049) Thanks @ereid7. -- Tools/web_search: normalize direct Perplexity model IDs while keeping OpenRouter model IDs unchanged. (#12795) Thanks @cdorsey. -- Model failover: treat HTTP 400 errors as failover-eligible, enabling automatic model fallback. (#1879) Thanks @orenyomtov. -- Errors: prevent false positive context overflow detection when conversation mentions "context overflow" topic. (#2078) Thanks @sbking. -- Errors: avoid rewriting/swallowing normal assistant replies that mention error keywords by scoping `sanitizeUserFacingText` rewrites to error-context. (#12988) Thanks @Takhoffman. -- Config: re-hydrate state-dir `.env` during runtime config loads so `${VAR}` substitutions remain resolvable. (#12748) Thanks @rodrigouroz. -- Gateway: no more post-compaction amnesia; injected transcript writes now preserve Pi session `parentId` chain so agents can remember again. (#12283) Thanks @Takhoffman. -- Gateway: fix multi-agent sessions.usage discovery. (#11523) Thanks @Takhoffman. - Agents: recover from context overflow caused by oversized tool results (pre-emptive capping + fallback truncation). (#11579) Thanks @tyler6204. -- Subagents/compaction: stabilize announce timing and preserve compaction metrics across retries. (#11664) Thanks @tyler6204. -- Cron: share isolated announce flow and harden scheduling/delivery reliability. (#11641) Thanks @tyler6204. -- Cron tool: recover flat params when LLM omits the `job` wrapper for add requests. (#12124) Thanks @tyler6204. - Gateway/CLI: when `gateway.bind=lan`, use a LAN IP for probe URLs and Control UI links. (#11448) Thanks @AnonO6. -- CLI: make `openclaw plugins list` output scannable by hoisting source roots and shortening bundled/global/workspace plugin paths. -- Hooks: fix bundled hooks broken since 2026.2.2 (tsdown migration). (#9295) Thanks @patrickshao. -- Routing: refresh bindings per message by loading config at route resolution so binding changes apply without restart. (#11372) Thanks @juanpablodlc. -- Exec approvals: render forwarded commands in monospace for safer approval scanning. (#11937) Thanks @sebslight. -- Config: clamp `maxTokens` to `contextWindow` to prevent invalid model configs. (#5516) Thanks @lailoo. -- Thinking: allow xhigh for `github-copilot/gpt-5.2-codex` and `github-copilot/gpt-5.2`. (#11646) Thanks @LatencyTDH. -- Thinking: honor `/think off` for reasoning-capable models. (#9564) Thanks @liuy. -- Discord: support forum/media thread-create starter messages, wire `message thread create --message`, and harden routing. (#10062) Thanks @jarvis89757. -- Paths: structurally resolve `OPENCLAW_HOME`-derived home paths and fix Windows drive-letter handling in tool meta shortening. (#12125) Thanks @mcaxtr. - Memory: set Voyage embeddings `input_type` for improved retrieval. (#10818) Thanks @mcinteerj. -- Memory: disable async batch embeddings by default for memory indexing (opt-in via `agents.defaults.memorySearch.remote.batch.enabled`). (#13069) Thanks @mcinteerj. -- Memory/QMD: reuse default model cache across agents instead of re-downloading per agent. (#12114) Thanks @tyler6204. -- Memory/QMD: run boot refresh in background by default, add configurable QMD maintenance timeouts, retry QMD after fallback failures, and scope QMD queries to OpenClaw-managed collections. (#9690, #9705, #10042) Thanks @vignesh07. -- Memory/QMD: initialize QMD backend on gateway startup so background update timers restart after process reloads. (#10797) Thanks @vignesh07. +- Memory/QMD: run boot refresh in background by default, add configurable QMD maintenance timeouts, and retry QMD after fallback failures. (#9690, #9705) +- Config/Memory: auto-migrate legacy top-level `memorySearch` settings into `agents.defaults.memorySearch`. (#11278, #9143) - Media understanding: recognize `.caf` audio attachments for transcription. (#10982) Thanks @succ985. - State dir: honor `OPENCLAW_STATE_DIR` for default device identity and canvas storage paths. (#4824) Thanks @kossoy. +- Tests: harden flaky hotspots by removing timer sleeps, consolidating onboarding provider-auth coverage, and improving memory test realism. (#11598) Thanks @gumadeiras. ## 2026.2.6 @@ -90,9 +45,6 @@ Docs: https://docs.openclaw.ai - Cron: scheduler reliability (timer drift, restart catch-up, lock contention, stale running markers). (#10776) Thanks @tyler6204. - Cron: store migration hardening (legacy field migration, parse error handling, explicit delivery mode persistence). (#10776) Thanks @tyler6204. -- Memory: set Voyage embeddings `input_type` for improved retrieval. (#10818) Thanks @mcinteerj. -- Memory/QMD: run boot refresh in background by default, add configurable QMD maintenance timeouts, retry QMD after fallback failures, and scope QMD queries to OpenClaw-managed collections. (#9690, #9705, #10042) Thanks @vignesh07. -- Media understanding: recognize `.caf` audio attachments for transcription. (#10982) Thanks @succ985. - Telegram: auto-inject DM topic threadId in message tool + subagent announce. (#7235) Thanks @Lukavyi. - Security: require auth for Gateway canvas host and A2UI assets. (#9518) Thanks @coygeek. - Cron: fix scheduling and reminder delivery regressions; harden next-run recompute + timer re-arming + legacy schedule fields. (#9733, #9823, #9948, #9932) Thanks @tyler6204, @pycckuu, @j2h4u, @fujiwara-tofu-shop. @@ -143,7 +95,6 @@ Docs: https://docs.openclaw.ai - Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204. - Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg. - macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety. -- Discord: enforce DM allowlists for agent components (buttons/select menus), honoring pairing store approvals and tag matches. (#11254) Thanks @thedudeabidesai. ## 2026.2.2-3 diff --git a/docs/concepts/memory.md b/docs/concepts/memory.md index 1990436548..22762bbef0 100644 --- a/docs/concepts/memory.md +++ b/docs/concepts/memory.md @@ -85,6 +85,8 @@ Defaults: - Enabled by default. - Watches memory files for changes (debounced). +- Configure memory search under `agents.defaults.memorySearch` (not top-level + `memorySearch`). - Uses remote embeddings by default. If `memorySearch.provider` is not set, OpenClaw auto-selects: 1. `local` if a `memorySearch.local.modelPath` is configured and the file exists. 2. `openai` if an OpenAI key can be resolved. diff --git a/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts b/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts index 1a33d33942..840f581476 100644 --- a/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts +++ b/src/config/config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts @@ -200,6 +200,24 @@ describe("legacy config detection", () => { expect(parsed.channels).toBeUndefined(); }); }); + it("flags top-level memorySearch as legacy in snapshot", async () => { + await withTempHome(async (home) => { + const configPath = path.join(home, ".openclaw", "openclaw.json"); + await fs.mkdir(path.dirname(configPath), { recursive: true }); + await fs.writeFile( + configPath, + JSON.stringify({ memorySearch: { provider: "local", fallback: "none" } }), + "utf-8", + ); + + vi.resetModules(); + const { readConfigFileSnapshot } = await import("./config.js"); + const snap = await readConfigFileSnapshot(); + + expect(snap.valid).toBe(false); + expect(snap.legacyIssues.some((issue) => issue.path === "memorySearch")).toBe(true); + }); + }); it("does not auto-migrate claude-cli auth profile mode on load", async () => { await withTempHome(async (home) => { const configPath = path.join(home, ".openclaw", "openclaw.json"); diff --git a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts index 0a97358850..c41f2f6495 100644 --- a/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts +++ b/src/config/config.legacy-config-detection.rejects-routing-allowfrom.test.ts @@ -173,6 +173,52 @@ describe("legacy config detection", () => { }); expect((res.config as { agent?: unknown }).agent).toBeUndefined(); }); + it("migrates top-level memorySearch to agents.defaults.memorySearch", async () => { + vi.resetModules(); + const { migrateLegacyConfig } = await import("./config.js"); + const res = migrateLegacyConfig({ + memorySearch: { + provider: "local", + fallback: "none", + query: { maxResults: 7 }, + }, + }); + expect(res.changes).toContain("Moved memorySearch → agents.defaults.memorySearch."); + expect(res.config?.agents?.defaults?.memorySearch).toMatchObject({ + provider: "local", + fallback: "none", + query: { maxResults: 7 }, + }); + expect((res.config as { memorySearch?: unknown }).memorySearch).toBeUndefined(); + }); + it("merges top-level memorySearch into agents.defaults.memorySearch", async () => { + vi.resetModules(); + const { migrateLegacyConfig } = await import("./config.js"); + const res = migrateLegacyConfig({ + memorySearch: { + provider: "local", + fallback: "none", + query: { maxResults: 7 }, + }, + agents: { + defaults: { + memorySearch: { + provider: "openai", + model: "text-embedding-3-small", + }, + }, + }, + }); + expect(res.changes).toContain( + "Merged memorySearch → agents.defaults.memorySearch (preserved explicit agents.defaults overrides).", + ); + expect(res.config?.agents?.defaults?.memorySearch).toMatchObject({ + provider: "openai", + model: "text-embedding-3-small", + fallback: "none", + query: { maxResults: 7 }, + }); + }); it("migrates tools.bash to tools.exec", async () => { vi.resetModules(); const { migrateLegacyConfig } = await import("./config.js"); diff --git a/src/config/legacy.migrations.part-3.ts b/src/config/legacy.migrations.part-3.ts index bb1ae80879..a762f74141 100644 --- a/src/config/legacy.migrations.part-3.ts +++ b/src/config/legacy.migrations.part-3.ts @@ -14,6 +14,34 @@ import { // tools.alsoAllow legacy migration intentionally omitted (field not shipped in prod). export const LEGACY_CONFIG_MIGRATIONS_PART_3: LegacyConfigMigration[] = [ + { + id: "memorySearch->agents.defaults.memorySearch", + describe: "Move top-level memorySearch to agents.defaults.memorySearch", + apply: (raw, changes) => { + const legacyMemorySearch = getRecord(raw.memorySearch); + if (!legacyMemorySearch) { + return; + } + + const agents = ensureRecord(raw, "agents"); + const defaults = ensureRecord(agents, "defaults"); + const existing = getRecord(defaults.memorySearch); + if (!existing) { + defaults.memorySearch = legacyMemorySearch; + changes.push("Moved memorySearch → agents.defaults.memorySearch."); + } else { + mergeMissing(existing, legacyMemorySearch); + defaults.memorySearch = existing; + changes.push( + "Merged memorySearch → agents.defaults.memorySearch (preserved explicit agents.defaults overrides).", + ); + } + + agents.defaults = defaults; + raw.agents = agents; + delete raw.memorySearch; + }, + }, { id: "auth.anthropic-claude-cli-mode-oauth", describe: "Switch anthropic:claude-cli auth profile mode to oauth", diff --git a/src/config/legacy.rules.ts b/src/config/legacy.rules.ts index 4de788a698..1f959c9944 100644 --- a/src/config/legacy.rules.ts +++ b/src/config/legacy.rules.ts @@ -85,6 +85,11 @@ export const LEGACY_CONFIG_RULES: LegacyConfigRule[] = [ message: "agent.* was moved; use agents.defaults (and tools.* for tool/elevated/exec settings) instead (auto-migrated on load).", }, + { + path: ["memorySearch"], + message: + "top-level memorySearch was moved; use agents.defaults.memorySearch instead (auto-migrated on load).", + }, { path: ["tools", "bash"], message: "tools.bash was removed; use tools.exec instead (auto-migrated on load).",