Skip to content

merge: mem-agent-0509 into mem-agent-0512#1712

Merged
syzsunshine219 merged 24 commits into
mem-agent-0512from
mem-agent-0509
May 12, 2026
Merged

merge: mem-agent-0509 into mem-agent-0512#1712
syzsunshine219 merged 24 commits into
mem-agent-0512from
mem-agent-0509

Conversation

@syzsunshine219
Copy link
Copy Markdown
Collaborator

Summary

Merge mem-agent-0509 line of work into the new integration branch mem-agent-0512.

This is part of the 0512 integration: the 0512 branch is freshly cut from main, and we are landing the 0509 + 0509-magent work plus the latest bug fix on top of it so we can release 2.0.0-beta.13.

What's included from mem-agent-0509

Notable items beyond main:

Test plan

Made with Cursor

hijzy and others added 24 commits May 9, 2026 16:28
…ding

Two co-located package-layout tidy-ups:

1. Rename `web/` to `viewer/`
   - `git mv web viewer`, `tests/unit/web` to `tests/unit/viewer`,
     `tsconfig.web.json` to `tsconfig.viewer.json`.
   - Updated build/runtime references: `vite.config.ts` (root + alias
     `@web` to `@viewer`), `bridge.cts` (staticRoot), `package.json`
     (`files`, scripts `build:viewer` / `viewer:dev`),
     `adapters/openclaw/index.ts` (resolveViewerStaticRoot
     candidates), `tsconfig.json` / `tsconfig.build.json` exclude
     entries, `.gitignore` (`viewer/dist/`), and the install
     adapter scripts' log lines.
   - Updated test import paths and code/doc comments across
     `tests/`, `docs/`, `viewer/README.md`, `viewer/ALGORITHMS.md`,
     `ARCHITECTURE.md`, `README.md`, etc.
   - No public surface change: package name, `main`, `exports`,
     HTTP routes (`/ui/`, `/api/v1/*`) all unchanged. Natural-English
     uses of "web" (e.g. "web framework", "open web") preserved.

2. Drop unfinished `site/` scaffolding
   - Remove `site/**`, `tsconfig.site.json`, `tests/unit/site/`.
   - Strip `siteRoot` and `/site/*` route from `server/middleware/static.ts`
     and `server/types.ts`.
   - Clean up `.npmignore`, `CHANGELOG.md`, `templates/README.user.md`,
     and tsconfig include/exclude entries that referenced `site/`.

Verification:
- `npm run lint` (tsc --noEmit) — pass
- `npm run build` + `npm run build:viewer` — pass; `viewer/dist/` produced
- `npm pack --dry-run` — `viewer/dist/*` shipped
- 110 viewer/install/http/e2e tests pass
- Pre-existing failures in reward / memory / migrator suites are
  unrelated (verified by re-running on the un-renamed HEAD).
…scaffolding (#1666)

## Summary

Two co-located, low-risk package-layout tidy-ups for
`apps/memos-local-plugin`:

### 1. Rename `web/` → `viewer/`

The directory was named `web/` for historical reasons but everything in
it is the **viewer** SPA (Vite + Preact dashboard). Aligning the name
with what it actually is.

- `git mv` rename of:
  - `web/` → `viewer/`
  - `tests/unit/web/` → `tests/unit/viewer/`
  - `tsconfig.web.json` → `tsconfig.viewer.json`
- Build/runtime references updated:
  - `vite.config.ts` (`root`, alias `@web` → `@viewer`)
  - `bridge.cts` (`staticRoot: viewer/dist`)
  - `package.json` (`files`, scripts `build:viewer` / `viewer:dev`)
  - `adapters/openclaw/index.ts` (`resolveViewerStaticRoot` candidates)
  - `tsconfig.json` / `tsconfig.build.json` (`exclude`)
  - `.gitignore` (`viewer/dist/`)
  - `adapters/{openclaw,hermes}/install.*.sh` log lines
- Test imports + code/doc comments updated across `tests/`, `docs/`,
`viewer/README.md`, `viewer/ALGORITHMS.md`, `ARCHITECTURE.md`,
`README.md`, etc.
- **No public surface change**: package name, `main`, `exports`, HTTP
routes (`/ui/`, `/api/v1/*`) all unchanged.
- Natural-English uses of "web" (e.g. \"web framework\", \"open web\")
preserved — only path/identifier references were touched.

### 2. Drop unfinished `site/` scaffolding

The `site/` directory was a half-built product website that's no longer
used; this removes the leftover scaffolding so it doesn't confuse
readers or get accidentally bundled.

- Remove `site/**`, `tsconfig.site.json`, `tests/unit/site/`.
- Strip `siteRoot` and `/site/*` route from
`server/middleware/static.ts` + `server/types.ts`.
- Clean up `.npmignore`, `CHANGELOG.md`, `templates/README.user.md`, and
tsconfig include/exclude entries that referenced `site/`.

## Test plan

- [x] `npm run lint` (tsc --noEmit) — pass
- [x] `npm run build` + `npm run build:viewer` — pass; `viewer/dist/`
produced
- [x] `npm pack --dry-run` — `viewer/dist/*` shipped in the tarball
- [x] 110 viewer / install / http / e2e unit tests pass
- [x] Verified pre-existing failures in reward / memory / migrator
suites are NOT caused by this PR (re-ran on `HEAD` before the rename —
same 8 failures).
- [ ] Manual smoke on the daemon: `npm run bridge:daemon` and confirm
the viewer is served from the renamed path
Add embedding maintenance APIs and viewer controls so imported memories and model changes can repair or rebuild vectors against the active provider. Treat remote embedding dimensions as provider-derived state, not user config, and aggregate explicit feedback corrections consistently.
## Summary
- Add embedding maintenance endpoints and viewer controls to repair
missing/mismatched vectors or rebuild all vectors after imports/model
changes.
- Infer remote embedding dimensions from provider responses instead of
exposing dimensions as user config, preventing bge-m3 vectors from being
truncated to 384.
- Aggregate multiple explicit feedback corrections in heuristic reward
fallback so later negative feedback can lower trace value and priority.

## Test plan
- npm run lint
- npm test -- tests/unit/config/load.test.ts
tests/unit/config/writer.test.ts tests/unit/embedding/normalize.test.ts
- npm test -- tests/unit/reward/human-scorer.test.ts
tests/unit/pipeline/memory-core.test.ts -t "heuristic|submitFeedback
aggregates|repairs missing"
- npm test -- tests/unit/pipeline/memory-core.test.ts
tests/unit/reward/human-scorer.test.ts tests/unit/server/http.test.ts
tests/unit/bridge/methods.test.ts
- npm run build:viewer
- npm pack --json
…on and interactive UI

- Refactor `install.ps1` to auto-detect OpenClaw/Hermes and add an interactive menu.
- Use `npm pack` and tarball extraction for robust package deployment.
- Automate configuration patching for `openclaw.json` and `config.yaml`.
- Update `postinstall.cjs` banner to drop the hardcoded `-Agent` argument.
## Description 

This PR significantly improves the Windows PowerShell installation
experience for the `memos-local-plugin`.

**Key Changes:**
1. **Auto-detection & Interactive UI**: Introduced an interactive menu
in `install.ps1` that automatically detects existing OpenClaw
(`~/.openclaw`) and Hermes (`~/.hermes`) environments.
2. **Robust Deployment**: Replaced simple file copying with `npm pack`
and tarball extraction to ensure a cleaner and more reliable package
deployment.
3. **Automated Configuration**: The script now automatically patches the
target agent's configuration files (`openclaw.json` for OpenClaw and
`config.yaml` for Hermes), reducing manual setup steps.
4. **Postinstall Update**: Removed the hardcoded `-Agent` argument from
the `postinstall.cjs` banner, as the PowerShell script now handles agent
selection automatically.


## Type of change 

Please delete options that are not relevant. 

- [x] New feature (non-breaking change which adds functionality) 
- [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

- [x] Test Script Or Test Steps (please provide) 

**Test Steps:**
1. On a Windows environment, run `powershell -ExecutionPolicy Bypass
-File install.ps1`.
2. Verify that the interactive menu correctly displays the auto-detected
agent environments.
3. Select an installation option (e.g., OpenClaw, Hermes, or Both).
4. Confirm that the tarball is generated and extracted successfully into
the target directory.
5. Verify that the respective configuration files (`openclaw.json` or
`config.yaml`) are correctly patched with the plugin details.
6. Verify that the Memory Viewer starts properly.

## 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
`https://github.com/MemTensor/MemOS-Docs` (if applicable) | 我已在
`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
Keep OpenClaw tool observations available for memory capture and strip retrieval metrics from episode prompt injection so recalled context remains answer-focused.
CI generates this file from secrets via
`scripts/generate-telemetry-credentials.cjs` immediately before
`npm publish` (see `.github/workflows/hermes-plugin-publish.yml`).
Local copies are only useful for development against a personal
ARMS workspace and must never be committed.

The repo-root `.gitignore` has a blanket `!apps/**/*.json` allow-rule
that overrides any per-package ignore for .json files; the closer
`apps/memos-local-plugin/.gitignore` wins because git's "closest
.gitignore wins" rule applies regardless of polarity. Adding the
explicit entry here is therefore sufficient.

Co-authored-by: Cursor <cursoragent@cursor.com>
The original v2 telemetry rollout (commit 3600f80) only wired the
Hermes-side `bridge.cts`. Three knock-on effects made the
`memos_local_hermes_v2` ARMS dashboards drift away from reality:

1. **OpenClaw adapter never emitted any events.** The whole
   in-process plugin path bypassed the `Telemetry` instance, so
   `agent_name=openclaw` was silently zero across `plugin_started`,
   `memory_search`, `memory_ingested`, `feedback_submitted`, and
   `viewer_opened`.
2. **`daily_active` counted process launches, not days.** The
   in-memory `dailyPingSent` boolean reset on every
   `bridge.cts` subprocess spawn (Hermes spawns one per `chat`),
   so DAU = startup count.
3. **`viewer_opened` only fired on the first
   `GET /api/v1/overview`** *per process*, then suppressed forever
   by a closure flag. Background pollers and CLI calls counted
   as "viewer opens"; restarts re-counted the same operator.
4. **`plugin_error` was declared but never invoked.** The crash
   visibility the dashboard implied did not exist.

Changes
-------

- `adapters/openclaw/index.ts`:
    Construct `Telemetry`, call `bindTelemetry`, emit
    `trackPluginStarted("openclaw")`, and pass the instance
    into `startHttpServer` so OpenClaw matches the Hermes
    surface 1:1. Plugin-root resolution shared with the
    existing viewer-static-root helper.

- `core/telemetry/sender.ts`:
    Persist the daily-ping date to
    `<stateDir>/memos-local/.last-daily-ping`. Read on every
    start; only emit when today's date differs from the file.
    Read failures degrade gracefully to "first time today"
    (over-report by ≤1, never under-report). Removed the
    obsolete in-memory `dailyPingSent` / `dailyPingDate`
    fields.

- `server/routes/telemetry.ts` (new) +
  `viewer/src/components/App.tsx`:
    Replace the GET-piggybacking `viewer_opened` with a
    dedicated `POST /api/v1/telemetry/viewer-opened` invoked
    once from the SPA's `<App />` mount effect. Endpoint is
    fire-and-forget on the client and always returns
    `{ ok: true }`. `server/routes/overview.ts` no longer
    fires the event.

- `core/pipeline/memory-core.ts`:
    Surface `MemosError.code` (or `unknown`) as the
    `plugin_error.error_type` when `onTurnStart` /
    `searchMemory` reject. Never the message — those can
    contain user/workspace text.

- `bridge.cts`:
    Register `process.on("uncaughtException" |
    "unhandledRejection")` immediately after binding telemetry.
    `uncaughtException` exits 1 (preserves supervisor
    semantics); `unhandledRejection` continues (Node 20+'s
    "exit by default" is too aggressive for a long-running
    bridge — log + ARMS event + keep going). New
    `classifyErrorCode()` reuses Node's `code` (`ENOENT`,
    `EADDRINUSE`, …), then constructor name, then `unknown`.
    Only registered on the dedicated bridge process; the
    OpenClaw adapter must not steal its host's global
    error hooks.

Tests
-----

- `tests/unit/telemetry/sender.test.ts` — three new cases
  covering: first launch emits `daily_active`; second launch
  same day / same `stateDir` does NOT re-emit; pre-seeded
  `.last-daily-ping` with yesterday's date triggers a fresh
  ping and overwrites the file with today's ISO date.
- `tests/unit/server/http.test.ts` — POST endpoint invokes
  `trackViewerOpened`; endpoint stays 200 when telemetry is
  unbound; GET `/api/v1/overview` no longer triggers the
  event (regressed deliberately).

Verified locally: 945 unit tests pass (+6 vs. baseline). 7
unrelated pre-existing failures in
`tests/unit/{reward,memory,storage}/...` are unchanged on this
branch and on `upstream/mem-agent-0509` head.

Co-authored-by: Cursor <cursoragent@cursor.com>
## Why

ARMS dashboards for the v2 plugin (event group `memos_local_hermes_v2`)
have been reporting suspiciously low volumes since the v2 rewrite.
Tracing through the code surfaced four independent issues that all
reduce or distort metrics:

1. **OpenClaw adapter never emitted any events.**
`adapters/openclaw/index.ts` bootstraps `MemoryCore` and starts the
viewer, but never constructs `Telemetry`. Only `bridge.cts` (the Hermes
path) wires it. So every OpenClaw user — `agent_name=openclaw` — has
been silently invisible across `plugin_started`, `memory_search`,
`memory_ingested`, `feedback_submitted`, `viewer_opened`.
2. **`daily_active` counted process launches, not days.** The dedup flag
(`dailyPingSent`) lived in memory; Hermes spawns one `bridge.cts`
subprocess per `hermes chat`, so DAU ≈ `plugin_started`.
3. **`viewer_opened` was wired to the first GET `/api/v1/overview` per
process.** Background pollers and CLI tooling triggered it; bridge
restarts re-counted the same operator; once-per-process meant active
users showed up once, period.
4. **`plugin_error` was declared but never invoked.** No call sites
existed in core or bridge.

## What

| # | Area | Change |
|---|---|---|
| 1 | `adapters/openclaw/index.ts` | Construct `Telemetry`,
`bindTelemetry`, emit `trackPluginStarted("openclaw")`, pass into
`startHttpServer`. Mirrors `bridge.cts` so OpenClaw and Hermes report
identical surfaces. |
| 2 | `core/telemetry/sender.ts` | `daily_active` dedup persisted to
`<stateDir>/memos-local/.last-daily-ping`. Read failure → "first time
today" (over-report by ≤1, never under-report). Removed the obsolete
`dailyPingSent`/`dailyPingDate` in-memory fields. |
| 3 | `server/routes/telemetry.ts` (new) +
`viewer/src/components/App.tsx` | `viewer_opened` now triggered by `POST
/api/v1/telemetry/viewer-opened` from the SPA's mount effect. Endpoint
is fire-and-forget, always 200. `server/routes/overview.ts` no longer
fires the event. |
| 4 | `core/pipeline/memory-core.ts` + `bridge.cts` | `trackError`
invoked from `onTurnStart` / `searchMemory` catches and from
process-level `uncaughtException` / `unhandledRejection` handlers. New
`classifyErrorCode()` keeps `error_type` to `MemosError.code` / Node
`code` / constructor name — never the message. |
| 5 | `apps/memos-local-plugin/.gitignore` | Defensive entry for
`telemetry.credentials.json` (CI-generated; never to be committed).
Counters the repo-root `!apps/**/*.json` allow-rule. Split out into its
own commit for clean review. |

## Tests

- `tests/unit/telemetry/sender.test.ts` (+3 cases): first launch emits
`daily_active`; second launch same-day same-`stateDir` does NOT re-emit;
pre-seeded `.last-daily-ping=2024-01-01` triggers a fresh ping and
overwrites with today's ISO date.
- `tests/unit/server/http.test.ts` (+3 cases): POST endpoint invokes
`trackViewerOpened`; endpoint returns 200 when telemetry is unbound; GET
`/api/v1/overview` no longer triggers the event.

```
Test Files  113 passed | 5 failed (pre-existing on mem-agent-0509)
Tests       945 passed | 7 failed | 1 skipped (953)
```

The 7 failures are unchanged on baseline `upstream/mem-agent-0509`
(verified by stash + re-run):
`tests/unit/{reward/reward.integration,reward/subscriber,storage/migrator,memory/l2/gain,memory/l3/cluster}.test.ts`
— none touch telemetry.

`npm run lint` (i.e. `tsc --noEmit`) passes clean.

## Risk / compatibility

- **Schema:** no changes. Same event group, same `view.name`, same
property keys. Existing ARMS dashboards keep working — they should just
see more rows starting next release.
- **Privacy:** no new fields carry user content. `error_type` is a
stable code (`ENOENT`, `MemosError.code`, `TypeError`, …), never the raw
message.
- **Behaviour:** `viewer_opened` count will jump because the event now
actually fires per browser tab open instead of once per server-process
lifetime. Expected — this is what the metric was always supposed to
mean.
- **Process semantics:** `uncaughtException` still calls
`process.exit(1)` (preserves supervisor behaviour); `unhandledRejection`
deliberately does not exit (Node 20+'s default-exit is too aggressive
for a long-running bridge — log + ARMS event + continue).

## Commits in this PR

1. `chore(memos-local-plugin): gitignore telemetry.credentials.json` —
single-file, zero-risk.
2. `fix(memos-local-plugin): close v2 ARMS telemetry coverage gaps` —
main change.

## Test plan

- [ ] Manual: `OPENCLAW_AGENT=openclaw memos-local` (or whichever
invocation reproduces an OpenClaw boot), then check ARMS for
`agent_name=openclaw` events on `memos_local_hermes_v2`.
- [ ] Manual: spawn two Hermes `chat` sessions on the same day → confirm
only one `daily_active` reaches ARMS.
- [ ] Manual: open the viewer in two browser tabs → expect two
`viewer_opened` events.
- [ ] Manual: kill the bridge with a forced `throw` → expect a
`plugin_error` with `error_source=uncaught_exception`.
## Summary
- Launch the TypeScript bridge through tsx's JS CLI entrypoint so
Windows does not run the POSIX shim through node.
- Persist a usable Node executable path during Windows installation and
decode bridge subprocess output as UTF-8 with replacement.

## Test plan
- Not run (not requested).
Automated PR from mem-agent-0509-niu to mem-agent-0509.
Automated PR from mem-agent-0509-niu to mem-agent-0509.
Automated PR from mem-agent-0509-niu to mem-agent-0509.
## Summary
- Preserve OpenClaw tool-call observations when `agent_end` transcripts
omit tool blocks, so memory capture still records tool activity.
- Enable OpenClaw conversation access during install so turns can be
captured after recall.
- Remove retrieval scores such as `best V` and `goal-sim` from episode
prompt injection.

## Test plan
- `npm test -- tests/unit/adapters/openclaw-bridge.test.ts
tests/unit/install/install-sh.test.ts tests/unit/retrieval/tier2.test.ts
tests/unit/retrieval/injector.test.ts`
- IDE diagnostics: no linter errors in touched TypeScript test/source
files.
@syzsunshine219 syzsunshine219 merged commit 72c8582 into mem-agent-0512 May 12, 2026
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