release: merge dev-v2.0.25 into main#2156
Conversation
Generate evidence-backed OpenClaw local plugin release notes through the configured draft service. Add dry-run and publish workflow safeguards, retry/repair validation, prerelease handling, failure reporting hooks, redacted inspection artifacts, and focused local plugin test coverage. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# Conflicts: # examples/basic_modules/llm.py # src/memos/mem_reader/multi_modal_struct.py
## Description Please include a summary of the change, the problem it solves, the implementation approach, and relevant context. List any dependencies required for this change. Related Issue (Required): Fixes #issue_number ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactor (does not change functionality, e.g. code style improvements, linting) - [ ] Documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Unit Test - [ ] Test Script Or Test Steps (please provide) - [ ] Pipeline Automated API Test (please provide) ## Checklist - [ ] I have performed a self-review of my own code | 我已自行检查了自己的代码 - [ ] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 - [ ] I have created related documentation issue/PR in [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) | 我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档 issue/PR(如果适用) - [ ] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) - [ ] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 ## Reviewer Checklist - [ ] closes #xxxx (Replace xxxx with the GitHub issue number) - [ ] Made sure Checks passed - [ ] Tests have been provided
* feat(memos): add OpenRouter provider routing * fix(memos): route OpenRouter prefs through all slots * Fix OpenRouter reasoning config types * fix(openrouter): harden routing detection * fix(openrouter): harden review follow-ups * fix(openrouter): preserve provider defaults --------- Co-authored-by: jiachengzhen <jiacz@memtensor.cn> Co-authored-by: shinetata <149466187+shinetata@users.noreply.github.com>
## Description Please include a summary of the change, the problem it solves, the implementation approach, and relevant context. List any dependencies required for this change. Related Issue (Required): Fixes #issue_number ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactor (does not change functionality, e.g. code style improvements, linting) - [ ] Documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Unit Test - [ ] Test Script Or Test Steps (please provide) - [ ] Pipeline Automated API Test (please provide) ## Checklist - [ ] I have performed a self-review of my own code | 我已自行检查了自己的代码 - [ ] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 - [ ] I have created related documentation issue/PR in [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) | 我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档 issue/PR(如果适用) - [ ] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) - [ ] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 ## Reviewer Checklist - [ ] closes #xxxx (Replace xxxx with the GitHub issue number) - [ ] Made sure Checks passed - [ ] Tests have been provided
…onfig (#2135) * fix: Adjust feedback update review flow & using independent * refactor: unify LLM provider environment config * fix: fix log for embedding models * fix: fix tests * fix: preserve text when downgrading feedback updates * fix: type parser factory config as base parser config * fix: Open Code Review problems fix
## Description Please include a summary of the change, the problem it solves, the implementation approach, and relevant context. List any dependencies required for this change. Related Issue (Required): Fixes #issue_number ## Type of change Please delete options that are not relevant. - [x] Bug fix (non-breaking change which fixes an issue) - [x] Refactor (does not change functionality, e.g. code style improvements, linting) ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Unit Test - [ ] Test Script Or Test Steps (please provide) - [ ] Pipeline Automated API Test (please provide) ## Checklist - [x] I have performed a self-review of my own code | 我已自行检查了自己的代码 - [x] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 - [ ] I have created related documentation issue/PR in [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) | 我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档 issue/PR(如果适用) - [x] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) - [x] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 ## Reviewer Checklist - [ ] closes #xxxx (Replace xxxx with the GitHub issue number) - [ ] Made sure Checks passed - [ ] Tests have been provided
…t (Kimi Code) (#2133) * fix(openclaw): route classifyTopic + arbitrateTopicSplit per provider (#1611) `Summarizer.classifyTopic` and `Summarizer.arbitrateTopicSplit` always dispatched to the OpenAI implementation regardless of the summarizer's configured provider. When configured against an Anthropic-only endpoint (e.g. Kimi Code's `/coding/v1/messages`), every call returned 404 because the OpenAI helper appended `/chat/completions` to a URL that does not exist — wasting tokens, polluting logs, adding event-loop latency. Fix (Option A from the issue): - Add native classifyTopic{Anthropic,Gemini,Bedrock} and arbitrateTopicSplit{Anthropic,Gemini,Bedrock} in the three provider files, mirroring the shape of the existing judgeNewTopic* helpers. - Re-export TOPIC_CLASSIFIER_PROMPT / TOPIC_ARBITRATION_PROMPT from openai.ts so all providers share prompt strings and parseTopicClassifyResult remains the single JSON parser — no behavioral drift across providers. - Rewire callTopicClassifier / callTopicArbitration switch statements so the anthropic / gemini / bedrock arms route to their native implementations instead of falling through to the OpenAI helpers. - Bedrock helpers require cfg.endpoint (throws `Bedrock topic-classifier|arbitration requires 'endpoint'`) matching every other Bedrock helper in the file. - Mirror every edit into packages/memos-core/src/ingest/providers/ so the byte-similar sibling tree cannot silently regress the bug after the next sync. Tests: new tests/topic-classifier-dispatch.test.ts (8 cases) stubs globalThis.fetch and asserts each provider hits the correct URL + body shape; includes a regression case where an Anthropic 404 surfaces an `Anthropic topic-classifier failed` error rather than the old `OpenAI topic-classifier failed` — the exact string from issue #1611. TDD baseline: 7/8 fail against buggy code. Post-fix: 8/8 pass. Existing tests/topic-judge-minimax-1315.test.ts (5/5) continues to pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(openclaw): harden topic-classifier/arbitrator providers per OCR review Address code-review findings on the topic-classifier + arbitrator dispatch helpers added in #2133 (issue #1611). Applied to both apps/memos-local-openclaw and packages/memos-core (byte-similar mirrors). Correctness / security fixes: - anthropic: validate cfg.apiKey up front instead of silently sending ""; move cfg.headers spread BEFORE x-api-key + anthropic-version so a misconfigured header cannot silently overwrite the credential - anthropic: guard content parsing — treat missing/non-array json.content as [] to avoid TypeError on unexpected API payloads - anthropic: reduce arbitrateTopicSplit max_tokens from 60 to 10 to match arbitrateTopicSplitOpenAI (single-word NEW/SAME reply) - gemini: validate cfg.apiKey up front; construct URL via new URL() + URLSearchParams so a caller-supplied endpoint that already contains a query string ("?version=v1beta") does not produce malformed "…?version=v1beta?key=…" - bedrock: emit warn log when arbitrateTopicSplit sees empty or unexpected text so silent bias toward SAME becomes visible at normal log levels (production usually suppresses debug) Intentionally not applied (out-of-scope refactors that would touch pre-existing helpers not in this PR): DRY-extract shared low-level callers for anthropic/gemini/bedrock (findings #4/#7/#10/#14) and the DEFAULT_BEDROCK_MODEL constant (finding #11). Existing tests unchanged: tests/topic-classifier-dispatch.test.ts (8/8) and tests/topic-judge-minimax-1315.test.ts (5/5) still pass. The new guards use apiKey values already provided by every test case, so no test edits were required. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(openclaw): address remaining OCR round-2 findings on topic-classifier providers Round 1 (commit 646c28a) did not fully converge OCR review. Round 2 targets the 2 repeated findings and 10 newly detected ones without expanding scope beyond the classifier/arbitration functions added by PR #2133. Bedrock (packages/memos-core + apps/memos-local-openclaw): - Fix TRUE MISS from Round 1: `arbitrateTopicSplitBedrock` was still using `maxTokens: 60` while Anthropic's arbitrator was already lowered to 10. Aligned to `maxTokens: 10`. - Introduce `DEFAULT_BEDROCK_TOPIC_MODEL` constant scoped to the two new functions only (`classifyTopicBedrock`, `arbitrateTopicSplitBedrock`). Pre-existing helpers (`judgeDedupBedrock`, `summarizeBedrock`, etc.) keep their inline default to stay out of scope. - Extract `bedrockConverseTopic()` shared transport used by the two new functions to eliminate the DRY duplication OCR flagged. Gemini (packages/memos-core + apps/memos-local-openclaw): - Add empty/unexpected-response `log.warn` branches to `arbitrateTopicSplitGemini`, mirroring the Bedrock arbitrator's defensive handling (Round 1 covered Bedrock only). - Extract `callGeminiTopic()` shared transport used by the two new functions to eliminate the DRY duplication OCR flagged. - Rejected escalating the empty-response case to `throw`: throwing would cascade through `Summarizer.tryChain` and burn tokens on every fallback; warn+default-to-SAME is the safer choice for a boundary detector. Anthropic (packages/memos-core + apps/memos-local-openclaw): - Extract `callAnthropicMessagesTopic()` shared transport used by the two new functions to eliminate the DRY duplication OCR flagged. Header spread order is preserved verbatim: `...cfg.headers` comes BEFORE the credential and `anthropic-version` so user-supplied headers cannot override them (this was the Round 1 security fix — do not undo). Pre-existing helpers in each provider are intentionally untouched to keep the diff minimum-scoped to PR #2133's classifier/arbitrator additions. Verification (executed in apps/memos-local-openclaw): - `./node_modules/.bin/vitest run tests/topic-classifier-dispatch.test.ts \\ tests/topic-judge-minimax-1315.test.ts` → 13/13 passed - `./node_modules/.bin/tsc --noEmit` on the 3 modified provider files → 0 errors - All 6 files (3 apps + 3 packages/memos-core mirrors) are byte-identical --------- Co-authored-by: MemOS AutoDev <autodev@memtensor.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…uses viewer dashboard (#2132) * fix: viewer dashboard drifts to zero after a namespace flip (#2131) The viewer's Overview/metrics/traces/session routes filtered reads through the core's mutable activeNamespace, which every turn/session rewrites from caller context hints (openclaw: profileId = ctx.agentId). When the gateway session or a sub-agent turn flipped the profile, all historical rows failed the visibility clauses and dashboard counts collapsed to zero. The reported root cause (missing chunks table) is a misdiagnosis: the only 2.0 reference to chunks is the legacy 1.0-import reader in server/routes/migrate.ts; the live pipeline queries traces/episodes/ sessions with vectors stored in BLOB columns, so no schema change is needed. Fix: complete the existing includeAllNamespaces viewer convention (already used by diag.ts/session.ts/memory.ts) — add the option to core.metrics() and core.listEpisodes(), and pass it from overview.ts, metrics.ts, trace.ts and session.ts. Scoped reads and turn-time retrieval isolation are unchanged; explicit owner filters still narrow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: align listApiLogs namespace scoping with viewer metrics feeds Follow-up to #2131 (OCR round 1/2): - listApiLogs: accept includeAllNamespaces in the contract and core facade (contract symmetry with listTraces/listSkills/listPolicies); metrics/tools now passes it explicitly so both feeds of the bump() aggregation are scoped identically - metrics(): document that the traces fetch feeding sessions/ writesToday/embeddings/dailyWrites is intentionally cross-namespace; only totalTurns respects includeAllNamespaces - listEpisodes: apply limit/offset after the visibility filter on the namespace-scoped path so pages are not silently under-filled by other namespaces' rows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: memos-autodev[bot] <autodev-bot@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(plugin): page dirty-closed reward recovery * fix(plugin): share dirty scan cursor type --------- Co-authored-by: HarveyXiang <harvey_xiang@163.com>
…op (#1953) * fix(adapter): fire session.close in daemon thread to unblock event loop on_session_end() called bridge.request("session.close") inline with a 30 s blocking urlopen(). gateway/run.py calls this synchronously from _handle_reset_command (an async fn), so the blocking I/O ran on the asyncio event loop thread, preventing Discord heartbeats from firing and causing forced reconnection after 10–30 s. The session.close response is unused and errors are already suppressed, so the call is semantically fire-and-forget. Moving it to a daemon thread is the correct fix: the event loop is never blocked, the request still goes out, and a 5 s timeout keeps it bounded if the bridge is dead. Reproducer: Violet 2026-06-12 09:54 (agent.log lines 3629–3791). Spec: ~/specs/memos-bridge-blocking-shutdown-spec.md * Fix #1897: bug(memos-local-plugin): Hermes background model status checks can trigger paid (#1899) * Fix #1897: fix(memos-local-plugin): add LLM circuit breaker for terminal provider errors Issue #1897 reported ~12,900 paid LLM requests in 24 h on Hermes against a DeepSeek key with insufficient balance. The local `system_model_status` row count (12,900) closely tracked the provider-side `request_count` (11,344) for the same billing window. The naming is misleading: `system_model_status` is not a health probe; it is the audit row written once per LLM call (ok / fallback / error) inside `core/llm/client.ts`. With no circuit breaker, every pipeline subscriber (capture / session-relation / reward / L2 / L3 / skill / retrieval LLM filter / world-model) kept firing on every turn / closed episode / induction, generating one paid request each. Add a per-`LlmClient` circuit breaker: - Trips on terminal errors: HTTP 401/402/403 or messages containing `insufficient balance` / `invalid api key` / `unauthorized` / `account suspended` / `billing`. - Open: short-circuits subsequent calls inside the facade without contacting the provider. Throws `MemosError(LLM_UNAVAILABLE)` with `details.circuitOpen=true` so existing catch blocks still work. - Half-open after cool-down (default 5 min, configurable, min 30 s): next call probes the provider; success closes the breaker, terminal failure re-opens it for another cool-down. - Host fallback rescues a call without tripping the breaker — fallback exists precisely to keep going when the primary is down. - Coalesces `system_model_status="circuit_open"` audit rows to at most one per ~25 s while the breaker stays open, so we don't replace paid spam with audit-row spam. - Exposes `circuitOpen` / `circuitOpenUntil` / `circuitOpenedReason` via `LlmClientStats` for the Overview viewer card. - Enabled by default; legacy behaviour available via `circuitBreaker.enabled = false`. Tests: 9 new vitest cases under `tests/unit/llm/client.test.ts` covering trip on 402, trip on "insufficient balance" message, no trip on generic transient, coalescing, half-open close on success, host-fallback rescues without trip, disabled mode, stats fields, and re-open on terminal probe failure. All 59 LLM and 28 pipeline tests pass; `tsc --noEmit` clean. Out of scope (tracked separately): 429 `Retry-After` handling (issue #1620), per-tool rate limits, daily budget caps. * Fix LLM breaker with host fallback --------- Co-authored-by: autodev-bot <autodev@memtensor.local> Co-authored-by: Jiang <33757498+hijzy@users.noreply.github.com> Co-authored-by: GU TIANCHUN <96930846+TianchunGu@users.noreply.github.com> Co-authored-by: Dubberman <48425266+whipser030@users.noreply.github.com> --------- Co-authored-by: Memtensor-AI <project@memtensor.cn> Co-authored-by: autodev-bot <autodev@memtensor.local> Co-authored-by: Jiang <33757498+hijzy@users.noreply.github.com> Co-authored-by: GU TIANCHUN <96930846+TianchunGu@users.noreply.github.com> Co-authored-by: Dubberman <48425266+whipser030@users.noreply.github.com>
feat(2c): add log timezone support Co-authored-by: Fayenix <fayenix@users.noreply.github.com> Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
Co-authored-by: Erick Wipprecht <53452309+chiefmojo@users.noreply.github.com>
* Fix #1897: fix(memos-local-plugin): add LLM circuit breaker for terminal provider errors Issue #1897 reported ~12,900 paid LLM requests in 24 h on Hermes against a DeepSeek key with insufficient balance. The local `system_model_status` row count (12,900) closely tracked the provider-side `request_count` (11,344) for the same billing window. The naming is misleading: `system_model_status` is not a health probe; it is the audit row written once per LLM call (ok / fallback / error) inside `core/llm/client.ts`. With no circuit breaker, every pipeline subscriber (capture / session-relation / reward / L2 / L3 / skill / retrieval LLM filter / world-model) kept firing on every turn / closed episode / induction, generating one paid request each. Add a per-`LlmClient` circuit breaker: - Trips on terminal errors: HTTP 401/402/403 or messages containing `insufficient balance` / `invalid api key` / `unauthorized` / `account suspended` / `billing`. - Open: short-circuits subsequent calls inside the facade without contacting the provider. Throws `MemosError(LLM_UNAVAILABLE)` with `details.circuitOpen=true` so existing catch blocks still work. - Half-open after cool-down (default 5 min, configurable, min 30 s): next call probes the provider; success closes the breaker, terminal failure re-opens it for another cool-down. - Host fallback rescues a call without tripping the breaker — fallback exists precisely to keep going when the primary is down. - Coalesces `system_model_status="circuit_open"` audit rows to at most one per ~25 s while the breaker stays open, so we don't replace paid spam with audit-row spam. - Exposes `circuitOpen` / `circuitOpenUntil` / `circuitOpenedReason` via `LlmClientStats` for the Overview viewer card. - Enabled by default; legacy behaviour available via `circuitBreaker.enabled = false`. Tests: 9 new vitest cases under `tests/unit/llm/client.test.ts` covering trip on 402, trip on "insufficient balance" message, no trip on generic transient, coalescing, half-open close on success, host-fallback rescues without trip, disabled mode, stats fields, and re-open on terminal probe failure. All 59 LLM and 28 pipeline tests pass; `tsc --noEmit` clean. Out of scope (tracked separately): 429 `Retry-After` handling (issue #1620), per-tool rate limits, daily budget caps. * Fix LLM breaker with host fallback * fix(plugin): bound recovery reflect replay LLM calls --------- Co-authored-by: autodev-bot <autodev@memtensor.local> Co-authored-by: Jiang <33757498+hijzy@users.noreply.github.com> Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
fix: guard against episode storm stalling foreground sessions (#1755) Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
…1955) The MemOS daemon (`bridge.cts`) resolved config inside `bootstrapMemoryCoreFull` but never called `initLogger`, so the active logger stayed on the `bootstrapConsoleOnly()` default with `tz` pinned to "UTC". This made `logging.timezone` (PR #44) inert in the daemon — and the rest of `logging.*` (level, channels, file/audit/llm/perf/events sinks) dead too. Pretty/compact timestamps kept printing UTC regardless of config. Add an opt-in `initLogging` flag to `BootstrapOptions`. When set, `bootstrapMemoryCoreFull` calls `initLogger(config, home)` right after config resolution, before anything logs. The standalone bridge passes it; embedded plugin hosts (`adapters/openclaw/index.ts`) leave it off so the host keeps control of its own logging. Test: bootstrap with `logging.timezone` set + `initLogging: true` stamps records with the configured tz; without the flag the logger is untouched.
* feat(api): align OpenMem v1 SDK with cloud API * fix: align generated skill guidance * feat(api): align OpenMem v1 SDK with cloud API * fix(memos-local): include json hint in user messages (#1756) Co-authored-by: shinetata <149466187+shinetata@users.noreply.github.com> --------- Co-authored-by: dingliang <2650876010@qq.com> Co-authored-by: Qi Weng <bittergreen.wengqi@hotmail.com> Co-authored-by: de1ty <7804799+de1tydev@users.noreply.github.com> Co-authored-by: shinetata <149466187+shinetata@users.noreply.github.com> Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
…xt-aware structured extraction
#2155) fix: Add dedicated document LLM, improve Markdown detection and context-aware structured extraction
🤖 Open Code ReviewTarget: PR #2156 🔍 OpenCodeReview found 125 issue(s) in this PR. 1.
|
✅ Automated Test Results: PASSEDAll tests passed (204/204 executed, 1 skipped). memos_github_open_source/smoke: 1/1, memos_local_openclaw/unit: 45/45, memos_local_plugin/changed-python-source: 3/3, memos_python_core/changed-repo-python: 155 passed, 1 skipped. Duration: 19s [advisory, non-gating] AI-generated tests on branch test/auto-gen-47c422590cb9b57f-20260724162555: 110/112 passed, 2 failed — these do NOT affect the PR verdict; review the branch manually. Branch: |
Description
Merge
dev-v2.0.25intomainto prepare the MemOSv2.0.25release.This release aggregates the fixes, features, performance improvements, and documentation updates currently integrated into the release branch. Major changes include:
The release is implemented by promoting the validated
dev-v2.0.25branch intomain. The package version has been confirmed as2.0.25in bothpyproject.tomlandsrc/memos/__init__.py.No release-specific dependencies are introduced by this merge PR. Any dependency changes are contained in the individual changes already integrated into the release branch.
Related Issue (Required): N/A — this is a release aggregation PR; related issues are linked from the included pull requests.
Type of change
How Has This Been Tested?
The individual changes included in
dev-v2.0.25contain corresponding unit and regression tests where applicable.Before merging, this release PR will be validated by the repository's required GitHub Actions test matrix across the supported Python versions and operating systems.
No separate manual API test was performed specifically for this release aggregation PR.
Checklist
-[x] I have performed a self-review of my own code | 我已自行检查了自己的代码