Skip to content

fix(core): restore LocalStorageBackend auto-wire in TdaiCore constructor (CR-2)#209

Open
ferminquant wants to merge 2 commits into
TencentCloud:feat/serverfrom
ferminquant:fix/cr2-storage-autowire
Open

fix(core): restore LocalStorageBackend auto-wire in TdaiCore constructor (CR-2)#209
ferminquant wants to merge 2 commits into
TencentCloud:feat/serverfrom
ferminquant:fix/cr2-storage-autowire

Conversation

@ferminquant

Copy link
Copy Markdown

Summary

Restore the LocalStorageBackend auto-wire in TdaiCore.constructor that the l1-writer CR-2 guard comment refers to but is missing in this build. The auto-wire was documented (l1-writer.ts:202-217 says "the gateway auto-wires a LocalStorageBackend at startup (server.ts:199-203)") but neither server.ts:261 nor the OpenClaw host-adapter entry actually constructs one before constructing TdaiCore, so this.storage is undefined in standalone installs.

This makes the CR-2 guard fire on every L1 write in standalone mode (no real data loss, but the warning is misleading) and leaves the original data-loss path open in service mode for any caller that forgets to pass storage explicitly.

Changes

  • src/core/tdai-core.ts — in the constructor, default this.storage to new LocalStorageBackend({ rootDir: this.dataDir, logger: this.logger }) when opts.storage is undefined. One import line, one logic line, plus a comment explaining the intent.

Why this shape

  • Why default in the constructor and not at the call site: there are at least three call sites (server.ts:134, server.ts:261, the bundled OpenClaw host-adapter) and the gateway may add more. Putting the fallback in one place is harder to forget than a chain of call-site changes.
  • Why ?? and not a config flag: the documented intent is that this is always safe in standalone mode (the LocalStorageBackend writes to the same dataDir the existing fs fallback would write to, with the same JSONL format). Adding a flag would imply a case where the operator wants the warning to keep firing, which is the opposite of what the guard comment says.
  • Why not change the warning text instead: the CR-2 root cause is still latent for service-mode callers who forget to pass storage. Lowering the warning would hide a real data-loss path. The constructor auto-wire makes the warning fire only when the operator actually has a problem.

Testing

I have this running on my local OpenClaw install (@tencentdb-agent-memory/memory-tencentdb v1.0.0 + OpenClaw v2026.5.20, single host, WSL2). The CR-2 warnings stop appearing in journalctl --user -u openclaw-gateway.service after restart with the patch. L1 records continue to land at ~/.openclaw/memory-tdai/records/<date>.jsonl with the same on-disk format (the LocalStorageBackend uses O_APPEND atomic appends, which is the same primitive the previous fs.appendFile path used).

I have not run the upstream test suite — my fork is a clean checkout. If maintainers want CI green before merge, I can rebase and run it locally if there's a Makefile or test script I should use.

Risk

  • Service mode: none. opts.storage ?? LocalStorageBackend only falls back when opts.storage is undefined. Callers that pass a CosStorageBackend (or any other custom storage) keep using it.
  • Standalone mode: behavior changes from "warn and write to local fs via fs.appendFile" to "write to local fs via LocalStorageBackend." The on-disk format is identical (both use fs.appendFile under the hood, the storage wrapper just adds the O_APPEND flag which is the default for appendFile). Records already on disk from the old path remain readable.
  • No new dependencies. LocalStorageBackend is already used in server.ts:362, 558, 1443, so the import is already in the dep graph at the package level.

Out of scope

  • The PipelineFactoryOptions / createPipeline interface also lacks a storage? field, which is a related but distinct issue. I left it alone in this PR to keep the diff small. Happy to send a follow-up PR if the maintainers want the data flow to be explicit at every layer.
  • The seed-runtime path also calls createPipeline and may have the same issue. Same — follow-up PR if needed.

Linked

Closes #208

…tor (CR-2)

The l1-writer CR-2 guard (l1-writer.ts:202-217) expects every writeMemory
call to be backed by a StorageAdapter. Its own comment says standalone
mode is supposed to auto-wire a LocalStorageBackend at startup, but the
auto-wire is missing for the OpenClaw host-adapter entry: server.ts:261
and the bundled dist/index.mjs:21372 both construct TdaiCore without
passing storage, leaving this.storage undefined.

Effect in standalone mode: every L1 write emits the CR-2 guard warning
4 times per extraction (once per memory), even though the data lands at
the correct JSONL path. Effect in service mode: callers that forget to
pass storage get a real data-loss path because writes fall back to
ephemeral pod fs.

Restore the auto-wire in TdaiCore.constructor: default this.storage to
new LocalStorageBackend({ rootDir: dataDir, logger }) when opts.storage
is undefined. Service-mode callers that pass a custom storage (e.g.
CosStorageBackend) still win because the fallback only fires when
opts.storage is undefined.

Closes TencentCloud#208
@Maxwell-Code07

Copy link
Copy Markdown
Collaborator

Thanks for your attention. We will review it and get back to you soon.

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.

2 participants