fix(typing): call markDispatchIdle in followup runner to prevent stuck indicator#26881
Merged
steipete merged 1 commit intoopenclaw:mainfrom Feb 26, 2026
Merged
Conversation
…k indicator The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595
Contributor
|
Landed on What was landed:
Status:
Thanks @codexGW for the fix and tests. |
|
Great news — thanks for the update. Since PR #26881 is already merged to |
This was referenced Feb 26, 2026
Closed
steipete
added a commit
that referenced
this pull request
Feb 26, 2026
brianleach
pushed a commit
to brianleach/openclaw
that referenced
this pull request
Feb 26, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
brianleach
pushed a commit
to brianleach/openclaw
that referenced
this pull request
Feb 26, 2026
This was referenced Feb 26, 2026
zerone0x
added a commit
to zerone0x/clawdbot
that referenced
this pull request
Feb 26, 2026
… finally block PR openclaw#26881 fixed the followup runner's missing typing.markDispatchIdle() call, but the same gap existed in the main reply pipeline (runReplyAgent). The main pipeline relied solely on the buffered dispatcher's finally block (dispatch.ts) to fire markDispatchIdle(). When the reply path exits before that finally executes — early error, abort, or code path that bypasses the dispatcher — the typing keepalive loop spins indefinitely (same root cause as openclaw#26993, openclaw#27053). Fix: add typing.markDispatchIdle() as a safety-net in runReplyAgent's own finally block, immediately after typing.markRunComplete(). Calling it twice is harmless: maybeStopOnIdle() is guarded by both the runComplete and dispatchIdle flags, so the second invocation is a no-op. Adds two regression tests to agent-runner.runreplyagent.test.ts: - markDispatchIdle is fired on successful run - markDispatchIdle is fired even when the agent throws Fixes openclaw#27172 Related: openclaw#26881 (same pattern, followup runner) Co-Authored-By: Claude <noreply@anthropic.com>
3 tasks
2 tasks
This was referenced Feb 26, 2026
Closed
This was referenced Feb 26, 2026
execute008
pushed a commit
to execute008/openclaw
that referenced
this pull request
Feb 27, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
execute008
pushed a commit
to execute008/openclaw
that referenced
this pull request
Feb 27, 2026
r4jiv007
pushed a commit
to r4jiv007/openclaw
that referenced
this pull request
Feb 28, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
r4jiv007
pushed a commit
to r4jiv007/openclaw
that referenced
this pull request
Feb 28, 2026
vincentkoc
pushed a commit
to Sid-Qin/openclaw
that referenced
this pull request
Feb 28, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
vincentkoc
pushed a commit
to Sid-Qin/openclaw
that referenced
this pull request
Feb 28, 2026
vincentkoc
pushed a commit
to rylena/rylen-openclaw
that referenced
this pull request
Feb 28, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
vincentkoc
pushed a commit
to rylena/rylen-openclaw
that referenced
this pull request
Feb 28, 2026
6 tasks
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 1, 2026
(cherry picked from commit 5e1bfb2)
steipete
pushed a commit
to Sid-Qin/openclaw
that referenced
this pull request
Mar 2, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
steipete
added a commit
to Sid-Qin/openclaw
that referenced
this pull request
Mar 2, 2026
hughdidit
pushed a commit
to hughdidit/DAISy-Agency
that referenced
this pull request
Mar 3, 2026
(cherry picked from commit 5e1bfb2)
dorgonman
pushed a commit
to kanohorizonia/openclaw
that referenced
this pull request
Mar 3, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
dorgonman
pushed a commit
to kanohorizonia/openclaw
that referenced
this pull request
Mar 3, 2026
karmafeast
pushed a commit
to karmaterminal/openclaw
that referenced
this pull request
Mar 3, 2026
Restores code that was accidentally removed alongside the continuation feature in the initial commit (e0dc060). These are upstream safety mechanisms that the feature lich didn't understand: 1. catch(error) block in runReplyAgent — keeps followup queue moving when an unexpected exception escapes the run path 2. typing.markDispatchIdle() in finally — stops typing keepalive on early exit/error (fix for openclaw#26881) 3. hasSessionRelatedCronJobs check — suppresses false 'I didn't schedule a reminder' warnings when existing cron job covers the commitment (fix for openclaw#32228) These regressions were correctly identified by automated review (chatgpt-codex-connector[bot] and greptile-apps[bot]).
zooqueen
pushed a commit
to hanzoai/bot
that referenced
this pull request
Mar 6, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
zooqueen
pushed a commit
to hanzoai/bot
that referenced
this pull request
Mar 6, 2026
thebenjaminlee
pushed a commit
to escape-velocity-ventures/openclaw
that referenced
this pull request
Mar 7, 2026
…k indicator (openclaw#26881) The followup runner (used for queued messages, inter-agent sends, heartbeat followups, etc.) only called typing.markRunComplete() in its finally block. The typing controller requires BOTH markRunComplete AND markDispatchIdle to trigger cleanup — but markDispatchIdle was only wired through the buffered dispatcher path, which followup turns bypass entirely. This caused the typing indicator to persist indefinitely on channels like Telegram when the agent replied with NO_REPLY or produced empty payloads, because the keepalive loop was never stopped. Adds markDispatchIdle() alongside markRunComplete() in the followup runner's finally block, and four test cases covering NO_REPLY, empty payloads, agent errors, and successful delivery. Complements openclaw#26295 which addressed the channel-level callback layer. Fixes openclaw#26595 Co-authored-by: Samantha <samantha@Samanthas-Mac-mini.local>
thebenjaminlee
pushed a commit
to escape-velocity-ventures/openclaw
that referenced
this pull request
Mar 7, 2026
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.
Problem
After the typing system refactor in 2026.2.24, the typing indicator can get stuck on channels like Telegram when the agent replies with
NO_REPLYor produces empty payloads during followup turns (queued messages, inter-agent sends, heartbeat followups).The typing controller requires both
markRunComplete()andmarkDispatchIdle()to trigger cleanup. The followup runner only calledmarkRunComplete()in itsfinallyblock.markDispatchIdle()is normally called by the buffered dispatcher'sfinallyblock — but followup turns bypass the dispatcher entirely, so the second signal never fires. The keepalive loop continues sendingtypingactions indefinitely.Fix
Add
typing.markDispatchIdle()alongsidetyping.markRunComplete()in the followup runner'sfinallyblock. This ensures both signals always fire regardless of whether the followup produced a reply, was silent, or errored.Tests
Four new test cases in
followup-runner.test.ts:NO_REPLY→ both signals fireAll 17 tests pass (13 existing + 4 new).
Context
Complements #26295 which fixed the channel-level callback layer (
closedflag increateTypingCallbacks). This PR fixes the controller-level lifecycle gap that #26295 doesn't cover.Relates to #26595, #8785.
Greptile Summary
Added
typing.markDispatchIdle()call in the followup runner's finally block to fix stuck typing indicators on channels like Telegram when followup turns produce NO_REPLY or empty payloads.markRunComplete()andmarkDispatchIdle()signals to trigger cleanupmarkDispatchIdle()in its finally blockConfidence Score: 5/5
Last reviewed commit: 5ea4712
(5/5) You can turn off certain types of comments like style here!