SIGN IN SIGN UP

fix(openclaw): probe append capability in local-daemon mode (#3686) (#3706)

`detectAppendCapability` was wired into the four external-API code paths only
(#1102: "wired into all 4 checkExternalApiHealth call sites"); local-daemon mode
has no such call site, so it was never probed. `supportsUpdateModeAppend` stayed
`false` there forever, retain fell back to per-turn document ids sequenced from
an in-memory counter, and every host restart replayed `…:turn:000001` onto the
previous cycle's document — which retain's default `update_mode: 'replace'`
deletes before reprocessing. A production deployment with months of daily
traffic on one session was left with 29 documents.

The daemon is a Hindsight API like any other. Treat it as one:

- probe `<daemon>/version` in all three local-daemon paths — initial start, the
  healthy-daemon re-check, and reinit — so append mode engages and document ids
  become session-stable
- `getActiveApiEndpoint()` resolves "the API we are talking to" (external URL or
  spawned daemon); `refreshQueueOperationIdCapability` uses it, so local-daemon
  retains finally carry `operation_id` instead of being hard-gated on
  `usingExternalApi` and replaying non-idempotently
- initialize the retain queue in both modes: a daemon that is still booting or
  has crashed is as unreachable as a remote API, and a failed retain was simply
  dropped
- stamp a per-process boot token into fallback ids (`…:turn:<boot>:000001`).
  The counter is in memory *and* FIFO-capped at MAX_TRACKED_SESSIONS, so ids
  could be recycled without any restart; this holds even when a probe fails
  transiently and the fallback re-engages.

Tests: new local-daemon-parity.test.ts drives the real `service.start()` against
a mocked daemon — probes /version and enables append, keeps the fallback when
the daemon reports `store_document_text: false`, picks up a queue file from a
previous session, and mints a fresh boot token per process. Verified red on the
pre-fix code.
N
Nicolò Boschi committed
d97b560e2ca1b0c8ddce9076a40c4e8a2467751e
Parent: 1b74e3e
Committed by GitHub <noreply@github.com> on 8/24/2026, 9:07:39 AM