feat: merge mem agent 0424#1661
Merged
Merged
Conversation
…+ V7 fixes
主要变更分四部分:
## 1) Hermes adapter (memory provider) 端到端打通
- 不再手动 `episode.open` —— 让 `turn.start` 内部自动开 episode 并把
真实 episodeId 回传给 adapter,避免 trace 写到孤立 episode、
on_session_end 关错 episode 导致 reward chain 静默失败。
- `sync_turn` 从延迟队列改为同步 flush,避免 daemon bridge 把 episode
当 orphan 关掉前数据丢失。
- 注册 Hermes plugin 的 `post_tool_call` hook,捕获每次 tool 执行的
name/args/result,前端任务详情页能看到完整工具调用记录。
- `bridge_client.close()` 不再 kill bridge 子进程;bridge.cts 在 stdin
EOF 后若 viewer 仍在线就保活为 daemon,使内存面板在 hermes chat 之间
持续可访问。
## 2) 双端口 viewer 架构
- openclaw → :18799,hermes → :18800,各自进程独占自己的端口。
- 删除原 hub-promoter / peer-core / peerCores 复杂的端口共享 + 只读 peer
路由方案(约 1000 行)。
- `server/http.ts` 简化为单 agent 模型;保留两条「兼容旧书签」逻辑:
- 同 agent 前缀(如 `/openclaw/...`)→ 内部 rewrite 后继续 dispatch
(GET/POST/PATCH 都安全)
- 跨 agent 前缀 → 302 跳到对方 well-known 端口
- `install.sh` 删除 `--port` 参数(用 `--port` 报错告知 per-agent 固定
端口),按 agent 输出对应端口的 URL。
- 适配器(`bridge.cts` / `adapters/openclaw/index.ts`)硬编码 viewer 端口,
忽略 `config.viewer.port` —— 防止老 config.yaml 把端口锁死在旧值。
## 3) V7 反馈链路修复,让 demo 真能跑出 L2 / L3 / Skill
- `closeEpisode` 在返回前 `await handle.flush()`,单 shot adapter
(Hermes `chat -q`)退出前等 reflect → reward → L2 → L3 → skill 全部
跑完。
- `reward/subscriber.drain()` 在停机时**立刻**触发所有 pending 的
implicit fallback reward,不再被 30s `feedbackWindowSec` timer 卡掉。
- `reward/reward.ts::looksLikeTrivialContent` 重写为字符权重而非按行短行
罚分,修复 markdown / 代码 / 列表输出被误判 trivial 的问题;同时去掉
`minContentCharsForCompletion` 在 ASCII 上的硬编码 200 floor,让
cfg 真正生效。
- `l2.subscriber` / `l3.subscriber` 暴露 `drain()` 方法,
`pipeline/orchestrator.ts::flush()` 串行 drain L2/L3,确保 single-shot
退出前 induction / abstraction 完成。
## 4) 前端分页显示精确总数 + 圆点状态修复 + 选择页删除
- 5 个 list endpoint(traces / policies / world-models / skills / episodes)
返回 `total` 字段;对应 repo 加 `count(filter)` 方法。
- 6 个 view(Memories / Tasks / Policies / WorldModels / Skills / Logs)
从 response 读 `total` 算 `Math.ceil(total / PAGE_SIZE)`,分页器
显示「第 N 页 / 共 M 页」精确总数。
- `bridge/methods.ts::EPISODE_OPEN` 透传 `userMessage`,避免任务页出现
`(adapter-initiated)` 占位符。
## 验证
完整跑通 task-cli 9 轮 demo,最终:
- L1 traces ✓
- Episodes / r_task ✓
- Tool calls 完整记录 ✓
- L2 policies (active) ✓
- L3 world_model(confidence=0.95)✓
- Skills (active, eta=0.7) ✓
- 收官查询同时命中 Tier 1 (skill) + Tier 2 (trace) + Tier 3 (world_model)
…auth cookie
Two viewer-side bugs surfaced when openclaw and hermes are installed
side by side on the same machine:
1. **Legacy DB migration always read openclaw's path.**
The "import from legacy plugin" feature hard-coded the source DB
to `~/.openclaw/memos-local/memos.db`, so running the migration
inside the hermes viewer imported openclaw's old memories. Make
the path agent-aware (`hermes` → `~/.hermes/memos-state/memos-local/memos.db`),
add a generic `/api/v1/migrate/legacy/{scan,run}` endpoint that
uses `options.agent`, and keep explicit `/openclaw/*` and
`/hermes/*` aliases for clarity. Response now carries `agent` +
`path` so the viewer / tests can verify which DB was read.
2. **Viewer logged out the other agent on refresh.**
Both servers issued the cookie name `memos_sess` with `Path=/`.
Browsers do not isolate cookies by port, so logging into one
agent overwrote the other's cookie; the next refresh failed MAC
verification and the AuthGate kicked the user back to the login
screen. Scope the cookie name per agent (`memos_sess_<agent>`),
plumb `options.agent` through `registerAuthRoutes` and
`requireSession`, and keep a legacy-name fallback on read so
already-logged-in users aren't kicked out by the upgrade itself.
Tests:
- `tests/unit/server/http.test.ts` covers the openclaw/hermes/legacy
migrate endpoints + the agent-aware path resolution.
- New `tests/unit/server/auth-cookie-isolation.test.ts` reproduces
the original "refresh-one-logs-out-the-other" scenario end-to-end
and pins per-agent isolation, cross-agent rejection, and legacy
cookie fallback.
…auth cookie (#1548) ## Summary Two viewer-side bugs surface as soon as **openclaw** and **hermes** are installed side by side on the same host. Both are fixed in this PR. ### 1. Legacy DB migration always read openclaw's path `server/routes/migrate.ts` hard-coded the source DB to `~/.openclaw/memos-local/memos.db`, so triggering "import from legacy plugin" inside the **hermes** viewer happily imported **openclaw's** old memories. The hermes legacy plugin actually lived at `~/.hermes/memos-state/memos-local/memos.db` (note the extra `memos-state` segment). - The migration now resolves the legacy path from `options.agent`: - `openclaw` → `~/.openclaw/memos-local/memos.db` - `hermes` → `~/.hermes/memos-state/memos-local/memos.db` - New generic endpoints `GET/POST /api/v1/migrate/legacy/{scan,run}` for the viewer to call (the running agent picks its own path). - Explicit `/openclaw/*` and `/hermes/*` aliases kept for clarity + back-compat. - Response now carries `agent` and `path` so the UI shows exactly which file was read. - New `server.migrate` log channel (registered in `core/logger/channels.ts` and `docs/LOGGING.md`). ### 2. Refreshing one viewer logged out the other Both servers issued the cookie name `memos_sess` with `Path=/`. Browsers do **not** isolate cookies by port, so: 1. Login to openclaw → `memos_sess=tokenA` (signed with openclaw's `sessionSecret`). 2. Login to hermes → `memos_sess=tokenB` (signed with hermes's `sessionSecret`). The second one **overwrites** the first. 3. Refresh openclaw → browser sends tokenB → openclaw verifies with its own secret → MAC fails → AuthGate boots the user back to the LoginScreen. The fix scopes the cookie name per agent (`memos_sess_<agent>`): - `registerAuthRoutes(routes, deps, options)` and `requireSession(..., agent)` now know which agent they serve. - `cookieNameFor(agent)` returns `memos_sess_<agent>` when an agent is configured, otherwise the legacy `memos_sess` (so single-agent installs and test fixtures keep working). - `readSessionCookie` falls back to the legacy name on read, so users who were already logged in before the upgrade are **not** kicked out by the deploy itself; the next response writes the new per-agent cookie and the transition is silent. - `clearSessionCookie` clears both the per-agent name and the legacy name on logout. ## Test plan - [x] `npx vitest run tests/unit/server` — 56 of 56 pre-existing tests still pass; 12 new tests pass: - 5 new migrate-route assertions in `tests/unit/server/http.test.ts` covering openclaw/hermes/legacy endpoints + the `agent` field + the path string. - 5 new cases in `tests/unit/server/auth-cookie-isolation.test.ts`: - per-agent cookie naming (no `memos_sess`, only `memos_sess_<agent>`) - end-to-end regression: a single browser jar holding **both** cookies → both viewers report `authenticated: true` (the original bug) - cross-agent cookie rejection (hermes refuses an openclaw cookie) - smooth upgrade: legacy `memos_sess` cookie is still honoured - 401 gating without a valid cookie - [x] `npm run lint` is clean on every file touched in this PR (the repo has unrelated pre-existing TS errors that this PR does not introduce). - [ ] Manual smoke: install both agents, log into each, F5 refresh either viewer — the other no longer drops to LoginScreen. Cookies tab shows `memos_sess_openclaw` and `memos_sess_hermes` coexisting. - [ ] Manual smoke: in the hermes viewer, Import → "Scan legacy DB" reports the `~/.hermes/memos-state/memos-local/memos.db` path (not `.openclaw/...`). ## Notes - The 5 pre-existing test failures on `mem-agent-0424` (`countEpisodes`/`countTraces`/`countSkills` missing from the test stub) are **not** introduced by this PR — they reproduce on the unmodified target branch.
- Fix box-drawing alignment: emoji (🧠, ✨) occupy 2 display columns, standardize all boxes to 50-col interior width with manual padding - Fix "Terminated: 15" noise from background process kills by using disown before kill - Fix ANSI escape codes leaking in output by switching printf from %s to %b format specifier - Suppress npm postinstall noise by redirecting stdout/stderr - Add numbered step indicators ([1] [2] [3]...) for install progress - Add spinner with elapsed time for viewer readiness check, remove premature lsof shortcut that returned before HTTP was actually ready - Gracefully handle launchctl kickstart conflict when macOS launchd KeepAlive auto-restarts the gateway after stop - Proactively free Hermes port before smoke test to avoid stale process conflicts from OpenClaw gateway reload - Improve interactive picker with [] brackets and emoji per option, right-align option keys - Rename banner to "MemOS Local Plugin Installer" - Consolidate better-sqlite3 warning from 4 lines to 1 line + tip
## Summary - **Fix box alignment**: emoji (🧠, ✨) occupy 2 display columns — standardize all boxes to 50-col interior with manual padding so right `│` aligns correctly - **Fix "Terminated: 15" noise**: use `disown` for background smoke-test processes so bash doesn't print job-control messages on kill - **Fix ANSI escape codes leaking**: switch `printf` from `%s` to `%b` so embedded `\033[…` sequences render as colors instead of literal text - **Suppress npm postinstall noise**: redirect `npm install` output to avoid `> node scripts/postinstall.cjs` and `up to date in 12s` cluttering the install log - **Add step numbering**: `[1] [2] [3]…` progress indicators make the install flow easy to follow - **Viewer readiness spinner**: replace premature `lsof` shortcut with actual HTTP check (`curl`) + spinner with elapsed timer — prevents "installed successfully" when viewer isn't actually ready yet - **Handle launchctl conflict**: when macOS `KeepAlive` auto-restarts the gateway after `openclaw gateway stop`, detect the already-running gateway instead of reporting a false error - **Free stale Hermes port**: proactively kill leftover processes on `:18800` before smoke test to avoid "port already in use" skip - **Improve interactive picker**: `[]` brackets, emoji per option (🦞 OpenClaw, 👩 Hermes, 📦 Both), right-aligned option keys - **Rename banner**: `🧠 MemOS Local Plugin Installer` - **Consolidate warnings**: better-sqlite3 Node 25+ warning reduced from 4 lines to 1 + tip ## Test plan - [ ] Run `bash install.sh --version 2.0.0-beta.1` with both OpenClaw and Hermes installed - [ ] Verify box borders align in terminal (banner, headers, success/error boxes) - [ ] Verify no "Terminated" messages or raw `\033[` codes in output - [ ] Verify viewer spinner waits for actual HTTP readiness - [ ] Test interactive picker in TTY mode (options display correctly) - [ ] Test non-interactive mode via pipe (`curl ... | bash -s -- --version ...`)
- Fix box-drawing alignment for emoji display width - Fix "Terminated" noise and ANSI escape code leaks - Suppress npm postinstall noise, add step numbering - Viewer readiness spinner with actual HTTP check - Handle launchctl KeepAlive conflict gracefully - Improve interactive picker with emoji and alignment
…lCalls for coverage check
The old verifier used a regex to guess "command-like tokens" from the
draft's natural language text, then searched for them in the evidence
text via substring matching. The third regex branch `[a-z_]{3,}` pulled
in English verbs (install, verify, retry...) as false positives, while
substring search missed synonyms and CJK text — causing systematically
low coverage scores despite high resonance.
Replace the entire coverage pipeline with structured tool name comparison:
- New `extractToolNames()` reads `trace.toolCalls[].name` + first token
of string `tc.input` (for shell-like tools) as ground truth
- Crystallize prompt v3 injects `EVIDENCE_TOOLS` whitelist and requires
LLM to output explicit `tools: string[]` field
- Verifier checks `draft.tools ⊆ evidenceTools` via Set comparison
- Delete `collectCommandTokens`, `STOPWORDS`, `actionBlob` regex logic
- Add `tools: string[]` to `SkillCrystallizationDraft` and `SkillProcedure`
- Packager persists tools and renders "Tools used" in invocation guide
…lCalls for coverage check (#1552) ## Summary - Replace the regex-based "command token guessing" in `verifier.ts` with structured tool name comparison using `trace.toolCalls` ground truth data - Add `extractToolNames()` utility that reads `tc.name` + first token of string `tc.input` from evidence traces - Crystallize prompt v3: inject `EVIDENCE_TOOLS` whitelist into the prompt, require LLM to output explicit `tools: string[]` field constrained to the whitelist - Verifier coverage check is now a clean set-containment: `draft.tools ⊆ evidenceTools` — no regex, no STOPWORDS, no `actionBlob` substring search - Add `tools: string[]` to `SkillCrystallizationDraft`, `SkillProcedure`; packager persists and renders "Tools used" section ## Motivation The old regex third branch `[a-z_]{3,}` pulled English verbs (install, verify, retry...) into the coverage denominator as false positives, while substring matching missed synonyms and CJK text. This caused systematically low coverage scores despite high resonance, blocking valid skills from passing verification. ## Test plan - [x] All 41 skill unit tests pass (verifier, crystallize, packager, lifecycle, eligibility, events, evidence, subscriber, integration) - [x] Verifier tests rewritten with structured `toolCalls` evidence and `tools` draft field - [x] Crystallize test verifies `tools` field parsing from LLM response - [x] Zero lint errors
- Remove unused import `shutdown_bridge` (F401) - Apply ruff format: normalize multiline function args and dict literals Also add AGENTS_*.md to .gitignore.
## Summary - Remove unused import `shutdown_bridge` (ruff F401) - Apply ruff format: normalize multiline function args and dict literals in `__init__.py` ## Verification ``` $ ruff check apps/memos-local-plugin/ All checks passed! $ ruff format --check apps/memos-local-plugin/ 4 files already formatted ```
## Summary - Add `AGENTS_*.md` to `.gitignore` to prevent developer-local agent instruction files from being committed
OpenClaw's gateway process is managed by macOS launchd, so calling process.exit(0) causes it to respawn automatically. Leverage this to provide a seamless config-save experience: - OpenClaw: POST /api/v1/admin/restart triggers process.exit(0), viewer shows a full-screen spinner overlay (matching the legacy memos-local-openclaw style), polls /api/v1/health until the service comes back, then auto-reloads the page. - Hermes: keeps the existing dismissible toast telling the user to restart manually, since hermes doesn't auto-respawn the bridge. Files changed: - server/routes/admin.ts: restart endpoint now exits for openclaw - server/routes/registry.ts: pass ServerOptions to admin routes - web/src/stores/restart.ts: agent-aware restart + health polling - web/src/components/RestartOverlay.tsx: full-screen spinner + toast - web/src/stores/i18n.ts: add restart overlay i18n keys (en + zh) - web/src/views/SettingsView.tsx: await async triggerCleared()
## Summary - **OpenClaw**: 在记忆面板保存模型配置后,自动触发 gateway 重启(通过 `process.exit(0)` + launchd respawn),前端展示全屏转圈圈 loading 页面(参考旧版 `memos-local-openclaw` 样式),轮询 `/api/v1/health` 直到服务恢复后自动刷新页面 - **Hermes**: 保持原有的底部 toast 提示,告知用户手动重启 `hermes chat` - 后端 `POST /api/v1/admin/restart` 端点现在根据 agent 类型区分行为:OpenClaw 执行真正的进程退出,Hermes 仍为 no-op ## Test plan - [ ] OpenClaw: 设置页修改模型配置 → 保存 → 全屏转圈圈 → gateway 自动重启 → 页面自动刷新 - [ ] Hermes: 设置页修改配置 → 保存 → 底部 toast 提示手动重启 - [ ] 超时场景: gateway 未恢复 → 显示失败提示 + 手动重启命令
…egradation All LLM-dependent modules were silently falling back to heuristic/skip when the LLM client was null (e.g. host bridge not attached), making it very hard to diagnose why the self-evolution pipeline produced no results. This was reported in the TaskCLI demo test (2026-04-27). Changes: 1. human-scorer.ts: upgrade `score.heuristic` debug → `score.llm_unavailable` warn with explicit reason (config disabled vs client null) 2. induce.ts (L2): add `l2.induce.llm_unavailable` warn when llm is null (previously returned silently with no log at all) 3. crystallize.ts (Skill): upgrade `skill.crystallize.llm_disabled` info → `skill.crystallize.llm_unavailable` warn with reason 4. abstract.ts (L3): add `l3.abstract.llm_unavailable` warn when llm is null (previously returned silently with no log at all) 5. reward.ts: add one-time `reward.llm_unavailable` warn at runner creation explaining the full downstream impact 6. reward.ts + types.ts + schema.ts + defaults.ts: extract hardcoded `toolTurns >= totalTurns * 0.7` and `assistantContentChars < 80` into configurable `algorithm.reward.toolHeavyRatio` (default 0.7) and `algorithm.reward.minAssistantCharsForToolHeavy` (default 80) 7. Fix test mocks to include the two new RewardConfig fields
…avy skip thresholds (#1557) ## Summary - 修复所有 LLM 依赖模块在 LLM 客户端为空时**静默降级**的问题,改为输出 `warn` 级别日志,便于诊断"自我进化链路未跑通"的根因 - 将 `decideSkipReason` 中硬编码的工具密集型判断阈值(`toolTurns >= totalTurns * 0.7` 和 `assistantContentChars < 80`)提取为可配置参数 ## 背景 TaskCLI demo 测试(2026-04-27)发现:当 OpenClaw 的 HostLlmBridge 未注入时,`memos-local-plugin` 内部 LLM 客户端为空,导致 reward/L2/Skill/L3 全部静默退化为 heuristic/跳过,但日志中几乎看不到任何提示。此外 `decideSkipReason` 的工具密集型启发式在 OpenClaw 大量使用工具的场景下误判过多 episode 为 skip。 ## Changes | 文件 | 改动 | |------|------| | `core/reward/human-scorer.ts` | `debug` → `warn` `score.llm_unavailable`,附原因 | | `core/memory/l2/induce.ts` | 新增 `warn` `l2.induce.llm_unavailable`(之前无日志) | | `core/skill/crystallize.ts` | `info` → `warn` `skill.crystallize.llm_unavailable`,附原因 | | `core/memory/l3/abstract.ts` | 新增 `warn` `l3.abstract.llm_unavailable`(之前无日志) | | `core/reward/reward.ts` | 新增一次性 `warn` `reward.llm_unavailable`;`decideSkipReason` 读取可配阈值 | | `core/reward/types.ts` | `RewardConfig` 新增 `toolHeavyRatio` + `minAssistantCharsForToolHeavy` | | `core/config/schema.ts` | 注册两个新的 reward 配置字段 | | `core/config/defaults.ts` | 设置默认值 0.7 / 80(保持向后兼容) | | `tests/unit/reward/*.test.ts` | 补充新字段到测试 mock | ## Test plan - [ ] 配置 `llm.provider: host` 但不注入 bridge → 日志应出现 `reward.llm_unavailable`、`score.llm_unavailable`、`l2.induce.llm_unavailable` 等 warn - [ ] 配置正常 LLM → 无新增 warn,行为不变 - [ ] 在 `config.yaml` 设置 `algorithm.reward.toolHeavyRatio: 0.9` → 工具密集型 episode 不再被误判 skip - [ ] 现有单元测试通过(`tests/unit/reward/`)
When llm.provider=host (the OpenClaw default) but no adapter has called registerHostLlmBridge(), the LLM client is technically non-null but every call fails at runtime with LLM_UNAVAILABLE. This caused: - reward pipeline: hasLlm=true → try LLM → catch → heuristic fallback on every single episode, burning cycles and producing misleading "score.llm_failed" warns instead of a clean "no LLM" skip - L2/Skill/L3: same pattern — always attempt then fail Root cause: the OpenClaw plugin SDK (OpenClawPluginApi) does not expose a completion method, so the adapter has no way to wire a HostLlmBridge. The bridge registration mechanism exists but was never called. Fix: after createLlmClient(), check if provider=host and bridge is null. If so, emit a clear "llm.host_bridge_missing" warn explaining the impact and the fix (switch to a direct provider), then set llm=null so all downstream modules cleanly skip LLM paths instead of failing on every invocation.
…1558) ## Summary 修复 `llm.provider: host`(OpenClaw 默认配置)下 HostLlmBridge 未注入导致整条自我进化链路静默失效的问题。 ## 问题 OpenClaw 默认配置 `llm.provider: host`,意思是"让宿主程序帮忙调用 AI 模型"。但实际上 OpenClaw 的 Plugin SDK 没有暴露 LLM completion 接口,adapter 中也没有(也无法)调用 `registerHostLlmBridge()`。 结果: 1. `createLlmClient({provider: "host"})` 成功创建了 client 对象(构造时不检查 bridge) 2. 下游模块看到 `llm !== null`,认为 LLM 可用 3. 每次调用时 `HostLlmProvider.complete()` 才发现 bridge 为 null,抛出 `LLM_UNAVAILABLE` 4. human-scorer / L2 induce / Skill crystallize / L3 abstract 全部走 catch 降级 5. **reward 永远 heuristic(rHuman=0)、经验/技能/环境认知全部跳过** ## 修复 在 `core/pipeline/memory-core.ts` 中,LLM client 创建后立即检测: - 如果 `provider=host` 且 `getHostLlmBridge()` 为 null - 输出明确的 `warn` 日志 `llm.host_bridge_missing`,说明影响和修复方法 - 将 `llm` 设为 `null`,让下游模块干净地走"无 LLM"路径 用户需要在 `config.yaml` 中把 `llm.provider` 改为直接可用的 provider(如 `openai_compatible`、`anthropic`、`gemini`)并配上 API key 和 endpoint。 ## Test plan - [ ] 默认 `host` provider + 无 bridge → 启动日志应出现 `llm.host_bridge_missing` warn - [ ] 配置 `openai_compatible` provider + 有效 key → 正常工作,无新 warn - [ ] health API 中 `llm.available` 应为 false(provider=host 无 bridge 时)
## 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
- Global search: real-time categorized dropdown (memories, tasks, skills, experiences, env knowledge) with top 3 results per category - Added backend `q` parameter support for skills and episodes APIs - Help page: full bilingual (en/zh) support for all sections - Settings: translated team sharing subtitle via i18n - Tasks page: skill pipeline reasons now localized via reasonKey/reasonParams - Chat bubbles: render user/assistant/thinking as Markdown (new component) - Header brand: simplified to "MemOS / 记忆面板" - Search bar: expanded to fill full topbar width - memory_add logs: fix empty content for tool sub-steps, fix role inference - Version: bridge.cts reads from package.json (no more alpha/beta mismatch) - Health endpoint: read model names from disk config (reflects unsaved changes) - Admin restart: Hermes bridge now exits on restart (like OpenClaw)
- bridge.cts: implement --daemon flag (pure HTTP, no stdio) so the Memory Viewer can run as a standalone daemon process - admin/restart: Hermes now spawns a fresh daemon bridge before exiting, ensuring the viewer port comes back up automatically (like OpenClaw) - install.sh: keep bridge running after install as a daemon instead of killing it after smoke test - restart.ts: unified restart flow for all agents — both OpenClaw and Hermes show spinner overlay + poll-until-up + auto-reload
- admin/restart: exit first to release port, then bash sleeps 1s and spawns the new daemon (avoids EADDRINUSE race condition) - restart.ts: Hermes uses quickPollUp (800ms intervals, 8s max) for fast recovery; OpenClaw keeps the slower launchd poll cycle - install.sh: revert spinner frames to original braille characters
## Summary - **Global search**: real-time categorized dropdown showing top 3 results per category (memories, tasks, skills, experiences, env knowledge) as the user types - **Hermes daemon mode**: Memory Viewer now stays alive persistently — install.sh keeps it running, config save auto-restarts via self-respawn (like OpenClaw's launchd) - **i18n fixes**: Help page fully bilingual, team sharing subtitle, task skill pipeline reasons all localized - **Markdown chat**: user/assistant/thinking bubbles in task drawer now render as Markdown - **Bug fixes**: memory_add log content for tool sub-steps, version mismatch (bridge.cts reads package.json), health endpoint reads disk config for model names - **Search bar**: expanded to fill full topbar width - **Brand text**: simplified to "MemOS / 记忆面板" ## Test plan - [ ] Install via `install.sh --version ./pkg.tgz` for Hermes — verify daemon stays up after install - [ ] Open Memory Viewer at :18800 — verify global search dropdown shows results - [ ] Switch language to English — verify Help page, task skill reasons display in English - [ ] Open task drawer — verify chat bubbles render markdown (code blocks, bold, links) - [ ] Modify model config in Settings → Save — verify viewer auto-restarts without manual intervention - [ ] Run `hermes chat` while daemon is running — verify it operates in headless mode
- admin/clear-data: Hermes now spawns replacement daemon after clearing DB (same pattern as admin/restart) - triggerCleared: increased poll attempts for Hermes (DB re-creation) - RestartOverlay: show agent-specific manual restart hint on failure (OpenClaw: gateway restart command; Hermes: pkill + hermes chat)
…1563) ## Summary - admin/clear-data: Hermes now spawns replacement daemon after clearing DB (same self-respawn pattern as admin/restart) - triggerCleared: increased poll attempts for Hermes (DB re-creation needs extra time) - RestartOverlay: show agent-specific manual restart hint on failure (Hermes: `pkill -f bridge.cts && hermes chat`) ## Test plan - [ ] On Hermes viewer, go to Settings → Clear All Data → verify viewer auto-recovers - [ ] If restart times out, verify error message shows Hermes-specific hint instead of OpenClaw gateway command
Previously the import endpoint lowercased the entire content-type header before parsing, which corrupted the boundary value (e.g. WebKitFormBoundaryXyZ → webkitformboundaryxyz). The body retained the original case, so the parser could not find any boundary match and returned "missing 'bundle' file field". Other improvements: - parseMultipartBundle now operates on Buffers directly (no binary encoding round-trip that could corrupt UTF-8 content) - handles boundaries with or without leading dashes in the header - adds JSON fallback when multipart parsing fails entirely - raises import body limit to 100MB so large databases can be uploaded - install.sh: explicit bridge daemon kill step with force-kill fallback
…ng (#1565) ## Summary Fixes "missing 'bundle' file field" error when importing JSON bundles via the viewer's Import page. **Root cause**: The import endpoint lowercased the entire `content-type` header (`ct.toLowerCase()`) before parsing, which corrupted the case-sensitive boundary value. For example, browsers send a header like `boundary=----WebKitFormBoundaryfCbu5kYxjTihKDLq` but the request body uses the original-case `WebKitFormBoundaryfCbu5kYxjTihKDLq`. After lowercasing, no match could be found, parser returned `null`, and the user saw the misleading "missing 'bundle' file field" error. **Fix**: Preserve the original case of the content-type header for boundary parsing; only lowercase a copy used for the type-prefix check. ## Other improvements - `parseMultipartBundle` now operates on Buffers directly (no binary encoding round-trip that could corrupt UTF-8 content) - Handles boundaries with or without leading dashes in the header value - Adds JSON fallback when multipart parsing fails entirely (so users can also POST raw JSON) - `install.sh`: explicit bridge daemon kill step with force-kill fallback for cleaner re-installs ## Test plan - [ ] Import a JSON bundle exported from another agent — verify it succeeds without "missing 'bundle' file field" error - [ ] Import a JSON bundle with non-ASCII content (Chinese chars) — verify content is not corrupted
The "Found legacy DB" / "No legacy database found" messages were hard-coded English. Move them to i18n so Chinese mode displays properly translated strings.
Align viewer pipeline messaging with runtime thresholds, keep abstract memories available during identifier-heavy recall, and prevent Hermes clear-data from leaving stale bridge writers attached to the old database. Co-authored-by: Cursor <cursoragent@cursor.com>
The retrieval ranker's limit was the SUM of per-tier topK values
(e.g. topK={tier1:3,tier2:3,tier3:3} → limit=9), allowing merged
results to exceed the caller's expected total. Now searchMemory
enforces per-tier caps before returning hits, so topK=3 per tier
returns at most 3 results per tier instead of up to 9 total.
Fixes [BUG-2026-05-08] skill-type overflow in search results.
Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve package metadata conflicts by keeping the base branch beta version and fix the merged retrieval filter type error. Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary - Merge the latest MemOS plugin work from the beta8/dev branch into the local branch. - Improve retrieval so abstract memories like skills and world models survive identifier-heavy keyword confirmation filtering. - Fix Hermes clear-data lifecycle handling and align task skill-status copy with runtime thresholds. ## Test plan - `ruff check .` - `ruff format --check .` - `npm run lint` - Packed and installed the local plugin tarball into OpenClaw and Hermes; verified both viewers returned HTTP 200. Made with [Cursor](https://cursor.com)
feat: add keyword recall for experiences
Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary - Render skill invocation guides as Markdown in the viewer. - Tolerate imported Hermes skill evidence anchor shapes in the skill drawer. - Keep OpenClaw install config compatible with strict hook schema validation. ## Test plan - npx vitest run tests/unit/install/install-sh.test.ts - npm run lint Made with [Cursor](https://cursor.com)
Bring in experience keyword recall while resolving injector prompt conflicts by keeping user-actionable experience content and omitting internal ids, scores, and confidence metadata from rendered prompts.
…rge-mem-agent-0424-dev-into-0424
Automated PR from mem-agent-0424-niu0428 to mem-agent-0424.
Automated PR from mem-agent-0424-niu0428 to mem-agent-0424.
* feat(memos-local-plugin): replace JSON activity stream with category dashboard
The Overview page's "Live activity" card used to dump raw JSON payloads
into a monospace stream — visually noisy and unreadable for end users.
Replace with a 3 × 2 grid of category tiles (Memory / Experience /
Environment knowledge / Skill / Retrieval / Feedback). Each tile shows
a 5-minute event count, a 30-bucket sparkline (10 s each), and the most
recent event in plain language ("Memory stored / 记忆存储",
"Experience generated / 经验生成", "Tier 1 retrieval hit / 第一层检索命中",
…). Raw payload + event type stay available via the hover tooltip on
each tile so power users can still inspect.
- new web/src/views/overview/event-meta.ts: exhaustive CoreEventType
-> { cat, icon, title, detail } mapping. TS will refuse to compile
if a future event type is added without a tile entry here.
- new web/src/views/overview/Sparkline.tsx: dependency-free SVG
line + area chart, colour bound to --cat CSS variable.
- new web/src/views/overview/ActivityDashboard.tsx: 3 × 2 grid with
its own 10 s clock tick so tiles slide left even when SSE is quiet.
- styles/components.css: drop .stream* block (no other consumers),
add .dash-grid / .dash-tile / .dash-tile__* with category-driven
--cat / --cat-soft palette pulled from the existing semantic tokens.
- i18n.ts: add 9 category labels, 38 event titles, 10 detail
templates and 5 relative-time labels in both EN and ZH; drop the
now-unused overview.live.{subtitle,empty,hint} keys.
- OverviewView.tsx: bump SSE buffer cap from 12 to 256 (a 5-min
window with multiple events per minute easily exceeds 12) and swap
the .stream block for <ActivityDashboard events={recent} />.
Vocabulary mirrors the existing product i18n: L2 → "经验" (not 策略),
L3 → "环境认知" (not 世界观). Titles use the noun-verb compound style
("记忆存储" / "经验生成") that operations logs already use elsewhere.
* feat(memos-local-plugin): add overview activity demos
* fix: drive overview activity from api logs
chore: prune memos plugin package contents Limit the published plugin package to runtime assets and document install.sh as the supported installation path.
* chore: prune memos plugin package contents Limit the published plugin package to runtime assets and document install.sh as the supported installation path. * chore: delete settings
Avoid showing placeholder summaries for grouped memory turns by selecting the first usable summary in the group. Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary - Avoid showing placeholder summaries like `(empty turn)` for grouped memory cards. - Use the first usable summary within a turn group for card, drawer, and export display. - Include the ruff formatting update produced by the Python style check. ## Test plan - `ruff check .` - `ruff format --check .` - `npm run lint` Made with [Cursor](https://cursor.com)
…1658) * fix: apply per-tier topK truncation in searchMemory The retrieval ranker's limit was the SUM of per-tier topK values (e.g. topK={tier1:3,tier2:3,tier3:3} → limit=9), allowing merged results to exceed the caller's expected total. Now searchMemory enforces per-tier caps before returning hits, so topK=3 per tier returns at most 3 results per tier instead of up to 9 total. Fixes [BUG-2026-05-08] skill-type overflow in search results. Co-authored-by: Cursor <cursoragent@cursor.com> * feat: streamline model provider options and add inherit/local hints - Embedding: keep local/openai_compatible/gemini, remove cohere/voyage/mistral/anthropic - Summarizer: add (inherit) option to reuse agent model, remove bedrock/host/local_only - Skill Evolver: keep inherit/openai_compatible/gemini/anthropic, remove bedrock - Add localHint for embedding (MiniLM-L6-v2 384-dim info) and inheritsLabel for summarizer - Update schema.ts and defaults.ts to allow empty provider for LLM inherit mode Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: jiachengzhen <jiacz@memtensor.cn> Co-authored-by: Cursor <cursoragent@cursor.com>
- Help: rebuild concept guide with launch-2.0 architecture SVG ported to dashboard tokens (theme-adaptive fills, strokes, text) and a wider 1000px cap. Right-channel labels are stacked vertically (per-character for CJK) so they read top-to-bottom without head tilt; the bottom band swaps the saturated near- black for a soft accent wash; product name / version are removed from the closing caption. - Help: replace branded section dividers with a plain 1px rule so part transitions stay visible without locked-in copy. - Overview: drop the Live Activity card's elevation shadow via the existing card--flat modifier. - Layout: add word-break: keep-all on view-header descriptions so CJK pairs like "含义" no longer split mid-word.
…DME (#1660) - Bump package version from 2.0.0-beta.10 to 2.0.0-beta.11. - Reformat install instructions and the runtime-data table in README.md for cleaner rendering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
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
Checklist
Reviewer Checklist