feat(discord): show typing indicator while processing an LLM call#1288
Open
CumpsD wants to merge 1 commit into
Open
feat(discord): show typing indicator while processing an LLM call#1288CumpsD wants to merge 1 commit into
CumpsD wants to merge 1 commit into
Conversation
Add a cross-channel processing signal that brackets each LLM model call and render it as Discord's native typing indicator. The agent now gives live feedback while it is thinking instead of staying silent until the turn ends. Core: - New ProcessingStateOutput(bool IsProcessing) SessionOutput and an opt-in OutputFilter.Processing flag. - LlmSessionActor emits IsProcessing=true at the start of each model call (FireLlmCall) and false when it ends: response received, call failed (emitted early so retries re-bracket), or LLM-call watchdog timeout. Because the stop fires when the response lands, the indicator is naturally off during tool execution and tool-approval waits, and resumes on the next model call. Discord: - DiscordSessionBindingActor subscribes to the new filter and drives the typing indicator via TriggerTypingAsync plus an 8s periodic timer (Discord typing auto-expires ~10s); it stops on the processing-off signal and on TurnCompleted. Typing is best-effort and never fails or retries a turn. - New IDiscordReplyClient.TriggerTypingAsync, implemented in DiscordNetReplyClient (reuses the existing channel resolution) and stubbed in the unconfigured client. The flag is opt-in and excluded from OutputFilter.Full, so existing subscribers are unaffected. Slack can adopt the same signal later. Tests: - LlmSessionProcessingStateTests: started->stopped on success and on failure. - DiscordFileFlowIntegrationTests: typing triggered during a turn. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
What
Adds a cross-channel processing signal that brackets each LLM model call and renders it as Discord's native typing indicator. The agent now gives live feedback while it is thinking, instead of staying silent until the turn finishes.
Why
Discord currently posts once when a turn completes — no feedback during long model calls. A typing indicator signals the agent is working.
How
Core (channel-agnostic)
ProcessingStateOutput(bool IsProcessing)SessionOutputand an opt-inOutputFilter.Processingflag.LlmSessionActoremitsIsProcessing=trueat the start of each model call (FireLlmCall) andfalsewhen it ends:HandleLlmResponseReceived),true),Discord
DiscordSessionBindingActorsubscribes to the new filter and drives typing viaTriggerTypingAsync+ an 8s periodic timer (Discord typing auto-expires ~10s). Stops on the processing-off signal and onTurnCompleted(backstop). Best-effort — never fails or retries a turn.IDiscordReplyClient.TriggerTypingAsync, implemented inDiscordNetReplyClient(reuses existing channel resolution), stubbed in the unconfigured client.The flag is excluded from
OutputFilter.Full, so existing subscribers are unaffected. Slack can adopt the same signal later by adding the flag and acase ProcessingStateOutput.Tests
LlmSessionProcessingStateTests— started→stopped on success and on failure.DiscordFileFlowIntegrationTests— typing triggered during a turn.Verification
dotnet slopwatch analyze: 0 issues.🤖 Generated with Claude Code