feat(viewer): UI improvements, global search, Hermes daemon mode - #1
Closed
hijzy wants to merge 3 commits into
Closed
feat(viewer): UI improvements, global search, Hermes daemon mode#1hijzy wants to merge 3 commits into
hijzy wants to merge 3 commits into
Conversation
added 3 commits
April 28, 2026 15:18
- 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
hijzy
pushed a commit
that referenced
this pull request
Aug 24, 2026
…enClaw 2026.3.31 (MemTensor#2037) * fix(memos-local-openclaw): migrate to OpenClaw 2026.3.31 memory API OpenClaw 2026.3.31 replaced the umbrella `registerMemoryCapability` with three focused registrars (`registerMemoryPromptSection`, `registerMemoryFlushPlan`, `registerMemoryRuntime`), so the plugin's call at index.ts:163 failed with `TypeError: api.registerMemoryCapability is not a function` and the whole plugin refused to load. The register() entry now feature-detects `registerMemoryPromptSection` and falls back to the legacy `registerMemoryCapability` for older gateways, warning if neither exists. Tests stub both entry points and a new tests/memory-registration-api.test.ts locks in the preference order, the fallback path, and the no-throw safeguard. Fixes MemTensor#1559 * refactor(memos-local-openclaw): hoist memory-registration API narrow + escalate missing-registrar log to error Address OpenClaw review feedback on the MemTensor#1559 fix: * Hoist the inline `{ registerMemoryPromptSection?, registerMemoryCapability? }` cast type to a named `MemoryRegistrationApi` interface at module scope so future maintainers see which host methods the feature detection covers and don't accidentally reach for other `OpenClawPluginApi` members through the narrowed reference. (OCR #1, MemTensor#3) * Escalate the "neither registrar available" log from `warn` to `error` so the fatal misconfiguration surfaces immediately in production dashboards rather than silently manifesting as broken memory recall. Falls back to `warn` when the host logger lacks `.error` for compatibility with legacy `HostLogger` shapes. (OCR MemTensor#2, MemTensor#4) * Expand `tests/memory-registration-api.test.ts` accordingly: assert `error` is called on the modern path and add a legacy-logger case that verifies the warn fallback still fires when `.error` is absent. * refactor(memos-local-openclaw): safer casts + fail-fast on missing memory registrar Address the second round of OpenClaw review feedback on the MemTensor#1559 fix: * Replace `api as unknown as MemoryRegistrationApi` with the safer intersection cast `api as OpenClawPluginApi & MemoryRegistrationApi`. This keeps every other typed member of `api` intact and communicates the actual intent — "the host may additionally expose these optional registrars" — instead of throwing away the whole type. (OCR #1) * Throw after logging in the "no registrar found" branch. Previously register() would keep spinning up stores, workers and tools even though the recall path was permanently broken, producing a plugin that *looks* healthy while silently never surfacing memories. Now the failure is visible at startup and the host can react. (OCR MemTensor#2) * Hoist the inline `{ error?: (msg: string) => void }` cast on `api.logger` into a named `ExtendedLogger` interface alongside `MemoryRegistrationApi`, so all remaining type-escape hatches live in one place and can be dropped once the SDK publishes matching types. (OCR MemTensor#3) * Update `tests/memory-registration-api.test.ts` accordingly: the "neither method" cases now assert both the error/warn log and that `register()` throws with a matching message, so the fail-fast contract is locked in. * test(memos-local-openclaw): flush res.end callback + advance past delayMs in update-install test The mock `res.end(payload)` in the update-install test ignored the optional flush callback, so `jsonResponseAndRestart` never scheduled its 1500ms SIGUSR1 setTimeout under `vi.useFakeTimers()`. Also bump the timer advance from 500ms to 2000ms to cover the actual default `delayMs=1500`. Fixes: "keeps the new version and restarts only after a successful postinstall" --------- Co-authored-by: MemOS AutoDev <autodev@memtensor.local> Co-authored-by: jiachengzhen <jiacz@memtensor.cn> Co-authored-by: zhaxi <syzsunshine219@gmail.com>
hijzy
pushed a commit
that referenced
this pull request
Aug 24, 2026
…us full-table vector scan (scan (MemTensor#2077) * fix(local-plugin): stop unbounded trace re-insertion + 100% CPU vector scan (MemTensor#2076) Two coupled root causes made the gateway Node process pin one CPU core at 100% with 4.2 GB RSS on startup for 40+ minutes on a 518k-row DB. Bug #1 — synchronous full-table vector scan (`core/storage/vector.ts`): `scanAndTopK` used `db.prepare(sql).all(params)`, materialising up to `hardCap` (default 100_000) rows in one synchronous step. Each row carries a multi-KB vector BLOB, so peak RSS was `O(hardCap × dim)` and the event loop was blocked while `topKCosine` walked the whole array. Fix: stream via `.iterate()`, maintain the top-K min-heap on hits directly (only k entries + one just-decoded vector live in JS memory at a time), and lower the default `hardCap` to 5_000 as a safer default (all production callers pass their own value explicitly). Bug MemTensor#2 — dedup pagination cap (`core/capture/capture.ts`): The four dedup call sites in `runLite` / `runLightweight` / `runReflect` / `persistRows` all used `tracesRepo.list({ episodeId })`, which is paginated and silently truncates to 500 rows via `_helpers.ts::clampLimit`. Once an episode exceeded 500 traces the older rows became invisible to dedup and the tail was re-inserted on every cycle. In the reporter's DB this had grown the `traces` table to 518_375 rows of which 84% were exact duplicates by `(episode_id, turn_id, user_text, agent_text, tool_calls_json)`. Fix: add `tracesRepo.listAllForEpisode(episodeId)`, an uncapped read ordered by `ts ASC`, and switch the four dedup call sites to it. Every other paginated `list({ episodeId, limit })` caller keeps its explicit page-size contract. Tests - `tests/unit/storage/traces-listall.test.ts` — 4 cases: 750-row episode returns in full, strict episode scoping, empty episode, `ts ASC` ordering. - `tests/unit/storage/vector-stream.test.ts` — 3 cases: parity with brute-force top-K on live DB, streaming keeps only top-K in memory yet still considers every row within the cap, explicit `hardCap` still truncates the candidate window. - Full plugin unit suite: 1128 pass, 1 skipped. Two pre-existing failures on `dev-v2.0.23` (startup-recovery source-string check, migrator schema-drift) are unrelated to this fix. Closes MemTensor#2076 * refactor(local-plugin): apply MemTensor#2077 open code review fixes Address the five findings from open code review on PR MemTensor#2077: 1. `traces.ts::listAllForEpisode` was hydrating all 25 columns including `vec_summary`/`vec_action` BLOBs while dedup callers only ever read the identity fields. Added `listDedupRowsForEpisode` — a streaming sibling that projects only the five dedup columns (ts/turn_id/user_text/agent_text/tool_calls_json) and uses `.iterate()` so peak RSS scales with scalar payload rather than total embedding footprint. `listAllForEpisode` kept as-is for `runReflect`, which still needs the full row (id/tags/vecSummary/ vecAction). 2. `vector.ts::scanAndTopK` streaming loop silently `continue`d on dimension mismatches, losing the `search.dim_mismatch` warning the old `topKCosine` path emitted. Restored the warn log with {expected,got,rowId} — the primary operator signal for detecting schema drift (re-embedding with a new model dimension) in production. Empty vectors keep the silent-skip semantics as before. 3. `vector.ts::scanAndTopK` had the meta-object construction duplicated verbatim in both heap-push branches. Hoisted into a single `buildMeta()` closure above the branch so future edits to the projection cannot drift between the two paths. 4. `capture.ts::persistRows` unconditionally called `listAllForEpisode` even when its caller (`runLite` / `runLightweight` / `runReflect`) had just scanned the same episode. Added an optional `existingSignatures?: Set<string>` param; all three call-sites now pass the pre-built signature set derived from their own dedup scan, eliminating the second full-episode scan. The set is cloned inside `persistRows` so the intra-batch dedup doesn't leak new signatures back to the caller. 5. `capture.ts::runLite` (and `runLightweight`) previously fetched full `TraceRow[]` via `listAllForEpisode` and threw everything away except the `ts` / `turnId` field. Switched both to `listDedupRowsForEpisode` so no BLOBs load for the extraction dedup pass. `traceIdentitySignature` widened to `Pick<TraceRow, "toolCalls" | "turnId" | "ts" | "agentText" | "userText">` so it can accept either `TraceRow` (runReflect path) or the narrow `TraceDedupRow` produced by the streaming helper. Tests - tests/unit/storage/traces-listall.test.ts — 4 new cases pin the narrow-projection contract (fields returned, empty episode, 750-row uncapped stream, strict episode scoping + ts ASC). - tests/unit/storage/vector-stream.test.ts — 2 new cases pin the dim-mismatch warning fires for non-empty mismatched vectors and stays silent for zero-length vectors. Verification - `npx tsc -p tsconfig.json --noEmit` → clean. - `npx vitest run tests/unit/storage/traces-listall.test.ts tests/unit/storage/vector-stream.test.ts` → 13/13 pass. - `npx vitest run tests/unit/capture` → 110/110 pass. - Full `npx vitest run tests/unit` → 1134/1137 pass; the two failures (storage/migrator, startup-recovery) reproduce on the unmodified PR head, so they are pre-existing and unrelated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(local-plugin): apply MemTensor#2077 open code review fixes (round 2) Second-pass open-code-review fixes on top of 3e25bc3. All three are minimal-diff / non-behavior-changing. 1. `vector.ts::scanAndTopK` was building the `buildMeta` closure inside the per-row streaming loop. On a hot search over the full `hardCap` this allocated one closure per iteration — pure GC pressure since only the two heap-push branches consume it. Hoisted the projection above the loop as a plain function taking the current row as an argument. Two variants pre-selected once based on `selectExtra.length` so filtered-out rows still pay nothing. 2. `traces.ts::listDedupRowsForEpisode` JSDoc claimed the helper "streams via `.iterate()` so peak memory scales with the scalar payload". That was misleading: the method uses `stmt.iterate()` internally but still accumulates every row into a `TraceDedupRow[]` before returning. The genuine saving is the narrow scalar-only projection (never touches `vec_summary` / `vec_action`), not streaming. Rewrote the JSDoc to describe the real cost model and name the `.iterate()` benefit accurately (avoids an intermediate `.all()` allocation, does not stream to caller). 3. `traces.ts::listAllForEpisode` JSDoc said "all hot fields required by dedup are projected, so a caller that only needs `ts`, `turnId`, or the identity signature can still iterate at full speed". That accidentally invited dedup callers back onto this method, which loads every BLOB column. Rewrote the JSDoc to state explicitly that vec_summary/vec_action BLOBs are loaded and redirect dedup-only callers to `listDedupRowsForEpisode`. Preserved the MemTensor#2076 context on why the uncapped variant exists. No behavioral change. No test changes needed. Verification - `npx tsc -p tsconfig.json --noEmit` → clean. - `npx vitest run tests/unit/storage/traces-listall.test.ts \ tests/unit/storage/vector-stream.test.ts` → 13/13 pass. - `npx vitest run tests/unit/capture` → 110/110 pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: avoid MemTensor#2077 capture merge conflict --------- Co-authored-by: MemOS AutoDev <autodev@memtensor.local> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: jiachengzhen <jiacz@memtensor.cn>
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.
Summary
Test plan
install.sh --version ./pkg.tgzfor Hermes — verify daemon stays up after installhermes chatwhile daemon is running — verify it operates in headless mode