Skip to content

fix(openclaw-adapter): start HTTP server before core.init() to unblock viewer at startup#1857

Open
34262315716 wants to merge 7 commits into
MemTensor:dev-20260604-v2.0.19from
34262315716:fix/openclaw-adapter-startup-order
Open

fix(openclaw-adapter): start HTTP server before core.init() to unblock viewer at startup#1857
34262315716 wants to merge 7 commits into
MemTensor:dev-20260604-v2.0.19from
34262315716:fix/openclaw-adapter-startup-order

Conversation

@34262315716

Copy link
Copy Markdown

Closes #1841 (OpenClaw adapter portion)

Summary

Reorders the OpenClaw adapter startup sequence in adapters/openclaw/index.ts so the HTTP viewer server binds its port before core.init() runs. core.init() is now a fire-and-forget background task.

This is the same fix as PR #1842 but applied to the OpenClaw adapter (adapters/openclaw/index.ts) instead of the Hermes daemon (bridge.cts).

Problem

In the OpenClaw adapter, the startup sequence was:

bootstrapMemoryCoreFull -> await core.init() -> startHttpServer -> return

core.init() performs orphan episode recovery including recoverDirtyClosedEpisodes(), which calls the LLM to rescore each dirty episode. Under API rate limiting, this can block for minutes.

Since the HTTP server starts after init, the viewer port (:18799) remains unresponsive during this time. Users see a blank page or connection refused when opening the viewer immediately after an OpenClaw restart.

Fix

// Before (broken):
bootstrapMemoryCoreFull -> await core.init() -> startHttpServer -> return

// After (fixed):
bootstrapMemoryCoreFull -> startHttpServer -> void core.init() -> return
  1. HTTP server starts first, responding to /api/v1/ping and /api/v1/health immediately
  2. Bridge and telemetry setup are unchanged (they don't depend on init)
  3. core.init() runs as a background task (core.init().catch(...))
  4. If init fails, the viewer continues serving cached data in degraded mode

Why this is safe

  • /api/v1/ping returns a hardcoded response — no core state needed
  • /api/v1/health calls core.health() which returns ok: false before init — the viewer can show a starting-up state
  • All viewer data endpoints read from SQLite, which is fully bootstrapped by bootstrapMemoryCoreFull() before either step
  • Bridge hooks (before_prompt_build, agent_end, etc.) call ensureLive() which only checks shutDown, not initialized — turns can proceed concurrently with background init
  • Background orphan recovery processes old episodes; new turn events create new episodes — no conflict

Changes

File Change
apps/memos-local-plugin/adapters/openclaw/index.ts Move startHttpServer before core.init(), run init as background task

Testing

  1. Viewer starts immediately: After restarting OpenClaw, curl http://127.0.0.1:18799/api/v1/ping should respond within seconds, even before init completes
  2. Init runs in background: Check ~/.openclaw/memos-plugin/logs/ for background core.init() completed or background core.init() failed after a delay
  3. No duplicate processes: Unlike the daemon case (fix: Daemon viewer fails to start when core.init() blocks on dirty episode rescoring — triggers zombie process avalanche #1841), OpenClaw's plugin loader doesn't spawn duplicate processes, but the viewer port is now responsive immediately
  4. Data available: The overview page shows cached data from previous sessions immediately; new data from background init appears as it completes

Ref: #1841, #1842

hijzy and others added 7 commits May 25, 2026 15:02
## Summary
- add an OpenClaw runtime lock to block duplicate plugin instances
before tools/hooks register
- fail startup on viewer port conflicts and clean up partial runtime
state
- keep lightweight local memories searchable/listable without an LLM
final filter, while preserving full-mode self-evolution boundaries
- cover runtime locking, duplicate startup, lightweight retrieval,
delayed agent_end recovery, and partial migration behavior

## Tests
- npm test -- --run tests/unit
- npm run lint
- npm run build
- git diff --check --cached
MemTensor#1807)

Automated PR from mem-agent-0520-niu to mem-agent-0520.
## 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
…k viewer at startup

Move startHttpServer() before core.init() in the OpenClaw adapter so the
viewer port (:18799) is available immediately, even when core.init()
blocks on orphan episode recovery and dirty reward rescoring from
previous sessions.

Previously the startup sequence was:
  bootstrapMemoryCoreFull() -> await core.init() -> startHttpServer()
                                 ^ blocks for minutes
                                  under API rate limits

Now it is:
  bootstrapMemoryCoreFull() -> startHttpServer() -> void core.init()
                                 ^ responds immediately
                                  ^ runs in background

This mirrors the fix in PR MemTensor#1842 (bridge.cts) applied to the OpenClaw
adapter. The HTTP server routes work without core.init() because:
- /api/v1/ping returns a hardcoded response
- /api/v1/health calls core.health() which works with the bootstrapped
  core (SQLite already open, providers already created)
- routes only check shutDown, not initialized
- The SQLite database is fully accessible after bootstrapMemoryCoreFull()

core.init() now runs as a background task. If it fails, the viewer
continues serving cached data in degraded mode.

Ref: MemTensor#1841 (original report: daemon viewer blocked by core.init())
@Memtensor-AI Memtensor-AI changed the base branch from main to dev-20260604-v2.0.19 June 10, 2026 15:45
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.

fix: Daemon viewer fails to start when core.init() blocks on dirty episode rescoring — triggers zombie process avalanche

3 participants