fix: clear WhatsApp typing indicator after response (#243)

WhatsApp's "typing..." indicator lingers for 15-25 seconds after the bot
finishes responding because there was no way to clear it. This adds
stopTypingIndicator() which sends a "paused" presence update to
immediately dismiss it.

- stopTypingIndicator?() added to ChannelAdapter interface (optional)
- WhatsApp adapter implements it via sendPresenceUpdate("paused")
- bot.ts calls it in the finally block after stream processing

Written by Cameron ◯ Letta Code

"First, solve the problem. Then, write the code." - John Johnson
This commit is contained in:
Cameron
2026-02-09 16:25:52 -08:00
committed by GitHub
parent 5f7cdd3471
commit 6f5a322840
4 changed files with 26 additions and 0 deletions

View File

@@ -22,6 +22,7 @@ export interface ChannelAdapter {
sendMessage(msg: OutboundMessage): Promise<{ messageId: string }>;
editMessage(chatId: string, messageId: string, text: string): Promise<void>;
sendTypingIndicator(chatId: string): Promise<void>;
stopTypingIndicator?(chatId: string): Promise<void>;
// Capabilities (optional)
supportsEditing?(): boolean;

View File

@@ -47,6 +47,7 @@ import {
sendWhatsAppMessage,
sendWhatsAppFile,
sendTypingIndicator,
stopTypingIndicator,
sendReadReceipt,
type LidMapper,
} from "./outbound.js";
@@ -1017,6 +1018,11 @@ export class WhatsAppAdapter implements ChannelAdapter {
if (!this.sock) return;
await sendTypingIndicator(this.sock, chatId);
}
async stopTypingIndicator(chatId: string): Promise<void> {
if (!this.sock) return;
await stopTypingIndicator(this.sock, chatId);
}
}
// Export types and config

View File

@@ -168,6 +168,24 @@ export async function sendTypingIndicator(
}
}
/**
* Stop typing indicator for a chat.
* Sends "paused" presence to immediately clear the "typing..." indicator
* instead of waiting for WhatsApp's built-in timeout (~15-25s).
*/
export async function stopTypingIndicator(
sock: import("@whiskeysockets/baileys").WASocket,
chatId: string
): Promise<void> {
if (!sock) return;
try {
await sock.sendPresenceUpdate("paused", chatId);
} catch {
// Ignore presence errors
}
}
/**
* Send read receipt for a message.
*

View File

@@ -725,6 +725,7 @@ export class LettaBot implements AgentSession {
}
} finally {
clearInterval(typingInterval);
adapter.stopTypingIndicator?.(msg.chatId)?.catch(() => {});
}
// Handle no-reply marker