Skip to content

fix(discord): stop typing indicator on silent/NO_REPLY runs#27039

Open
keshav55 wants to merge 2 commits intoopenclaw:mainfrom
keshav55:fix/discord-typing-silent-reply
Open

fix(discord): stop typing indicator on silent/NO_REPLY runs#27039
keshav55 wants to merge 2 commits intoopenclaw:mainfrom
keshav55:fix/discord-typing-silent-reply

Conversation

@keshav55
Copy link
Contributor

Summary

Fixes #27011 — Discord typing indicator persists indefinitely when the model run produces a silent or NO_REPLY response.

Root Cause

The typing controller in src/auto-reply/reply/typing.ts requires both markRunComplete() and markDispatchIdle() to be called before it triggers cleanup() (which clears typing timers and stops the indicator). This is enforced at lines 126-134 in maybeStopOnIdle():

private maybeStopOnIdle(): void {
  if (this.runComplete && this.dispatchIdle) {
    this.cleanup();
  }
}

In agent-runner.ts, the agent runner correctly calls typing.markRunComplete() in its finally block (line 733). However, createReplyDispatcherWithTyping only exposes markDispatchIdle — not markRunComplete — in its return type. The Discord handler (message-handler.process.ts) only calls markDispatchIdle() in its finally block (line 724).

When a run produces content (tool results, block replies, or a final reply), this works fine:

  1. agent-runner.ts calls typing.markRunComplete() via the typing controller reference
  2. The reply dispatcher's onIdle callback calls typingController.markDispatchIdle()
  3. Both flags are set → cleanup() fires

But on silent/NO_REPLY runs where no replies are enqueued, the dispatcher's onIdle fires via markComplete() microtask (line 189-198 in reply-dispatcher.ts). The Discord handler's finally block then calls markDispatchIdle() again — but markRunComplete() was only called internally by the agent runner on its own typing controller reference. If the timing of the markComplete() microtask resolution races with the Discord finally block, or if the typing controller reference hasn't been set yet, the runComplete flag may never be propagated through the dispatcher's wrapper, leaving the typing indicator stuck.

Fix

Expose markRunComplete alongside markDispatchIdle in createReplyDispatcherWithTyping's return type and implementation. Update the Discord handler to call markRunComplete() in its finally block before markDispatchIdle(), ensuring both flags are always set regardless of whether the agent runner's internal cleanup reached the typing controller.

Changes

src/auto-reply/reply/reply-dispatcher.ts

  • Added markRunComplete to ReplyDispatcherWithTypingResult type
  • Added markRunComplete implementation that delegates to typingController?.markRunComplete()

src/discord/monitor/message-handler.process.ts

  • Destructure markRunComplete from createReplyDispatcherWithTyping
  • Call markRunComplete() in the finally block before markDispatchIdle()

Test plan

  • Deploy with a Discord bot and trigger a silent/NO_REPLY response (e.g., system prompt that instructs NO_REPLY for certain inputs)
  • Verify typing indicator stops within a few seconds instead of persisting indefinitely
  • Verify normal replies still show typing → response → typing stops as expected

@openclaw-barnacle openclaw-barnacle bot added channel: discord Channel integration: discord size: S labels Feb 26, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 26, 2026

Greptile Summary

Fixed Discord typing indicator persisting on silent/NO_REPLY runs by ensuring both cleanup flags are set.

The typing controller requires both runComplete and dispatchIdle flags to trigger cleanup. Previously, on silent/NO_REPLY runs where no replies are enqueued, the runComplete flag might not be propagated through the dispatcher wrapper due to timing issues. The fix exposes markRunComplete from createReplyDispatcherWithTyping and ensures the Discord handler calls it explicitly in the finally block alongside markDispatchIdle.

  • Minimal, focused changes that directly address the root cause
  • Implementation is idempotent and safe (handles multiple calls, null typing controller)
  • Follows existing patterns and integrates cleanly with the codebase

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes are minimal, well-designed, and directly address the identified issue. The implementation uses idempotent operations with proper null safety, and the fix ensures reliable cleanup regardless of timing variations
  • No files require special attention

Last reviewed commit: 628fb16

@keshav55 keshav55 force-pushed the fix/discord-typing-silent-reply branch from 628fb16 to d2b85b4 Compare February 27, 2026 22:57
@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord size: S stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discord typing indicator persists forever on silent/NO_REPLY runs

1 participant