Skip to content

feat: merge mem agent 0424#1661

Merged
hijzy merged 163 commits into
mainfrom
mem-agent-0424
May 8, 2026
Merged

feat: merge mem agent 0424#1661
hijzy merged 163 commits into
mainfrom
mem-agent-0424

Conversation

@hijzy

@hijzy hijzy commented May 8, 2026

Copy link
Copy Markdown
Collaborator

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 (if applicable) | 我已在 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

hijzy and others added 30 commits April 24, 2026 18:15
…+ 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.
MatthewZhuang and others added 27 commits May 8, 2026 14:19
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.
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.
@hijzy hijzy self-assigned this May 8, 2026
@hijzy hijzy merged commit eb44d9b into main May 8, 2026
16 checks passed
@hijzy hijzy deleted the mem-agent-0424 branch May 14, 2026 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants