Repository navigation
fix(openclaw): retain from plugin copies OpenClaw never started - #5517
Merged
Merged
Conversation
OpenClaw re-evaluates the plugin module for each plugin registry it loads but only calls service.start() on the first. On 2026.9.x the agent_end hook runs in a later copy, where serviceAbortController is null, so runRetain returned at its lifecycle guard with no log line. Recall kept working through its pre-start lifetime, which hid the loss. - Recall and retain now share one lifecycle snapshot (captureHookLifecycle): the started service's, or the pre-start one in a never-started copy. An explicit stop() still turns hooks off. - lazyReinit opens the retain queue in a never-started copy, so a failed retain is replayed instead of dropped. Verified on OpenClaw 2026.9.6: before, retains never landed; after, agent_end runs in an unstarted copy and every turn is retained. Closes #4828 Closes #4721 Closes #4537
This was referenced Oct 12, 2026
This was referenced Oct 20, 2026
Merged
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.
Closes #4828, #4721, #4537.
Bug: OpenClaw re-evaluates the plugin module for every plugin registry it loads, but calls
service.start()only on the first. On 2026.9.x theagent_endhook runs in a later copy whoseserviceAbortControllerisnull, sorunRetainreturned at its lifecycle guard without logging anything. Recall kept working through its pre-start lifetime, which hid the loss.Fix
captureHookLifecycle(): the started service's, or the pre-start one in a copy that was never started. An explicitstop()still turns hooks off (existing behaviour, still tested).lazyReinitopens the retain queue in a never-started copy, so a failed retain is replayed instead of dropped (openclaw: retain silently dropped on OpenClaw 2026.9.5 due to aborted/null serviceAbortController in lazyReinit fallback #4537).Tests:
retain-registry-reload.test.tsloads two separate module copies, starts only the first, and drivesagent_endthrough the second. It checks the retain is sent, a failed retain is queued, and a stopped copy stays silent. The first two fail onmain.Verified on real OpenClaw 2026.9.6 (local Hindsight API, 2 turns each with a unique code word):
agent_endranservice.startservice.start(started=false, from temporary probe logs)On OpenClaw 2026.10.2
agent_endis dispatched to the started copy, so retain already worked there. Recall still runs in an unstarted copy on 10.2, so the shared lifecycle keeps both paths consistent.